diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/community/zabbix | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/zabbix')
339 files changed, 52909 insertions, 0 deletions
diff --git a/ansible_collections/community/zabbix/.ansible-lint b/ansible_collections/community/zabbix/.ansible-lint new file mode 100644 index 000000000..dca5850ab --- /dev/null +++ b/ansible_collections/community/zabbix/.ansible-lint @@ -0,0 +1,10 @@ +--- +exclude_paths: +- ${HOME}/.cache/ + +skip_list: +- command-instead-of-shell # Use shell only when shell functionality is required +- experimental # all rules tagged as experimental +- meta-no-info # meta/main.yml should contain relevant info +- no-handler # Tasks that run when changed should likely be handlers +- unnamed-task # All tasks should be named diff --git a/ansible_collections/community/zabbix/.github/ISSUE_TEMPLATE/bug_report.md b/ansible_collections/community/zabbix/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..025b9e65d --- /dev/null +++ b/ansible_collections/community/zabbix/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,59 @@ +--- +name: Bug report +about: Create a report to help us improve +title: +labels: +assignees: + +--- + +<!--- Verify first that your issue is not already reported on GitHub --> +<!--- Also test if the latest release and devel branch are affected too --> +<!--- Complete *all* sections as described, this form is processed automatically --> + +##### SUMMARY +<!--- Explain the problem briefly below --> + +##### ISSUE TYPE +- Bug Report + +##### COMPONENT NAME +<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure --> + +##### ANSIBLE VERSION +<!--- Paste verbatim output from "ansible --version" between quotes --> +```paste below + +``` + +##### CONFIGURATION +<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes --> +```paste below + +``` + +##### OS / ENVIRONMENT / Zabbix Version +<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. --> + + +##### STEPS TO REPRODUCE +<!--- Describe exactly how to reproduce the problem, using a minimal test-case --> + +<!--- Paste example playbooks or commands between quotes below --> +```yaml + +``` + +<!--- HINT: You can paste gist.github.com links for larger files --> + +##### EXPECTED RESULTS +<!--- Describe what you expected to happen when running the steps above --> + + +##### ACTUAL RESULTS +<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) --> + +<!--- Paste verbatim command output between quotes --> +```paste below + +```
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/.github/ISSUE_TEMPLATE/feature_request.md b/ansible_collections/community/zabbix/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..033d0feb9 --- /dev/null +++ b/ansible_collections/community/zabbix/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,25 @@ +--- +name: ✨ Feature request +about: Suggest an idea for this project +--- +<!--- Verify first that your feature was not already discussed on GitHub --> +<!--- Complete *all* sections as described, this form is processed automatically --> + +##### SUMMARY +<!--- Describe the new feature/improvement briefly below --> + +##### ISSUE TYPE +- Feature Idea + +##### COMPONENT NAME +<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure --> + +##### ADDITIONAL INFORMATION +<!--- Describe how the feature would be used, why it is needed and what it would solve --> + +<!--- Paste example playbooks or commands between quotes below --> +```yaml + +``` + +<!--- HINT: You can also paste gist.github.com links for larger files --> diff --git a/ansible_collections/community/zabbix/.github/workflows/agent.yml b/ansible_collections/community/zabbix/.github/workflows/agent.yml new file mode 100644 index 000000000..86e377eaf --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/agent.yml @@ -0,0 +1,83 @@ +--- +name: "community.zabbix.zabbix_agent" +on: + push: + paths: + - "roles/zabbix_agent/**" + - "molecule/zabbix_agent/**" + - "molecule/requirements.txt" + - ".github/workflows/agent.yml" + pull_request: + paths: + - "roles/zabbix_agent/**" + - "molecule/zabbix_agent/**" + - "molecule/requirements.txt" + - ".github/workflows/agent.yml" +jobs: + molecule: + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + molecule_distro: + - container: centos8 + image: geerlingguy/docker-rockylinux8-ansible:latest + - container: centos7 + image: geerlingguy/docker-centos7-ansible:latest + - container: fedora32 + image: geerlingguy/docker-fedora32-ansible:latest + - container: ubuntu2004 + image: geerlingguy/docker-ubuntu2004-ansible + - container: pgsql-ubuntu1804 + image: geerlingguy/docker-ubuntu1804-ansible + - container: debian11 + image: geerlingguy/docker-debian11-ansible + - container: debian10 + image: geerlingguy/docker-debian10-ansible + - container: debian9 + image: geerlingguy/docker-debian9-ansible + scenario_name: + - default + - autopsk + - agent2 + - agent2autopsk + exclude: # zabbix-agent2 is not supported on debian8 + - molecule_distro: + container: debian8 + scenario_name: agent2 + - molecule_distro: + container: debian8 + scenario_name: agent2autopsk + + steps: + - name: Check out code + uses: actions/checkout@v1 + + - name: Set up Python 3.9 + uses: actions/setup-python@v1 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r molecule/requirements.txt + + - name: Install ansible.netcommon collection + run: ansible-galaxy collection install ansible.netcommon + + - name: Build the collection + run: | + collection_file=$( basename $(ansible-galaxy collection build -f | awk -F" " '{print $NF}')) + echo "COLLECTION_FILE=$collection_file" >> $GITHUB_ENV + + - name: Install the collection + run: ansible-galaxy collection install $COLLECTION_FILE + + - name: Run role tests + working-directory: molecule/zabbix_agent_tests + run: >- + MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }} + MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }} + MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }} + molecule -c common/molecule.yml test -s ${{ matrix.scenario_name }} diff --git a/ansible_collections/community/zabbix/.github/workflows/javagateway.yml b/ansible_collections/community/zabbix/.github/workflows/javagateway.yml new file mode 100644 index 000000000..2c84dcf1f --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/javagateway.yml @@ -0,0 +1,59 @@ +--- +name: "community.zabbix.zabbix_javagateway" +on: + push: + paths: + - 'roles/zabbix_javagateway/**' + - 'molecule/zabbix_javagateway/**' + - 'molecule/requirements.txt' + - '.github/workflows/javagateway.yml' + pull_request: + paths: + - 'roles/zabbix_javagateway/**' + - 'molecule/zabbix_javagateway/**' + - 'molecule/requirements.txt' + - '.github/workflows/javagateway.yml' +jobs: + molecule: + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + molecule_distro: + - container: centos + image: geerlingguy/docker-centos8-ansible:latest + - container: ubuntu + image: geerlingguy/docker-ubuntu2004-ansible + - container: debian + image: geerlingguy/docker-debian10-ansible + collection_role: + - zabbix_javagateway + steps: + - name: Check out code + uses: actions/checkout@v1 + + - name: Set up Python 3.9 + uses: actions/setup-python@v1 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r molecule/requirements.txt + + - name: Build the collection + run: | + collection_file=$( basename $(ansible-galaxy collection build -f | awk -F" " '{print $NF}')) + echo "COLLECTION_FILE=$collection_file" >> $GITHUB_ENV + + - name: Install the collection + run: ansible-galaxy collection install $COLLECTION_FILE + + - name: Run role tests + run: >- + MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }} + MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }} + MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }} + MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }} + molecule test -s ${{ matrix.collection_role }} diff --git a/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml b/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml new file mode 100644 index 000000000..4e4dd0a30 --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml @@ -0,0 +1,83 @@ +--- +name: plugins-integration +on: + push: + paths: + - "plugins/**" + - "tests/integration/**" + - ".github/workflows/plugins-integration.yml" + pull_request: + paths: + - "plugins/**" + - "tests/integration/**" + - ".github/workflows/plugins-integration.yml" + +jobs: + integration: + runs-on: ubuntu-latest + name: I (${{ matrix.zabbix_container.version}} Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}}) + strategy: + fail-fast: false + matrix: + zabbix_container: + - version: "4.0" + - version: "5.0" + # - version: "5.4" # only activate after basic compatibility + - version: "6.0" + - version: "6.2" + - version: "6.4" + ansible: + # https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-changelogs + - stable-2.12 + - stable-2.13 + - stable-2.14 + - devel + python: + - 3.9 + + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/community/zabbix + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + - name: Install dependencies + run: pip install docker-compose zabbix-api + + - name: Install ansible.netcommon collection + run: ansible-galaxy collection install ansible.netcommon -p /home/runner/work/community.zabbix/community.zabbix + working-directory: ./ansible_collections/community/zabbix + + # For Zabbix integration tests we need to test against different versions of + # the Zabbix server. To do this we spin up a Docker container using the `matrix` + # of version and ports specified earlier. + - name: Zabbix container server provisioning + run: docker-compose up -d + working-directory: ./ansible_collections/community/zabbix + env: + zabbix_version: ${{ matrix.zabbix_container.version }} + + # Run the integration tests + # As we need to connect to an existing docker container we can't use `--docker` here as the VMs would be on different + # (non-routing) networks, so we run them locally and ensure any required dependencies are installed via `--requirements` + - name: Run integration test + run: ansible-test integration -v --color --continue-on-error --diff --python ${{ matrix.python }} --requirements --coverage + working-directory: ./ansible_collections/community/zabbix + + # ansible-test support producing code coverage date + - name: Generate coverage report + run: ansible-test coverage xml -v --requirements --group-by command --group-by version + working-directory: ./ansible_collections/community/zabbix + + # See the repots at https://codecov.io/gh/ansible-collections/community.zabbix + - uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: false diff --git a/ansible_collections/community/zabbix/.github/workflows/proxy.yml b/ansible_collections/community/zabbix/.github/workflows/proxy.yml new file mode 100644 index 000000000..c13634afc --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/proxy.yml @@ -0,0 +1,82 @@ +--- +name: "community.zabbix.zabbix_proxy" +on: + push: + paths: + - "roles/zabbix_proxy/**" + - "molecule/zabbix_proxy/**" + - "molecule/requirements.txt" + - ".github/workflows/proxy.yml" + pull_request: + paths: + - "roles/zabbix_proxy/**" + - "molecule/zabbix_proxy/**" + - "molecule/requirements.txt" + - ".github/workflows/proxy.yml" +jobs: + molecule: + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + molecule_distro: + - container: mysql-centos + image: geerlingguy/docker-rockylinux8-ansible:latest + group: mysql + - container: pgsql-centos + image: geerlingguy/docker-rockylinux8-ansible:latest + group: postgresql + - container: sqlite-centos + image: geerlingguy/docker-rockylinux8-ansible:latest + group: sqlite3 + - container: mysql-ubuntu + image: geerlingguy/docker-ubuntu2004-ansible + group: mysql + - container: pgsql-ubuntu + image: geerlingguy/docker-ubuntu2004-ansible + group: postgresql + command: /sbin/init + - container: sqlite-ubuntu + image: geerlingguy/docker-ubuntu2004-ansible + group: sqlite3 + command: /sbin/init + - container: mysql-debian + image: geerlingguy/docker-debian11-ansible + group: mysql + - container: pgsql-debian + image: geerlingguy/docker-debian11-ansible + group: postgresql + - container: sqlite-debian + image: geerlingguy/docker-debian11-ansible + group: sqlite3 + collection_role: + - zabbix_proxy + steps: + - name: Check out code + uses: actions/checkout@v1 + + - name: Set up Python 3.9 + uses: actions/setup-python@v1 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r molecule/requirements.txt + + - name: Build the collection + run: | + collection_file=$( basename $(ansible-galaxy collection build -f | awk -F" " '{print $NF}')) + echo "COLLECTION_FILE=$collection_file" >> $GITHUB_ENV + + - name: Install the collection + run: ansible-galaxy collection install $COLLECTION_FILE + + - name: Run role tests + run: >- + MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }} + MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }} + MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }} + MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }} + molecule test -s ${{ matrix.collection_role }} diff --git a/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml b/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml new file mode 100644 index 000000000..98954a82f --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml @@ -0,0 +1,73 @@ +--- +name: repo-sanity +on: + push: + pull_request: + +jobs: + tox-linters: + name: Tox-Lint (py${{ matrix.python }}) + strategy: + matrix: + python: + - 3.9 + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/community/zabbix + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + + - name: Install dependencies + run: pip install flake8 tox + + - name: Run lint test for py3 + run: tox -elinters-py3 -vv + working-directory: ./ansible_collections/community/zabbix + if: matrix.python != '2.7' + + sanity: + name: Sanity (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) + strategy: + matrix: + ansible: + # It's important that Sanity is tested against all stable-X.Y branches + # Testing against `devel` may fail as new tests are added. + + # https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-changelogs + - stable-2.12 + - stable-2.13 + - stable-2.14 + - devel + python: + - 3.9 + runs-on: ubuntu-latest + steps: + # ansible-test requires the collection to be in a directory in the form + # .../ansible_collections/NAMESPACE/COLLECTION_NAME/ + + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/community/zabbix + + - name: Set up Python ${{ matrix.ansible }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + + # Install the head of the given branch (devel, stable-2.10) + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + # run ansible-test sanity inside of Docker. + # The docker container has all the pinned dependencies that are required. + # Explicity specify the version of Python we want to test + - name: Run sanity tests + run: ansible-test sanity --docker -v --color --exclude molecule/ --python ${{ matrix.python }} + working-directory: ./ansible_collections/community/zabbix diff --git a/ansible_collections/community/zabbix/.github/workflows/server.yml b/ansible_collections/community/zabbix/.github/workflows/server.yml new file mode 100644 index 000000000..8a8930e02 --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/server.yml @@ -0,0 +1,72 @@ +--- +name: "community.zabbix.zabbix_server" +on: + push: + paths: + - "roles/zabbix_server/**" + - "molecule/zabbix_server/**" + - "molecule/requirements.txt" + - ".github/workflows/server.yml" + pull_request: + paths: + - "roles/zabbix_server/**" + - "molecule/zabbix_server/**" + - "molecule/requirements.txt" + - ".github/workflows/server.yml" +jobs: + molecule: + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + molecule_distro: + - container: mysql-centos + image: geerlingguy/docker-rockylinux8-ansible:latest + group: mysql + - container: pgsql-centos + image: geerlingguy/docker-rockylinux8-ansible:latest + group: postgresql + - container: mysql-ubuntu + image: geerlingguy/docker-ubuntu2004-ansible + group: mysql + - container: pgsql-ubuntu + image: geerlingguy/docker-ubuntu2004-ansible + group: postgresql + command: /sbin/init + - container: mysql-debian + image: geerlingguy/docker-debian11-ansible + group: mysql + - container: pgsql-debian + image: geerlingguy/docker-debian11-ansible + group: postgresql + collection_role: + - zabbix_server + steps: + - name: Check out code + uses: actions/checkout@v1 + + - name: Set up Python 3.9 + uses: actions/setup-python@v1 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r molecule/requirements.txt + + - name: Build the collection + run: | + collection_file=$( basename $(ansible-galaxy collection build -f | awk -F" " '{print $NF}')) + echo "COLLECTION_FILE=$collection_file" >> $GITHUB_ENV + + - name: Install the collection + run: ansible-galaxy collection install $COLLECTION_FILE + + - name: Run role tests + run: >- + MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }} + MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }} + MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }} + MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }} + molecule test -s ${{ matrix.collection_role }} diff --git a/ansible_collections/community/zabbix/.github/workflows/web.yml b/ansible_collections/community/zabbix/.github/workflows/web.yml new file mode 100644 index 000000000..81c506082 --- /dev/null +++ b/ansible_collections/community/zabbix/.github/workflows/web.yml @@ -0,0 +1,71 @@ +--- +name: "community.zabbix.zabbix_web" +on: + push: + paths: + - "roles/zabbix_web/**" + - "molecule/zabbix_web/**" + - "molecule/requirements.txt" + - ".github/workflows/web.yml" + pull_request: + paths: + - "roles/zabbix_web/**" + - "molecule/zabbix_web/**" + - "molecule/requirements.txt" + - ".github/workflows/web.yml" +jobs: + molecule: + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + molecule_distro: + - container: mysql-centos8 + image: geerlingguy/docker-rockylinux8-ansible:latest + group: mysql + - container: pgsql-centos8 + image: geerlingguy/docker-rockylinux8-ansible:latest + group: postgresql + - container: mysql-ubuntu18 + image: geerlingguy/docker-ubuntu1804-ansible + group: mysql + - container: pgsql-ubuntu20 + image: geerlingguy/docker-ubuntu2004-ansible + group: postgresql + - container: mysql-debian + image: geerlingguy/docker-debian11-ansible + group: mysql + - container: pgsql-debian + image: geerlingguy/docker-debian11-ansible + group: postgresql + collection_role: + - zabbix_web + steps: + - name: Check out code + uses: actions/checkout@v1 + + - name: Set up Python 3.9 + uses: actions/setup-python@v1 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r molecule/requirements.txt + + - name: Build the collection + run: | + collection_file=$( basename $(ansible-galaxy collection build -f | awk -F" " '{print $NF}')) + echo "COLLECTION_FILE=$collection_file" >> $GITHUB_ENV + + - name: Install the collection + run: ansible-galaxy collection install $COLLECTION_FILE + + - name: Run role tests + run: >- + MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }} + MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }} + MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }} + MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }} + molecule test -s ${{ matrix.collection_role }} diff --git a/ansible_collections/community/zabbix/.gitignore b/ansible_collections/community/zabbix/.gitignore new file mode 100644 index 000000000..a27e8241a --- /dev/null +++ b/ansible_collections/community/zabbix/.gitignore @@ -0,0 +1,22 @@ +tests/output +__pycache__ + +# ignore visual studio code things, and intelliJ +.vscode +.idea + +# ignore Python Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# unit test +.tox/ + +# ignore dev stuff +.devcontainer +local_play.yml diff --git a/ansible_collections/community/zabbix/.yamllint b/ansible_collections/community/zabbix/.yamllint new file mode 100644 index 000000000..1de050bc6 --- /dev/null +++ b/ansible_collections/community/zabbix/.yamllint @@ -0,0 +1,20 @@ +--- +# Based on ansible-lint config +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + indentation: + spaces: consistent + indent-sequences: whatever + key-ordering: disable + line-length: disable + new-lines: + type: unix + truthy: + check-keys: false diff --git a/ansible_collections/community/zabbix/CHANGELOG.rst b/ansible_collections/community/zabbix/CHANGELOG.rst new file mode 100644 index 000000000..cf83e116c --- /dev/null +++ b/ansible_collections/community/zabbix/CHANGELOG.rst @@ -0,0 +1,615 @@ +============================== +community.zabbix Release Notes +============================== + +.. contents:: Topics + + +v1.9.3 +====== + +Minor Changes +------------- + +- httpapi plugin - updated to work with Zabbix 6.4. +- zabbix_action, zabbix_authentication, zabbix_discovery_rule, zabbix_mediatype, zabbix_user, zabbix_user_directory, zabbix_usergroup - updated to work with Zabbix 6.4. +- zabbix_agent role - Add support for SUSE Linux Enterprise Server for SAP Applications ("SLES_SAP"). +- zabbix_host - add missing variants for SNMPv3 authprotocol and privprotocol introduced by Zabbix 6 +- zabbix_proxy role - Add variable zabbix_proxy_dbpassword_hash_method to control whether you want postgresql user password to be hashed with md5 or want to use db default. When zabbix_proxy_dbpassword_hash_method is set to anything other than md5 then do not hash the password with md5 so you could use postgresql scram-sha-256 hashing method. +- zabbix_server role - Add variable zabbix_server_dbpassword_hash_method to control whether you want postgresql user password to be hashed with md5 or want to use db default. When zabbix_server_dbpassword_hash_method is set to anything other than md5 then do not hash the password with md5 so you could use postgresql scram-sha-256 hashing method. +- zabbix_usergroup module - userdirectory, hostgroup_rights and templategroup_rights parameters added (Zabbix >= 6.2) +- zabbix_web role - possibility to add custom includes in apache vhost config + +Bugfixes +-------- + +- compatibility with ansible.netcommon 5.0.0 +- treat sendto parameter in module zabbix_user according to real media type, do not rely on media name +- zabbix-proxy role - fix tags for postgresql task. +- zabbix_agent role - Fix MacOS install never executed because of the missing include_tasks "Darwin.yml" in the "main.yml" task file and wrong user permission on folder/files. +- zabbix_user module - ability to specify several e-mail addresses in Zabbix User's media + +v1.9.2 +====== + +Bugfixes +-------- + +- zabbix_agent and zabbix_proxy roles - fixed a bug whith ansible_python_interpreter not being set correctly in some corner cases +- zabbix_agent role - Fix MacOS install never executed because of the missing include_tasks "Darwin.yml" in the "main.yml" task file and wrong user permission on folder/files. +- zabbix_agent, zabbix_proxy and zabbix_server roles - make Ansible 2.14 compatible by removing warn parameter + +v1.9.1 +====== + +Minor Changes +------------- + +- zabbix suport for rhel 9 + +Bugfixes +-------- + +- all modules - remove deprecation warnings for modules parameters related to zabbix-api when these parapmeters are not explicetely defined +- all roles and modules integration tests - replace deprecated include module whith include_tasks +- zabbix_agent, zabbix_proxy roles, all modules - make httpapi connection work with HTTP Basic Authorization +- zabbix_proxy - do not set ServerPort config parameter which was removed in Zabbix 6.0 +- zabbix_server role Debian.yml task - remove warn: arg for shell module as the arg is deprecated since ansible-core above 2.13 +- zabbix_user_role module - creation of a User Role with Super Admin type + +v1.9.0 +====== + +Major Changes +------------- + +- all modules are opting away from zabbix-api and using httpapi ansible.netcommon plugin. We will support zabbix-api for backwards compatibility until next major release. See our README.md for more information about how to migrate +- zabbix_agent and zabbix_proxy roles are opting away from zabbix-api and use httpapi ansible.netcommon plugin. We will support zabbix-api for backwards compatibility until next major release. See our README.md for more information about how to migrate + +Minor Changes +------------- + +- ansible_zabbix_url_path introduced to be able to specify non-default Zabbix WebUI path, e.g. http://<FQDN>/zabbixeu +- collection now supports creating ``module_defaults`` for ``group/community.zabbix.zabbix`` (see https://github.com/ansible-collections/community.zabbix/issues/326) +- fixed ``zabbix_server`` role failure running in check_mode (see https://github.com/ansible-collections/community.zabbix/issues/804) +- zabbix_agent - give Zabbix Agent access to the Linux DMI table allowing system.hw.chassis info to populate. +- zabbix_template - add support for template tags +- zabbix_user_role module added +- zabbix_web - add support for Ubuntu 22.04 jammy + +Bugfixes +-------- + +- The inventory script had insufficient error handling in case the Zabbix API provided an empty interfaces list. This bugfix checks for an exisiting interfaces element, then for the minimal length of 1 so that the first interface will only be accessed when it really exists in the api response. (https://github.com/ansible-collections/community.zabbix/issues/826) +- zabbix-proxy - updated to install correct sources for Debian arm64 family +- zabbix_agent - Filter IPv6 addresses from list of IP as Zabbix host creation expects IPv4 +- zabbix_agent - installation on Windows will no longer fail when zabbix_agent2 is used +- zabbix_host - fix updating of host without interfaces +- zabbix_proxy - correctly provision tls_accept and tls_connect on Zabbix backend +- zabbix_proxy - updated the datafiles_path fact for the zabbix_proxy and zabbix_server roles due to upstream change +- zabbix_server - move location of the fping(6) variables to distribution specific files (https://github.com/ansible-collections/community.zabbix/issues/812) +- zabbix_server - updated the datafiles_path fact for the zabbix_proxy and zabbix_server roles due to upstream change + +v1.8.0 +====== + +Minor Changes +------------- + +- roles - Minimized the config templates for the zabbix_agent, zabbix_javagateway, zabbix_proxy, and zabbix_server roles to make them version independent. +- roles - Support for Zabbix 6.2 has been added +- roles - Updated the version defaults to select the latest version supported by an operating system. +- zabbix_action - added another condition operator naming options (contains, does not contain,...) +- zabbix_agent - Set a ansible_python_interpreter to localhost based on the env the playbook is executed from. +- zabbix_agent - add option to set host tags using ``zabbix_agent_tags``. +- zabbix_agent - add possiblity to set include file pattern using ``zabbix_agent(2)_include_pattern`` variable. +- zabbix_agent - is now able to manage directories and upload files for TLS PSK configuration used with Windows operating systems +- zabbix_agent - new options for Windows installations zabbix_win_install_dir_conf/bin +- zabbix_agent - when configuring firewalld, make sure the new rule is applied immediately +- zabbix_authentication - module updated to support Zabbix 6.2 +- zabbix_host - using ``tls_psk_identity`` or ``tls_psk`` parameters with Zabbix >= 5.4 makes this module non-idempotent +- zabbix_host - will no longer wipe tls_connect en tls_accept settings when not specified on update +- zabbix_mediatype - added support for time units in ``attempt_interval`` parameter +- zabbix_template - added support for template groups (Zabbix >= 6.2) +- zabbix_template_info - add template_id return value +- zabbix_template_info - add yaml and none formats +- zabbix_user_directory - added new module to support multiple sources for LDAP authentication + +Bugfixes +-------- + +- zabbix_host - fixed idempotency of the module when hostmacros or snmp interfaces are used +- zabbix_script - fix compatibility with Zabbix <5.4. +- zabbix_script - should no longer fail when description is not set + +v1.7.0 +====== + +Minor Changes +------------- + +- helpers.helper_compare_lists() changed logic to not consider the order of elements in lists. (https://github.com/ansible-collections/community.zabbix/pull/683) +- zabbix_action, zabbix_maintenance, zabbix_mediatype, zabbix_proxy, zabbix_service - updated to work with Zabbix 6.0. (https://github.com/ansible-collections/community.zabbix/pull/683) +- zabbix_script module added (https://github.com/ansible-collections/community.zabbix/issues/634) + +Bugfixes +-------- + +- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``. +- zabbix_action - will no longer wipe `esc_step_to` and `esc_step_from` (https://github.com/ansible-collections/community.zabbix/issues/692) +- zabbix_agent - added support for zabbix-agent on Ubuntu 22.04 (https://github.com/ansible-collections/community.zabbix/pull/681) +- zabbix_agent - now properly creates webroot for issuing LE certificates (https://github.com/ansible-collections/community.zabbix/pull/677, https://github.com/ansible-collections/community.zabbix/pull/682) +- zabbix_proxy (module) - passive proxy should be now correctly created in Zabbix 6.0 (https://github.com/ansible-collections/community.zabbix/pull/697) +- zabbix_proxy (role) - fixed accidental regression of TLS psk file being generated for passive agent (#528) caused in (#663) (https://github.com/ansible-collections/community.zabbix/issues/680) + +New Modules +----------- + +- community.zabbix.zabbix_script - Create/update/delete Zabbix scripts + +v1.6.0 +====== + +Minor Changes +------------- + +- all modules - prepare for deprecation of distutils LooseVersion. +- collection - Add dependencies to other collections. This helps Ansible Galaxy automatically downloading collections that this collection relies on to run. +- connection.httpapi (plugin) - add initial httpapi connection plugin. +- httpapi.jsonrpc (plugin) - add initial httpapi for future handling of json-rpc. +- new module zabbix authentication for configuring global authentication settings in Zabbix Server's Settings section of GUI. +- new module zabbix_autoregister for configuring global autoregistration settings in Zabbix Server's Settings section of GUI. +- new module zabbix_housekeeping for configuring global housekeeping settings in Zabbix Server's Settings section of GUI. +- test_zabbix_host_info - fix Template/Group names for 5.4 +- test_zabbix_screen - disable testing for screen in 5.4 (deprecated) +- zabbix_action - additional fixes to make module work with Zabbix 6.0 (https://github.com/ansible-collections/community.zabbix/pull/664) +- zabbix_action - module ported to work with Zabbix 6.0 (https://github.com/ansible-collections/community.zabbix/pull/648, https://github.com/ansible-collections/community.zabbix/pull/653) +- zabbix_action - should now correctly actions with maintenance_status conditions (https://github.com/ansible-collections/community.zabbix/pull/667) +- zabbix_agent - Check if 'firewalld' exist and is running when handler is executed. +- zabbix_agent - Fixed use of bare variables in conditions (https://github.com/ansible-collections/community.zabbix/pull/663) +- zabbix_agent - Install the correct Python libxml2 package on SLES15 +- zabbix_agent - Move inclusion of the apache.yml tasks to later stage during execution of role. +- zabbix_agent - Prepare for Zabbix 6.0. +- zabbix_agent - Specify a minor version with zabbix_agent_version_minor for RH systems. +- zabbix_agent - There was no way to configure a specific type for the macro. +- zabbix_agent - Use multiple aliases in the configuration file with ``zabbix_agent_zabbix_alias`` or ``zabbix_agent2_zabbix_alias``. +- zabbix_maintenance - added new module parameter `tags`, which allows configuring Problem Tags on maintenances. +- zabbix_maintenance - fixed to work with Zabbix 6.0+ and Python 3.9+ (https://github.com/ansible-collections/community.zabbix/pull/665) +- zabbix_proxy - Prepare for Zabbix 6.0. +- zabbix_proxy - Specify a minor version with zabbix_proxy_version_minor for RH systems. +- zabbix_proxy - Support for Sangoma and treat it like a RHEL system. +- zabbix_server - Check the 'zabbix_server_install_database_client' variable in RedHat tasks. +- zabbix_server - Prepare for Zabbix 6.0. +- zabbix_server - Specify a minor version with zabbix_server_version_minor for RH systems. +- zabbix_user - change alias property to username (changed in 5.4) (alias is now an alias for username) +- zabbix_user_info - change alias property to username (changed in 5.4) (alias is now an alias for username) +- zabbix_web - Change format ENCRYPTION, VERIFY_HOST from string to boolean. +- zabbix_web - Specify a minor version with zabbix_web_version_minor for RH systems. + +Bugfixes +-------- + +- Various modules and plugins - use vendored version of ``distutils.version`` instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.zabbix/pull/603). This superseedes #597. +- ZapiWrapper (module_utils) - fix only partial zabbix version is returned. +- zabbix_agent - Install Zabbix packages when zabbix_repo == other is used with yum. +- zabbix_agent - Install the Agent for MacOSX sooner than its configuration. +- zabbix_agent - The ``Install gpg key`` task for Debian did not work when a http proxy is configured. +- zabbix_agent - Use the correct URL with correct version. +- zabbix_agent - Use the correct path to determine Zabbix Agent 2 installation on Windows. +- zabbix_agent - Using the correct hostgroup as default now. +- zabbix_agent - fix for the autopsk, incl. tests with Molecule. +- zabbix_host - Added small notification that an user should have read access to get hostgroups overview. +- zabbix_host - adapter changed properties for interface comparisson +- zabbix_maintenance - should now work when creating maintenace on Zabbix 6.0 server +- zabbix_proxy - 'zcat' the zipped sql files to /tmp before executing it. +- zabbix_proxy - Check MySQL version before settings mysql_innodb_default_row_format value. +- zabbix_proxy - Install Zabbix packages when zabbix_repo == other is used with yum. +- zabbix_server - 'zcat' the zipped sql files to /tmp before executing it. +- zabbix_server - Check MySQL version before settings mysql_innodb_default_row_format value. +- zabbix_server - Install Zabbix packages when zabbix_repo == other is used with yum. +- zabbix_template - setting correct null values to fix unintentional changes +- zabbix_web - Added some default variables if the geerlingguys apache role is not used. +- zabbix_web - Specified the correct versions for php. + +New Plugins +----------- + +Connection +~~~~~~~~~~ + +- community.zabbix.httpapi - Use httpapi to run command on network appliances + +Httpapi +~~~~~~~ + +- community.zabbix.jsonrpc - HttpApi Plugin for Zabbix + +New Modules +----------- + +- community.zabbix.zabbix_authentication - Update Zabbix authentication +- community.zabbix.zabbix_autoregister - Update Zabbix autoregistration +- community.zabbix.zabbix_housekeeping - Update Zabbix housekeeping + +v1.5.1 +====== + +Minor Changes +------------- + +- Enabled usage of environment variables for modules by adding a fallback lookup in the module_utils/helpers.py - zabbix_common_argument_spec + +Bugfixes +-------- + +- template - use templateid property when linking templates for ``template.create`` and ``template.update`` API calls. +- zabbix inventory - Moved ZABBIX_VALIDATE_CERTS to correct option, validate_certs. +- zabbix_agent - Create the actual configuration file for Windows setups. +- zabbix_agent - Fix typo for correct using the zabbix_windows_service.exists +- zabbix_agent - tlspsk_auto to support become on Linux and ignore on windows +- zabbix_user - fix zabbix_user require password only on internal. + +v1.5.0 +====== + +Minor Changes +------------- + +- Added requirements.txt to collection root to be used with Ansible Builder. See https://ansible-builder.readthedocs.io/en/latest/collection_metadata.html +- some roles are now using new naming for API connection parameters (https://github.com/ansible-collections/community.zabbix/pull/492 and https://github.com/ansible-collections/community.zabbix/pull/495). +- some roles can now utilize an option `zabbix_repo_yum_gpgcheck` to enable/disable GPG check for YUM repository (https://github.com/ansible-collections/community.zabbix/pull/438). +- zabbix inventory - Enabled the usage of environment variables in zabbix inventory plugin. +- zabbix inventory plugin - can now use environment variables ZABBIX_SERVER, ZABBIX_USERNAME and ZABBIX_PASSWORD for connection purposes to the Zabbix API. +- zabbix_agent - `zabbix_agent_loadmodule` can also be configured with a list. +- zabbix_agent - new `zabbix_api_timeout` option. +- zabbix_agent - now supports DenyKeys configuration. +- zabbix_hostmacro - now supports creating macros of type secret and vault. +- zabbix_proxy (role) - new `zabbix_api_timeout` option. +- zabbix_proxy_info - new module that allows to retrieve information about configured Zabbix Proxies. +- zabbix_server - added support for TimescaleDB (https://github.com/ansible-collections/community.zabbix/pull/428). + +Breaking Changes / Porting Guide +-------------------------------- + +- all roles now reference other roles and modules via their fully qualified collection names, which makes Ansible 2.10 minimum supported version for roles (See https://github.com/ansible-collections/community.zabbix/pull/477). + +Bugfixes +-------- + +- all roles now support installing zabbix 4.0 version on Ubuntu 20.04. +- all roles now supports installations on Debian 11. +- zabbix inventory - Change default value for host_zapi_query from list "[]" to dict "{}". +- zabbix_action - should no longer fail with Zabbix version 5.4. +- zabbix_agent - `zabbix_win_install_dir` no longer ignored for zabbix_agentd.d and zabbix log directories. +- zabbix_agent - auto-recovery for Windows installation has been fixed (https://github.com/ansible-collections/community.zabbix/pull/470). +- zabbix_agent - deploying zabbix_agent2 under Windows should now be possible (Thanks to https://github.com/ansible-collections/community.zabbix/pull/433 and https://github.com/ansible-collections/community.zabbix/pull/453). +- zabbix_agent - fixed AutoPSK for Windows deployments (https://github.com/ansible-collections/community.zabbix/pull/450). +- zabbix_host - Fix error when updating hosts caused by Zabbix bug not returning the inventory_mode field for hosts(https://github.com/ansible-collections/community.zabbix/issues/385). +- zabbix_host - will not break when `tls_psk*` parameters are set with Zabbix version 5.4. +- zabbix_proxy (module) - now supports configuring `tls_psk*` parameters. +- zabbix_proxy (role) - TLS config should now properly configure certificates. +- zabbix_proxy (role) - should no longer fail on permission problems wren configured to use SQLite database and now installs correct package sqlite3 on Debian systems. +- zabbix_web - `zabbix_nginx_vhost_*` parameters are no longer ignored. +- zabbix_web - executing role with `--tags` should now correctly include distribution specific variables (https://github.com/ansible-collections/community.zabbix/pull/448). +- zabbix_web - now correctly restarts php-fpm service (https://github.com/ansible-collections/community.zabbix/pull/427). +- zabbix_web - permissions for accesing php-fpm socket has been fixed (See https://github.com/ansible-collections/community.zabbix/pull/426). + +New Modules +----------- + +- community.zabbix.zabbix_proxy_info - Gather information about Zabbix proxy + +v1.4.0 +====== + +Minor Changes +------------- + +- all roles were updated to support Zabbix 5.4 release (https://github.com/ansible-collections/community.zabbix/pull/405) +- new inventory plugin zabbix_inventory (https://github.com/ansible-collections/community.zabbix/pull/373) +- new module plugin zabbix_globalmacro (https://github.com/ansible-collections/community.zabbix/pull/377) +- zabbix_agent - `zabbix_agent_src_reinstall` now defaults to `False` (https://github.com/ansible-collections/community.zabbix/pull/403) +- zabbix_agent - now supports setting AllowKey (https://github.com/ansible-collections/community.zabbix/pull/358) +- zabbix_globalmacros - it is now possible to create global macros using this module (https://github.com/ansible-collections/community.zabbix/pull/377). +- zabbix_inventory - Created Ansible - Zabbix inventory plugin to create dynamic inventory from Zabbix. +- zabbix_maintenance - it is now possible to target hosts by their technical name if it differs from the visible name +- zabbix_proxy - Add MySQL Python 3 package installation. +- zabbix_server - Add MySQL Python 3 package installation. +- zabbix_server - now supports setting StartLLDProcessors (https://github.com/ansible-collections/community.zabbix/pull/361) +- zabbix_user - now supports parameter `username` as an alternative to `alias` (https://github.com/ansible-collections/community.zabbix/pull/406) +- zabbix_user - removed some of the default values because a configuration should be changed only if specified as a parameter (https://github.com/ansible-collections/community.zabbix/pull/382). +- zabbix_web - now supports setting SAML certificates (https://github.com/ansible-collections/community.zabbix/pull/408) + +Bugfixes +-------- + +- zabbix_agent - StatusPort will be configured only when `zabbix_agent2_statusport` is defined (https://github.com/ansible-collections/community.zabbix/pull/378) +- zabbix_agent - fixed issue preventing installation of zabbix-agent 4.2 on Ubuntu Focal 20.04 (https://github.com/ansible-collections/community.zabbix/pull/390) +- zabbix_agent - role will now configure correct port for hostinterface in Zabbix Server if `zabbix_agent2_listenport` is defined (https://github.com/ansible-collections/community.zabbix/pull/400) +- zabbix_agent - should no longer be failing on Windows platform due to re-running all of the tasks for the 2nd time (https://github.com/ansible-collections/community.zabbix/pull/376) +- zabbix_agent - should no longer fail while cleaning up zabbix_agent installation if Zabbix Agent2 is being used (https://github.com/ansible-collections/community.zabbix/pull/409) +- zabbix_agent - will no longer install zabbix_get package on Debian systems when `zabbix_agent_install_agent_only` is defined (https://github.com/ansible-collections/community.zabbix/pull/363) +- zabbix_host - fixed issue where module was idempotent when multiple host interfaces of the same type were present (https://github.com/ansible-collections/community.zabbix/pull/391) +- zabbix_proxy (role) - will no longer fail on proxy creation in Zabbix Server when TLS parameters are used (https://github.com/ansible-collections/community.zabbix/pull/388) +- zabbix_server - Removed the removal everything from /tmp directory command as it removes things that it shouldnt do. +- zabbix_template - first time import of template now works with Zabbix 5.4 (https://github.com/ansible-collections/community.zabbix/pull/407), please note that rerunning the task will fail as there are breaking changes in Zabbix 5.4 API that module not yet covers. +- zabbix_user - now works with Zabbix 5.4 (https://github.com/ansible-collections/community.zabbix/pull/406) + +New Plugins +----------- + +Inventory +~~~~~~~~~ + +- community.zabbix.zabbix_inventory - Zabbix Inventory Plugin + +New Modules +----------- + +- community.zabbix.zabbix_globalmacro - Create/update/delete Zabbix Global macros + +v1.3.0 +====== + +Release Summary +--------------- + +| Release date: 2021-03-20 | Last major release to support Zabbix server 3.X versions in plugins. + +Minor Changes +------------- + +- zabbix_agent - added support for installations on arm64 systems (https://github.com/ansible-collections/community.zabbix/pull/320). +- zabbix_proxy - now supports configuring StatsAllowedIP (https://github.com/ansible-collections/community.zabbix/pull/337). +- zabbix_server - added support for installtions on arm64 systems (https://github.com/ansible-collections/community.zabbix/pull/320). +- zabbix_web - added support for installtions on arm64 systems (https://github.com/ansible-collections/community.zabbix/pull/320). + +Security Fixes +-------------- + +- zabbix_action - no longer exposes remote SSH command password used in operations, recovery & acknowledge operations to system logs (https://github.com/ansible-collections/community.zabbix/pull/345). +- zabbix_discovery_rule - no longer exposes SNMPv3 auth and priv passphrases to system logs (https://github.com/ansible-collections/community.zabbix/pull/345). +- zabbix_host - no longer exposes SNMPv3 auth and priv passphrases to system logs (https://github.com/ansible-collections/community.zabbix/pull/345). + +Bugfixes +-------- + +- zabbix_action - now properly filters discovery rule checks by name (https://github.com/ansible-collections/community.zabbix/pull/349). +- zabbix_agent - corrected version for Windows agents (https://github.com/ansible-collections/community.zabbix/pull/316). +- zabbix_agent - fixed download URL for MacOS (https://github.com/ansible-collections/community.zabbix/pull/325). +- zabbix_server - now installs correct MySQL client packages on RHEL8 systems (https://github.com/ansible-collections/community.zabbix/pull/343). +- zabbix_template - fixed an issue with Python2 where module wouldn't decode Unicode characters (https://github.com/ansible-collections/community.zabbix/pull/322). +- zabbix_web - fixed installation of python3-libsemanage package RHEL7 and older systems (https://github.com/ansible-collections/community.zabbix/pull/330). +- zabbix_web - role should now correctly determine naming of PHP packages on older systems (https://github.com/ansible-collections/community.zabbix/pull/344). +- zabbix_web - updated default PHP version for Debian10 (https://github.com/ansible-collections/community.zabbix/pull/323). + +v1.2.0 +====== + +Release Summary +--------------- + +| Release date: 2021-01-11 | Last major release to support Zabbix server 3.X versions in plugins. + +Minor Changes +------------- + +- Updated the roles to support Zabbix 5.2. +- zabbix_agent - Added a new property `zabbix_agent_dont_detect_ip` when set to true, it won't detect the ips and no need to install the python module `netaddr`. +- zabbix_agent - Added parameter `zabbix_agent_package_remove` when set to `true` and `zabbix_agent2` is set to `true` it will uninstall the `zabbix-agent` service and package. +- zabbix_agent - added `zabbix_agent_install_agent_only` Will only install the Zabbix Agent package and not the `zabbix-sender` or `zabbix-get` packages. +- zabbix_template - Fixed to decode Unicode Escape of multibyte strings in an importing template data(https://github.com/ansible-collections/community.zabbix/pull/226). +- zabbix_user - added new parameters to set timezone and role_name for users (https://github.com/ansible-collections/community.zabbix/pull/260). +- zabbix_user - user_medias now defaults to None and is optional (https://github.com/ansible-collections/community.zabbix/pull/264). +- zabbix_web - added `zabbix_web_rhel_release` which enable scl on RHEL (https://github.com/ansible-collections/community.zabbix/pull/266). +- zabbix_web - quality of life improvements when using Nginx (https://github.com/ansible-collections/community.zabbix/pull/304). + +Bugfixes +-------- + +- When installing the Zabbix packages, we disable all other yum repositories except the one for the Zabbix. +- zabbix_agent - Agent 2 also be able to use userparameters file. +- zabbix_agent - Also work on SLES 12 sp5 +- zabbix_agent - Documented the property 'zabbix_proxy_ip' in the documentation. +- zabbix_agent - There was an task that wasn't able to use an http(s)_proxy environment while installing an package. +- zabbix_agent - Windows - Able to create PSK file +- zabbix_agent - Windows - Fixing download links to proper version/url +- zabbix_agent - Windows - Removal of not working property +- zabbix_agent - Zabbix packages were not able to install properly on Fedora. When the packages are installed, the version will be appended to the package name. This is eofr all RedHat related OS'es. +- zabbix_agent - fixed issue with zabbix_agent2_tlspsk_auto having no effect when using zabbix_agent2 +- zabbix_agent - fixed issue with zabbix_api_create_hosts and TLS configuration when using zabbix_agent2, where zabbix_agent_tls* settings were used instead of zabbix_agent2_tls* +- zabbix_host - module will no longer require ``interfaces`` to be present when creating host with Zabbix 5.2 (https://github.com/ansible-collections/community.zabbix/pull/291). +- zabbix_host - should no longer fail with 'host cannot have more than one default interface' error (https://github.com/ansible-collections/community.zabbix/pull/309). +- zabbix_proxy (role) - Added missing paragraph for the SQLite3 as database. +- zabbix_proxy (role) - The become option was missing in some essential tasks when installing the Zabbix Proxy with SQLite3 as database. +- zabbix_proxy (role) - Various documentation fixes removing the Zabbix Server and replaced it with actual Zabbix Proxy information. +- zabbix_proxy - Added new property 'zabbix_proxy_ip' to determine ip for host running the Zabbix Proxy. +- zabbix_proxy - The 'interface' option was missing when creating an Proxy via the API. +- zabbix_template - fixed documentation for ``macros`` argument (https://github.com/ansible-collections/community.zabbix/pull/296). +- zabbix_template - fixed encode error when using Python2 (https://github.com/ansible-collections/community.zabbix/pull/297). +- zabbix_template - fixed issue when importing templates to zabbix version. >= 5.2 +- zabbix_template_info - fixed encode error when using Python2 (https://github.com/ansible-collections/community.zabbix/pull/297). +- zabbix_user - disable no_log warning for option override_password. +- zabbix_user - fixed issue where module couldn't create a user since Zabbix 5.2 (https://github.com/ansible-collections/community.zabbix/pull/260). +- zabbix_web - fixed issue Role cannot install Zabbix web 5.0 on RHEL 7 (https://github.com/ansible-collections/community.zabbix/issues/202). + +v1.1.0 +====== + +Release Summary +--------------- + +| Release date: 2020-10-22 + + +Minor Changes +------------- + +- all roles - added ``zabbix_{agent,web,server,proxy,javagateway}_conf_mode`` option for configuring a mode of the configuration file for each Zabbix service. +- zabbix_proxy (role) - added an option ``innodb_default_row_format`` for MariaDB/MySQL if it isn't set to ``dynamic``. +- zabbix_server - fixed installation output when using MySQL database to not print PostgreSQL. +- zabbix_user - ``passwd`` no longer required when ALL groups in ``usrgrps`` use LDAP as ``gui_access`` (see `#240 <https://github.com/ansible-collections/community.zabbix/issues/232>`_). +- zabbix_user - no longer requires ``usrgrps`` when ``state=absent`` (see `#240 <https://github.com/ansible-collections/community.zabbix/issues/232>`_). +- zabbix_web - added several configuration options for the PHP-FPM setup to configure the listen (socket) file. +- zabbix_web - added support for configuring Zabbix Web with Nginx, same way as with Apache. + +Bugfixes +-------- + +- all roles - missing ``become`` set to ``true`` was added to each task that requires admin privleges. +- zabbix_agent - added new properties and updated documentation to allow for correct Zabbix Agent2 configuration. +- zabbix_agent - fixed bug where Nginx prevented Apache from working as it was part of the FPM configuration. + +v1.0.0 +====== + +Release Summary +--------------- + +| Release date: 2020-08-16 + + +Minor Changes +------------- + +- Added the possibility to configure the ``mode`` for the ``zabbix_{agent,server,proxy}_include`` directories. +- all roles - added the possibility to configure the ``mode`` for the ``yum`` repositories files in case it contains credentials. +- zabbix_agent - ``zabbix-sender`` and ``zabbix-get`` will not be installed when ``zabbix_repo`` is set to ``epel``, as they are not part of the repository. +- zabbix_agent - added option to change between HTTP/HTTPS with ``zabbix_repo_yum_schema``. +- zabbix_agent - can also install the zabbix-agent2 application when ``zabbix_agent2`` is set to ``true``. +- zabbix_proxy (role) - a user and group are created on the host when ``zabbix_repo`` is set to ``epel``. +- zabbix_proxy (role) - now supports ``startpreprocessors`` setting and encryption when connecting to database (see `#164 <https://github.com/ansible-collections/community.zabbix/pull/164>`_). +- zabbix_server - a user and group are created on the host when ``zabbix_repo`` is set to ``epel``. +- zabbix_server - added option to change between HTTP/HTTPS with ``zabbix_repo_yum_schema``. +- zabbix_server - now supports ``startpreprocessors`` setting and encryption when connecting to database (see `#164 <https://github.com/ansible-collections/community.zabbix/pull/164>`_). +- zabbix_web - a property is added ``zabbix_web_doubleprecision`` which currently is set to ``false`` for default installations. For new installations this should be set to ``True``. For upgraded installations, please read database `upgrade notes <https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500>`_ (Paragraph "Enabling extended range of numeric (float) values") before enabling this option. +- zabbix_web - added option to change between HTTP/HTTPS with ``zabbix_repo_yum_schema``. +- zabbix_web - don't remove the files that Zabbix will install during installation when you don't want to configure a virtual host configuration. + +Breaking Changes / Porting Guide +-------------------------------- + +- zabbix_javagateway - options ``javagateway_pidfile``, ``javagateway_listenip``, ``javagateway_listenport`` and ``javagateway_startpollers`` renamed to ``zabbix_javagateway_xyz`` (see `UPGRADE.md <https://github.com/ansible-collections/community.zabbix/blob/main/docs/UPGRADE.md>`_). + +Bugfixes +-------- + +- all roles - a ``handler`` is configured when ``zabbix_http(s)_proxy`` is defined which will remove the proxy line from the repository files. This results that execution of the roles are not idempotent anymore. +- zabbix_proxy (role) - ``StartPreprocessors`` only works with version 4.2 or higher. When a lower version is used, it will not be added to the configuration. +- zabbix_proxy (role) - only install the sql files that needs to be executed for when ``zabbix_repo`` is set to ``epel``. +- zabbix_server - ``StartPreprocessors`` only works with version 4.2 or higher. When a lower version is used, it will not be added to the configuration. +- zabbix_server - only install the sql files that needs to be executed for when ``zabbix_repo`` is set to ``epel``. + +v0.3.0 +====== + +Release Summary +--------------- + +| Release date: 2020-07-26 + + +Minor Changes +------------- + +- All roles now **support Zabbix 5.0** and by default install this version (see `#131 <https://github.com/ansible-collections/community.zabbix/pull/131>`_ and `#121 <https://github.com/ansible-collections/community.zabbix/pull/121>`_). +- Roles will now install gnupg on Debian OS family if not present. +- zabbix_action - no longer requires ``password`` and ``ssh_*key_file`` parameters at the same time for ``remote_command`` operations of type SSH. +- zabbix_action - parameter ``ssh_auth_type`` for SSH ``remote_command`` operation now correctly identifies which other parameters are required. +- zabbix_discovery_rule - refactoring module to use ``module_utils`` classes and functions, adjust return values on success, add documentation for return values. +- zabbix_discovery_rule - refactoring the module to remove unnecessary variables and fix a variable typo. +- zabbix_mediatype - new options ``message_templates``, ``description`` and many more related to ``type=webhook``. +- zabbix_mediatype - now supports new ``webhook`` media type. + +Bugfixes +-------- + +- zabbix_action - choices for the ``inventory`` paramter sub option in ``*operations`` arguments have been clarified to ``manual`` and ``automatic``. +- zabbix_action - fixed error on changed API fields ``*default_message`` and ``*default_subject`` for Zabbix 5.0 (see `#92 <https://github.com/ansible-collections/community.zabbix/pull/92>`_). +- zabbix_action - module will no longer fail when searching for global script provided to ``script_name`` parameter. +- zabbix_action - now correctly selects mediatype for the (normal|recovery|update) operations with Zabbix 4.4 and newer. +- zabbix_agent - fixed installation of agent on Windows to directories with spaces. +- zabbix_agent - role should no longer fail when looking for ``getenforce`` binary. +- zabbix_host - module will no longer convert context part of user macro to upper case. +- zabbix_proxy (role) - will now correctly install python3-libsemanage on RHEL OS family. +- zabbix_service - fixed the zabbix_service has no idempotency with Zabbix 5.0. +- zabbix_web - now no longer fails when rendering apache vhost template. + +New Modules +----------- + +- community.zabbix.zabbix_discovery_rule - Create/delete/update Zabbix discovery rules +- community.zabbix.zabbix_usergroup - Create/delete/update Zabbix user groups + +v0.2.0 +====== + +Release Summary +--------------- + +| Release date: 2020-06-15 + +Minor Changes +------------- + +- Documentation for roles moved to ``docs/`` sub-directory in the collection. +- New **role zabbix_agent** - previously known as dj-wasabi/zabbix-agent (also see `UPGRADE.md <https://github.com/ansible-collections/community.zabbix/blob/main/docs/UPGRADE.md>`_ for each role). +- New **role zabbix_javagateway** - previously known as dj-wasabi/zabbix-javagateway. +- New **role zabbix_proxy** - previously known as dj-wasabi/zabbix-proxy. +- New **role zabbix_server** - previously known as dj-wasabi/zabbix-server. +- New **role zabbix_web** - previously known as dj-wasabi/zabbix-web. +- zabbix_action - new alias ``update_operations`` for ``acknowledge_operations`` parameter. +- zabbix_host - ``macros`` now support new macro types ``text`` and ``secret``. +- zabbix_host - new option ``details`` (additional SNMP details) for ``interfaces`` parameter. +- zabbix_host - now supports Zabbix 5.0. +- zabbix_proxy (module) - now supports Zabbix 5.0. +- zabbix_screen - ``host_group`` parameter now accepts multiple groups. + +Bugfixes +-------- + +- zabbix_action - documented ``value2`` parameter and ``notify_all_involved`` option. +- zabbix_maintenance - changing value of ``description`` parameter now actually updates maintenance's description. +- zabbix_template - is now able to perform ``state=dump`` when using ``ansible-playbook --check``. +- zabbix_template - no longer imports template from ``template_json`` or ``template_xml`` when using ``ansible-playbook --check``. + +v0.1.0 +====== + +Release Summary +--------------- + +| Release date: 2020-06-15 + + +Minor Changes +------------- + +- zabbix inventory plugin now no longer prints DeprecationWarning when used with Python3 due to SafeConfigParser. +- zabbix_action - arguments ``event_source`` and ``esc_period`` no longer required when ``state=absent``. +- zabbix_host - fixed inventory_mode key error, which occurs with Zabbix 4.4.1 or more (see `#65304 <https://github.com/ansible/ansible/issues/65304>`_). +- zabbix_host - was not possible to update a host where visible_name was not set in zabbix. +- zabbix_mediatype - Fixed to support zabbix 4.4 or more and python3 (see `#67693 <https://github.com/ansible/ansible/pull/67693>`_). +- zabbix_template - fixed error when providing empty ``link_templates`` to the module (see `#66417 <https://github.com/ansible/ansible/issues/66417>`_). +- zabbix_template - fixed invalid (non-importable) output provided by exporting XML (see `#66466 <https://github.com/ansible/ansible/issues/66466>`_). +- zabbix_user - Fixed an issue where module failed with zabbix 4.4 or above (see `#67475 <https://github.com/ansible/ansible/pull/67475>`_). + +Deprecated Features +------------------- + +- zabbix_proxy (module) - deprecates ``interface`` sub-options ``type`` and ``main`` when proxy type is set to passive via ``status=passive``. Make sure these suboptions are removed from your playbook as they were never supported by Zabbix in the first place. + +Bugfixes +-------- + +- zabbix_action - allow str values for ``esc_period`` options (see `#66841 <https://github.com/ansible/ansible/pull/66841>`_). +- zabbix_action - no longer requires ``esc_period`` and ``event_source`` arguments when ``state=absent``. +- zabbix_host - now supports configuring user macros and host tags on the managed host (see `#66777 <https://github.com/ansible/ansible/pull/66777>`_). +- zabbix_host_info - ``host_name`` based search results now include host groups. +- zabbix_hostmacro - ``macro_name`` now accepts macros in zabbix native format as well (e.g. ``{$MACRO}``). +- zabbix_hostmacro - ``macro_value`` is no longer required when ``state=absent``. +- zabbix_proxy (module) - ``interface`` sub-options ``type`` and ``main`` are now deprecated and will be removed in community.general 3.0.0. Also, the values passed to ``interface`` are now checked for correct types and unexpected keys. +- zabbix_proxy (module) - added option proxy_address for comma-delimited list of IP/CIDR addresses or DNS names to accept active proxy requests from. +- zabbix_template - add new option omit_date to remove date from exported/dumped template (see `#67302 <https://github.com/ansible/ansible/pull/67302>`_). +- zabbix_template - adding new update rule templateLinkage.deleteMissing for newer zabbix versions (see `#66747 <https://github.com/ansible/ansible/pull/66747>`_). +- zabbix_template_info - add new option omit_date to remove date from exported/dumped template (see `#67302 <https://github.com/ansible/ansible/pull/67302>`_). diff --git a/ansible_collections/community/zabbix/CODE_OF_CONDUCT.md b/ansible_collections/community/zabbix/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..4fa46f96c --- /dev/null +++ b/ansible_collections/community/zabbix/CODE_OF_CONDUCT.md @@ -0,0 +1,82 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting one of the project maintainers at: +* d3defi@gmail.com +* sky.jokerxx@gmail.com +* github@werner-dijkerman.nl + +Or Ansible project directly at codeofconduct@ansible.com. + +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/ansible_collections/community/zabbix/CONTRIBUTING.md b/ansible_collections/community/zabbix/CONTRIBUTING.md new file mode 100644 index 000000000..df591ef1c --- /dev/null +++ b/ansible_collections/community/zabbix/CONTRIBUTING.md @@ -0,0 +1,169 @@ +# Contribution guidelines + +**Table of contents** + +- [Contribution guidelines](#contribution-guidelines) + * [Contributing](#contributing) + * [Coding guidelines](#coding-guidelines) + + [Zabbix roles](#zabbix-roles) + + [Zabbix modules](#zabbix-modules) + * [Testing and Development](#testing-and-development) + + [Testing Zabbix roles](#testing-zabbix-roles) + + [Testing Zabbix modules](#testing-zabbix-modules) +- [Additional information](#additional-information) + * [Virtualenv](#virtualenv) + * [Links](#links) + +Thank you very much for taking time to improve this Ansible collection. We appreciate your every contribution. Please make sure you are familiar with the content presented in this document to avoid any delays during reviews or merge. + +Please note that this project is released with following codes of conduct and by participating in the project you agree to abide by them: +* [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md) +* [Community Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) + +If you are interested in joining us as a maintainer, please open an issue. + +## Contributing + +1. Fork this repository with community Zabbix collection. +2. Create a new branch and apply your changes to it. In addition to that: + 1. Ensure that any changes you introduce to this collection are reflected in the documentation. + 2. Ensure that your PR contains valid [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#changelogs). + 3. Include tests with your contribution to ensure that future pull requests will not break your functionality. + 4. Make sure that tests succeed. +3. Push the branch to your forked repository. +4. Submit a new pull request into this collection. + +*Notes:* +* Pull requests that fail during the tests will not be merged. If you have trouble narrowing down cause of a failure and would like some help, do not hesitate to ask for it in comments. +* If you plan to propose an extensive feature or breaking change, please open an issue first. This allows collection maintainers to comment on such change in advance and avoid possible rejection of such contribution. + +## Coding guidelines + +Style guides are important because they ensure consistency in the content, look, and feel of a book or a website. Any contributions to this collection must adhere to the following rules: + +* [Ansible style guide](http://docs.ansible.com/ansible/latest/dev_guide/style_guide/). +* Use "Ansible" when referring to the product and ``ansible`` when referring to the command line tool, package and so on. + +### Zabbix roles + +* Playbooks should be written in multi-line YAML format using ``key: value``. + * The form ``key=value`` is suitable for ``ansible`` ad-hoc execution, not for ``ansible-playbook``. +* Every task should always have a ``name:`` keyword associated with it. + +### Zabbix modules + +These rules are required for any contributions proposing a new Zabbix module or updating an existing one. Modules should: + +* Be compatible with [currently supported Zabbix releases](https://www.zabbix.com/life_cycle_and_release_policy). +* Include the same set of general options as other Zabbix modules: + * In `DOCUMENTATION` block via `extends_documentation_fragment` keyword. + * In module `argument_spec` as a set of module parameters. +* Implement proper logout mechanism as other modules do. +* Use the same version of `zabbix-api` library as defined in collection requirements. +* Comply with [Ansible module best practices](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html). + +## Testing and Development + +It is recommended to use Docker for the testing as this repository is utilizing it for its own CI. Read [Docker installation guide](https://docs.docker.com/install/) for more information. + +Make sure you start your work on the current state of the repository with `main` branch up to date. The best way to both try new changes and run shipped tests is by cloning the repository to Ansible project: + +```bash +cd <ANSIBLE-PROJECT>/ +mkdir -p collections/ansible_collections/community +git clone git@github.com:<USERNAME>/community.zabbix.git collections/ansible_collections/community/zabbix +``` + +Functionality can be verified by looking at the documentation of a module: +```bash +ansible-doc community.zabbix.zabbix_host +``` + +Once this is done, you can reference modules and roles from testing playbook likes this: + +```yaml +- hosts: myserver + roles: + - role: community.zabbix.zabbix_agent + zabbix_agent_server: 10.0.0.1 + ... + + tasks: + - name: Configure Zabbix host + community.zabbix.zabbix_host: + server_url: http://10.0.0.1/ + ... + delegate_to: localhost +``` + +### Testing Zabbix roles + +*This section is subject to change as our CI regarding roles is being reworked and may not work for you right now!* + +Roles make use of [Molecule](https://molecule.readthedocs.io/en/latest/) to verify and test the execution of each role. In order to start testing with Molecule, you need to install the required dependencies. Requirements file can be found in the root of the [dj-wasabi/ansible-ci-base](https://github.com/dj-wasabi/ansible-ci-base) repository. + +It is recommended to create a [new Python virtual environment](#virtualenv) for this to not clutter your global Python installation. First, install the dependencies: + +```bash +pip install -r requirements.txt +``` + +Note that Docker is required when testing roles as Molecule is configured to use it. Once everything is installed, validate your role changes with: + +```bash +molecule test +``` + +### Testing Zabbix modules + +Modules are tested via `ansible-test` command. Configurations for integration and sanity tests for the command are contained within `tests` directory. Refer to the [official documentation](https://docs.ansible.com/ansible/latest/dev_guide/testing_integration.html) for introduction to module integration testing within Ansible. Please note that this may fail if you get your directory structure wrong. If this happens, please see the start of [Testing and Development](#testing-and-development) regarding the placement of the collection. + +Running test suites locally requires a few dependencies to be installed. Same as for the roles, it is recommended to use [Python virtual environment](#virtualenv): + +```bash +pip install docker-compose +``` + +Integration test suite for modules can be run with the commands below: + +```bash +export zabbix_version=X.Y +docker-compose up -d +ansible-test integration -v --color --continue-on-error --diff [test_zabbix_xyz] +docker-compose down +``` +*Notes*: +* `zabbix_version=X.Y` will be expanded to Docker image `ubuntu-X.Y-latest` +* Details for both variables and values that are in use can be read from [ansible-test.yml](.github/workflows/ansible-test.yml). + +Sanity test suite for the modules can be run with the commands: + +```bash +ansible-test sanity -v --color --docker --python 3.6 +``` + +# Additional information + +## Virtualenv + +It is recommended to use virtualenv for development and testing work to prevent any conflicting dependencies with other projects. + +A few resources describing virtualenvs: + +* http://thepythonguru.com/python-virtualenv-guide/ +* https://realpython.com/python-virtual-environments-a-primer/ +* https://www.dabapps.com/blog/introduction-to-pip-and-virtualenv-python/ + +## Links + +* [Ansible](https://www.ansible.com/) +* [Ansible style guide](http://docs.ansible.com/ansible/latest/dev_guide/style_guide/) +* [Ansible module best practices](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html) +* [Integration testing with `ansible-test`](https://docs.ansible.com/ansible/latest/dev_guide/testing_integration.html) +* [Docker installation guide](https://docs.docker.com/install/) +* [Molecule](https://molecule.readthedocs.io/) +* [Molecule V2 with your own role](https://werner-dijkerman.nl/2017/09/05/using-molecule-v2-to-test-ansible-roles/) +* [dj-wasabi/ansible-ci-base](https://github.com/dj-wasabi/ansible-ci-base) +* [Current Zabbix releases](https://www.zabbix.com/life_cycle_and_release_policy) + +**End note**: Have fun making changes. If a feature helps you, others may find it useful as well and we will be happy to merge it. diff --git a/ansible_collections/community/zabbix/FILES.json b/ansible_collections/community/zabbix/FILES.json new file mode 100644 index 000000000..80415b832 --- /dev/null +++ b/ansible_collections/community/zabbix/FILES.json @@ -0,0 +1,3596 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/ISSUE_TEMPLATE", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/ISSUE_TEMPLATE/bug_report.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2198c3a25f580fb743064df8a8fc34fe8a6bbc9a1ad4466b37d1857d53746a88", + "format": 1 + }, + { + "name": ".github/ISSUE_TEMPLATE/feature_request.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d07bd877d38e16657c68cbd89c1c79eeda6debe008cb82745de6a705f984e442", + "format": 1 + }, + { + "name": ".github/workflows", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows/agent.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7f6609467d2f142f82e08d9a3675286695188b1f96eae451c5a92f9fc92ad880", + "format": 1 + }, + { + "name": ".github/workflows/javagateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4768caf2de9e672c21e17389ed2e8ae19009198270cd37fc73f3b2ee745da85f", + "format": 1 + }, + { + "name": ".github/workflows/plugins-integration.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c15c0360234358038f7f2d9835eedfc2f90aaf5fec5fccc95d0ac8c99c0c453a", + "format": 1 + }, + { + "name": ".github/workflows/proxy.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9d6b75380b849fb9e88a2484c599cf52206242f7caf1bb964e1a3431836be0c0", + "format": 1 + }, + { + "name": ".github/workflows/repo-sanity.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "547ff5f443f05cba80f3a80180f7418b1df7e015701ebb8125b1fb6151a9cb77", + "format": 1 + }, + { + "name": ".github/workflows/server.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "db95b5b85610665607a70cfc1dd50eed1224ededa3c3513b56601385964d9c9a", + "format": 1 + }, + { + "name": ".github/workflows/web.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1530135054b317b5605a4fbe8680faa74e87007080ae0f59f111ba1fa4e2a5b0", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/.gitkeep", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "changelogs/.plugin-cache.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0b56a72dcc4aae26837ecd516b88b5889b0fbf0085367125e47a1eb0d79fe4cc", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4c0e5e697fb8f013a1a392689a23d91da029b6b9b321c49b218b6cb69d51dec0", + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1f5044955801b7dabf74a5e011cb53a4b207444c7ca08d22a94121a42183b478", + "format": 1 + }, + { + "name": "changelogs/roles_zabbix64.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f4d624707b0cf06c6b382891d2c759289219e03ea633da90622623082c1bafb6", + "format": 1 + }, + { + "name": "docs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "docs/PUBLISHING_TO_GALAXY.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "df53d35672848c736b9cf780b968936413631d41c9abbad1c3da9d7782d7955d", + "format": 1 + }, + { + "name": "docs/RELEASE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e6e82418946c80ed2d063090f5444132de3973d16116bc1c7a484b92ac9fb15a", + "format": 1 + }, + { + "name": "docs/UPGRADE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e4e1d4fa54395501c71f8c70b369c16aa4b4edf15b5a65a1746cb727d98f51f0", + "format": 1 + }, + { + "name": "docs/ZABBIX_AGENT_ROLE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ee2a165aac204d9df3bca010af9f662e99b3442bc10da941d00d87285d51bbca", + "format": 1 + }, + { + "name": "docs/ZABBIX_JAVAGATEWAY_ROLE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b4182c4262079bb61943eabdd08dce46e0240d30dc3b61494fe1fdba11dca828", + "format": 1 + }, + { + "name": "docs/ZABBIX_PROXY_ROLE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ac111a4c75c45c1c320381b8f1032e52be9822bf1b7c5713591f8077d3223b56", + "format": 1 + }, + { + "name": "docs/ZABBIX_SERVER_ROLE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d9e5f1ebef97ef13cd79fa70e4d2e1fbbd48090e239a13be019edd2a179f45d0", + "format": 1 + }, + { + "name": "docs/ZABBIX_WEB_ROLE.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5aad816040102389cc79090e613ff22231337424f20bfe9626d022b153023ac5", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "50679314811f43a872bd27d00dcdce7ae167a1612307c3bd16dc63aa17dddb42", + "format": 1 + }, + { + "name": "molecule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/playbooks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/playbooks/converge.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6081b72ff03c46e191faea23fbda8f7709be3c7c12f40efac22fb72c4c159b28", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/playbooks/prepare.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5ae566f4f24a278f50574ebff1b64c60dfb7aae0a587ec54e8ad35a75a7e6ea3", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/agent2_common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/agent2_common/test_agent2.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e7642af39f5baa9d06a8ee65daa6282801738665f107c959583e783cf20ae8f5", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/autopsk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/autopsk/test_auto_psk.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "124bf032a9b6aeafa8baedd5e68902e1c003735170d2e5441cf7b2e90b5ac63a", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/common/test_agent.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "047aa3486e4c15a37be84128d3072a8c25c2488f8755141d686e29611483cb9a", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/no_auto_psk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/no_auto_psk/test_no_auto_psk.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eca308952f132c7c5d2945a15ff6f83b61ae69b74316b264158adfb234b1ff8f", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/tests/test_docker.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bcfe5cda25b569e30dccb5352166739890e87fd38e5400e3302e660bc31a678c", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/common/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2e9bf77259593522020af1a6b70b85ecd0d1f02b0c8807801b4bb63ab2f886ef", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2/tests/agent2_common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2/tests/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2/tests/no_auto_psk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2/tests/conftest.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a3e823c5509147bedb9518d7b2eff0923c32aa39802fad461fdeba2d697f78f4", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "54630476f85b1859cf8f37f43b64631c0b6b87b1d1a151ae9f0ab8baaa7ce7ad", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/agent2_common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/autopsk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/conftest.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a3e823c5509147bedb9518d7b2eff0923c32aa39802fad461fdeba2d697f78f4", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/agent2autopsk/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2cf2499517fdea3d8ec5cd7897eb22fb81d8142251ed2f554383c5fe3bbaed34", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/autopsk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/autopsk/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/autopsk/tests/autopsk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/autopsk/tests/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/autopsk/tests/conftest.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a2a2830d334a90ed4a678feb60bcc7db603433c4a8078e99a22e878079f7a99d", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/autopsk/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b0a7ef16797c0d9fd964d7e1e57ebc3fe0c4d1a93cc7d0c6407ece5a1edd304a", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/default", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/default/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/default/tests/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/default/tests/no_auto_psk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/default/tests/conftest.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a2a2830d334a90ed4a678feb60bcc7db603433c4a8078e99a22e878079f7a99d", + "format": 1 + }, + { + "name": "molecule/zabbix_agent_tests/molecule/default/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "406858bb7a26281e2f49664b1978e14d17442b8cb6bd7cbd96a8f0cfe6915047", + "format": 1 + }, + { + "name": "molecule/zabbix_javagateway", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_javagateway/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_javagateway/tests/test_default.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "42216040435b108d772efea497ef5f03e13d6d9c36358df9959d587902ed4140", + "format": 1 + }, + { + "name": "molecule/zabbix_javagateway/converge.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c41ec5d85027442c2d6eb2ad88245e313a507cdb669f1b89ec3c7eb98d6d0d6b", + "format": 1 + }, + { + "name": "molecule/zabbix_javagateway/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "403c27814ef8c997cd3c483c48337f5e2ce6384a799bb1cdab54c3ac01b1016c", + "format": 1 + }, + { + "name": "molecule/zabbix_javagateway/prepare.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1b6c9f53dce0f4a63df8d386fc1aa264335af706dd00943f8ff66dd735250e22", + "format": 1 + }, + { + "name": "molecule/zabbix_proxy", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_proxy/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_proxy/tests/test_default.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "48e48563e12a400b8e24268456f3534f0887217baf48e5fae587c5ec9f59ba39", + "format": 1 + }, + { + "name": "molecule/zabbix_proxy/converge.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "82b284a5ec5707b2a2ea3bb7c7e41fb8f2f583eb255b60e25b61935de3e09236", + "format": 1 + }, + { + "name": "molecule/zabbix_proxy/destroy.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "99cb34a22f36b18227686720c750aa70745fdd22227d5aeb08a42891998ac09a", + "format": 1 + }, + { + "name": "molecule/zabbix_proxy/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "780d05e996542297e40e112566587ba18cbea58becb58c298a94a6c65a7c2c18", + "format": 1 + }, + { + "name": "molecule/zabbix_proxy/prepare.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "37c3e8879e3a5fb94115a8745f19e4fdd6eca693b852d048ad881c2de3e13f9d", + "format": 1 + }, + { + "name": "molecule/zabbix_server", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_server/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_server/tests/test_default.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "23f62965273df247d7ae99c4a171ef2f22b352d63e7af18eb617b3aebf0a1840", + "format": 1 + }, + { + "name": "molecule/zabbix_server/converge.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "81898048b5c3fae5ee132d104e2b47303e3e1746d10f8b61ad8b8c3e91fbf9a1", + "format": 1 + }, + { + "name": "molecule/zabbix_server/destroy.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "99cb34a22f36b18227686720c750aa70745fdd22227d5aeb08a42891998ac09a", + "format": 1 + }, + { + "name": "molecule/zabbix_server/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "25b8acf6faf7dffa24083bae88ae7b9b4044741e8cd85083ce48cdd5c6a1b39c", + "format": 1 + }, + { + "name": "molecule/zabbix_server/prepare.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "01f51c7913635ba28f9fc720a540a2b59c7b71123c51e3b9e6bd4493b2bb5de8", + "format": 1 + }, + { + "name": "molecule/zabbix_web", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_web/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "molecule/zabbix_web/tests/test_default.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "81f986130198995bbaeb722b7659e214830e1cc91e00313e87b3e6cbca38b6c1", + "format": 1 + }, + { + "name": "molecule/zabbix_web/converge.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "342a9bd906308c1ad2b4c68efbe16ba8e66ad0658fc7e1f584947f3d817fbdd3", + "format": 1 + }, + { + "name": "molecule/zabbix_web/destroy.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "99cb34a22f36b18227686720c750aa70745fdd22227d5aeb08a42891998ac09a", + "format": 1 + }, + { + "name": "molecule/zabbix_web/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cec08cba46b8c5f66fe3b9f018014a7c506fa145ca90a02472942f955c4c2910", + "format": 1 + }, + { + "name": "molecule/zabbix_web/prepare.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e42cb66ee3a4f8a6149adc9d85538e73d66d7fd43f9b5af95335ca4d186a0c20", + "format": 1 + }, + { + "name": "molecule/zabbix_web/requirements.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a3d0f0e25e6a98d180c59e851e0b99699f947d5d7a8599d8b85e4567e325dc3d", + "format": 1 + }, + { + "name": "molecule/requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5da70582c0669065d3948183fd74a508a2ecb80f683e4499050b39415931858b", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments/connection_persistent.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b3d6dc35fc7752bd61b55722c5ae88ae02170b93fb85960b7b1430c2bb7146df", + "format": 1 + }, + { + "name": "plugins/doc_fragments/zabbix.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "64d6a3931787f894153e068ae4e91fddfe8127ed7e61ea903a45a60269b1406b", + "format": 1 + }, + { + "name": "plugins/httpapi", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/httpapi/zabbix.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "65146ad205a7cc5d5d5d08b5f4172582878ceb8a9c01f26b36447f18fac996ce", + "format": 1 + }, + { + "name": "plugins/inventory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/inventory/zabbix_inventory.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bc0ec92bd5b83af4f840d8dfc0c6ec1da5f88093a75a57ad0456cc3fc7690959", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/module_utils/_version.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1bdef9acb4f7b98135dee7366e5b26df32c52664175039b877a604b2865dadb5", + "format": 1 + }, + { + "name": "plugins/module_utils/api_request.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a1a0b0b8fc8189a3dc6facd77621cb14e99511319a0b082a7803fb0976d8d080", + "format": 1 + }, + { + "name": "plugins/module_utils/base.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "54657e0efada7dc5e77dca6546721031478f8bdd298f690509076b17e15e9af4", + "format": 1 + }, + { + "name": "plugins/module_utils/helpers.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2eaf8c62644252eb35908db596c4226df48ba3340bfadc95bf6102aeabf851f5", + "format": 1 + }, + { + "name": "plugins/module_utils/wrappers.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b592fdc7a1a516f00d256702a24530507bb9e63acee9469f78776a6066429b55", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/zabbix_group_facts.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "72829e189f762da9a094b5a2d6d79783abb09311fef0ca321e4bc6ca8cf6f308", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_host_facts.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9d0341ced4e1d0c2d36276d1d0fe7271a530b89b5f751541a5cf7a32012f6847", + "format": 1 + }, + { + "name": "plugins/modules/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_action.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f2eeb69c809b3aba15df826b79233b43209a6de279d8bbd3b5e09cd7cd016aa1", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_authentication.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04357311ce1b7345a774bb630ab4b76f8a2fa02e766e9053cf92777bedac0659", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_autoregister.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a21144832a5d33b502beea5c30eef7117822ebdb2e2829b541151c5deee6d65a", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_discovery_rule.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed9c604f7ed63e7f9021a6fcfe5a42998e27bcc59ef118593d7bd32810be0adf", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_globalmacro.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "93a2dff2fdec0e4c9270951f851a6b705fd83097579c6dfa224da75a70c9fd3d", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_group.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8c4997b0b63820066e3804edaf37e6c595566e1bdcb747e2a2b4ac7d8329e0cd", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_group_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "72829e189f762da9a094b5a2d6d79783abb09311fef0ca321e4bc6ca8cf6f308", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_host.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f73e0a24b2fdfe72d83a0a2453431a847aec7bde7dd544ad214322bbb60599ce", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_host_events_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "488889c8ca3f4b6e9acbb27c9c26b92d8180de9a600c0b676996bb4797208813", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_host_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9d0341ced4e1d0c2d36276d1d0fe7271a530b89b5f751541a5cf7a32012f6847", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_hostmacro.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9f477dc001793c78a94dbd141e700d56423e56fed515035080647829b7c7e4a3", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_housekeeping.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c4b26c8caa59756d48ba0e5b95776829982502f3d8870d71c93cea9107315d8d", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_maintenance.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "364f6004001d05fa7750e254de4732674978abb28fb2e1cc11172275be9c84d5", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_map.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d5dc24b8b8ef92874326de6fdab300bdeb2f6a71545fea10ee64a0a1d9ab18d4", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_mediatype.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6a0b555e69e815d00fbdb7e37041e0f216a6c621a1abd7b67b228b14d7294821", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_proxy.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f442459b52bab35073f9366dfe0bc16afd219ad505d91b6b681734f563884ae4", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_proxy_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e02f116191199752c9087cd867cc4ad0bacd19338a36978c740f408548e2c312", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_screen.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1f74721c60d1db5e8aa8031876db2d88e2192aee39851c9bf1a6e219fad99fee", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_script.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a4dc1c9b646b8586121a5d89d382c4e8162c0ee9072d659e5cb68e7c895d9ea3", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_service.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "07c6a4604e5d780165daaa43cf304bbc858fee747c30dc7561ddc00643db23f8", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_template.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b57132f5e62c804acc1828b459a2e70efa49945201ceedbcf71951b4594f50ef", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_template_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "910e1b679b257e0b64d807d4162e85d29fb6d6b8f05c2fb9ec9f0d51eb85fc8e", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_user.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2397b8173b49107a3238de5ecaf0509bcd1842c55e1329fe765f2f6d902caaa2", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_user_directory.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "821641cedc3d4a5cfa669f063b434dc0b07b4fb5b128392d96c4c24c25e5d126", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_user_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5073676377f2089d55e17f23c86bfe5b4a7c5014b2aa52a05242b7d49251a65d", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_user_role.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b5cc955ca1ac15ba0d15b2159387facb6e12590865e63c9d9b2061f603ee37ac", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_usergroup.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a7f908ac23ad94f1f3f5916e8fa48cb864e5401d00126532a4668c14681e605b", + "format": 1 + }, + { + "name": "plugins/modules/zabbix_valuemap.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "285b6b71d55ac7d8844f79a6d8c100bd899279aaa7ee35bea78d10ea810615e6", + "format": 1 + }, + { + "name": "roles", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ee2a165aac204d9df3bca010af9f662e99b3442bc10da941d00d87285d51bbca", + "format": 1 + }, + { + "name": "roles/zabbix_agent/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "12b9fc863285e0cdd2d5be2f81bfbd62e68d8ebe11dbb66b18a5ed50347b9a21", + "format": 1 + }, + { + "name": "roles/zabbix_agent/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/files/win_sample", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/files/win_sample/doSomething.ps1", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/zabbix_agent/files/sample.conf", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3aa3b604a215baf40d9d4318ba4f7197a1c58df7277fa349fbafd7666ed2d941", + "format": 1 + }, + { + "name": "roles/zabbix_agent/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "acad5ae4f8591346fcea52d1682ab85ffbd5b9f43595da6f68003755eddf81c5", + "format": 1 + }, + { + "name": "roles/zabbix_agent/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "711e51291c34046ab48ab02e04d12dc475a366574d3a9a74b766087e94a5833b", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/tests/test_agent.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "12fbdb469e65f0db8195e61c0dad1bf924bcda267e14d2bbb6006392e2df52db", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/tests/test_default.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c7cc3d29745b0c8bc7730858de639184b8125d481511130023ed1c5dcc64c32b", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/Dockerfile.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "45fcdc65bf0c38188ae34f4db3ddf66a0fc572ffb1c3fe66055edab399d53f09", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/INSTALL.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "61ec9005b35344df43db785d54f69a5fe87cc1783014e404e068497f6773f924", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/molecule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3c886d4bca694a6b19e3d15909f5738b771e6ef9eab31987ef6e63eb480d62e5", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/playbook.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7acb20ce65dd661f2a8f2ff1492cd385a7d603d7e946f2331e3be0f64f7c2c60", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/prepare.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "03966cfb5f1589ae0177403025b7cf62bb94bc8e4a551e14fbb87c2a73f8c208", + "format": 1 + }, + { + "name": "roles/zabbix_agent/molecule/with-server/requirements.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7cb18ed88555380f82e4f37d4cfae43303cf2071ac8b407aaa32d37aec0be804", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Darwin.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1761047e511995d4aeda5eeda1db4133b2f6f3e18193027a4351bfeee6bada76", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cacac2625d62892a4da290bc4ac8e36ca7f83c84f5ddf4145cf17a73dfbd70f9", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Docker.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7406219975281823e907acb14e0cfebef02496bc5b85e89380b0c446f9e95ec4", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Linux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95bcf03c9ac71b4825684bedf69d4069d549c18a13c5943b1f6f89775acf495e", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5cb57a73eed1d8f5152b3b1ad8cb15c8cd0297158b96c27ee42e7629c52aeeda", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Suse.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "71a60660c5dc62b42d22a8798464af1533f364ed28a2fa0bd14cf8fc33f0c66c", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Windows.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "aa1070768c380a56084c56b4b786be3d5319d8758f0315d41f9bb2ec1a37d760", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/Windows_conf.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9b90e2b63ab6910636900c305044e67c540ddf2fa3a359a0744f5d73ecf35b3f", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/api.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7ebe1e547cd1ee30e82ebdf6927c050d61733e938955abb28284542e5ceca8da", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/firewall.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8b74b8d9c33d31c6bd972f96187a8ebe407ed7b4e8d4f56c32563ad9a88f5e03", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/macOS.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "07214cf9e01f2d1b382dee5fa8af5a592f91b64a327d10379c5f50e977bf771b", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cf4a07124914b3173aa8f2cfa25aa3b575dd0bd6e8ab15ddc4377699b980bbf9", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/remove.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1a19cc7cd1fca702c9d88b573bf8ecdf062396aaf45ad6f6abd4fe4bb1a57d9a", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a22d30b558ddcbf9251868fe7accd96208bb813a9fe3878536184f68be55cd19", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "107052aaa9b9e206e09a0991f160996b2b390101f71e06ab3f3a8ba7afee5dea", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "db9d50614a7bc0247fd8aeefb53cc94fb083f4af5780c9b349acd05b0a9d7ae7", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "89a391fe07d61221c3d1fad2b217c3ce917d929d0c93a6872febb4b38fc9ed16", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6887ed6b41bbb92b719848be16779655fee4a6bcd4b09d6acca293c25801e24a", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c2d7c59ef98c62873349927d0ca6856375bab84f3b80f5c77365d8599a64d4e3", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_common.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4f214f550557b61a8dd48d05a10a6b507e6ad66b6f40665d6eee762929e7e1d3", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_linux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "238105b3e8d92db2f70ed8a724c8e317e943138b52c1d98e169614589563ec0d", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/tlspsk_auto_windows.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d6ef817e770cc8b55b174aa9f02196f68084856945d2bbf9edc79fb4adaa98d8", + "format": 1 + }, + { + "name": "roles/zabbix_agent/tasks/userparameter.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eb96d45277305e0ce2e5b3bfe264614791ffd4ff9fbaa61f88bc780ac18ea86a", + "format": 1 + }, + { + "name": "roles/zabbix_agent/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/templates/userparameters", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/templates/userparameters/mysql.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3aa3b604a215baf40d9d4318ba4f7197a1c58df7277fa349fbafd7666ed2d941", + "format": 1 + }, + { + "name": "roles/zabbix_agent/templates/userparameters/win_sample.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "97f7f02ba1bdf4c130838aea75f1246232b2b4cc00a36cea4bfc9123df1698c0", + "format": 1 + }, + { + "name": "roles/zabbix_agent/templates/zabbix_agent2.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "313aa178efad06ed5e47570ad86b65a1fe434131afe275bb7c2515ffa09f211f", + "format": 1 + }, + { + "name": "roles/zabbix_agent/templates/zabbix_agentd.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c724b3b877eaf83a2c083bb69aca3e946be294ff4308f0abaf5294e29164cf36", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/Darwin.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "db7f6b6b2dd80ddaf2e8d281c78f350a4849b74deda63ef63338b7699527fa20", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "37e4c7f331e4c1e92a79fa3d17ec2e4adc06b83d23a3e644f0ac74e294437217", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0f9fb95f6406336aa72a9736463d118362cde397991129391db58038c1897ab0", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/Sangoma.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6b0b76e02ac840a2cb89b691d4ae0e6a55e441fa81bd0cc6a9487b0f1bc02019", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/Suse.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a0cc3ac65514ccdbd0f6035eb823aa916d7ea8dda1d0b3d9c4a7f783529bc290", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/Windows.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "af541365edb39dd0d046a3ae36770b01f6f7881001587f68c707e2d171662f6b", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/zabbix_agent/vars/zabbix.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2f18e3250d44f4cba423e73e08e1bfff9be95645e559837588901f3e137e5886", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b4182c4262079bb61943eabdd08dce46e0240d30dc3b61494fe1fdba11dca828", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "87b1aed24ee0aca58a4c4c97bef77b339bb9810816476187310d0ff93e118833", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/files/systemd.service", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "df08ce5450891ea88a7fec5a1c56c5d4c243e1b3ef128dcb26e37714b48e88c9", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9ad072b7d35f1d0e200857c59e5cc8b3c6417427c313bbbdff78fedd95354310", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eefd2527d9e1e50e0dbf2905a46dc29eb8fe677b54ffed00d8f6f4260480df30", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/tasks/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cf47a37619f9b6665ee00315c0855d6a1ec9b5840caf651808f66d6c9bf3a099", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/tasks/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2146cb8284148aa9d5397cbd34d42b8ecb726c53468923fb38e9a4c7328d9d63", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "944ef7efad86d6facb498db0ef23de2524ba271973b2f7c3f5e89b1f6aa630ac", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7d2324bdb590456ae36fe2efd638307dd1e9b22279fdeb8483689a5316842875", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/vars/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f4eb8a4a848b0eae37caae62c36ae4d1e35dabe5aab2357203f1427b5ad55491", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/vars/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ee454bd3e000b6cb6bf752ecbd4a29f6a10a2773a148f945220ea91076450493", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a66f3b3709565944ed24f42a65761b62325279bc54222f3200bff2ab96616944", + "format": 1 + }, + { + "name": "roles/zabbix_javagateway/vars/zabbix.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2257dcb583cc09be9a13c17c9966b63aa7e14d39cd39d8557eccc0734ff0e9ae", + "format": 1 + }, + { + "name": "roles/zabbix_proxy", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ac111a4c75c45c1c320381b8f1032e52be9822bf1b7c5713591f8077d3223b56", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c16dd23a720096fd637c8657a49d8081e2b50f86ed22d0b2b3557991ff23e086", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/files/install_semodule.bsx", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "729d5b564427618c3acad7c499736930070ed3c7cbd542dedf341722db68cfa0", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "02effc86ecae774f9c4e208da774604bc32a1aa263225d77b817a501d2d3df7d", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1b6248de4d50ab09df5f595799aa31a4f9b10ff17a7e2a45a96fe799e41bd52a", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8a35de709c48c4224dece469ca5f45bf81671482294251194c17ffd7a4c488c5", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b770f37ceb3ae2f48a8fe8b21b3d305f973c07574ad9079e28a7685179b47978", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "12a3f45c5eb455cb937e1b48f524991a3eacfd53461cb5f71358a3a79ba75afb", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/mysql.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3f3d72cc83e4c5cbe9cedd034359ead81c09567126b75240e4ebe284c45d44a4", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/postgresql.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0e29dc6547af5aab28881b169743a468447a8a2e43f81e93f039b72f12a1c724", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "09b879efd086b9b6b85323dfcc9880366001e6766a376ffe0a3d7debf74dcd8b", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/tasks/sqlite3.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "62e88f189a7a692fffcfc5fe245d725c6c5685778e7b83155abaae89727ce737", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/templates/zabbix_proxy.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e47e91ec1f3da19270f6d5091b18b6b04af7a43761052f10582a151fa973be99", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_proxy/vars/Amazon.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7d87cd61d18e6d90032bfe0a42d18cb1bf651001280e06ac60a7850e7be5e733", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/vars/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0b725e04160bcf663d6d88baa8b99d90500e2026def7a5b157fa6d582c5836a6", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/vars/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "262daf894cef6d121f54caf8b14dc627f1c2a438c28448235c7fa8d288e59f9d", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2a54870b52848a1bdf2dcbcd7e86f46509f868c02c51ca4f315457282b5a9c78", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/vars/zabbix.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "52df6b43e568fd07f963c088f523b2ffcc903da18bc1037fed1952e7dc86f384", + "format": 1 + }, + { + "name": "roles/zabbix_proxy/requirements.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f669210dc6814ed6c193a746cd8bfd1eb13448269b3d8f6b2d209f9418b907cb", + "format": 1 + }, + { + "name": "roles/zabbix_server", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d9e5f1ebef97ef13cd79fa70e4d2e1fbbd48090e239a13be019edd2a179f45d0", + "format": 1 + }, + { + "name": "roles/zabbix_server/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95107b5a298c2a5733353856c52973332cc89945cbabf376f6b5e62265cfb244", + "format": 1 + }, + { + "name": "roles/zabbix_server/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/files/install_semodule.bsx", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "729d5b564427618c3acad7c499736930070ed3c7cbd542dedf341722db68cfa0", + "format": 1 + }, + { + "name": "roles/zabbix_server/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ffb85ad6d8b0d9e5b40d855e11940f1b1907ed58c8345f1d8121d02f4472a70a", + "format": 1 + }, + { + "name": "roles/zabbix_server/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0487f93463794453a72406f64a054fefeec900959fc97293b38282fd3c59a201", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "99fc338cab1bee724ad370677868d5ca78cf401697698fe99862218d138eefd9", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6c15f6cd24f0bcee1131194568127733889d3ed546d68f4f4bef4dfa0575a2cd", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c6a7a3b01e6eea7d6bf89126d2157e9dca2d7fa0ca0ba24f1defbc0e38364d04", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/mysql.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ea1cf201defad2ed9e7e5e8b28e178a762ff283e6c3ef22a7bd59fa6ba7ecd9c", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/postgresql.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "21872ed7e12aabd0ea72bca9c68fa1247c370302ea7c4a702f3b102058dae41d", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/scripts.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ae57630fcbe0bbb4c702a2a173bc0e8f746c5d2ab5ff107074ee86c8329b56d2", + "format": 1 + }, + { + "name": "roles/zabbix_server/tasks/selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f2fc0f9f1a0c932873d0095d4ebaeb90cdc7160c7789949c0c1f4e1199e7d2c9", + "format": 1 + }, + { + "name": "roles/zabbix_server/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/templates/zabbix_server.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "aedb97e7c1166029b2f0078cf1aabc90b2932c658a2b08ad4b14eafcab2a411d", + "format": 1 + }, + { + "name": "roles/zabbix_server/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_server/vars/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b2d7348d3930df0cefb747be395295f54adb0ed5920df21f174fadc786b1168a", + "format": 1 + }, + { + "name": "roles/zabbix_server/vars/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ec10a5fd9114e8c195f4f11344b6e48241fa1a98eb3bff9da0219185d424b9c0", + "format": 1 + }, + { + "name": "roles/zabbix_server/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6c2f64c03ed593623b3d2dab34ac73df7d929a29f65827eef39ad083ce73a364", + "format": 1 + }, + { + "name": "roles/zabbix_server/vars/zabbix.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "78d5ef518d81987451e5e05ba5465a90bfb3471aff4f6ababe8dbbd3e0d8d132", + "format": 1 + }, + { + "name": "roles/zabbix_server/requirements.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a29c610f03bc687057abf37a69f05afea72484890a5ef3d0f0127bd6ab96598f", + "format": 1 + }, + { + "name": "roles/zabbix_web", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5aad816040102389cc79090e613ff22231337424f20bfe9626d022b153023ac5", + "format": 1 + }, + { + "name": "roles/zabbix_web/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "646af635c64aa409be510450ea21b66fac15f000193b2675cb8bba34dc7add9b", + "format": 1 + }, + { + "name": "roles/zabbix_web/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "17914993fcbae9e8c40f256e0ab37de2f9f858161d578d5aea092fa655491581", + "format": 1 + }, + { + "name": "roles/zabbix_web/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a4323c1de12142fd1f613a272f51a471e0f94aee30035cc554bf6fdc2bff13fc", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "32b9873fb6312b16ba6af8332db19144f5c02e1f7e8c997302d10fe241f3aa57", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8abf1ccc3ba445542f0318f1e7473c3d7d82aaab16d1502cdf78def689ed716b", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/access.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7949a75447930d99585497abe2dd063b8b309bd1d1215d95458fd8fe7842d491", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/apache.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8d7c2f668004c83b3244f819a9fe152d2f76cc232719f4b2dc0ab8ba0ae22c2d", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/apache_Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fb94333d3a7055e24d6bf7fb9da89dbc294160e8025e7ec902c7168be47b3346", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/apache_RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dae8aa03b819ae47f82db8805c1c4e47c29db5e8f2dba1aead94e74899e231c6", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b7ce3a35777bffe7fe7ee0564307b2d6d5c5842c6b8e1e9d4a01d5933b90c83c", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/nginx.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b7de6c00cae54176d63d8d21dab85070b22a95cb919dcca711a3588a733054d6", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/php_Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "135f474e5db359bc75a288ac4fcc76b79af1c804b3b2b8e34ae758c06f395bb9", + "format": 1 + }, + { + "name": "roles/zabbix_web/tasks/selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cc983ba894c3b7e9759722a13dc20ffa6814306d69a8f8f53003aa87496e5f64", + "format": 1 + }, + { + "name": "roles/zabbix_web/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/templates/apache_vhost.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04ed070405b18a24cd9b8788d1e7ad6c11b6c3f28033056bf4d38d3dc36906f4", + "format": 1 + }, + { + "name": "roles/zabbix_web/templates/nginx_vhost.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bc02f95677b2d1fce3f74bf8bd778a73a2702256743595551976711333ab0c3e", + "format": 1 + }, + { + "name": "roles/zabbix_web/templates/php-fpm.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "908ec55fb71d004f7745b4cd1788e005a32c96b0f46cb8295ad8bfa4eb247cc3", + "format": 1 + }, + { + "name": "roles/zabbix_web/templates/zabbix.conf.php.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5cf7a3042220dd33ebc0593d0a2a55d035419768db41fc33b02b0f4226f62715", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Debian-10.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b22f4fb2ddd44a45a5196bfdc2eb488aa0f20fc50182dad5801fcb7d9100373b", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Debian-11.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a80f687d7a145445cc9d3ece5f075047ad0b8419c162dee68d4d7e1d64c97b7c", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Debian-8.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "329443560941bda266833e38ba4139ac070b477db817db61728ed18817b8131d", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Debian-9.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a80f687d7a145445cc9d3ece5f075047ad0b8419c162dee68d4d7e1d64c97b7c", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Debian.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "62372051217390f4891cb03268c9d8e4588e13bed6877a8cc0b88231f6e9ef8a", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/RedHat-7.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a0083ec5ca4323c00334ef0591d67d036630bc3cbdc6e0301bc8c351eda6e2d0", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/RedHat-8.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3aab6d6cccbefb155a14f035b05e558dbe9b76a620a15d467351d94c61c8483c", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/RedHat-9.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f0dc3ae984a19e65ec9b7fbf9b9cdd6236aa15d34997dade35bcb79057807b78", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/RedHat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fbf732fe22f313440135a050db0d865f18fa43dd457b6723eb8e4c116849e5b0", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Ubuntu-18.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b22f4fb2ddd44a45a5196bfdc2eb488aa0f20fc50182dad5801fcb7d9100373b", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Ubuntu-20.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a80f687d7a145445cc9d3ece5f075047ad0b8419c162dee68d4d7e1d64c97b7c", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/Ubuntu-22.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0c50f32893fb2fcdec448107ddee75b0c5f600771df5c3e1299d28a705f736c7", + "format": 1 + }, + { + "name": "roles/zabbix_web/vars/zabbix.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a853c154c0da014fc883ed968e2f13c8e6792ffcd104d5e7a41bebc9f8519288", + "format": 1 + }, + { + "name": "scripts", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "scripts/inventory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "scripts/inventory/zabbix.ini", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "be08243c8bdc7c88f8fef16108e10face4d04d03764cb569718a241c181c5515", + "format": 1 + }, + { + "name": "scripts/inventory/zabbix.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dd78405dee6d2fb6c7280691c6feb0b2b26e89987cf58f8ec3c2acc0598a15bb", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_zabbix", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_zabbix/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_zabbix/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "50d2a9c75fbc340fd30b17b29030573a415ff2c56e41d1a2d5c1c2e2e7148ee7", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_zabbix/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_zabbix/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eaf72c686373517bd17032b53d62728d24f16590591f88d3092d13ef3585ee1b", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_action", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_action/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_action/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_action/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_action/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ebd7a2249b07d828e4da440a2524c02c8765f424a921e905ead81ef771cd2327", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_authentication", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_authentication/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_authentication/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_authentication/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_authentication/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a66e69e3d84f449a4be7d1d5f4eaaa92897b1b85a48f97287bcd09f7dd645395", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "60cac0799f832fea3d3ce6dee90ecb51227d4faf9420df902d2a2d033aac850c", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_autoregister", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_autoregister/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_autoregister/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_autoregister/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_autoregister/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "27a337939722af1c7eeacad529d54bf69af98fff68d52675e465c353716d166a", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_discovery_rule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_discovery_rule/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_discovery_rule/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_discovery_rule/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "32f946e351919a3759ad3b2c32f5b8a1f5fff35ce8591c18eef78dfd9296a3a1", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_globalmacro", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_globalmacro/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_globalmacro/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_globalmacro/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "437c3e9253e968a944d82dab70bb0495dff0724c74d5ee2322f2d816d50cf4ea", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e2712df59c9db85ad1fd37e6a2c7af620d38d06c755d5064db8143c76a1fc870", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_group_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0782df463b5143e4882d0381761bf73248007f49d22fbf3699e4d046d8903a58", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2d4ee657d0794ad05e89d7f25cd3ff21e29d4dbc183db05e448d3bb65bfb2145", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6bb205e8b50e693df53d03542b086d9072b9bf32b552e57a3fc148593b304e3e", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c86cd33bccf27eef9fdf7521774a375d01b59d3faa610c9f5aa7f382aa85fb62", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "46d1b84b5802e4489b5093335da4b04900665b987c6d7c2990918af8cf550dd3", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5aaf98c089043b50e8c57cfc965bc059682ab2e12c032c100b2fb40fba0dba43", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_host_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2f47878f8a650cb631f463d86b7cd9fcd34b8c3b00980157929047102d43a0d9", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_hostmacro", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_hostmacro/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_hostmacro/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_hostmacro/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "836f37cd9c40daee414510261d881e43f31187b2a84c101f03f3e5e045fb4a9b", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_housekeeping", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_housekeeping/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_housekeeping/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_housekeeping/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bca231a73ba8b7b845c263b641f3deadbc059d35aa5a56ace74a7ca51d438a71", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_maintenance", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_maintenance/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_maintenance/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_maintenance/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_maintenance/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "59b1762e359119c49345f90512cf419f12d6108ce81672005620b54848897585", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_mediatype", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_mediatype/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_mediatype/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_mediatype/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_mediatype/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "56ea6ef6bc6ed6ad2d03ea203999b1faa60745c20d1a359434c7b564a138620b", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_module_defaults_group", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_module_defaults_group/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_module_defaults_group/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_module_defaults_group/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d00ba227df2acf39ebabd71a7126ab8ccb8344f0b200cd0938a3aaad944f06dc", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d3fc86b4ac8240ea44fdb3225d5c97b4b45dc55603fe3116a490717fb78b2c95", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c0069278d407546960e2fbabb73aba0481ec28c0353a6218c3c3c12a3cbc9d61", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_screen", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_screen/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_screen/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_screen/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_screen/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "67b46ec9773624ff4840804a82a4e39cc039e22c7e52186e5c24d82845b5d8f4", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_script", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_script/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_script/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_script/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_script/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "88ce48d121b448cc5d7104eb887fc5ce437409b29d8bbf66e0423355af8a9e73", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "235ca09962f973a0c15fee386c5f795d2e9957dd733276c8f685211d4fd1750c", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_service/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b8c83f814b46f17b42353ad57c506249df2f0f9a84d5050efca3bc83e754df4b", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7159551e8100611ba88f2cb601276a3d3111edf5734dce6b3aebf698a9622a4c", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template1-changed_50_lower.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "57b1cc97b965f593b6ad8f3ea63bc20f59240327cd62b8423e61a1b12e4795eb", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template1_50_higher_decode_unicode.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "32d3a07c35f3556fc8c18bb9efcd798f1118da32eafaef20fdd0d19f3c926c28", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template1_50_lower.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fa6758a5f3cb23359fd20b9aa90c85db27376fa90e51aa9101a900f3b56dc3b2", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3f17ebb04e5f380f8486ca6444bfe7269fb70275c7aa5e1110724e8f37289b5a", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template3-changed_54_higher.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "45f327aaaee5badfcb9aff585e0b9f944970316d509488f5c2eb48c815b71f3e", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template3_54_higher.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6b2fe7a877f33fd88ef9406495b909e9d0bcbce9309cd62e071e9b1378cbff20", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/files/template3_54_higher.xml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b8db09706617b51c8b4173edabde248aa403e6efa4153f2a22a43411b068a710", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b022be250062c840f5f6bc6b60d90d52c08d3b4f85a34f0f6f48153300e04b80", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "da7627d6dfe9cbc0230ee0609493b9783198a7df59208ededec1831db8476e26", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecd0bb5df803e40f683226ae38126faf7f64cb140e792283c658854a166fc211", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7159551e8100611ba88f2cb601276a3d3111edf5734dce6b3aebf698a9622a4c", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_template_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fcbb64754d966c9d86a7d87260231caa3c53e2a55901f3b3bde72aca5cd751a2", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "960a32c864695d7b54d7ca3ebbd6362f75f68f743814c807daa6c3a25d6ac1f3", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8429bc7fe7d6eb2c2995bf0ba11f86a5a372b8f69d85e2c6e201c3fb7e89ef2d", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d358b1fcd45a8d856b9cc09907e6b9067be79fd28b06d0b5f405858b8d50432", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_directory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_directory/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_directory/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_directory/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_directory/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "afa7e354768d1130b16aed9d20fa8d0a380862b09aeb8d2b2a1dfe26da7c459b", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "59b6b651e26c5446ee51ca5d8a13303e984f3e07cb48c1582191c60c3fbf42ca", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6ee6a2f0426d77871f9ca6050be5199982f6207777f29d978802ea308d52d32a", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_role", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_role/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_role/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_role/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_user_role/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "291ef542c12c0fc5733ed61244f28fd19de5c5243afb3f3e8633a0311d93cbf9", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_usergroup", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_usergroup/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_usergroup/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81", + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_usergroup/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/test_zabbix_usergroup/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "701e889a652a7969c946234c571539d820bcd13fc7011650e858e42bcb0e8f09", + "format": 1 + }, + { + "name": "tests/sanity", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.10.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3fc63c84b6cef2e284d1e5aaa1c4f564e6b27d7ed7961626cbbb8495bdc105b3", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.11.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3fc63c84b6cef2e284d1e5aaa1c4f564e6b27d7ed7961626cbbb8495bdc105b3", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.12.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.13.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.14.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.15.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.9.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b4e32eab851387385a480a7d46bf2d81335209f52cf1c671b2ea98a452a4f3d2", + "format": 1 + }, + { + "name": ".ansible-lint", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bc980970679479078eecb1ca1dc5d9f87a3e4d2d5ae21e5417dd59e0357d57e2", + "format": 1 + }, + { + "name": ".gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1a10d9ab655f99e50b057fe85f896dae304c1bcb8e59c793cc88c61321e2713f", + "format": 1 + }, + { + "name": ".yamllint", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "12ef94e479c99c6e5e633d702a4043d1a9702c714fea28480bcd56117c5fa369", + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ec873a72b857853deae0579634953269e2ebe7b8ff95522446a8b4172ecf7123", + "format": 1 + }, + { + "name": "CODE_OF_CONDUCT.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5c18a80f7f461c2fb2ed69961a1c918eb3653f86ecf0506e79ef74200836f38a", + "format": 1 + }, + { + "name": "CONTRIBUTING.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "51891b42027e0b07b423a132022fb03a93a696bc00f1347af29754fb545a8a72", + "format": 1 + }, + { + "name": "LICENSE", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986", + "format": 1 + }, + { + "name": "MAINTAINERS", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ce7450363429434d6c59c5851a30d97303a5dddce5f03661ba005fe20d26b0ed", + "format": 1 + }, + { + "name": "PSF-license.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "83b042fc7d6aca0f10d68e45efa56b9bc0a1496608e7e7728fe09d1a534a054a", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e59ef9030664aba9bfff75bee58c59a9f33e9154b988508b7a1d1a4542d4d0fa", + "format": 1 + }, + { + "name": "docker-compose.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d8eb78609cb12e60dc6779d439f5effed1d4293c9ccfe9c59c6120788880dadf", + "format": 1 + }, + { + "name": "requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tox.ini", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2f0b2af9b832273ad8a626c937125bfd380f3fe8271922a0739f7e14806bc20e", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/LICENSE b/ansible_collections/community/zabbix/LICENSE new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/ansible_collections/community/zabbix/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/ansible_collections/community/zabbix/MAINTAINERS b/ansible_collections/community/zabbix/MAINTAINERS new file mode 100644 index 000000000..86f57896b --- /dev/null +++ b/ansible_collections/community/zabbix/MAINTAINERS @@ -0,0 +1,6 @@ +D3DeFi (https://gitter.im/D3DeFi, d3defi@gmail.com) +ragingpastry +BGmot +pyrodie18 +lzadjsf +mu1f407 diff --git a/ansible_collections/community/zabbix/MANIFEST.json b/ansible_collections/community/zabbix/MANIFEST.json new file mode 100644 index 000000000..a54e80845 --- /dev/null +++ b/ansible_collections/community/zabbix/MANIFEST.json @@ -0,0 +1,40 @@ +{ + "collection_info": { + "namespace": "community", + "name": "zabbix", + "version": "1.9.3", + "authors": [ + "Dusan Matejka (@D3DeFi)", + "sky-joker (@sky-joker)", + "Werner Dijkerman (@dj-wasabi)" + ], + "readme": "README.md", + "tags": [ + "monitoring", + "zabbix" + ], + "description": "Collection allowing to configure resources in Zabbix monitoring system", + "license": [], + "license_file": "LICENSE", + "dependencies": { + "ansible.windows": "*", + "ansible.netcommon": "*", + "ansible.posix": "*", + "community.general": "*", + "community.mysql": "*", + "community.postgresql": "*" + }, + "repository": "https://github.com/ansible-collections/community.zabbix.git", + "documentation": "https://github.com/ansible-collections/community.zabbix.git", + "homepage": "https://github.com/ansible-collections/community.zabbix", + "issues": "https://github.com/ansible-collections/community.zabbix/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e476cd027a2477b8d6417c251a409f4c2b040c9ee9a78ce6facf099912452868", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/PSF-license.txt b/ansible_collections/community/zabbix/PSF-license.txt new file mode 100644 index 000000000..35acd7fb5 --- /dev/null +++ b/ansible_collections/community/zabbix/PSF-license.txt @@ -0,0 +1,48 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/ansible_collections/community/zabbix/README.md b/ansible_collections/community/zabbix/README.md new file mode 100644 index 000000000..ca0f79717 --- /dev/null +++ b/ansible_collections/community/zabbix/README.md @@ -0,0 +1,243 @@ +# Zabbix collection for Ansible + +Plugins: + +![plugins](https://github.com/ansible-collections/community.zabbix/workflows/plugins-integration/badge.svg) ![repo-sanity](https://github.com/ansible-collections/community.zabbix/workflows/repo-sanity/badge.svg) + +Roles: + +![Zabbix Agent](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_agent/badge.svg) ![Zabbix Server](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_server/badge.svg) ![Zabbix Proxy](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_proxy/badge.svg) ![Zabbix Web](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_web/badge.svg) ![Zabbix Javagateway](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_javagateway/badge.svg) + +**Table of Contents** + +- [Zabbix collection for Ansible](#zabbix-collection-for-ansible) + * [Introduction](#introduction) + * [Included content](#included-content) + * [Installation](#installation) + + [Requirements](#requirements) + + [Installing the Collection from Ansible Galaxy](#installing-the-collection-from-ansible-galaxy) + + [Upgrading collection](#upgrading-collection) + * [Usage](#usage) + * [Supported Zabbix versions](#supported-zabbix-versions) + * [Collection life cycle and support](#collection-life-cycle-and-support) + * [Contributing](#contributing) + * [License](#license) + +## Introduction + +This repo hosts the `community.zabbix` Ansible Collection. + +The collection includes a variety of Ansible content to help automate the management of resources in Zabbix. + +## Included content + +Click on the name of a plugin or module to view that content's documentation: + + - **Inventory Sources**: + - [zabbix](scripts/inventory/zabbix.py) - Zabbix Inventory Script + - [zabbix_inventory](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_inventory_inventory.html) - Zabbix Ansible Inventory Plugin + - **Modules**: + - [zabbix_action](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_action_module.html) + - [zabbix_authentication](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_authentication_module.html) + - [zabbix_autoregister](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_autoregister_module.html) + - [zabbix_discovery_rule](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_discovery_rule_module.html) + - [zabbix_globalmacro](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_globalmacro_module.html) + - [zabbix_group_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_group_info_module.html) + - [zabbix_group](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_group_module.html) + - [zabbix_host_events_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_events_info_module.html) + - [zabbix_host_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_info_module.html) + - [zabbix_host](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_module.html) + - [zabbix_hostmacro](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_hostmacro_module.html) + - [zabbix_housekeeping](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_housekeeping_module.html) + - [zabbix_maintenance](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_maintenance_module.html) + - [zabbix_map](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_map_module.html) + - [zabbix_mediatype](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_mediatype_module.html) + - [zabbix_proxy_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_proxy_info_module.html) + - [zabbix_proxy](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_proxy_module.html) + - [zabbix_screen](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_screen_module.html) + - [zabbix_script](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_script_module.html) + - [zabbix_service](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_service_module.html) + - [zabbix_template_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_template_info_module.html) + - [zabbix_template](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_template_module.html) + - [zabbix_user_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_user_info_module.html) + - [zabbix_user](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_user_module.html) + - [zabbix_usergroup](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_usergroup_module.html) + - [zabbix_valuemap](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_valuemap_module.html) + - **Roles**: + - [zabbix_agent](docs/ZABBIX_AGENT_ROLE.md) + - [zabbix_javagateway](docs/ZABBIX_JAVAGATEWAY_ROLE.md) + - [zabbix_proxy](docs/ZABBIX_PROXY_ROLE.md) + - [zabbix_server](docs/ZABBIX_SERVER_ROLE.md) + - [zabbix_web](docs/ZABBIX_WEB_ROLE.md) + +## Installation + +### Requirements + +Each component in this collection requires additional dependencies. Review components you are interested in by visiting links present in the [Included content](#included-content) section. + +This is especially important for some of the Zabbix roles that require you to **install additional standalone roles** from Ansible Galaxy. + +For the majority of modules, however, you can get away with just: + +```bash +pip install zabbix-api +``` +#### Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now frequently required: `ansible.posix` and `community.general`. Installing the collections: + +```bash +ansible-galaxy collection install ansible.posix +ansible-galaxy collection install community.general +ansible-galaxy collection install ansible.netcommon +``` +### Installing the Collection from Ansible Galaxy + +Before using the Zabbix collection, you need to install it with the Ansible Galaxy CLI: + +```bash +ansible-galaxy collection install community.zabbix +``` + +You can also include it in a `requirements.yml` file along with other required collections and install them via `ansible-galaxy collection install -r requirements.yml`, using the format: + +```yaml +--- +collections: + - name: community.zabbix + version: 1.9.3 + - name: ansible.posix + version: 1.3.0 + - name: community.general + version: 3.7.0 +``` + +### Upgrading collection + +Make sure to read [UPGRADE](docs/UPGRADE.md) document before installing newer version of this collection. + +## Usage + +*Please note that these are not working examples. For documentation on how to use content included in this collection, refer to the links in the [Included content](#included-content) section.* + +To use a module or role from this collection, reference them with their Fully Qualified Collection Namespace (FQCN) like so: + +```yaml +--- +- name: Using Zabbix collection to install Zabbix Agent + hosts: localhost + roles: + - role: community.zabbix.zabbix_agent + zabbix_agent_server: zabbix.example.com + ... + +- name: If Zabbix WebUI runs on non-default (zabbix) path, e.g. http://<FQDN>/zabbixeu + set_fact: + ansible_zabbix_url_path: 'zabbixeu' + +- name: Using Zabbix collection to manage Zabbix Server's elements with username/password + hosts: zabbix.example.com + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 80 + ansible_httpapi_use_ssl: false # Set to true for HTTPS + ansible_httpapi_validate_certs: false # For HTTPS et to true to validate server's certificate + ansible_user: Admin + ansible_httpapi_pass: zabbix + tasks: + - name: Ensure host is monitored by Zabbix + community.zabbix.zabbix_host: + ... + +- name: Using Zabbix collection to manage Zabbix Server's elements with authentication key + hosts: zabbix.example.net + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 80 + ansible_httpapi_use_ssl: false # Set to true for HTTPS + ansible_httpapi_validate_certs: false # For HTTPS set to true to validate server's certificate + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + tasks: + - name: Ensure host is monitored by Zabbix + community.zabbix.zabbix_host: + ... +``` + +Or you include collection name `community.zabbix` in the playbook's `collections` element, like this: + +```yaml +--- +- name: Using Zabbix collection + hosts: localhost + collections: + - community.zabbix + + roles: + - role: zabbix_agent + zabbix_agent_server: zabbix.example.com + ... + +- name: Using Zabbix collection to manage Zabbix Server's elements with username/password + hosts: zabbix.example.com + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 80 + ansible_httpapi_use_ssl: false # Set to true for HTTPS + ansible_httpapi_validate_certs: false # For HTTPS et to true to validate server's certificate + ansible_user: Admin + ansible_httpapi_pass: zabbix + tasks: + - name: Ensure host is monitored by Zabbix + zabbix.zabbix_host: + ... + +- name: Using Zabbix collection to manage Zabbix Server's elements with authentication key + hosts: zabbix.example.net + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 80 + ansible_httpapi_use_ssl: false # Set to true for HTTPS + ansible_httpapi_validate_certs: false # For HTTPS et to true to validate server's certificate + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + tasks: + - name: Ensure host is monitored by Zabbix + zabbix_host: + ... +``` + +If Basic Authentication is required to access Zabbix server add following variables: +``` +zabbix_api_http_user: "user" +zabbix_api_http_password: "password" +``` + +## Supported Zabbix versions + +Main priority is to support Zabbix releases which have official full support from Zabbix LLC. Please checkout the versions at [Zabbix Life Cycle & Release Policy](https://www.zabbix.com/life_cycle_and_release_policy) page. + +> We aim to cover at least two LTS releases. For example, currently we support LTS 4.0 + 5.0 and with LTS 6.0 we will drop 4.0. But we do our best to also include the latest point releases - for example currently this is 5.4 which should be supperseeded by 6.2 then. + +Support for Zabbix LTS versions will be dropped with Major releases of the collection and mostly affect modules. Each role is following its unique support matrix. You should always consult documentation of roles in *docs/* directory. + +If you find any inconsistencies with the version of Zabbix you are using, feel free to open a pull request or an issue and we will try to address it as soon as possible. In case of pull requests, please make sure that your changes will not break any existing functionality for currently supported Zabbix releases. + +## Collection life cycle and support + +See [RELEASE](docs/RELEASE.md) document for more information regarding life cycle and support for the collection. + +## Contributing + +See [CONTRIBUTING](CONTRIBUTING.md) for more information about how to contribute to this repository. + +Please also feel free to stop by our [Gitter community](https://gitter.im/community-zabbix/community). + +## License + +GNU General Public License v3.0 or later + +See [LICENSE](LICENSE) to see the full text. diff --git a/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml b/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml new file mode 100644 index 000000000..afdd4fd6c --- /dev/null +++ b/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml @@ -0,0 +1,164 @@ +objects: {} +plugins: + become: {} + cache: {} + callback: {} + cliconf: {} + connection: {} + httpapi: + zabbix: + description: HttpApi Plugin for Zabbix + name: zabbix + version_added: 1.8.0 + inventory: + zabbix_inventory: + description: Zabbix Inventory Plugin + name: zabbix_inventory + version_added: 1.4.0 + lookup: {} + module: + zabbix_action: + description: Create/Delete/Update Zabbix actions + name: zabbix_action + namespace: '' + version_added: null + zabbix_authentication: + description: Update Zabbix authentication + name: zabbix_authentication + namespace: '' + version_added: 1.6.0 + zabbix_autoregister: + description: Update Zabbix autoregistration + name: zabbix_autoregister + namespace: '' + version_added: 1.6.0 + zabbix_discovery_rule: + description: Create/delete/update Zabbix discovery rules + name: zabbix_discovery_rule + namespace: '' + version_added: null + zabbix_globalmacro: + description: Create/update/delete Zabbix Global macros + name: zabbix_globalmacro + namespace: '' + version_added: 1.4.0 + zabbix_group: + description: Create/delete Zabbix host groups + name: zabbix_group + namespace: '' + version_added: null + zabbix_group_info: + description: Gather information about Zabbix hostgroup + name: zabbix_group_info + namespace: '' + version_added: null + zabbix_host: + description: Create/update/delete Zabbix hosts + name: zabbix_host + namespace: '' + version_added: null + zabbix_host_events_info: + description: Get all triggers about a Zabbix host + name: zabbix_host_events_info + namespace: '' + version_added: null + zabbix_host_info: + description: Gather information about Zabbix host + name: zabbix_host_info + namespace: '' + version_added: null + zabbix_hostmacro: + description: Create/update/delete Zabbix host macros + name: zabbix_hostmacro + namespace: '' + version_added: null + zabbix_housekeeping: + description: Update Zabbix housekeeping + name: zabbix_housekeeping + namespace: '' + version_added: 1.6.0 + zabbix_maintenance: + description: Create Zabbix maintenance windows + name: zabbix_maintenance + namespace: '' + version_added: null + zabbix_map: + description: Create/update/delete Zabbix maps + name: zabbix_map + namespace: '' + version_added: null + zabbix_mediatype: + description: Create/Update/Delete Zabbix media types + name: zabbix_mediatype + namespace: '' + version_added: null + zabbix_proxy: + description: Create/delete/get/update Zabbix proxies + name: zabbix_proxy + namespace: '' + version_added: null + zabbix_proxy_info: + description: Gather information about Zabbix proxy + name: zabbix_proxy_info + namespace: '' + version_added: 1.5.0 + zabbix_screen: + description: Create/update/delete Zabbix screens + name: zabbix_screen + namespace: '' + version_added: null + zabbix_script: + description: Create/update/delete Zabbix scripts + name: zabbix_script + namespace: '' + version_added: 1.7.0 + zabbix_service: + description: Create/update/delete Zabbix service + name: zabbix_service + namespace: '' + version_added: null + zabbix_template: + description: Create/update/delete/dump Zabbix template + name: zabbix_template + namespace: '' + version_added: null + zabbix_template_info: + description: Gather information about Zabbix template + name: zabbix_template_info + namespace: '' + version_added: null + zabbix_user: + description: Create/update/delete Zabbix users + name: zabbix_user + namespace: '' + version_added: null + zabbix_user_directory: + description: Create/update/delete Zabbix user directories + name: zabbix_user_directory + namespace: '' + version_added: null + zabbix_user_info: + description: Gather information about Zabbix user + name: zabbix_user_info + namespace: '' + version_added: null + zabbix_user_role: + description: Adds or removes zabbix roles + name: zabbix_user_role + namespace: '' + version_added: null + zabbix_usergroup: + description: Create/delete/update Zabbix user groups + name: zabbix_usergroup + namespace: '' + version_added: null + zabbix_valuemap: + description: Create/update/delete Zabbix value maps + name: zabbix_valuemap + namespace: '' + version_added: null + netconf: {} + shell: {} + strategy: {} + vars: {} +version: 1.9.3 diff --git a/ansible_collections/community/zabbix/changelogs/changelog.yaml b/ansible_collections/community/zabbix/changelogs/changelog.yaml new file mode 100644 index 000000000..dc62a39eb --- /dev/null +++ b/ansible_collections/community/zabbix/changelogs/changelog.yaml @@ -0,0 +1,878 @@ +ancestor: null +releases: + 0.1.0: + changes: + bugfixes: + - zabbix_action - allow str values for ``esc_period`` options (see `#66841 <https://github.com/ansible/ansible/pull/66841>`_). + - zabbix_action - no longer requires ``esc_period`` and ``event_source`` arguments + when ``state=absent``. + - zabbix_host - now supports configuring user macros and host tags on the managed + host (see `#66777 <https://github.com/ansible/ansible/pull/66777>`_). + - zabbix_host_info - ``host_name`` based search results now include host groups. + - zabbix_hostmacro - ``macro_name`` now accepts macros in zabbix native format + as well (e.g. ``{$MACRO}``). + - zabbix_hostmacro - ``macro_value`` is no longer required when ``state=absent``. + - zabbix_proxy (module) - ``interface`` sub-options ``type`` and ``main`` are + now deprecated and will be removed in community.general 3.0.0. Also, the values + passed to ``interface`` are now checked for correct types and unexpected keys. + - zabbix_proxy (module) - added option proxy_address for comma-delimited list + of IP/CIDR addresses or DNS names to accept active proxy requests from. + - zabbix_template - add new option omit_date to remove date from exported/dumped + template (see `#67302 <https://github.com/ansible/ansible/pull/67302>`_). + - zabbix_template - adding new update rule templateLinkage.deleteMissing for + newer zabbix versions (see `#66747 <https://github.com/ansible/ansible/pull/66747>`_). + - zabbix_template_info - add new option omit_date to remove date from exported/dumped + template (see `#67302 <https://github.com/ansible/ansible/pull/67302>`_). + deprecated_features: + - zabbix_proxy (module) - deprecates ``interface`` sub-options ``type`` and + ``main`` when proxy type is set to passive via ``status=passive``. Make sure + these suboptions are removed from your playbook as they were never supported + by Zabbix in the first place. + minor_changes: + - zabbix inventory plugin now no longer prints DeprecationWarning when used + with Python3 due to SafeConfigParser. + - zabbix_action - arguments ``event_source`` and ``esc_period`` no longer required + when ``state=absent``. + - zabbix_host - fixed inventory_mode key error, which occurs with Zabbix 4.4.1 + or more (see `#65304 <https://github.com/ansible/ansible/issues/65304>`_). + - zabbix_host - was not possible to update a host where visible_name was not + set in zabbix. + - zabbix_mediatype - Fixed to support zabbix 4.4 or more and python3 (see `#67693 + <https://github.com/ansible/ansible/pull/67693>`_). + - zabbix_template - fixed error when providing empty ``link_templates`` to the + module (see `#66417 <https://github.com/ansible/ansible/issues/66417>`_). + - zabbix_template - fixed invalid (non-importable) output provided by exporting + XML (see `#66466 <https://github.com/ansible/ansible/issues/66466>`_). + - zabbix_user - Fixed an issue where module failed with zabbix 4.4 or above + (see `#67475 <https://github.com/ansible/ansible/pull/67475>`_). + release_summary: '| Release date: 2020-06-15 + + ' + fragments: + - 010release.yml + release_date: '2020-06-15' + 0.2.0: + changes: + bugfixes: + - zabbix_action - documented ``value2`` parameter and ``notify_all_involved`` + option. + - zabbix_maintenance - changing value of ``description`` parameter now actually + updates maintenance's description. + - zabbix_template - is now able to perform ``state=dump`` when using ``ansible-playbook + --check``. + - zabbix_template - no longer imports template from ``template_json`` or ``template_xml`` + when using ``ansible-playbook --check``. + minor_changes: + - Documentation for roles moved to ``docs/`` sub-directory in the collection. + - New **role zabbix_agent** - previously known as dj-wasabi/zabbix-agent (also + see `UPGRADE.md <https://github.com/ansible-collections/community.zabbix/blob/main/docs/UPGRADE.md>`_ + for each role). + - New **role zabbix_javagateway** - previously known as dj-wasabi/zabbix-javagateway. + - New **role zabbix_proxy** - previously known as dj-wasabi/zabbix-proxy. + - New **role zabbix_server** - previously known as dj-wasabi/zabbix-server. + - New **role zabbix_web** - previously known as dj-wasabi/zabbix-web. + - zabbix_action - new alias ``update_operations`` for ``acknowledge_operations`` + parameter. + - zabbix_host - ``macros`` now support new macro types ``text`` and ``secret``. + - zabbix_host - new option ``details`` (additional SNMP details) for ``interfaces`` + parameter. + - zabbix_host - now supports Zabbix 5.0. + - zabbix_proxy (module) - now supports Zabbix 5.0. + - zabbix_screen - ``host_group`` parameter now accepts multiple groups. + release_summary: '| Release date: 2020-06-15 ' + fragments: + - 020release.yml + release_date: '2020-06-15' + 0.3.0: + changes: + bugfixes: + - zabbix_action - choices for the ``inventory`` paramter sub option in ``*operations`` + arguments have been clarified to ``manual`` and ``automatic``. + - zabbix_action - fixed error on changed API fields ``*default_message`` and + ``*default_subject`` for Zabbix 5.0 (see `#92 <https://github.com/ansible-collections/community.zabbix/pull/92>`_). + - zabbix_action - module will no longer fail when searching for global script + provided to ``script_name`` parameter. + - zabbix_action - now correctly selects mediatype for the (normal|recovery|update) + operations with Zabbix 4.4 and newer. + - zabbix_agent - fixed installation of agent on Windows to directories with + spaces. + - zabbix_agent - role should no longer fail when looking for ``getenforce`` + binary. + - zabbix_host - module will no longer convert context part of user macro to + upper case. + - zabbix_proxy (role) - will now correctly install python3-libsemanage on RHEL + OS family. + - zabbix_service - fixed the zabbix_service has no idempotency with Zabbix 5.0. + - zabbix_web - now no longer fails when rendering apache vhost template. + minor_changes: + - All roles now **support Zabbix 5.0** and by default install this version (see + `#131 <https://github.com/ansible-collections/community.zabbix/pull/131>`_ + and `#121 <https://github.com/ansible-collections/community.zabbix/pull/121>`_). + - Roles will now install gnupg on Debian OS family if not present. + - zabbix_action - no longer requires ``password`` and ``ssh_*key_file`` parameters + at the same time for ``remote_command`` operations of type SSH. + - zabbix_action - parameter ``ssh_auth_type`` for SSH ``remote_command`` operation + now correctly identifies which other parameters are required. + - zabbix_discovery_rule - refactoring module to use ``module_utils`` classes + and functions, adjust return values on success, add documentation for return + values. + - zabbix_discovery_rule - refactoring the module to remove unnecessary variables + and fix a variable typo. + - zabbix_mediatype - new options ``message_templates``, ``description`` and + many more related to ``type=webhook``. + - zabbix_mediatype - now supports new ``webhook`` media type. + release_summary: '| Release date: 2020-07-26 + + ' + fragments: + - 030release.yml + modules: + - description: Create/delete/update Zabbix discovery rules + name: zabbix_discovery_rule + namespace: '' + - description: Create/delete/update Zabbix user groups + name: zabbix_usergroup + namespace: '' + release_date: '2020-07-26' + 1.0.0: + changes: + breaking_changes: + - zabbix_javagateway - options ``javagateway_pidfile``, ``javagateway_listenip``, + ``javagateway_listenport`` and ``javagateway_startpollers`` renamed to ``zabbix_javagateway_xyz`` + (see `UPGRADE.md <https://github.com/ansible-collections/community.zabbix/blob/main/docs/UPGRADE.md>`_). + bugfixes: + - all roles - a ``handler`` is configured when ``zabbix_http(s)_proxy`` is defined + which will remove the proxy line from the repository files. This results that + execution of the roles are not idempotent anymore. + - zabbix_proxy (role) - ``StartPreprocessors`` only works with version 4.2 or + higher. When a lower version is used, it will not be added to the configuration. + - zabbix_proxy (role) - only install the sql files that needs to be executed + for when ``zabbix_repo`` is set to ``epel``. + - zabbix_server - ``StartPreprocessors`` only works with version 4.2 or higher. + When a lower version is used, it will not be added to the configuration. + - zabbix_server - only install the sql files that needs to be executed for when + ``zabbix_repo`` is set to ``epel``. + minor_changes: + - Added the possibility to configure the ``mode`` for the ``zabbix_{agent,server,proxy}_include`` + directories. + - all roles - added the possibility to configure the ``mode`` for the ``yum`` + repositories files in case it contains credentials. + - zabbix_agent - ``zabbix-sender`` and ``zabbix-get`` will not be installed + when ``zabbix_repo`` is set to ``epel``, as they are not part of the repository. + - zabbix_agent - added option to change between HTTP/HTTPS with ``zabbix_repo_yum_schema``. + - zabbix_agent - can also install the zabbix-agent2 application when ``zabbix_agent2`` + is set to ``true``. + - zabbix_proxy (role) - a user and group are created on the host when ``zabbix_repo`` + is set to ``epel``. + - zabbix_proxy (role) - now supports ``startpreprocessors`` setting and encryption + when connecting to database (see `#164 <https://github.com/ansible-collections/community.zabbix/pull/164>`_). + - zabbix_server - a user and group are created on the host when ``zabbix_repo`` + is set to ``epel``. + - zabbix_server - added option to change between HTTP/HTTPS with ``zabbix_repo_yum_schema``. + - zabbix_server - now supports ``startpreprocessors`` setting and encryption + when connecting to database (see `#164 <https://github.com/ansible-collections/community.zabbix/pull/164>`_). + - zabbix_web - a property is added ``zabbix_web_doubleprecision`` which currently + is set to ``false`` for default installations. For new installations this + should be set to ``True``. For upgraded installations, please read database + `upgrade notes <https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500>`_ + (Paragraph "Enabling extended range of numeric (float) values") before enabling + this option. + - zabbix_web - added option to change between HTTP/HTTPS with ``zabbix_repo_yum_schema``. + - zabbix_web - don't remove the files that Zabbix will install during installation + when you don't want to configure a virtual host configuration. + release_summary: '| Release date: 2020-08-16 + + ' + fragments: + - 100-release-prep.yaml + - role-agent-supports-zabbix-agent2.yaml + - role-all-configure-mode-include.yaml + - role-all-configure-mode-with-handlers.yaml + - role-all-fix-epel-installations.yaml + - role-web-add-doubleprecision.yaml + - role-web-zabbix_vhost-dont-remove-files.yaml + release_date: '2020-08-16' + 1.1.0: + changes: + bugfixes: + - all roles - missing ``become`` set to ``true`` was added to each task that + requires admin privleges. + - zabbix_agent - added new properties and updated documentation to allow for + correct Zabbix Agent2 configuration. + - zabbix_agent - fixed bug where Nginx prevented Apache from working as it was + part of the FPM configuration. + minor_changes: + - all roles - added ``zabbix_{agent,web,server,proxy,javagateway}_conf_mode`` + option for configuring a mode of the configuration file for each Zabbix service. + - zabbix_proxy (role) - added an option ``innodb_default_row_format`` for MariaDB/MySQL + if it isn't set to ``dynamic``. + - zabbix_server - fixed installation output when using MySQL database to not + print PostgreSQL. + - zabbix_user - ``passwd`` no longer required when ALL groups in ``usrgrps`` + use LDAP as ``gui_access`` (see `#240 <https://github.com/ansible-collections/community.zabbix/issues/232>`_). + - zabbix_user - no longer requires ``usrgrps`` when ``state=absent`` (see `#240 + <https://github.com/ansible-collections/community.zabbix/issues/232>`_). + - zabbix_web - added several configuration options for the PHP-FPM setup to + configure the listen (socket) file. + - zabbix_web - added support for configuring Zabbix Web with Nginx, same way + as with Apache. + release_summary: '| Release date: 2020-10-22 + + ' + fragments: + - 240-zabbix-user-nopass-ldap.yaml + - role-agent-correct-usage-acl.yaml + - role-agent-zabbix-agent2-props.yaml + - role-server-screen-output.yaml + - role-web-add-support-for-nginx.yaml + - role-web-added-some-properties.yaml + - roles-all-add-become.yaml + - roles-all-configure-conf-mode.yaml + - roles-server-proxy-add-innodb-check.yaml + release_date: '2020-10-22' + 1.2.0: + changes: + bugfixes: + - When installing the Zabbix packages, we disable all other yum repositories + except the one for the Zabbix. + - zabbix_agent - Agent 2 also be able to use userparameters file. + - zabbix_agent - Also work on SLES 12 sp5 + - zabbix_agent - Documented the property 'zabbix_proxy_ip' in the documentation. + - zabbix_agent - There was an task that wasn't able to use an http(s)_proxy + environment while installing an package. + - zabbix_agent - Windows - Able to create PSK file + - zabbix_agent - Windows - Fixing download links to proper version/url + - zabbix_agent - Windows - Removal of not working property + - zabbix_agent - Zabbix packages were not able to install properly on Fedora. + When the packages are installed, the version will be appended to the package + name. This is eofr all RedHat related OS'es. + - zabbix_agent - fixed issue with zabbix_agent2_tlspsk_auto having no effect + when using zabbix_agent2 + - zabbix_agent - fixed issue with zabbix_api_create_hosts and TLS configuration + when using zabbix_agent2, where zabbix_agent_tls* settings were used instead + of zabbix_agent2_tls* + - zabbix_host - module will no longer require ``interfaces`` to be present when + creating host with Zabbix 5.2 (https://github.com/ansible-collections/community.zabbix/pull/291). + - zabbix_host - should no longer fail with 'host cannot have more than one default + interface' error (https://github.com/ansible-collections/community.zabbix/pull/309). + - zabbix_proxy (role) - Added missing paragraph for the SQLite3 as database. + - zabbix_proxy (role) - The become option was missing in some essential tasks + when installing the Zabbix Proxy with SQLite3 as database. + - zabbix_proxy (role) - Various documentation fixes removing the Zabbix Server + and replaced it with actual Zabbix Proxy information. + - zabbix_proxy - Added new property 'zabbix_proxy_ip' to determine ip for host + running the Zabbix Proxy. + - zabbix_proxy - The 'interface' option was missing when creating an Proxy via + the API. + - zabbix_template - fixed documentation for ``macros`` argument (https://github.com/ansible-collections/community.zabbix/pull/296). + - zabbix_template - fixed encode error when using Python2 (https://github.com/ansible-collections/community.zabbix/pull/297). + - zabbix_template - fixed issue when importing templates to zabbix version. + >= 5.2 + - zabbix_template_info - fixed encode error when using Python2 (https://github.com/ansible-collections/community.zabbix/pull/297). + - zabbix_user - disable no_log warning for option override_password. + - zabbix_user - fixed issue where module couldn't create a user since Zabbix + 5.2 (https://github.com/ansible-collections/community.zabbix/pull/260). + - zabbix_web - fixed issue Role cannot install Zabbix web 5.0 on RHEL 7 (https://github.com/ansible-collections/community.zabbix/issues/202). + minor_changes: + - Updated the roles to support Zabbix 5.2. + - zabbix_agent - Added a new property `zabbix_agent_dont_detect_ip` when set + to true, it won't detect the ips and no need to install the python module + `netaddr`. + - zabbix_agent - Added parameter `zabbix_agent_package_remove` when set to `true` + and `zabbix_agent2` is set to `true` it will uninstall the `zabbix-agent` + service and package. + - zabbix_agent - added `zabbix_agent_install_agent_only` Will only install the + Zabbix Agent package and not the `zabbix-sender` or `zabbix-get` packages. + - zabbix_template - Fixed to decode Unicode Escape of multibyte strings in an + importing template data(https://github.com/ansible-collections/community.zabbix/pull/226). + - zabbix_user - added new parameters to set timezone and role_name for users + (https://github.com/ansible-collections/community.zabbix/pull/260). + - zabbix_user - user_medias now defaults to None and is optional (https://github.com/ansible-collections/community.zabbix/pull/264). + - zabbix_web - added `zabbix_web_rhel_release` which enable scl on RHEL (https://github.com/ansible-collections/community.zabbix/pull/266). + - zabbix_web - quality of life improvements when using Nginx (https://github.com/ansible-collections/community.zabbix/pull/304). + release_summary: '| Release date: 2021-01-11 | Last major release to support + Zabbix server 3.X versions in plugins.' + fragments: + - 226-zabbix_template.yaml + - 254-disable-no-log-warning.yml + - 260-zabbix_user.yml + - 264-allow-user_medias-to-be-optional.yaml + - 266-zabbix_web.yml + - 297-zabbix_template_modules.yml + - 309-host-interfaces.yaml + - agent-missing-proxy-task.yaml + - agent-not-detect-ips.yml + - agent-use-version-for-rh.yml + - agent2-psk-fixes.yml + - module-zabbix_host-interfaces-not-required.yaml + - module-zabbix_template-argspec-doc.yaml + - proxy-able-to-use-interface.yaml + - role-agent-allow-uninstall-agent.yaml + - role-agent-userparameter.yaml + - role-agent-windows-service-handling.yaml + - role-agent-work-with-sles.yaml + - role-proxy-sqlite3-zabbix-proxy.yaml + - roles-all-enable-zabbix-disable-rest.yaml + - roles-all-update-to-zabbix-52.yml + - templatescreens-fix.yml + release_date: '2021-01-11' + 1.3.0: + changes: + bugfixes: + - zabbix_action - now properly filters discovery rule checks by name (https://github.com/ansible-collections/community.zabbix/pull/349). + - zabbix_agent - corrected version for Windows agents (https://github.com/ansible-collections/community.zabbix/pull/316). + - zabbix_agent - fixed download URL for MacOS (https://github.com/ansible-collections/community.zabbix/pull/325). + - zabbix_server - now installs correct MySQL client packages on RHEL8 systems + (https://github.com/ansible-collections/community.zabbix/pull/343). + - zabbix_template - fixed an issue with Python2 where module wouldn't decode + Unicode characters (https://github.com/ansible-collections/community.zabbix/pull/322). + - zabbix_web - fixed installation of python3-libsemanage package RHEL7 and older + systems (https://github.com/ansible-collections/community.zabbix/pull/330). + - zabbix_web - role should now correctly determine naming of PHP packages on + older systems (https://github.com/ansible-collections/community.zabbix/pull/344). + - zabbix_web - updated default PHP version for Debian10 (https://github.com/ansible-collections/community.zabbix/pull/323). + minor_changes: + - zabbix_agent - added support for installations on arm64 systems (https://github.com/ansible-collections/community.zabbix/pull/320). + - zabbix_proxy - now supports configuring StatsAllowedIP (https://github.com/ansible-collections/community.zabbix/pull/337). + - zabbix_server - added support for installtions on arm64 systems (https://github.com/ansible-collections/community.zabbix/pull/320). + - zabbix_web - added support for installtions on arm64 systems (https://github.com/ansible-collections/community.zabbix/pull/320). + release_summary: '| Release date: 2021-03-20 | Last major release to support + Zabbix server 3.X versions in plugins.' + security_fixes: + - zabbix_action - no longer exposes remote SSH command password used in operations, + recovery & acknowledge operations to system logs (https://github.com/ansible-collections/community.zabbix/pull/345). + - zabbix_discovery_rule - no longer exposes SNMPv3 auth and priv passphrases + to system logs (https://github.com/ansible-collections/community.zabbix/pull/345). + - zabbix_host - no longer exposes SNMPv3 auth and priv passphrases to system + logs (https://github.com/ansible-collections/community.zabbix/pull/345). + fragments: + - 316-zbx-agent-windows-long-version.yaml + - 322-zabbix_template.yml + - 323-zabbix_web.yml + - 325-zbx-agent-macos.yaml + - 330-zabbix_web-selinux.yaml + - 337-zabbix_proxy-statsAllowedIP.yaml + - 343-zabbix_server-rhel8-mysql.yaml + - 344-zabbix_web-legacyphp.yaml + - 345-security-fixes-no_log.yaml + - 349-zabbix_action-dcheck-filter.yaml + - raspberry-server.yaml + - raspberry.yaml + release_date: '2021-03-20' + 1.4.0: + changes: + bugfixes: + - zabbix_agent - StatusPort will be configured only when `zabbix_agent2_statusport` + is defined (https://github.com/ansible-collections/community.zabbix/pull/378) + - zabbix_agent - fixed issue preventing installation of zabbix-agent 4.2 on + Ubuntu Focal 20.04 (https://github.com/ansible-collections/community.zabbix/pull/390) + - zabbix_agent - role will now configure correct port for hostinterface in Zabbix + Server if `zabbix_agent2_listenport` is defined (https://github.com/ansible-collections/community.zabbix/pull/400) + - zabbix_agent - should no longer be failing on Windows platform due to re-running + all of the tasks for the 2nd time (https://github.com/ansible-collections/community.zabbix/pull/376) + - zabbix_agent - should no longer fail while cleaning up zabbix_agent installation + if Zabbix Agent2 is being used (https://github.com/ansible-collections/community.zabbix/pull/409) + - zabbix_agent - will no longer install zabbix_get package on Debian systems + when `zabbix_agent_install_agent_only` is defined (https://github.com/ansible-collections/community.zabbix/pull/363) + - zabbix_host - fixed issue where module was idempotent when multiple host interfaces + of the same type were present (https://github.com/ansible-collections/community.zabbix/pull/391) + - zabbix_proxy (role) - will no longer fail on proxy creation in Zabbix Server + when TLS parameters are used (https://github.com/ansible-collections/community.zabbix/pull/388) + - zabbix_server - Removed the removal everything from /tmp directory command + as it removes things that it shouldnt do. + - zabbix_template - first time import of template now works with Zabbix 5.4 + (https://github.com/ansible-collections/community.zabbix/pull/407), please + note that rerunning the task will fail as there are breaking changes in Zabbix + 5.4 API that module not yet covers. + - zabbix_user - now works with Zabbix 5.4 (https://github.com/ansible-collections/community.zabbix/pull/406) + minor_changes: + - all roles were updated to support Zabbix 5.4 release (https://github.com/ansible-collections/community.zabbix/pull/405) + - new inventory plugin zabbix_inventory (https://github.com/ansible-collections/community.zabbix/pull/373) + - new module plugin zabbix_globalmacro (https://github.com/ansible-collections/community.zabbix/pull/377) + - zabbix_agent - `zabbix_agent_src_reinstall` now defaults to `False` (https://github.com/ansible-collections/community.zabbix/pull/403) + - zabbix_agent - now supports setting AllowKey (https://github.com/ansible-collections/community.zabbix/pull/358) + - zabbix_globalmacros - it is now possible to create global macros using this + module (https://github.com/ansible-collections/community.zabbix/pull/377). + - zabbix_inventory - Created Ansible - Zabbix inventory plugin to create dynamic + inventory from Zabbix. + - zabbix_maintenance - it is now possible to target hosts by their technical + name if it differs from the visible name + - zabbix_proxy - Add MySQL Python 3 package installation. + - zabbix_server - Add MySQL Python 3 package installation. + - zabbix_server - now supports setting StartLLDProcessors (https://github.com/ansible-collections/community.zabbix/pull/361) + - zabbix_user - now supports parameter `username` as an alternative to `alias` + (https://github.com/ansible-collections/community.zabbix/pull/406) + - zabbix_user - removed some of the default values because a configuration should + be changed only if specified as a parameter (https://github.com/ansible-collections/community.zabbix/pull/382). + - zabbix_web - now supports setting SAML certificates (https://github.com/ansible-collections/community.zabbix/pull/408) + fragments: + - 350-zabbix_maintenance-visible_name.yaml + - 373-create_zabbix_inventory.yaml + - 377-create_globalmacros_module.yaml + - 382-zabbix_user.yml + - 391-zabbix_host-intf_idempotency_fix.yml + - zabbix-proxy-package-installation.yaml + - zabbix-server-tmp-dir.yml + - zbx-catch-all.yml + modules: + - description: Create/update/delete Zabbix Global macros + name: zabbix_globalmacro + namespace: '' + plugins: + inventory: + - description: Zabbix Inventory Plugin + name: zabbix_inventory + namespace: null + release_date: '2021-06-29' + 1.5.0: + changes: + breaking_changes: + - all roles now reference other roles and modules via their fully qualified + collection names, which makes Ansible 2.10 minimum supported version for roles + (See https://github.com/ansible-collections/community.zabbix/pull/477). + bugfixes: + - all roles now support installing zabbix 4.0 version on Ubuntu 20.04. + - all roles now supports installations on Debian 11. + - zabbix inventory - Change default value for host_zapi_query from list "[]" + to dict "{}". + - zabbix_action - should no longer fail with Zabbix version 5.4. + - zabbix_agent - `zabbix_win_install_dir` no longer ignored for zabbix_agentd.d + and zabbix log directories. + - zabbix_agent - auto-recovery for Windows installation has been fixed (https://github.com/ansible-collections/community.zabbix/pull/470). + - zabbix_agent - deploying zabbix_agent2 under Windows should now be possible + (Thanks to https://github.com/ansible-collections/community.zabbix/pull/433 + and https://github.com/ansible-collections/community.zabbix/pull/453). + - zabbix_agent - fixed AutoPSK for Windows deployments (https://github.com/ansible-collections/community.zabbix/pull/450). + - zabbix_host - Fix error when updating hosts caused by Zabbix bug not returning + the inventory_mode field for hosts(https://github.com/ansible-collections/community.zabbix/issues/385). + - zabbix_host - will not break when `tls_psk*` parameters are set with Zabbix + version 5.4. + - zabbix_proxy (module) - now supports configuring `tls_psk*` parameters. + - zabbix_proxy (role) - TLS config should now properly configure certificates. + - zabbix_proxy (role) - should no longer fail on permission problems wren configured + to use SQLite database and now installs correct package sqlite3 on Debian + systems. + - zabbix_web - `zabbix_nginx_vhost_*` parameters are no longer ignored. + - zabbix_web - executing role with `--tags` should now correctly include distribution + specific variables (https://github.com/ansible-collections/community.zabbix/pull/448). + - zabbix_web - now correctly restarts php-fpm service (https://github.com/ansible-collections/community.zabbix/pull/427). + - zabbix_web - permissions for accesing php-fpm socket has been fixed (See https://github.com/ansible-collections/community.zabbix/pull/426). + minor_changes: + - Added requirements.txt to collection root to be used with Ansible Builder. + See https://ansible-builder.readthedocs.io/en/latest/collection_metadata.html + - some roles are now using new naming for API connection parameters (https://github.com/ansible-collections/community.zabbix/pull/492 + and https://github.com/ansible-collections/community.zabbix/pull/495). + - some roles can now utilize an option `zabbix_repo_yum_gpgcheck` to enable/disable + GPG check for YUM repository (https://github.com/ansible-collections/community.zabbix/pull/438). + - zabbix inventory - Enabled the usage of environment variables in zabbix inventory + plugin. + - zabbix inventory plugin - can now use environment variables ZABBIX_SERVER, + ZABBIX_USERNAME and ZABBIX_PASSWORD for connection purposes to the Zabbix + API. + - zabbix_agent - `zabbix_agent_loadmodule` can also be configured with a list. + - zabbix_agent - new `zabbix_api_timeout` option. + - zabbix_agent - now supports DenyKeys configuration. + - zabbix_hostmacro - now supports creating macros of type secret and vault. + - zabbix_proxy (role) - new `zabbix_api_timeout` option. + - zabbix_proxy_info - new module that allows to retrieve information about configured + Zabbix Proxies. + - zabbix_server - added support for TimescaleDB (https://github.com/ansible-collections/community.zabbix/pull/428). + fragments: + - 0-copy_ignore_txt.yml + - 415-inventory_mode-fix.yaml + - 456-zabbix-hostmacro-secret-vault.yml + - 505-awx_compatibility-fixes.yml + - zbx-missing-1.5.0.yml + - zbx-proxy-info.yaml + modules: + - description: Gather information about Zabbix proxy + name: zabbix_proxy_info + namespace: '' + release_date: '2021-11-02' + 1.5.1: + changes: + bugfixes: + - template - use templateid property when linking templates for ``template.create`` + and ``template.update`` API calls. + - zabbix inventory - Moved ZABBIX_VALIDATE_CERTS to correct option, validate_certs. + - zabbix_agent - Create the actual configuration file for Windows setups. + - zabbix_agent - Fix typo for correct using the zabbix_windows_service.exists + - zabbix_agent - tlspsk_auto to support become on Linux and ignore on windows + - zabbix_user - fix zabbix_user require password only on internal. + minor_changes: + - Enabled usage of environment variables for modules by adding a fallback lookup + in the module_utils/helpers.py - zabbix_common_argument_spec + fragments: + - 508-zabbix-env-vars.yml + - 512-inventory-bugfix.yaml + - 521-agent-typo.yaml + - 523-templateid-property.yml + - 527-agent-windows-config-creation.yaml + - 537-TLSPSK.yaml + - 543-internal-user.yaml + release_date: '2021-12-05' + 1.6.0: + changes: + bugfixes: + - 'Various modules and plugins - use vendored version of ``distutils.version`` + instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.zabbix/pull/603). + This superseedes #597.' + - ZapiWrapper (module_utils) - fix only partial zabbix version is returned. + - zabbix_agent - Install Zabbix packages when zabbix_repo == other is used with + yum. + - zabbix_agent - Install the Agent for MacOSX sooner than its configuration. + - zabbix_agent - The ``Install gpg key`` task for Debian did not work when a + http proxy is configured. + - zabbix_agent - Use the correct URL with correct version. + - zabbix_agent - Use the correct path to determine Zabbix Agent 2 installation + on Windows. + - zabbix_agent - Using the correct hostgroup as default now. + - zabbix_agent - fix for the autopsk, incl. tests with Molecule. + - zabbix_host - Added small notification that an user should have read access + to get hostgroups overview. + - zabbix_host - adapter changed properties for interface comparisson + - zabbix_maintenance - should now work when creating maintenace on Zabbix 6.0 + server + - zabbix_proxy - 'zcat' the zipped sql files to /tmp before executing it. + - zabbix_proxy - Check MySQL version before settings mysql_innodb_default_row_format + value. + - zabbix_proxy - Install Zabbix packages when zabbix_repo == other is used with + yum. + - zabbix_server - 'zcat' the zipped sql files to /tmp before executing it. + - zabbix_server - Check MySQL version before settings mysql_innodb_default_row_format + value. + - zabbix_server - Install Zabbix packages when zabbix_repo == other is used + with yum. + - zabbix_template - setting correct null values to fix unintentional changes + - zabbix_web - Added some default variables if the geerlingguys apache role + is not used. + - zabbix_web - Specified the correct versions for php. + minor_changes: + - all modules - prepare for deprecation of distutils LooseVersion. + - collection - Add dependencies to other collections. This helps Ansible Galaxy + automatically downloading collections that this collection relies on to run. + - connection.httpapi (plugin) - add initial httpapi connection plugin. + - httpapi.jsonrpc (plugin) - add initial httpapi for future handling of json-rpc. + - new module zabbix authentication for configuring global authentication settings + in Zabbix Server's Settings section of GUI. + - new module zabbix_autoregister for configuring global autoregistration settings + in Zabbix Server's Settings section of GUI. + - new module zabbix_housekeeping for configuring global housekeeping settings + in Zabbix Server's Settings section of GUI. + - test_zabbix_host_info - fix Template/Group names for 5.4 + - test_zabbix_screen - disable testing for screen in 5.4 (deprecated) + - zabbix_action - additional fixes to make module work with Zabbix 6.0 (https://github.com/ansible-collections/community.zabbix/pull/664) + - zabbix_action - module ported to work with Zabbix 6.0 (https://github.com/ansible-collections/community.zabbix/pull/648, + https://github.com/ansible-collections/community.zabbix/pull/653) + - zabbix_action - should now correctly actions with maintenance_status conditions + (https://github.com/ansible-collections/community.zabbix/pull/667) + - zabbix_agent - Check if 'firewalld' exist and is running when handler is executed. + - zabbix_agent - Fixed use of bare variables in conditions (https://github.com/ansible-collections/community.zabbix/pull/663) + - zabbix_agent - Install the correct Python libxml2 package on SLES15 + - zabbix_agent - Move inclusion of the apache.yml tasks to later stage during + execution of role. + - zabbix_agent - Prepare for Zabbix 6.0. + - zabbix_agent - Specify a minor version with zabbix_agent_version_minor for + RH systems. + - zabbix_agent - There was no way to configure a specific type for the macro. + - zabbix_agent - Use multiple aliases in the configuration file with ``zabbix_agent_zabbix_alias`` + or ``zabbix_agent2_zabbix_alias``. + - zabbix_maintenance - added new module parameter `tags`, which allows configuring + Problem Tags on maintenances. + - zabbix_maintenance - fixed to work with Zabbix 6.0+ and Python 3.9+ (https://github.com/ansible-collections/community.zabbix/pull/665) + - zabbix_proxy - Prepare for Zabbix 6.0. + - zabbix_proxy - Specify a minor version with zabbix_proxy_version_minor for + RH systems. + - zabbix_proxy - Support for Sangoma and treat it like a RHEL system. + - zabbix_server - Check the 'zabbix_server_install_database_client' variable + in RedHat tasks. + - zabbix_server - Prepare for Zabbix 6.0. + - zabbix_server - Specify a minor version with zabbix_server_version_minor for + RH systems. + - zabbix_user - change alias property to username (changed in 5.4) (alias is + now an alias for username) + - zabbix_user_info - change alias property to username (changed in 5.4) (alias + is now an alias for username) + - zabbix_web - Change format ENCRYPTION, VERIFY_HOST from string to boolean. + - zabbix_web - Specify a minor version with zabbix_web_version_minor for RH + systems. + fragments: + - 144-check-if-service-is-running.yml + - 329-only-do-apache-stuff.yml + - 356-zbx-maint-tags.yml + - 360-fix-macos-install.yml + - 367-add-dependencies.yml + - 414-specify-minor-version.yml + - 444-add-initial-httpapi.yml + - 560-prepare-zabbix-60-roles.yml + - 570-fix-autopsk.yml + - 574-fix-windows-url.yml + - 583-change-var-type.yml + - 587-host-cannot-have-same-type.yml + - 588-template-not-found.yml + - 589-failed-to-get-screen.yml + - 591-invalid-parameter.yml + - 592-has-no-attribute.yml + - 597-prepare-distutils.yml + - 599-multiple-aliases.yml + - 603-vendor-distutils.yml + - 612-use-correct-value.yml + - 620-add-macro-type.yml + - 622-fix-environmentsettings.yml + - 630-zabbix-autoreg.yml + - 638-sangoma-rhel.yml + - 645-zabbix-authentication.yml + - 647-zabbix-housekeeping.yml + - 648-653-zbx_action.yaml + - 654-check-zabbix_server_install_database_client-rhel.yml + - 664-zbx_action.yaml + - 665-zbx_maint.yaml + - 668-zabbix_agent-sles15.yml + - various-wd.yml + modules: + - description: Update Zabbix authentication + name: zabbix_authentication + namespace: '' + - description: Update Zabbix autoregistration + name: zabbix_autoregister + namespace: '' + - description: Update Zabbix housekeeping + name: zabbix_housekeeping + namespace: '' + plugins: + connection: + - description: Use httpapi to run command on network appliances + name: httpapi + namespace: null + httpapi: + - description: HttpApi Plugin for Zabbix + name: jsonrpc + namespace: null + release_date: '2022-03-21' + 1.7.0: + changes: + bugfixes: + - Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``. + - zabbix_action - will no longer wipe `esc_step_to` and `esc_step_from` (https://github.com/ansible-collections/community.zabbix/issues/692) + - zabbix_agent - added support for zabbix-agent on Ubuntu 22.04 (https://github.com/ansible-collections/community.zabbix/pull/681) + - zabbix_agent - now properly creates webroot for issuing LE certificates (https://github.com/ansible-collections/community.zabbix/pull/677, + https://github.com/ansible-collections/community.zabbix/pull/682) + - zabbix_proxy (module) - passive proxy should be now correctly created in Zabbix + 6.0 (https://github.com/ansible-collections/community.zabbix/pull/697) + - zabbix_proxy (role) - fixed accidental regression of TLS psk file being generated + for passive agent (#528) caused in (#663) (https://github.com/ansible-collections/community.zabbix/issues/680) + minor_changes: + - helpers.helper_compare_lists() changed logic to not consider the order of + elements in lists. (https://github.com/ansible-collections/community.zabbix/pull/683) + - zabbix_action, zabbix_maintenance, zabbix_mediatype, zabbix_proxy, zabbix_service + - updated to work with Zabbix 6.0. (https://github.com/ansible-collections/community.zabbix/pull/683) + - zabbix_script module added (https://github.com/ansible-collections/community.zabbix/issues/634) + fragments: + - 1.7.0-missing-fragments.yml + - 683-zbx60.yml + - 685-zabbix-script.yml + - 699-proxy-role-regression.yml + - psf-license.yml + modules: + - description: Create/update/delete Zabbix scripts + name: zabbix_script + namespace: '' + release_date: '2022-05-24' + 1.8.0: + changes: + bugfixes: + - zabbix_host - fixed idempotency of the module when hostmacros or snmp interfaces + are used + - zabbix_script - fix compatibility with Zabbix <5.4. + - zabbix_script - should no longer fail when description is not set + minor_changes: + - roles - Minimized the config templates for the zabbix_agent, zabbix_javagateway, + zabbix_proxy, and zabbix_server roles to make them version independent. + - roles - Support for Zabbix 6.2 has been added + - roles - Updated the version defaults to select the latest version supported + by an operating system. + - zabbix_action - added another condition operator naming options (contains, + does not contain,...) + - zabbix_agent - Set a ansible_python_interpreter to localhost based on the + env the playbook is executed from. + - zabbix_agent - add option to set host tags using ``zabbix_agent_tags``. + - zabbix_agent - add possiblity to set include file pattern using ``zabbix_agent(2)_include_pattern`` + variable. + - zabbix_agent - is now able to manage directories and upload files for TLS + PSK configuration used with Windows operating systems + - zabbix_agent - new options for Windows installations zabbix_win_install_dir_conf/bin + - zabbix_agent - when configuring firewalld, make sure the new rule is applied + immediately + - zabbix_authentication - module updated to support Zabbix 6.2 + - zabbix_host - using ``tls_psk_identity`` or ``tls_psk`` parameters with Zabbix + >= 5.4 makes this module non-idempotent + - zabbix_host - will no longer wipe tls_connect en tls_accept settings when + not specified on update + - zabbix_mediatype - added support for time units in ``attempt_interval`` parameter + - zabbix_template - added support for template groups (Zabbix >= 6.2) + - zabbix_template_info - add template_id return value + - zabbix_template_info - add yaml and none formats + - zabbix_user_directory - added new module to support multiple sources for LDAP + authentication + fragments: + - 602-change-intrepeter.yml + - 711-minimize-role-config-templates.yml + - 727-script-compatibility.yml + - 731-template-info-formats.yml + - 738-template-groups.yml + - 741-host-tls-psk-fix.yml + - 743-agent-tags.yml + - 744-mediatype-attemptinterval-timeunits.yml + - 749-action-operator-naming.yml + - 753-host-tls-settings.yml + - 755-user-directory-module.yml + - 770-agent-include-pattern.yml + - 771-auto-select-version.yml + - firewalld_immediate.yaml + - missing.yml + release_date: '2022-08-15' + 1.9.0: + changes: + bugfixes: + - The inventory script had insufficient error handling in case the Zabbix API + provided an empty interfaces list. This bugfix checks for an exisiting interfaces + element, then for the minimal length of 1 so that the first interface will + only be accessed when it really exists in the api response. (https://github.com/ansible-collections/community.zabbix/issues/826) + - zabbix-proxy - updated to install correct sources for Debian arm64 family + - zabbix_agent - Filter IPv6 addresses from list of IP as Zabbix host creation + expects IPv4 + - zabbix_agent - installation on Windows will no longer fail when zabbix_agent2 + is used + - zabbix_host - fix updating of host without interfaces + - zabbix_proxy - correctly provision tls_accept and tls_connect on Zabbix backend + - zabbix_proxy - updated the datafiles_path fact for the zabbix_proxy and zabbix_server + roles due to upstream change + - zabbix_server - move location of the fping(6) variables to distribution specific + files (https://github.com/ansible-collections/community.zabbix/issues/812) + - zabbix_server - updated the datafiles_path fact for the zabbix_proxy and zabbix_server + roles due to upstream change + major_changes: + - all modules are opting away from zabbix-api and using httpapi ansible.netcommon + plugin. We will support zabbix-api for backwards compatibility until next + major release. See our README.md for more information about how to migrate + - zabbix_agent and zabbix_proxy roles are opting away from zabbix-api and use + httpapi ansible.netcommon plugin. We will support zabbix-api for backwards + compatibility until next major release. See our README.md for more information + about how to migrate + minor_changes: + - ansible_zabbix_url_path introduced to be able to specify non-default Zabbix + WebUI path, e.g. http://<FQDN>/zabbixeu + - collection now supports creating ``module_defaults`` for ``group/community.zabbix.zabbix`` + (see https://github.com/ansible-collections/community.zabbix/issues/326) + - fixed ``zabbix_server`` role failure running in check_mode (see https://github.com/ansible-collections/community.zabbix/issues/804) + - zabbix_agent - give Zabbix Agent access to the Linux DMI table allowing system.hw.chassis + info to populate. + - zabbix_template - add support for template tags + - zabbix_user_role module added + - zabbix_web - add support for Ubuntu 22.04 jammy + fragments: + - 326-module_defaults-group.yml + - 526-swap-tls-accept-connect-in-proxy.yaml + - 778-zbx-agent2-win.yml + - 784-allow-system.hw.chassis-to-populate-on-linux.yml + - 786-web-add-ubuntu-22-04-support.yml + - 792-update-host-without-iface-fix.yml + - 795-zbx-agent-win-ipv6.yml + - 800-add-template-tags.yml + - 806-httpapi-connection-plugin.yml + - 812-fping-binary-location.yml + - 813-sql-scripts-moved-to-usr-share.yml + - 821-zabbix-proxy-debian-arm64.yml + - 822-roles-to-httpapi.yml + - 823-zabbix_server-role-in-check-mode.yml + - 827-fixing-bug-for-empty-interfaces-list.yml + - module_zabbix-user-role.yml + - modules-url-path.yml + release_date: '2022-11-07' + 1.9.1: + changes: + bugfixes: + - all modules - remove deprecation warnings for modules parameters related to + zabbix-api when these parapmeters are not explicetely defined + - all roles and modules integration tests - replace deprecated include module + whith include_tasks + - zabbix_agent, zabbix_proxy roles, all modules - make httpapi connection work + with HTTP Basic Authorization + - zabbix_proxy - do not set ServerPort config parameter which was removed in + Zabbix 6.0 + - 'zabbix_server role Debian.yml task - remove warn: arg for shell module as + the arg is deprecated since ansible-core above 2.13' + - zabbix_user_role module - creation of a User Role with Super Admin type + minor_changes: + - zabbix suport for rhel 9 + fragments: + - 845-rhel-9-support.yml + - 850-proxy-serverport.yml + - 857-deprecation-warnings.yml + - 859-remove-warn-arg.yml + - 866-user-role-superadmin.yml + - 868-include-to-include-tasks.yml + - fix-httpapi-http-auth.yml + release_date: '2023-01-09' + 1.9.2: + changes: + bugfixes: + - zabbix_agent and zabbix_proxy roles - fixed a bug whith ansible_python_interpreter + not being set correctly in some corner cases + - zabbix_agent role - Fix MacOS install never executed because of the missing + include_tasks "Darwin.yml" in the "main.yml" task file and wrong user permission + on folder/files. + - zabbix_agent, zabbix_proxy and zabbix_server roles - make Ansible 2.14 compatible + by removing warn parameter + fragments: + - 897.yml + - missing.yml + release_date: '2023-02-11' + 1.9.3: + changes: + bugfixes: + - compatibility with ansible.netcommon 5.0.0 + - treat sendto parameter in module zabbix_user according to real media type, + do not rely on media name + - zabbix-proxy role - fix tags for postgresql task. + - zabbix_agent role - Fix MacOS install never executed because of the missing + include_tasks "Darwin.yml" in the "main.yml" task file and wrong user permission + on folder/files. + - zabbix_user module - ability to specify several e-mail addresses in Zabbix + User's media + minor_changes: + - httpapi plugin - updated to work with Zabbix 6.4. + - zabbix_action, zabbix_authentication, zabbix_discovery_rule, zabbix_mediatype, + zabbix_user, zabbix_user_directory, zabbix_usergroup - updated to work with + Zabbix 6.4. + - zabbix_agent role - Add support for SUSE Linux Enterprise Server for SAP Applications + ("SLES_SAP"). + - zabbix_host - add missing variants for SNMPv3 authprotocol and privprotocol + introduced by Zabbix 6 + - zabbix_proxy role - Add variable zabbix_proxy_dbpassword_hash_method to control + whether you want postgresql user password to be hashed with md5 or want to + use db default. When zabbix_proxy_dbpassword_hash_method is set to anything + other than md5 then do not hash the password with md5 so you could use postgresql + scram-sha-256 hashing method. + - zabbix_server role - Add variable zabbix_server_dbpassword_hash_method to + control whether you want postgresql user password to be hashed with md5 or + want to use db default. When zabbix_server_dbpassword_hash_method is set to + anything other than md5 then do not hash the password with md5 so you could + use postgresql scram-sha-256 hashing method. + - zabbix_usergroup module - userdirectory, hostgroup_rights and templategroup_rights + parameters added (Zabbix >= 6.2) + - zabbix_web role - possibility to add custom includes in apache vhost config + fragments: + - 871.yml + - 880.yml + - 886.yml + - 890.yml + - 897.yml + - 899.yml + - 910-postgres-proxy.yml + - 935-custom-includes-apache.yml + - netcommon50-fix.yaml + - zabbix64.yml + - zabbix_user_media_mailto.yml + - zabbix_user_sendto.yaml + release_date: '2023-04-03' diff --git a/ansible_collections/community/zabbix/changelogs/config.yaml b/ansible_collections/community/zabbix/changelogs/config.yaml new file mode 100644 index 000000000..237a9b7d4 --- /dev/null +++ b/ansible_collections/community/zabbix/changelogs/config.yaml @@ -0,0 +1,32 @@ +--- +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +ignore_other_fragment_extensions: true +keep_fragments: false +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: community.zabbix +trivial_section_name: trivial +use_fqcn: true diff --git a/ansible_collections/community/zabbix/changelogs/fragments/.gitkeep b/ansible_collections/community/zabbix/changelogs/fragments/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/zabbix/changelogs/fragments/.gitkeep diff --git a/ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml b/ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml new file mode 100644 index 000000000..d9b8eb397 --- /dev/null +++ b/ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml @@ -0,0 +1,2 @@ +minor_changes: + - all roles - updated to support Zabbix 6.4. diff --git a/ansible_collections/community/zabbix/docker-compose.yml b/ansible_collections/community/zabbix/docker-compose.yml new file mode 100644 index 000000000..512e4877f --- /dev/null +++ b/ansible_collections/community/zabbix/docker-compose.yml @@ -0,0 +1,37 @@ +--- +version: '3.7' +services: + zabbix-db: + image: postgres:13 + environment: + POSTGRES_DB: "zabbix" + POSTGRES_USER: "zabbix" + POSTGRES_PASSWORD: "zabbix" + zabbix-server: + image: zabbix/zabbix-server-pgsql:ubuntu-${zabbix_version}-latest + environment: + DB_SERVER_HOST: "zabbix-db" + POSTGRES_USER: "zabbix" + POSTGRES_PASSWORD: "zabbix" + POSTGRES_DB: "zabbix" + depends_on: + - "zabbix-db" + links: + - "zabbix-db" + zabbix-web: + image: zabbix/zabbix-web-nginx-pgsql:ubuntu-${zabbix_version}-latest + environment: + DB_SERVER_HOST: "zabbix-db" + POSTGRES_USER: "zabbix" + POSTGRES_PASSWORD: "zabbix" + POSTGRES_DB: "zabbix" + ZBX_SERVER_HOST: "zabbix-server" + PHP_TZ: "Asia/Tokyo" + depends_on: + - "zabbix-db" + - "zabbix-server" + links: + - "zabbix-db" + - "zabbix-server" + ports: + - "8080:8080" diff --git a/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md b/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md new file mode 100644 index 000000000..7258bf6c8 --- /dev/null +++ b/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md @@ -0,0 +1,41 @@ +# Publishing New Versions + +## Steps to take on forked repository + +1. Create new branch X.Y.Zprep. +2. Check all merged PRs since last release and verify they had changelog fragments included. If not add them to _changelogs/fragments/missing.yml_ and commit. +3. Generate a changelog entries for new version: + + + ``` + # python3 -m venv antsibull-env && source antsibull-env/bin/activate && pip3 install antsibull-changelog + antsibull-changelog release --version X.Y.Z --date YYYY-MM-DD + ``` + +4. Update `galaxy.yml` file and `requirements.yml` example in `README.md` with the new `version` for the collection and commit. +5. Push new branch for the review `git push origin X.Y.Zprep`. +6. Before merging, ensure that date used for `antsibull-changelog` command is consistent with the day that PR was merged on. + +## Steps to take on ansible-collections/community.zabbix + +1. After merging the branch from previous steps, tag the version via git and push to GitHub: + + + ``` + git tag -a X.Y.Z + git push origin X.Y.Z + ``` + +2. Create new Release pointing to new X.Y.Z tag https://github.com/ansible-collections/community.zabbix/releases + +Additional manual steps are required when automatic publish to Ansible Galaxy is not enabled in the repository. This +requires a user who has access to the `community.zabbix` namespace on Ansible Galaxy to publish the build artifact. + +3. Run the following commands to build and release the new version on Galaxy: + + ``` + ansible-galaxy collection build + ansible-galaxy collection publish ./community-zabbix-$VERSION_HERE.tar.gz + ``` + +After the version is published, verify it exists on the [Zabbix Collection Galaxy page](https://galaxy.ansible.com/community/zabbix). diff --git a/ansible_collections/community/zabbix/docs/RELEASE.md b/ansible_collections/community/zabbix/docs/RELEASE.md new file mode 100644 index 000000000..0c6cc2e81 --- /dev/null +++ b/ansible_collections/community/zabbix/docs/RELEASE.md @@ -0,0 +1,46 @@ +# Release cycle and versioning + +## Versioning +Versioning is using SemVer (X.Y.Z): +- The X is a **major version** and is incremented when: + - Support for older Zabbix versions is removed. + - Support for older Ansible versions is removed. + - Support for older Python versions is removed. + - Modules, roles or plugins are removed. + - Module or role functionality is removed. + - Other breaking changes or backward-incompatible changes are introduced. + +- The Y is a **minor version** and is incremented when: + - Support for new Zabbix versions is added. + - Support for new Ansible versions is added. + - Support for new Python versions is added. + - A new module, role, plugin, etc., is added. + - New features are introduced to modules, roles, plugins. + - A functionality of components is adjusted in a backward-compatible way. + +- The Z is a **patch version** and is incremented when: + - Bugs are fixed in a backward-compatible way. + - Documentation fixes and smaller changes are introduced. +## Releases +Release dates are not fixed. Instead, they will be discussed at the beginning of each month following this guideline: +- The version increment will depend on the content that will be included in the release, as discussed in the *Versioning* section. +- New collection releases may be a result of this discussion if necessary. +- There may be several releases during the month if needed. +## Collection support +The latest release of the community.zabbix is always supported. +Older releases, which are included in the still supported Ansible versions, may obtain occasional backports or bug fixes when necessary. [1] + +[1] [Collection versioning requirements](https://github.com/ansible-collections/overview/blob/main/collection_requirements.rst#versioning-and-deprecation) +## Branches +Branch *main* always holds the code for the latest supported release. +New branch *stable-X.Y* is pushed before starting a new *major (X+1)* version development in the main branch. + +The *stable-X.Y* branch provides a way to merge any necessary backports and release bug fixes for older major versions of this collection while they are still included in currently supported ansible releases. +> For example, if the current version of the collection is *1.3.2* and a new version *2.0.0* is being released, the branch *stable-1.Y* should be pushed prior to the release, matching the last commit that was included with the *1.3.2* release. + +## Merging +Merging follows this guideline: +- *Main branch* (previously master branch) is the current branch. +- *stable-X.Y* is a separate branch used to fix issues in older supported collection releases. +- There should be a separate branch for each contribution. +- There should be a separate pull request for each version increment. diff --git a/ansible_collections/community/zabbix/docs/UPGRADE.md b/ansible_collections/community/zabbix/docs/UPGRADE.md new file mode 100644 index 000000000..7784f5842 --- /dev/null +++ b/ansible_collections/community/zabbix/docs/UPGRADE.md @@ -0,0 +1,194 @@ +__Upgrade__ + +Table of content + +- [1.0.0](#100) + * [Roles](#roles) + + [Proxy](#proxy) + + [Java Gateway](#java-gateway) +- [0.2.0](#020) + * [Roles](#roles-1) + + [Agent](#agent) + + [Server](#server) + + [Proxy](#proxy-1) + + [Web](#web) + + [Java Gateway](#java-gateway-1) + +This document provides an overview of all the changes that are needed to be applied to have a correctly working environment per version. If a version is not part of this document, then there are no changes needed to apply. + +## 1.5.0 + +### Roles + +#### Agent + +The following properties are added in the `zabbix_agent` role. + +* `zabbix_api_timeout = 30` +* `zabbix_agent_tls_subject = "{{ zabbix_agent_tlsservercertsubject }}"` +* `zabbix_agent2_server = "{{ zabbix_agent_server }}"` +* `zabbix_agent2_serveractive = "{{ zabbix_agent_serveractive }}"` +* `zabbix_agent2_allow_key = "{{ zabbix_agent_allow_key }}"` +* `zabbix_agent2_deny_key = "{{ zabbix_agent_deny_key }}"` +* `zabbix_agent2_tls_subject = "{{ zabbix_agent2_tlsservercertsubject }}"` + +NOTE: The original properties can still be used but it's suggested to update to +use the new ones. + +The following properties are renamed in the `zabbix_agent` role. + +| From | To | +|-------------------------------|-------------------------------| +| zabbix_url | zabbix_api_server_url | +| zabbix_agent_server_url | zabbix_api_server_url | +| zabbix_http_user | zabbix_api_http_user | +| zabbix_http_password | zabbix_api_http_password | +| zabbix_api_user | zabbix_api_login_user | +| zabbix_api_pass | zabbix_api_login_pass | +| zabbix_validate_certs | zabbix_api_validate_certs | +| zabbix_create_hostgroup | zabbix_agent_hostgroups_state | +| zabbix_macros | zabbix_agent_macros | +| zabbix_inventory_mode | zabbix_agent_inventory_mode | +| zabbix_link_templates | zabbix_agent_link_templates | +| zabbix_proxy | zabbix_agent_proxy | +| zabbix_update_host | zabbix_agent_host_update | +| zabbix_create_host | zabbix_agent_host_state | +| zabbix_visible_hostname | zabbix_agent_visible_hostname | + +NOTE: the old parameters are still valid but it's suggested to update to use the +new ones. + +#### Proxy + +The following properties are added in the `zabbix_proxy` role. + +* `zabbix_api_timeout = 30` +* `zabbix_proxy_tls_subject = "{{ zabbix_proxy_tlsservercertsubject }}"` + +The following properties are renamed in the `zabbix_proxy` role. + +| From | To | +|----------------------------|---------------------------------| +| zabbix_server_host | zabbix_proxy_server | +| zabbix_server_port | zabbix_proxy_serverport | +| zabbix_proxy_localbuffer | zabbix_proxy_proxylocalbuffer | +| zabbix_proxy_offlinebuffer | zabbix_proxy_proxyofflinebuffer | +| zabbix_create_proxy | zabbix_proxy_state | +| zabbix_url | zabbix_api_server_url | +| zabbix_http_user | zabbix_api_http_user | +| zabbix_http_password | zabbix_api_http_password | +| zabbix_api_user | zabbix_api_login_user | +| zabbix_api_pass | zabbix_api_login_pass | +| zabbix_validate_certs | zabbix_api_validate_certs | + +NOTE: the old parameters are still valid but it's suggested to update to use the +new ones. + +## 1.0.0 + +### Roles + +#### Proxy + +The following property is renamed in the `zabbix_proxy` role. + +|From|To| +|----|--| +|`zabbix_version`|`zabbix_proxy_version`| + +NOTE: The `zabbix_version` can still be used, but will be deprecated in later releases. + +#### Java Gateway + +The following properties are renamed in the `zabbix_javagateway` role. + +|From|To| +|----|--| +|`zabbix_version`|`zabbix_javagateway_version`| +|`javagateway_package_state`|`zabbix_javagateway_package_state`| +|`javagateway_pidfile`|`zabbix_javagateway_pidfile`| +|`javagateway_listenip`|`zabbix_javagateway_listenip`| +|`javagateway_listenport`|`zabbix_javagateway_listenport`| +|`javagateway_startpollers`|`zabbix_javagateway_startpollers`| + +NOTE: The `zabbix_version` can still be used, but will be deprecated in later releases. + +## 0.2.0 + +### Roles + +#### Agent + +A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-agent` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-agent` to `zabbix_agent`. + +Example of using the role in this collection: +```yaml +- hosts: all + roles: + - role: community.zabbix.zabbix_agent + zabbix_agent_server: 192.168.33.30 + zabbix_agent_serveractive: 192.168.33.30 +``` + +#### Server + +A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-server` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-server` to `zabbix_server`. + +Example of using the role in this collection:: +```yaml +- hosts: zabbix-server + roles: + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +#### Proxy + +A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-proxy` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-proxy` to `zabbix_proxy`. + +Example of using the role in this collection:: +```yaml +- hosts: zabbix-proxy + roles: + - role: community.zabbix.zabbix_proxy + zabbix_proxy_server: 192.168.1.1 + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +#### Web + +A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-web` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-web` to `zabbix_web`. + +Example of using the role in this collection:: +```yaml +- hosts: zabbix-web + become: yes + roles: + - role: geerlingguy.apache + - role: community.zabbix.zabbix_web + zabbix_url: zabbix.mydomain.com + zabbix_server_hostname: zabbix-server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +#### Java Gateway + +A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-javagateway` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-javagateway` to `zabbix_javagateway`. + +Example of using the role in this collection:: +```yaml +- hosts: zabbix-server + roles: + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + zabbix_server_javagateway: 192.168.1.1 + - role: community.zabbix.zabbix_javagateway +``` diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md new file mode 100644 index 000000000..f3fe06c9d --- /dev/null +++ b/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md @@ -0,0 +1,556 @@ +# community.zabbix.zabbix_agent role + +![Zabbix Agent](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_agent/badge.svg) + +**Table of Contents** + +- [Requirements](#requirements) + * [Operating systems](#operating-systems) + + [Windows](#windows) + * [Local system access](#local-system-access) + * [Zabbix Versions](#zabbix-versions) +- [Getting started](#getting-started) + * [Minimal Configuration](#minimal-configuration) + * [Issues](#issues) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [SElinux](#selinux) + + [Zabbix Agent](#zabbix-agent) + + [Zabbix Agent vs Zabbix Agent 2 configuration](#zabbix-agent-vs-zabbix-agent-2-configuration) + * [TLS Specific configuration](#tls-specific-configuration) + * [Zabbix API variables](#zabbix-api-variables) + * [Windows Variables](#windows-variables) + * [macOS Variables](#macos-variables) + * [Docker Variables](#docker-variables) + * [FirewallD/Iptables](#firewalld-iptables) + * [IPMI variables](#ipmi-variables) + * [proxy](#proxy) +- [Dependencies](#dependencies) +- [Example Playbook](#example-playbook) + * [zabbix_agent2_plugins](#zabbix-agent2-plugins) + * [agent_interfaces](#agent-interfaces) + * [Other interfaces](#other-interfaces) + * [Vars in role configuration](#vars-in-role-configuration) + * [Combination of group_vars and playbook](#combination-of-group-vars-and-playbook) + * [Example for TLS PSK encrypted agent communication](#example-for-tls-psk-encrypted-agent-communication) +- [Molecule](#molecule) +- [Deploying Userparameters](#deploying-userparameters) +- [License](#license) +- [Author Information](#author-information) + +# Requirements +## Operating systems +This role will work on the following operating systems: + + * Red Hat + * Fedora + * Debian + * Ubuntu + * opensuse + * Windows (Best effort) + * macOS + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`and `community.general`. Installing the collections: + +```sh +ansible-galaxy collection install ansible.posix +ansible-galaxy collection install community.general +``` +If you are willing to create host_groups and hosts in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too: + +``` +ansible-galaxy collection install ansible.netcommon +``` + +### Docker + +When you are a Docker user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.docker`. This collection is needed as the `docker_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.docker +``` + +### Windows + +When you are a Windows user and using Ansible 2.10 or newer, then there are dependencies on collections named `ansible.windows` and `community.windows`. These collections are needed as the `win_` modules are now part of collections and not standard in Ansible anymmore. Installing the collections: + +```sh +ansible-galaxy collection install ansible.windows +ansible-galaxy collection install community.windows +``` + +For more information, see: https://github.com/ansible-collections/community.zabbix/issues/236 + +## Local system access + +To successfully complete the install the role requires `python-netaddr` on the controller to be able to manage IP addresses. This requires that the library is available on your local machine (or that `pip` is installed to be able to run). This will likely mean that running the role will require `sudo` access to your local machine and therefore you may need the `-K` flag to be able to enter your local machine password if you are not running under root. + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases: + +| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----|-----|-----|----------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V | +| Red Hat Fam 6 | V | V | V | V | V | V | | | V | +| Red Hat Fam 5 | | | V | V | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | V | V | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | V | V | V | V | V | V | V | V | | +| Ubuntu 14.04 trusty | V | V | V | V | V | V | V | V | V | +| Debian 10 buster | V | V | V | V | V | V | V | | | +| Debian 9 stretch | V | V | | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +# Getting started + +## Minimal Configuration + +In order to get the Zabbix Agent running, you'll have to define the following properties before executing the role: + +* `zabbix_agent_version` +* `zabbix_agent(2)_server` +* `zabbix_agent(2)_serveractive` (When using active checks) + +The `zabbix_agent_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_agent_version: 4.0`, `zabbix_agent_version: 3.4` or `zabbix_agent_version: 2.2`. + +The `zabbix_agent(2)_server` (and `zabbix_agent(2)_serveractive`) should contain the ip or fqdn of the host running the Zabbix Server. + +## Issues + +Due to issue discussed on [#291](https://github.com/dj-wasabi/ansible-zabbix-agent/issues/291), the Ansible Version 2.9.{0,1,2} isn't working correctly on Windows related targets. + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_agent_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_agent_version_minor`: When you want to specify a minor version to be installed. Is also used for `zabbix_sender` and `zabbix_get`. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. + +### SElinux + +* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the server will run. + +### Zabbix Agent + +* `zabbix_agent_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact. +* `zabbix_agent2`: Default: `False`. When you want to install the `Zabbix Agent2` instead of the "old" `Zabbix Agent`. +* `zabbix_agent_listeninterface`: Interface zabbix-agent listens on. Leave blank for all. +* `zabbix_agent_package_remove`: If `zabbix_agent2: True` and you want to remove the old installation. Default: `False`. +* `zabbix_agent_package`: The name of the zabbix-agent package. Default: `zabbix-agent`. In case for EPEL, it is automatically renamed. +* `zabbix_sender_package`: The name of the zabbix-sender package. Default: `zabbix-sender`. In case for EPEL, it is automatically renamed. +* `zabbix_get_package`: The name of the zabbix-get package. Default: `zabbix-get`. In case for EPEL, it is automatically renamed. +* `zabbix_agent_package_state`: If Zabbix-agent needs to be `present` or `latest`. +* `zabbix_agent_interfaces`: A list that configured the interfaces you can use when configuring via API. +* `zabbix_agent_install_agent_only`: Only install the Zabbix Agent and not the `zabbix-sender` and `zabbix-get` packages. Default: `False` +* `zabbix_agent_userparameters`: Default: `[]]`. List of userparameter names and scripts (if any). Detailed description is given in the [Deploying Userparameters](#deploying-userparameters) section. + * `name`: Userparameter name (should be the same with userparameter template file name) + * `scripts_dir`: Directory name of the custom scripts needed for userparameters +* `zabbix_agent_userparameters_templates_src`: indicates the relative path (from `templates/`) where userparameter templates are searched +* `zabbix_agent_userparameters_scripts_src`: indicates the relative path (from `files/`) where userparameter scripts are searched +* `zabbix_agent_runas_user`: Drop privileges to a specific, existing user on the system. Only has effect if run as 'root' and AllowRoot is disabled. +* `zabbix_agent_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip. +* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely. +* `zabbix_agent_apt_priority`: Add a weight (`Pin-Priority`) for the APT repository. +* `zabbix_agent_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. +* `zabbix_agent_dont_detect_ip`: Default `false`. When set to `true`, it won't detect available ip addresses on the host and no need for the Python module `netaddr` to be installed. +* `zabbix_agent_chassis`: Default: `false`. When set to `true`, it will give Zabbix Agent access to the Linux DMI table allowing system.hw.chassis info to populate. + +### Zabbix Agent vs Zabbix Agent 2 configuration + +The following provides an overview of all the properties that can be set in the Zabbix Agent configuration file. When `(2)` is used in the name of the property, like `zabbix_agent(2)_pidfile`, it will show that you can configure `zabbix_agent_pidfile` for the Zabbix Agent configuration file and `zabbix_agent2_pidfile` for the Zabbix Agent 2 configuration file. + +Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2. + +* `zabbix_agent(2)_server`: The ip address for the zabbix-server or zabbix-proxy. +* `zabbix_agent(2)_serveractive`: The ip address for the zabbix-server or zabbix-proxy for active checks. +* `zabbix_agent(2)_allow_key`: list of AllowKey configurations. +* `zabbix_agent(2)_deny_key`: list of DenyKey configurations. +* `zabbix_agent(2)_pidfile`: name of pid file. +* `zabbix_agent(2)_logfile`: name of log file. +* `zabbix_agent(2)_logfilesize`: maximum size of log file in mb. +* `zabbix_agent(2)_logtype`: Specifies where log messages are written to +* `zabbix_agent(2)_debuglevel`: specifies debug level +* `zabbix_agent(2)_sourceip`: source ip address for outgoing connections. +* `zabbix_agent_enableremotecommands`: whether remote commands from zabbix server are allowed. +* `zabbix_agent_logremotecommands`: enable logging of executed shell commands as warnings. +* `zabbix_agent(2)_listenport`: agent will listen on this port for connections from the server. +* `zabbix_agent2_statusport`: Agent will listen on this port for HTTP status requests. +* `zabbix_agent(2)_listenip`: list of comma delimited ip addresses that the agent should listen on. +* `zabbix_agent_startagents`: number of pre-forked instances of zabbix_agentd that process passive checks. +* `zabbix_agent(2)_hostname`: unique, case sensitive hostname. +* `zabbix_agent(2)_hostnameitem`: item used for generating hostname if it is undefined. +* `zabbix_agent(2)_hostmetadata`: optional parameter that defines host metadata. +* `zabbix_agent(2)_hostmetadataitem`: optional parameter that defines an item used for getting the metadata. +* `zabbix_agent(2)_refreshactivechecks`: how often list of active checks is refreshed, in seconds. +* `zabbix_agent(2)_buffersend`: do not keep data longer than n seconds in buffer. +* `zabbix_agent(2)_buffersize`: maximum number of values in a memory buffer. the agent will send all collected data to zabbix server or proxy if the buffer is full. +* `zabbix_agent2_enablepersistentbuffer`: 0 - disabled, in-memory buffer is used (default); 1 - use persistent buffer +* `zabbix_agent2_persistentbufferperiod`: Zabbix Agent2 will keep data for this time period in case of no connectivity with Zabbix server or proxy. Older data will be lost. Log data will be preserved. +* `zabbix_agent2_persistentbufferfile`: Zabbix Agent2 will keep SQLite database in this file * n is valid if `EnablePersistentBuffer=1` +* `zabbix_agent_maxlinespersecond`: maximum number of new lines the agent will send per second to zabbix server or proxy processing 'log' and 'logrt' active checks. +* `zabbix_agent_allowroot`: allow the agent to run as 'root'. if disabled and the agent is started by 'root', the agent will try to switch to user 'zabbix' instead. has no effect if started under a regular user. +* `zabbix_agent(2)_zabbix_alias`: sets an alias for parameter. it can be useful to substitute long and complex parameter name with a smaller and simpler one. Can be both a string as an list. +* `zabbix_agent(2)_timeout`: spend no more than timeout seconds on processing +* `zabbix_agent(2)_include`: you may include individual files or all files in a directory in the configuration file. +* `zabbix_agent(2)_include_pattern`: Optional file pattern used for included files. +* `zabbix_agent(2)_include_mode`: The mode for the directory mentioned above. +* `zabbix_agent(2)_unsafeuserparameters`: allow all characters to be passed in arguments to user-defined parameters. +* `zabbix_agent_loadmodulepath`: Full path to location of agent modules. +* `zabbix_agent_loadmodule`: Module to load at agent startup. Modules are used to extend functionality of the agent. +* `zabbix_agent2_controlsocket`: The control socket, used to send runtime commands with '-R' option. +* `zabbix_agent_allowroot`: Allow the agent to run as 'root'. 0 - do not allow, 1 - allow +* `zabbix_agent2_plugins`: A list containing plugin configuration. +* `zabbix_agent(2)_listenbacklog`: The maximum number of pending connections in the queue. + +## TLS Specific configuration + +These variables are specific for Zabbix 3.0 and higher. When `(2)` is used in the name of the property, like `zabbix_agent(2)_tlsconnect`, it will show that you can configure `zabbix_agent_tlsconnect` for the Zabbix Agent configuration file and `zabbix_agent2_tlsconnect` for the Zabbix Agent 2 configuration file. + +* `zabbix_agent(2)_tlsconnect`: How the agent should connect to server or proxy. Used for active checks. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_agent(2)_tlsaccept`: What incoming connections to accept. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_agent(2)_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification. +* `zabbix_agent(2)_tlscrlfile`: Full pathname of a file containing revoked certificates. +* `zabbix_agent(2)_tlsservercertissuer`: Allowed server certificate issuer. +* `zabbix_agent(2)_tlsservercertsubject`: Allowed server certificate subject. +* `zabbix_agent(2)_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain. +* `zabbix_agent(2)_tlskeyfile`: Full pathname of a file containing the agent private key. +* `zabbix_agent(2)_tlspskidentity`: Unique, case sensitive string used to identify the pre-shared key. +* `zabbix_agent(2)_tlspskidentity_file`: Full pathname of a file containing the pre-shared key identity. +* `zabbix_agent(2)_tlspskfile`: Full pathname of a file containing the pre-shared key. +* `zabbix_agent(2)_tlspsk_secret`: The pre-shared secret key that should be placed in the file configured with `agent_tlspskfile`. +* `zabbix_agent(2)_tlspsk_auto`: Enables auto generation and storing of individual pre-shared keys and identities on clients. Is false by default. If set to true and if `zabbix_agent_tlspskfile` and `zabbix_agent_tlspsk_secret` are undefined, it generates the files `/etc/zabbix/tls_psk_auto.identity` and `/etc/zabbix/tls_psk_auto.secret`, which are populated by values automatically (identity is set to hostname, underscore and 4 random alphanumeric digits; secret is 64 random alphanumeric digits) in such a way that the values are generated once and are never overwritten. + +The results are stored in the Ansible variables `zabbix_agent_tlspskidentity` and `zabbix_agent_tlspsk_secret`, so that they may be used later in the code, for example with [zabbix_host](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_module.html) to configure the Zabbix server or with `debug: msg:` to display them to the user. + +## Zabbix API variables + +These variables need to be overridden when you want to make use of the Zabbix API for automatically creating and or updating hosts. + +Host encryption configuration will be set to match agent configuration. + +* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth. +* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth. +* `zabbix_api_create_hosts`: Default: `False`. When you want to enable the Zabbix API to create/delete the host. This has to be set to `True` if you want to make use of `zabbix_agent_host_state`. +* `zabbix_api_create_hostgroup`: When you want to enable the Zabbix API to create/delete the hostgroups. This has to be set to `True` if you want to make use of `zabbix_agent_hostgroups_state`.Default: `False` +* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com +* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080 +* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS +* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used +* `zabbix_api_login_user`: Username of user which has API access. +* `zabbix_api_login_pass`: Password for the user which has API access. +* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu` +* `zabbix_agent_hostgroups_state`: present (Default) if the hostgroup needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_hostgroup` is set to `True`. +* `zabbix_host_status`: enabled (Default) when host in monitored, disabled when host is disabled for monitoring. +* `zabbix_agent_host_state`: present (Default) if the host needs to be created or absent is you want to delete it. This only works when `zabbix_api_create_hosts` is set to `True`. +* `zabbix_agent_host_update`: yes (Default) if the host should be updated if already present. This only works when `zabbix_api_create_hosts` is set to `True`. +* `zabbix_useuip`: 1 if connection to zabbix-agent is made via ip, 0 for fqdn. +* `zabbix_host_groups`: A list of hostgroups which this host belongs to. +* `zabbix_agent_link_templates`: A list of templates which needs to be link to this host. The templates should exist. +* `zabbix_agent_macros`: A list with macro_key and macro_value for creating hostmacro's. +* `zabbix_agent_tags`: A list with tag and (optionally) value for creating host tags. +* `zabbix_agent_inventory_mode`: Configure Zabbix inventory mode. Needed for building inventory data, manually when configuring a host or automatically by using some automatic population options. This has to be set to `automatic` if you want to make automatically building inventory data. +* `zabbix_agent_visible_hostname` : Configure Zabbix visible name inside Zabbix web UI for the node. +* `zabbix_agent_description`: Description of the host in Zabbix. +* `zabbix_agent_inventory_zabbix`: Adds Facts for a zabbix inventory + +## Windows Variables + +**NOTE** + +_Supporting Windows is a best effort (I don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._ +When `(2)` is used in the name of the property, like `zabbix_agent(2)_win_logfile`, it will show that you can configure `zabbix_agent_win_logfile` for the Zabbix Agent configuration file and `zabbix_agent2_win_logfile` for the Zabbix Agent 2 configuration file. + +Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2. + +* `zabbix(2)_win_package`: file name pattern (zip only). This will be used to generate the `zabbix(2)_win_download_link` variable. +* `zabbix_version_long`: The long (major.minor.patch) version of the Zabbix Agent. This will be used to generate the `zabbix(2)_win_package` and `zabbix(2)_win_download_link` variables. This takes precedence over `zabbix_agent_version`. +* `zabbix(2)_win_download_link`: The download url to the `win.zip` file. +* `zabbix_win_install_dir`: The directory where Zabbix needs to be installed. +* `zabbix_win_install_dir_conf`: The directory where Zabbix configuration file needs to be installed. +* `zabbix_win_install_dir_bin`: The directory where Zabbix binary file needs to be installed. +* `zabbix_agent(2)_win_logfile`: The full path to the logfile for the Zabbix Agent. +* `zabbix_agent_win_include`: The directory in which the Zabbix Agent specific configuration files are stored. +* `zabbix_agent_win_svc_recovery`: Enable Zabbix Agent service auto-recovery settings. +* `zabbix_win_firewall_management`: Enable Windows firewall management (add service and port to allow rules). Default: `True` + +## macOS Variables + +* `zabbix_version_long`: The long (major.minor.patch) version of the Zabbix Agent. This will be used to generate the `zabbix_mac_download_link` link. +* `zabbix_mac_download_link`: The download url to the `pkg` file. + +## Docker Variables + +When you don't want to install the Zabbix Agent on the host, but would like to run it in a container then these properties are useful. When `zabbix_agent_docker` is set to `True`, then a +Docker image will be downloaded and a Container will be started. No other installations will be done on the host, with the exception of the PSK file and the "Zabbix Include Directory". + +The following directories are mounted in the Container: + +``` + - /etc/zabbix/zabbix_agentd.d:/etc/zabbix/zabbix_agentd.d + - /:/hostfs:ro + - /etc:/hostfs/etc:ro + - /proc:/hostfs/proc:ro + - /sys:/hostfs/sys:ro + - /var/run:/var/run +``` + +Keep in mind that using the Zabbix Agent in a Container requires changes to the Zabbix Template for Linux as `/proc`, `/sys` and `/etc` are mounted in a directory `/hostfs`. + +* `zabbix_agent_docker`: Default: `False`. When set to `True`, it will install a Docker container on the target host instead of installation on the target. +* `zabbix_agent_docker_state`: Default: `started` +* `zabbix_agent_docker_name`: The name of the Container. Default: `zabbix-agent` +* `zabbix_agent_docker_image`: The name of the Docker image. Default: `zabbix/zabbix-agent` +* `zabbix_agent_docker_image_tag`: The tag of the Docker image. +* `zabbix_agent_docker_user_gid`: The group id of the zabbix user in the Container. +* `zabbix_agent_docker_user_uid`: The user id of the zabbix user in the Container. +* `zabbix_agent_docker_network_mode`: The name of the (Docker) network that should be used for the Container. Default `host`. +* `zabbix_agent_docker_restart_policy`: Default: `unless-stopped`. The restart policy of the Container. +* `zabbix_agent_docker_privileged`: When set to `True`, the container is running in privileged mode. +* `zabbix_agent_docker_ports`: A list with `<PORT>:<PORT>` values to open ports to the container. +* `zabbix_agent_docker_security_opts`: A list with available security options. +* `zabbix_agent_docker_volumes`: A list with all directories that needs to be available in the Container. +* `zabbix_agent_docker_env`: A dict with all environment variables that needs to be set for the Container. + +## FirewallD/Iptables + +* `zabbix_agent_firewall_enable`: If IPtables needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport`. +* `zabbix_agent_firewall_source`: When provided, IPtables will be configuring to only allow traffic from this IP address/range. +* `zabbix_agent_firewalld_enable`: If firewalld needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport` and `zabbix_agent_jmx_listenport` if defined. +* `zabbix_agent_firewalld_source`: When provided, firewalld will be configuring to only allow traffic for IP configured in `zabbix_agent_server`. +* `zabbix_agent_firewalld_zone`: When provided, the firewalld rule will be attached to this zone (only if zabbix_agent_firewalld_enable is set to true). The default behavior is to use the default zone define by the remote host firewalld configuration. +* `zabbix_agent_firewall_action`: Default: `insert`. When to `insert` the rule or to `append` to IPTables. +* `zabbix_agent_firewall_chain`: Default `INPUT`. Which `chain` to add the rule to IPTables. + + +## IPMI variables + +* `zabbix_agent_ipmi_authtype`: IPMI authentication algorithm. Possible values are 1 (callback), 2 (user), 3 (operator), 4 (admin), 5 (OEM), with 2 being the API default. +* `zabbix_agent_ipmi_password`: IPMI password. +* `zabbix_agent_ipmi_privilege`: IPMI privilege level. Possible values are 1 (callback), 2 (user), 3 (operator), 4 (admin), 5 (OEM), with 2 being the API default. +* `zabbix_agent_ipmi_username`: IPMI username. + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +# Dependencies + +There are no dependencies on other roles. + +# Example Playbook + +## zabbix_agent2_plugins + +Specifically for the Zabbix Agent 2, a list of extra plugins can be configured. The following provides an overview of configuring the `SystemRun` plugin by setting the `LogRemoteCommands` to `0`: + +```yaml +zabbix_agent2_plugins: + - name: SystemRun + options: + - parameter: LogRemoteCommands + value: 0 +``` + +In the `zabbix_agent2.conf` an entry will be created with the following content: + +``` +Plugins.SystemRun.LogRemoteCommands=0 +``` + +## agent_interfaces + +This will configure the Zabbix Agent interface on the host. +```yaml +zabbix_agent_interfaces: + - type: 1 + main: 1 + useip: "{{ zabbix_useuip }}" + ip: "{{ zabbix_agent_ip }}" + dns: "{{ ansible_fqdn }}" + port: "{{ zabbix_agent_listenport }}" +``` + +## Other interfaces + +You can also configure the `zabbix_agent_interfaces` to add/configure snmp, jmx and ipmi interfaces. + +You'll have to use one of the following type numbers when configuring it: + +| Type Interface | Nr | +|-----------------|-------| +| Zabbix Agent | 1 | +| snmp | 2 | +| ipmi | 3 | +| jmx | 4 | + +Configuring a snmp interface will look like this: + +``` +zabbix_agent_interfaces: + - type: 2 + main: 1 + useip: "{{ zabbix_useuip }}" + ip: "{{ agent_ip }}" + dns: "{{ ansible_fqdn }}" + port: "{{ agent_listenport }}" +``` + +## Vars in role configuration +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: all + roles: + - role: community.zabbix.zabbix_agent + zabbix_agent_server: 192.168.33.30 + zabbix_agent_serveractive: 192.168.33.30 + zabbix_api_server_url: http://zabbix.example.com + zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0 + zabbix_api_login_user: Admin + zabbix_api_login_pass: zabbix + zabbix_agent_host_state: present + zabbix_host_groups: + - Linux Servers + zabbix_agent_link_templates: + - Template OS Linux + - Apache APP Template + zabbix_agent_macros: + - macro_key: apache_type + macro_value: reverse_proxy + macro_type: text + zabbix_agent_tags: + - tag: environment + value: production +``` + +## Combination of group_vars and playbook +You can also use the group_vars or the host_vars files for setting the variables needed for this role. File you should change: `group_vars/all` or `host_vars/<zabbix_server>` (Where <zabbix_server> is the hostname of the machine running Zabbix Server) + +```yaml + zabbix_agent_server: 192.168.33.30 + zabbix_agent_serveractive: 192.168.33.30 + zabbix_api_server_url: http://zabbix.example.com + zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0 + zabbix_api_login_user: Admin + zabbix_api_login_pass: zabbix + zabbix_agent_host_state: present + zabbix_host_groups: + - Linux Servers + zabbix_agent_link_templates: + - Template OS Linux + - Apache APP Template + zabbix_agent_macros: + - macro_key: apache_type + macro_value: reverse_proxy + zabbix_agent_tags: + - tag: environment + value: production +``` + +and in the playbook only specifying: + +```yaml + - hosts: all + roles: + - role: community.zabbix.zabbix_agent +``` + +## Example for TLS PSK encrypted agent communication + +Variables e.g. in the playbook or in `host_vars/myhost`: + +```yaml + zabbix_agent_tlsaccept: psk + zabbix_agent_tlsconnect: psk + zabbix_agent_tlspskidentity: "myhost PSK" + zabbix_agent_tlspsk_secret: b7e3d380b9d400676d47198ecf3592ccd4795a59668aa2ade29f0003abbbd40d + zabbix_agent_tlspskfile: /etc/zabbix/zabbix_agent_pskfile.psk +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# Deploying Userparameters + +The following steps are required to install custom userparameters and/or scripts: + +* Put the desired userparameter file in the `templates/userparameters` directory and name it as `<userparameter_name>.j2`. For example: `templates/userparameters/mysql.j2`. You can change the default directory to a custom one modifying `zabbix_agent_userparameters_templates_src` variable. +* Put the scripts directory (if any) in the `files/scripts` directory. For example: `files/scripts/mysql`. You can change the default directory to a custom one modifying `zabbix_agent_userparameters_scripts_src` variable. +* Add `zabbix_agent_userparameters` variable to the playbook as a list of dictionaries and define userparameter name and scripts directory name (if there are no scripts just no not specify the `scripts_dir` variable). + +Example: + +```yaml +- hosts: mysql_servers + tasks: + - include_role: + name: community.zabbix.zabbix_agent + vars: + zabbix_agent_server: zabbix.mydomain.com + zabbix_agent_userparameters: + - name: mysql + scripts_dir: mysql + - name: galera + +``` + +Example of the "templates/userparameters/mysql.j2" file: + +``` +UserParameter=mysql.ping_to,mysqladmin -uroot ping | grep -c alive +``` + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md new file mode 100644 index 000000000..70427d97c --- /dev/null +++ b/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md @@ -0,0 +1,142 @@ +# community.zabbix.zabbix_javagateway role + +![Zabbix Javagateway](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_javagateway/badge.svg) + +**Table of Contents** + +- [Overview](#overview) + * [Operating systems](#operating-systems) + * [Zabbix Versions](#zabbix-versions) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [Java Gatewaty](#java-gatewaty) + + [proxy](#proxy) +- [Dependencies](#dependencies) +- [Example Playbook](#example-playbook) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +## Operating systems + +This role will work on the following operating systems: + + * Red Hat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases. + +| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.2 | 5.0 | 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----------|-----|-----|-----|-----------|-----------| +| Red Hat Fam 8 | V | V | V | V | V | V | | | +| Red Hat Fam 7 | | | | V | V | V | V | V | +| Red Hat Fam 6 | | | | V | V | | | V | +| Red Hat Fam 5 | | | | V | V | | | V | +| Fedora | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | | | | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | V | V | V | V | V | +| Debian 10 buster | V | V | V | V | V | V | | | +| Debian 9 stretch | | | | V | V | V | V | | +| Debian 8 jessie | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | V | V | +| macOS 10.15 | | | | | | V | V | | +| macOS 10.14 | | | | | | V | V | | + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_javagateway_version`: This is the version of zabbix. Default: 5.2. Can be overridden to 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. +* `zabbix_javagateway_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed. +* `zabbix_javagateway_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. + +### Java Gatewaty + +* `zabbix_javagateway_pidfile`: Default: `/run/zabbix/zabbix_java_gateway.pid`. The location for the pid file. +* `zabbix_javagateway_listenip`: Default: `0.0.0.0`. The IP address to listen on. +* `zabbix_javagateway_listenport`: Default: `10052`. The port on which Java Gateway is listening on. +* `zabbix_javagateway_startpollers`: Default: `5`. The amount of pollers to start. + +### proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +# Dependencies + +The java gateway can be installed on either the zabbix-server or the zabbix-proxy machine. So one of these should be installed. You'll need to provide an parameter in your playbook for using the javagateway. + +When using the zabbix-server: +```yaml + roles: + - role: community.zabbix.zabbix_server + zabbix_server_javagateway: 192.168.1.2 +``` + +or when using the zabbix-proxy: +```yaml + roles: + - role: community.zabbix.zabbix_proxy + zabbix_proxy_server: 192.168.1.1 + zabbix_proxy_javagateway: 192.168.1.2 +``` + +# Example Playbook + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: zabbix-server + sudo: yes + roles: + - role: community.zabbix.zabbix_server + zabbix_server_javagateway: 192.168.1.2 + - role: community.zabbix.zabbix_javagateway +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md new file mode 100644 index 000000000..6682f6c18 --- /dev/null +++ b/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md @@ -0,0 +1,387 @@ +# community.zabbix.zabbix_proxy role + +![Zabbix Proxy](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_proxy/badge.svg) + +**Table of Contents** + +- [Overview](#overview) + * [Operating systems](#operating-systems) + * [Zabbix Versions](#zabbix-versions) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [SElinux](#selinux) + + [Zabbix Proxy](#zabbix-proxy) + + [Database specific](#database-specific) + + [TLS Specific configuration](#tls-specific-configuration) + * [proxy](#proxy) + * [Database](#database) + + [MySQL](#mysql) + - [Local Setup](#local-setup) + - [Separate Setup](#separate-setup) + + [PostgreSQL](#postgresql) + - [Local Setup](#local-setup-1) + - [Separate Setup](#separate-setup-1) + + [SQLite3](#sqlite3) + * [Zabbix API variables](#zabbix-api-variables) +- [Example Playbook](#example-playbook) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +## Operating systems + +This role will work on the following operating systems: + + * Red Hat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +# Requirements +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collection is now required: `ansible.posix`. Installing the collection: + +```sh +ansible-galaxy collection install ansible.posix +``` + +If you are willing to create proxy in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too: + +``` +ansible-galaxy collection install ansible.netcommon +``` + +### MySQL + +When you are a MySQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.mysql`. This collections are needed as the `mysql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.mysql +``` + +### PostgreSQL + +When you are a PostgreSQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.postgresql`. This collections are needed as the `postgresql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.postgresql +``` + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases. + +| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V | +| Red Hat Fam 6 | | | | | V | V | | | V | +| Red Hat Fam 5 | | | | | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | | V | V | V | V | V | +| Debian 10 buster | V | | V | V | V | V | V | | | +| Debian 9 stretch | V | | V | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_proxy_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_proxy_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. + +### SElinux + +* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the Proxy will run. + +### Zabbix Proxy + +* `zabbix_proxy_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact. +* `zabbix_proxy_server`: The ip or dns name for the zabbix-server machine. +* `zabbix_proxy_serverport`: The port on which the zabbix-server is running. Default: 10051 +* `*zabbix_proxy_package_state`: Default: `present`. Can be overridden to `latest` to update packages +* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client. +* `zabbix_proxy_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip. +* `zabbix_proxy_manage_service`: Default: `True`. When you run multiple Zabbix proxies in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-proxy service, because Pacemaker is in control of zabbix-proxy service. +* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely. +* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started.This parameter is supported since Zabbix 4.2.0. +* `zabbix_proxy_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_logtype`: Specifies where log messages are written to: system, file, console. +* `zabbix_proxy_logfile`: Name of log file. +* `zabbix_proxy_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_proxy_include`. +* `zabbix_proxy_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. +* `zabbix_proxy_statsallowedip`: Default: `127.0.0.1`. Allowed IP foe remote gathering of the ZabbixPorixy internal metrics. +* `zabbix_proxy_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission +* `zabbix_proxy_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified. +* `zabbix_proxy_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'. +* `zabbix_proxy_listenbacklog`: The maximum number of pending connections in the queue. + +### Database specific + +* `zabbix_proxy_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database. +* `zabbix_proxy_database`: Default: `mysql`. The type of database used. Can be: `mysql`, `pgsql` or `sqlite3` +* `zabbix_proxy_database_long`: Default: `mysql`. The type of database used, but long name. Can be: `mysql`, `postgresql` or `sqlite3` +* `zabbix_proxy_dbhost`: The hostname on which the database is running. Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections) Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_dbname`: The database name which is used by the Zabbix Proxy. +* `zabbix_proxy_dbuser`: The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_dbpassword`: The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_dbport`: The database port which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False. +* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client. Default true +* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False. +* `zabbix_proxy_dbencoding`: Default: `utf8`. The encoding for the MySQL database. +* `zabbix_proxy_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database.zabbix_proxy_ +* `zabbix_server_allowunsupporteddbversions`: Allow proxy to work with unsupported database versions. +* `zabbix_proxy_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`. + +### TLS Specific configuration + +These variables are specific for Zabbix 3.0 and higher: + +* `zabbix_proxy_tlsconnect`: How the agent should connect to server or proxy. Used for active checks. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_proxy_tlsaccept`: What incoming connections to accept. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_proxy_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification. +* `zabbix_proxy_tlscrlfile`: Full pathname of a file containing revoked certificates. +* `zabbix_proxy_tlsservercertissuer`: Allowed server certificate issuer. +* `zabbix_proxy_tlsservercertsubject`: Allowed server certificate subject. +* `zabbix_proxy_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain. +* `zabbix_proxy_tlskeyfile`: Full pathname of a file containing the agent private key. +* `zabbix_proxy_dbtlsconnect`: Setting this option enforces to use TLS connection to database: + +`required` - connect using TLS +`verify_ca` - connect using TLS and verify certificate +`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate + +On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported. +By default not set to any option and the behaviour depends on database configuration. +This parameter is supported since Zabbix 5.0.0. + +* `zabbix_proxy_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlscertfile`: Full pathname of file containing Zabbix Proxy certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlscipher`: The list of encryption ciphers that Zabbix Proxy permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlscipher13`: The list of encryption ciphersuites that Zabbix Proxy permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0. + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +## Database + +With Zabbix Proxy you can make use of 2 different databases: + +* `mysql` +* `postgresql` +* `SQLite3` + +In the following paragraphs we dive into both setups. + +### MySQL + +To make the Zabbix Proxy work with a `MySQL` database, there are 2 types on setup: + +1. Local setup, `MySQL` running on same host as the Zabbix Proxy; +2. Separate setup, `MySQL` running on a different host than the Zabbix Proxy. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `MySQL` instance on the host. Example: `geerlingguy.mysql` can be used, but also others can be used. Please make sure that before installing the Zabbix Proxy, you have a fully functional `MySQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: mysql +zabbix_proxy_database_long: mysql +zabbix_proxy_dbport: 3306 +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `MySQL`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `MySQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `MySQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: mysql +zabbix_proxy_database_long: mysql +zabbix_proxy_dbport: 3306 +zabbix_proxy_dbhost: mysql-host +zabbix_proxy_dbhost_run_install: false +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +zabbix_proxy_privileged_host: '%' +zabbix_proxy_mysql_login_host: mysql-host +zabbix_proxy_mysql_login_user: root +zabbix_proxy_mysql_login_password: changeme +zabbix_proxy_mysql_login_port: 3306 +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `MySQL`. + +The `zabbix_proxy_privileged_host` can be set to the hostname/ip of the host running Zabbix Proxy for security related purposes. Also make sure that `zabbix_proxy_mysql_login_password` is set to the correct password for the user provided with `zabbix_proxy_mysql_login_host` to create a database and user in the `MySQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `MySQL` on a different host will be running. + +### PostgreSQL + +To make the Zabbix Proxy work with a `PgSQL` database, there are 2 types on setup: + +1. Local setup, `PgSQL` running on same host as the Zabbix Proxy; +2. Separate setup, `PgSQL` running on a different host than the Zabbix Proxy. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `PgSQL` instance on the host. Example: `geerlingguy.postgresql` can be used, but also others can be used. Please make sure that before installing the Zabbix Proxy, you have a fully functional `PgSQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: pgsql +zabbix_proxy_database_long: postgresql +zabbix_proxy_dbport: 5432 +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `PgSQL`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `PgSQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `PgSQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: pgsql +zabbix_proxy_database_long: postgresql +zabbix_proxy_dbport: 5432 +zabbix_proxy_dbhost: pgsql-host +zabbix_proxy_dbhost_run_install: false +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +zabbix_proxy_privileged_host: '%' +zabbix_proxy_pgsql_login_host: pgsql-host +zabbix_proxy_pgsql_login_user: postgres +zabbix_proxy_pgsql_login_password: changeme +zabbix_proxy_pgsql_login_port: 5432 +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `PgSQL`. + +The `zabbix_proxy_privileged_host` can be set to the hostname/ip of the host running Zabbix Proxy for security related purposes. Also make sure that `zabbix_proxy_mysql_login_password` is set to the correct password for the user provided with `zabbix_proxy_mysql_login_host` to create a database and user in the `PgSQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `PgSQL` on a different host will be running.zabbix_proxy_ + +### SQLite3 + +The SQLite3 can only be used on the same host as on which the Zabbix Proxy is running. If you want to use a seperate host for running the database for the proxy, please consider going for MySQL or PostGreSQL. + +The following properties needs to be set when using `SQLite3` as the database: + +```yaml +zabbix_proxy_database: sqlite3 +zabbix_proxy_database_long: sqlite3 +zabbix_proxy_dbname: /path/to/sqlite3.db +``` + +NOTE: When using `zabbix_proxy_dbname: zabbix_proxy` (Which is default with this role), it will automatically be stored on `/var/lib/zabbix/zabbix_proxy.db` + +## Zabbix API variables + +These variables need to be overridden when you want to make use of the Zabbix API for automatically creating and or updating proxies, i.e. when `zabbix_api_create_proxy` is set to `True`. + +* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth. +* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth. +* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com +* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080 +* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS +* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used +* `zabbix_api_login_user`: Username of user which has API access. +* `zabbix_api_login_pass`: Password for the user which has API access. +* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu` +* `zabbix_api_create_proxy`: When you want to enable the Zabbix API to create/delete the proxy. This has to be set to `True` if you want to make use of `zabbix_proxy_state`. Default: `False` +* `zabbix_proxy_name`: name of the Zabbix proxy as it is seen by Zabbix server +* `zabbix_proxy_state`: present (Default) if the proxy needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_proxy` is set to `True`. +* `zabbix_proxy_status`: active (Default) if the proxy needs to be active or passive. +* `zabbix_api_timeout`: timeout for API calls (default to 30 seconds) + +# Example Playbook + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: zabbix-proxy + roles: + - role: community.zabbix.zabbix_proxy + zabbix_proxy_server: 192.168.1.1 + zabbix_proxy_database: mysql + zabbix_proxy_database_long: mysql +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md new file mode 100644 index 000000000..4643fbc3f --- /dev/null +++ b/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md @@ -0,0 +1,385 @@ +# community.zabbix.zabbix_server role + +![Zabbix Server](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_server/badge.svg) + +**Table of Contents** + +- [Overview](#overview) +- [Requirements](#requirements) + * [Operating systems](#operating-systems) + * [Zabbix Versions](#zabbix-versions) +- [Installation](#installation) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [SElinux](#selinux) + + [Zabbix Server](#zabbix-server) + + [Database specific](#database-specific) + + [TLS Specific configuration](#tls-specific-configuration) + + [Custom Zabbix Scripts](#custom-zabbix-scripts) + * [proxy](#proxy) + * [Database](#database) + + [MySQL](#mysql) + - [Local Setup](#local-setup) + - [Separate Setup](#separate-setup) + + [PostgreSQL](#postgresql) + - [Local Setup](#local-setup-1) + - [Separate Setup](#separate-setup-1) +- [Example Playbook](#example-playbook) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +This is a Ansible role for installing and maintaining the zabbix-server. This will only install the Zabbix Server component and not the Zabbix Web. + +# Requirements + +## Operating systems + +This role will work on the following operating systems: + + * Red Hat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collection is now required: `ansible.posix`. Installing the collection: + +```sh +ansible-galaxy collection install ansible.posix +``` + +### MySQL + +When you are a MySQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.mysql`. This collections are needed as the `mysql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.mysql +``` + +### PostgreSQL + +When you are a PostgreSQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.postgresql`. This collections are needed as the `postgresql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.postgresql +``` + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases: + +| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | | | | | | V | V | V | V | +| Red Hat Fam 6 | | | | | V | V | | | V | +| Red Hat Fam 5 | | | | | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | | V | V | V | V | V | +| Debian 10 buster | | | V | V | V | V | V | | | +| Debian 9 stretch | | | V | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +See https://support.zabbix.com/browse/ZBX-18790 why RHEL7 is not supported anymore. + +# Installation + +Installing this role is very simple: `ansible-galaxy install community.zabbix.zabbix_server` + +Please be aware that this role only installs the Zabbix Server and not the Zabbix Web. If you do want to have a Zabbix Web, please execute the following command: `ansible-galaxy install community.zabbix.zabbix_web` + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_server_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_server_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. +* `zabbix_service_state`: Default: `started`. Can be overridden to stopped if needed +* `zabbix_service_enabled`: Default: `True` Can be overridden to `False` if needed + +### SElinux + +* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the server will run. +* `selinux_allow_zabbix_can_network`: Default: `False`. +* `selinux_allow_zabbix_can_http`: Default: `False`. + +### Zabbix Server + +* `zabbix_server_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed. +* `zabbix_server_listenport`: Default: `10051`. On which port the Zabbix Server is available. +* `zabbix_server_install_recommends`: Default: `True`. `False` does not install the recommended packages that come with the zabbix-server install. +* `zabbix_server_manage_service`: Default: `True`. When you run multiple Zabbix servers in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-server service, because Pacemaker is in control of zabbix-server service and in this case, it needs to be set to `False`. +* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started. This parameter is supported since Zabbix 4.2.0. +* `zabbix_server_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_server_include`. +* `zabbix_server_conf_mode`: Default: `0640`. The "mode" for the Zabbix configuration file. +* `zabbix_server_listenbacklog`: The maximum number of pending connections in the queue. +* `zabbix_server_trendcachesize`: Size of trend cache, in bytes. +* `zabbix_server_trendfunctioncachesize`: Size of trend function cache, in bytes. +* `zabbix_server_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission +* `zabbix_server_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified. +* `zabbix_server_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'. +* `zabbix_server_startreportwriters`: Number of pre-forked report writer instances. +* `zabbix_server_webserviceurl`: URL to Zabbix web service, used to perform web related tasks. +* `zabbix_server_servicemanagersyncfrequency`: How often Zabbix will synchronize configuration of a service manager (in seconds). +* `zabbix_server_problemhousekeepingfrequency`: How often Zabbix will delete problems for deleted triggers (in seconds). +* `zabbix_server_connectors`: Number of pre-forked instances of preprocessing workers. + +### High Availability + +These variables are specific for Zabbix 6.0 and higher: + +* `zabbix_server_hanodename`: The high availability cluster node name. When empty, server is working in standalone mode; a node with empty name is registered with address for the frontend to connect to. (Default: empty) +* `zabbix_server_nodeaddress`: IP or hostname with optional port to specify how frontend should connect to the server. + +### Database specific + +* `zabbix_server_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database. +* `zabbix_server_database`: Default: `pgsql`. The type of database used. Can be: `mysql` or `pgsql` +* `zabbix_server_database_long`: Default: `postgresql`. The type of database used, but long name. Can be: `mysql` or `postgresql` +* `zabbix_server_dbhost`: The hostname on which the database is running. +* `zabbix_server_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections) +* `zabbix_server_dbname`: The database name which is used by the Zabbix Server. +* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server. +* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server. +* `zabbix_server_dbport`: The database port which is used by the Zabbix Server. +* `zabbix_server_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`. +* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False. +* `zabbix_server_install_database_client`: Default: `True`. False does not install database client. Default true +* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False. +* `zabbix_database_timescaledb`:False / True. When you want to use timescaledb extension into the database, you can set it to True (this option only works for postgreSQL database). +* `zabbix_server_dbencoding`: Default: `utf8`. The encoding for the MySQL database. +* `zabbix_server_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database. +* `zabbix_server_allowunsupporteddbversions`: Allow server to work with unsupported database versions. + +### TLS Specific configuration + +These variables are specific for Zabbix 3.0 and higher: + +* `zabbix_server_tlsconnect`: How the agent should connect to server or proxy. Used for active checks. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_server_tlsaccept`: What incoming connections to accept. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_server_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification. +* `zabbix_server_tlscrlfile`: Full pathname of a file containing revoked certificates. +* `zabbix_server_tlsservercertissuer`: Allowed server certificate issuer. +* `zabbix_server_tlsservercertsubject`: Allowed server certificate subject. +* `zabbix_server_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain. +* `zabbix_server_tlskeyfile`: Full pathname of a file containing the agent private key. +* `zabbix_server_dbtlsconnect`: Setting this option enforces to use TLS connection to database: + +`required` - connect using TLS +`verify_ca` - connect using TLS and verify certificate +`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate + +On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported. +By default not set to any option and the behaviour depends on database configuration. +This parameter is supported since Zabbix 5.0.0. + +* `zabbix_server_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlscertfile`: Full pathname of file containing Zabbix server certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlscipher`: The list of encryption ciphers that Zabbix server permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlscipher13`: The list of encryption ciphersuites that Zabbix server permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0. + +### Custom Zabbix Scripts + +Define these variables to copy scripts to your respective scripts path. + +* `zabbix_server_alertscripts`: List of alertscripts to be added to `zabbix_server_alertscriptspath` +* `zabbix_server_externalscripts`: List of alertscripts to be added to `zabbix_server_externalscriptspath` + +Example: + +```yaml + zabbix_server_alertscripts: + - path: "{{ lookup('first_found', 'zabbix-scripts/somescript.php') }}" + name: "somescript.php" +``` + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +## Database + +With Zabbix Server you can make use of 2 different databases: + +* `mysql` +* `postgresql` + +In the following paragraphs we dive into both setups. + +### MySQL + +To make the Zabbix Server work with a `MySQL` database, there are 2 types on setup: + +1. Local setup, `MySQL` running on same host as the Zabbix Server; +2. Separate setup, `MySQL` running on a different host than the Zabbix Server. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `MySQL` instance on the host. Example: `geerlingguy.mysql` can be used, but also others can be used. Please make sure that before installing the Zabbix Server, you have a fully functional `MySQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: mysql +zabbix_server_database_long: mysql +zabbix_server_dbport: 3306 +zabbix_server_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `MySQL`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `MySQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `MySQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: mysql +zabbix_server_database_long: mysql +zabbix_server_dbport: 3306 +zabbix_server_dbhost: mysql-host +zabbix_server_dbhost_run_install: false +zabbix_server_dbpassword: <SOME_SECRET_STRING> +zabbix_server_privileged_host: '%' +zabbix_server_mysql_login_host: mysql-host +zabbix_server_mysql_login_user: root +zabbix_server_mysql_login_password: changeme +zabbix_server_mysql_login_port: 3306 +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `MySQL`. + +The `zabbix_server_privileged_host` can be set to the hostname/ip of the host running Zabbix Server for security related purposes. Also make sure that `zabbix_server_mysql_login_password` is set to the correct password for the user provided with `zabbix_server_mysql_login_host` to create a database and user in the `MySQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `MySQL` on a different host will be running. + +### PostgreSQL + +To make the Zabbix Server work with a `PgSQL` database, there are 2 types on setup: + +1. Local setup, `PgSQL` running on same host as the Zabbix Server; +2. Separate setup, `PgSQL` running on a different host than the Zabbix Server. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `PgSQL` instance on the host. Example: `geerlingguy.postgresql` can be used, but also others can be used. Please make sure that before installing the Zabbix Server, you have a fully functional `PgSQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: pgsql +zabbix_server_database_long: postgresql +zabbix_server_dbport: 5432 +zabbix_server_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `PgSQL`. Set `zabbix_server_dbpassword_hash_method` for PostgreSQL 10 and newer if they default to `scram-sha-256`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `PgSQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `PgSQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: pgsql; +zabbix_server_database_long: postgresql +zabbix_server_dbport: 5432 +zabbix_server_dbhost: pgsql-host +zabbix_server_dbhost_run_install: false +zabbix_server_dbpassword: <SOME_SECRET_STRING> +zabbix_server_privileged_host: '%' +zabbix_server_pgsql_login_host: pgsql-host +zabbix_server_pgsql_login_user: postgres +zabbix_server_pgsql_login_password: changeme +zabbix_server_pgsql_login_port: 5432 +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `PgSQL`. Set `zabbix_server_dbpassword_hash_methodh` for PostgreSQL 10 and newer if they default to `scram-sha-256`. + +The `zabbix_server_privileged_host` can be set to the hostname/ip of the host running Zabbix Server for security related purposes. Also make sure that `zabbix_server_mysql_login_password` is set to the correct password for the user provided with `zabbix_server_mysql_login_host` to create a database and user in the `PgSQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `PgSQL` on a different host will be running. + +# Example Playbook + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: zabbix-server + roles: + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via Github Actions to validate the change on a new installation. Each PR should result into a correct working Zabbix Server installation and PR's will not be merged once this process fails. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md new file mode 100644 index 000000000..cef5d62e7 --- /dev/null +++ b/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md @@ -0,0 +1,349 @@ +# community.zabbix.zabbix_web role + +![Zabbix Web](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_web/badge.svg) + +**Table of Contents** + +- [Overview](#overview) +- [Requirements](#requirements) + - [Operating Systems](#operating-systems) + - [Zabbix Versions](#zabbix-versions) +- [Installation](#installation) +- [Role Variables](#role-variables) + - [Main variables](#main-variables) + - [Overall Zabbix](#overall-zabbix) + - [Zabbix Web specific](#zabbix-web-specific) + - [Apache configuration](#apache-configuration) + - [Nginx configuration](#nginx-configuration) + - [PHP-FPM](#php-fpm) + - [Zabbix Server](#zabbix-server) + * [proxy](#proxy) +- [Example Playbook](#example-playbook) + - [Single instance](#single-instance) + - [Multi host setup](#multi-host-setup) + - [Adding Environment Variables for zabbix_web](#adding-environment-variables-for-zabbixweb) + - [Using Elasticsearch for history storage](#using-elasticsearch-for-history-storage) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +# Requirements +## Operating Systems + +This role will work on the following operating systems: + + * RedHat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`. The `community.general` collection is required when defining the `zabbix_web_htpasswd` variable (see variable section below). Installing the collections: + +```sh +ansible-galaxy collection install ansible.posix +ansible-galaxy collection install community.general +``` + +## Zabbix Versions + +See the following list of supported Operating Systems with the Zabbix releases. + +| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----------|-----|-----|------------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | | V | V | V | V | V | V | V | V | +| Red Hat Fam 6 | | | | | V | V | | | V | +| Red Hat Fam 5 | | | | | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 22.04 jammy | V | V | V | | | | | | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | V | | | +| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | | V | V | V | V | V | +| Debian 10 buster | V | V | V | V | V | V | V | | | +| Debian 9 stretch | | | V | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +# Installation + +Installing this role is very simple: `ansible-galaxy install community.zabbix.zabbix_web` + +When the Zabbix Web needs to be running on the same host as the Zabbix Server, please also install the Zabbix Server by executing the following command: `ansible-galaxy install community.zabbix.zabbix_server` + +Default username/password for the Zabbix Web interface is the default. + +Username: Admin +Password: zabbix + +# Role Variables + +## Main variables + +The following is an overview of all available configuration defaults for this role. + +### Overall Zabbix + +* `zabbix_web_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_web_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. + +* `zabbix_web_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed. +* `zabbix_web_centos_release`: Default: True. When the `centos-release-scl` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`. +* `zabbix_web_rhel_release`: Default: True. When the `scl-utils` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`. +* `zabbix_web_doubleprecision`: Default: `False`. For upgraded installations, please read database [upgrade notes](https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500) (Paragraph "Enabling extended range of numeric (float) values") before enabling this option. +* `zabbix_web_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. + +### Zabbix Web specific + +* `zabbix_api_server_url`: This is the url on which the zabbix web interface is available. Default is zabbix.example.com, you should override it. For example, see "Example Playbook" +* `zabbix_url_aliases`: A list with Aliases for the Apache Virtual Host configuration. +* `zabbix_timezone`: Default: `Europe/Amsterdam`. This is the timezone. The Apache Virtual Host needs this parameter. +* `zabbix_vhost`: Default: `true`. When you don't want to create an Apache Virtual Host configuration, you can set it to False. +* `zabbix_web_env`: (Optional) A Dictionary of PHP Environments settings. +* `zabbix_web_conf_web_user`: When provided, the user (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`). +* `zabbix_web_conf_web_group`: When provided, the group (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`). +* `zabbix_web_htpasswd`: (Optional) Allow HTTP authentication at the webserver level via a htpasswd file. +* `zabbix_web_htpasswd_file`: Default: `/etc/zabbix/web/htpasswd`. Allows the change the default path to the htpasswd file. +* `zabbix_web_htpasswd_users`: (Optional) Dictionary for creating users via `htpasswd_user` and passphrases via `htpasswd_pass` in htpasswd file. +* `zabbix_web_allowlist_ips`: (Optional) Allow web access at webserver level to a list of defined IPs or CIDR. +* `zabbix_web_connect_ha_backend`: (Optional) Default: `false`. When set to `true` values for Zabbix server will not be written and frontend gets values from database to connect to active cluster node. Set `true` when operating Zabbix servers in a cluste (only >=6.0). +* `zabbix_saml_idp_crt`: (Optional) The path to the certificate of the Identity Provider used for SAML authentication +* `zabbix_saml_sp_crt`: (Optional) The path to the public certificate of Zabbix as Service Provider +* `zabbix_saml_sp_key`: (Optional) The path to the private certificate of Zabbix as Service Provider + +#### Apache configuration + +* `zabbix_apache_vhost_port`: The port on which Zabbix HTTP vhost is running. +* `zabbix_apache_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running. +* `zabbix_apache_vhost_listen_ip`: On which interface the Apache Virtual Host is available. +* `zabbix_apache_can_connect_ldap`: Default: `false`. Set SELinux boolean to allow httpd to connect to LDAP. +* `zabbix_php_install`: Default: `true`. True / False. Switch for extra install of packages for PHP, currently on for Debian/Ubuntu. +* `zabbix_web_max_execution_time`: +* `zabbix_web_memory_limit`: +* `zabbix_web_post_max_size`: +* `zabbix_web_upload_max_filesize`: +* `zabbix_web_max_input_time`: +* `zabbix_apache_include_custom_fragment`: Default: `true`. Includes php_value vars max_execution_time, memory_limit, post_max_size, upload_max_filesize, max_input_time and date.timezone in vhost file.. place those in php-fpm configuration. +* `zabbix_apache_tls`: If the Apache vhost should be configured with TLS encryption or not. +* `zabbix_apache_redirect`: If a redirect should take place from HTTP to HTTPS +* `zabbix_apache_tls_crt`: The path to the TLS certificate file. +* `zabbix_apache_tls_key`: The path to the TLS key file. +* `zabbix_apache_tls_chain`: The path to the TLS certificate chain file. +* `zabbix_apache_SSLPassPhraseDialog`: Type of pass phrase dialog for encrypted private keys. +* `zabbix_apache_SSLSessionCache`: Type of the global/inter-process SSL Session Cache +* `zabbix_apache_SSLSessionCacheTimeout`: Number of seconds before an SSL session expires in the Session Cache +* `zabbix_apache_SSLCryptoDevice`: Enable use of a cryptographic hardware accelerator +* `zabbix_apache_custom_includes`: Configure custom includes. Default: `[]` + +When `zabbix_apache_tls_crt`, `zabbix_apache_tls_key` and/or `zabbix_apache_tls_chain` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files. + +See https://httpd.apache.org/docs/current/mod/mod_ssl.html for SSL* configuration options for Apache HTTPD. + +#### Nginx configuration + +* `zabbix_nginx_vhost_port`: The port on which Zabbix HTTP vhost is running. +* `zabbix_nginx_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running. +* `zabbix_nginx_tls`: If the Nginx vhost should be configured with TLS encryption or not. +* `zabbix_nginx_tls_crt`: The path to the TLS certificate file. +* `zabbix_nginx_tls_key`: The path to the TLS key file. +* `zabbix_nginx_tls_dhparam`: The path to the TLS DHParam file. +* `zabbix_nginx_tls_session_cache`: Type of the global/inter-process SSL Session Cache +* `zabbix_nginx_tls_session_timeout`: +* `zabbix_nginx_tls_session_tickets`: +* `zabbix_nginx_tls_protocols`: The TLS Protocols to accept. +* `zabbix_nginx_tls_ciphers`: The TLS Ciphers to be allowed. + +When `zabbix_nginx_tls_crt` and `zabbix_nginx_tls_key` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files. + +#### PHP-FPM + +The following properties are specific to Zabbix 5.0 and for the PHP(-FPM) configuration: + +* `zabbix_php_version`: Either `7.3` or `7.4` (Based on the OS Family). When you want to override the PHP Version. +* `zabbix_php_fpm_session`: The directory where sessions will be stored. If none are provided, defaults are used. +* `zabbix_php_fpm_listen`: The path to a socket file or ipaddress:port combination on which PHP-FPM needs to listen. If none are provided, defaults are used. +* `zabbix_php_fpm_conf_listen`: Default: `true`. If we want to configure the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_conf_user`: The owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file). +* `zabbix_php_fpm_conf_enable_user`: Default: `true`. If we want to configure the owner of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_conf_group`: The group of the owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file). +* `zabbix_php_fpm_conf_enable_group`: Default: `true`. If we want to configure the group of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_conf_mode`: The mode for the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file). +* `zabbix_php_fpm_conf_enable_mode`: Default: `true`. If we want to configure the mode of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_dir_etc`: etc HOME root directory of PHP-FPM setup. +* `zabbix_php_fpm_dir_var`: Var HOME root directory of PHP-FPM setup. + +### Zabbix Server + +* `zabbix_server_name`: The name of the Zabbix Server. +* `zabbix_server_database`: The type of database used. Can be: mysql or pgsql +* `zabbix_server_database_long`: The type of database used, but long name. Can be: mysql or postgresql +* `zabbix_server_hostname`: The hostname on which the zabbix-server is running. Default set to: {{ inventory_hostname }} +* `zabbix_server_listenport`: On which port the Zabbix Server is available. Default: 10051 +* `zabbix_server_dbhost`: The hostname on which the database is running. +* `zabbix_server_dbname`: The database name which is used by the Zabbix Server. +* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server. +* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server. +* `zabbix_server_dbport`: The database port which is used by the Zabbix Server. + +The following properties are related when using Elasticsearch for history storage: + +* `zabbix_server_history_url`: String with url to the Elasticsearch server or a list if the types are stored on different Elasticsearch URLs. +* `zabbix_server_history_types`: List of history types to store in Elasticsearch. + +See the following links for more information regarding Zabbix and Elasticsearch +https://www.zabbix.com/documentation/3.4/manual/appendix/install/elastic_search_setup +https://www.zabbix.com/documentation/4.0/manual/appendix/install/elastic_search_setup + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +# Example Playbook + +There are two ways of using the zabbix-web: + +* Single instance +* Multi host setup + +## Single instance + +When there is one host running both Zabbix Server and the Zabbix Web (Running MySQL as database): + +```yaml +- hosts: zabbix-server + become: yes + roles: + - role: geerlingguy.apache + - role: geerlingguy.php + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + - role: community.zabbix.zabbix_web + zabbix_api_server_url: zabbix.mydomain.com + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +## Multi host setup + +This is a two host setup. On one host (Named: "zabbix-server") the Zabbix Server is running, and the other host (Named: zabbix-web) runs Zabbix Web (with MySQL as database): + +```yaml +- hosts: zabbix-server + become: yes + roles: + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + +- hosts: zabbix-web + become: yes + roles: + - role: geerlingguy.apache + - role: geerlingguy.php + - role: community.zabbix.zabbix_web + zabbix_api_server_url: zabbix.mydomain.com + zabbix_server_hostname: zabbix-server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +## Adding Environment Variables for zabbix_web + +Sometimes you need to add environment variables to your +zabbix.conf.php, for example to add LDAP CA certificates. To do this add a `zabbix_web_env` dictionary: + +```yaml +- hosts: zabbix-web + become: yes + roles: + - role: geerlingguy.apache + - role: geerlingguy.php + php_memory_limit: "128M" + php_max_execution_time: "300" + php_upload_max_filesize: "256M" + php_packages: + - php + - php-fpm + - php-acpu + - role: geerlingguy.apache-php-fpm + - role: community.zabbix.zabbix_web + zabbix_api_server_url: zabbix.mydomain.com + zabbix_server_hostname: zabbix-server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + zabbix_web_env: + LDAPTLS_CACERT: /etc/ssl/certs/ourcert.pem +``` + +## Using Elasticsearch for history storage + +To use Elasticsearch for history storage you need to configure the `zabbix_server_history_url` and `zabbix_server_history_types`. You will also need to configure Elasticsearch +in the zabbix_server role. + +Zabbix can store the following history types +in Elasticsearch: +* Numeric (unsigned) - `uint` +* Numeric (float) - `dbl` +* Character - `str` +* Log - `log` +* Text - `text` + +To store all history types in the same history URL the following variables should be set (make sure history url points to your Elasticsearch cluster): + +``` +zabbix_server_history_url: "http://localhost:9200" +zabbix_server_history_types: + - 'str' + - 'text' + - 'log' + - 'uint' + - 'dbl' +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/meta/runtime.yml b/ansible_collections/community/zabbix/meta/runtime.yml new file mode 100644 index 000000000..3e4fe8b79 --- /dev/null +++ b/ansible_collections/community/zabbix/meta/runtime.yml @@ -0,0 +1,34 @@ +--- +requires_ansible: '>=2.9.10' +action_groups: + zabbix: + - zabbix_action + - zabbix_authentication + - zabbix_autoregister + - zabbix_discovery_rule + - zabbix_globalmacro + - zabbix_group_facts + - zabbix_group_info + - zabbix_group + - zabbix_host_events_info + - zabbix_host_facts + - zabbix_host_info + - zabbix_hostmacro + - zabbix_host + - zabbix_housekeeping + - zabbix_maintenance + - zabbix_map + - zabbix_mediatype + - zabbix_proxy_info + - zabbix_proxy + - zabbix_screen + - zabbix_script + - zabbix_service + - zabbix_template_info + - zabbix_template + - zabbix_user_directory + - zabbix_usergroup + - zabbix_user_info + - zabbix_user + - zabbix_user_role + - zabbix_valuemap diff --git a/ansible_collections/community/zabbix/molecule/requirements.txt b/ansible_collections/community/zabbix/molecule/requirements.txt new file mode 100644 index 000000000..bec205a0a --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/requirements.txt @@ -0,0 +1,11 @@ +# Install CI dependencies for the Zabbix Roles +ansible==7.0.0 +ansible-compat==0.5.0 +ansible-core==2.14.2 +docker==5.0.2 +molecule==3.5.1 +molecule-docker==1.0.2 +netaddr==0.8.0 +pytest-testinfra==6.1.0 +ipaddr==2.2.0 +ipaddress==1.0.23 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml new file mode 100644 index 000000000..a0222246f --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml @@ -0,0 +1,58 @@ +--- +driver: + name: docker + +platforms: + - name: zabbix-agent-${MY_MOLECULE_CONTAINER:-centos} + image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"} + command: ${MY_MOLECULE_DOCKER_COMMAND:-""} + privileged: true + pre_build_image: true + networks: + - name: zabbix + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + groups: + - agent + +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + prepare: ../../common/playbooks/prepare.yml + converge: ../../common/playbooks/converge.yml + env: + ANSIBLE_REMOTE_TMP: /tmp/ + ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix + ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles + inventory: + group_vars: + all: + zabbix_agent_src_reinstall: false + zabbix_install_pip_packages: false + zabbix_agent_server: 192.168.3.33 + zabbix_agent_serveractive: 192.168.3.33 + zabbix_agent_listenip: 0.0.0.0 + zabbix_agent_tlsconnect: psk + zabbix_agent_tlsaccept: psk + +scenario: + test_sequence: + - dependency + - lint + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - side_effect + - verify + - cleanup + - destroy +verifier: + name: testinfra + lint: + name: flake8 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/converge.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/converge.yml new file mode 100644 index 000000000..7ce55d49e --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/converge.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: zabbix_agent diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml new file mode 100644 index 000000000..3ce015db6 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml @@ -0,0 +1,86 @@ +--- +- name: Prepare + hosts: all + tasks: + - name: "Installing packages on CentOS family" + package: + pkg: + - net-tools + - which + state: present + register: zabbix_agent_prepare_packages_install + until: zabbix_agent_prepare_packages_install is succeeded + when: + - ansible_os_family == 'RedHat' + + - name: "Installing packages on CentOS (Sangoma) family" + package: + pkg: + - net-tools + - which + state: present + register: zabbix_agent_prepare_packages_install + until: zabbix_agent_prepare_packages_install is succeeded + when: + - ansible_os_family == 'Sangoma' + + - name: "Installing packages on Debian family" + apt: + name: + - "{{ 'net-tools' if ansible_distribution_major_version not in ['10','18', '20'] else 'iproute2' }}" + state: present + update_cache: true + register: zabbix_agent_prepare_packages_install + until: zabbix_agent_prepare_packages_install is succeeded + when: + - ansible_os_family == 'Debian' + + - name: "Installing packages on Suse family" + shell: zypper install -y python-xml python-libxml2 net-tools which + register: zabbix_agent_prepare_packages_install + until: zabbix_agent_prepare_packages_install is succeeded + when: ansible_os_family == 'Suse' + tags: + - skip_ansible_lint + +- name: Prepare + hosts: docker + tasks: + - name: "Download Docker CE repo file" + get_url: + url: https://download.docker.com/linux/centos/docker-ce.repo + dest: /etc/yum.repos.d/docker-ce.repo + mode: 0644 + register: zabbix_agent_prepare_docker_repo + until: zabbix_agent_prepare_docker_repo is succeeded + + - name: "Installing Epel" + package: + pkg: + - epel-release + state: present + register: zabbix_agent_prepare_docker_install + until: zabbix_agent_prepare_docker_install is succeeded + + - name: "Installing Docker" + package: + pkg: + - docker-ce + - python-pip + - python-setuptools + state: present + register: zabbix_agent_prepare_docker_install + until: zabbix_agent_prepare_docker_install is succeeded + + - name: "Installing Docker Python" + pip: + name: + - docker + state: present + register: zabbix_agent_prepare_docker_install + until: zabbix_agent_prepare_docker_install is succeeded + + - name: "Starting Docker service" + service: + name: docker + state: started diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/agent2_common/test_agent2.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/agent2_common/test_agent2.py new file mode 100644 index 000000000..f1b3b0534 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/agent2_common/test_agent2.py @@ -0,0 +1,12 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent2") + + +def test_zabbix_agent2_dot_conf(host, zabbix_agent_file): + assert zabbix_agent_file.contains("Plugins.SystemRun.LogRemoteCommands=0") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/autopsk/test_auto_psk.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/autopsk/test_auto_psk.py new file mode 100644 index 000000000..859f2a255 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/autopsk/test_auto_psk.py @@ -0,0 +1,24 @@ +import pytest +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbix_agent_dot_conf(host, zabbix_agent_conf): + assert zabbix_agent_conf.contains("TLSAccept=psk") + assert zabbix_agent_conf.contains( + f"TLSPSKIdentity={host.ansible.get_variables()['inventory_hostname']}" + ) + assert zabbix_agent_conf.contains("TLSPSKFile=/etc/zabbix/tls_psk_auto.secret") + + +def test_zabbix_agent_autopsk(host): + psk_file = host.file("/etc/zabbix/tls_psk_auto.secret") + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.size == 64 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py new file mode 100644 index 000000000..96d4a1716 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py @@ -0,0 +1,49 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbixagent_running_and_enabled(host, zabbix_agent_service): + # Find out why this is not working for linuxmint and opensuse + if host.system_info.distribution not in ["linuxmint", "opensuse", "ubuntu"]: + assert zabbix_agent_service.is_running + assert zabbix_agent_service.is_enabled + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.user == "root" + assert zabbix_agent_conf.group == "root" + assert zabbix_agent_conf.mode == 0o644 + + assert zabbix_agent_conf.contains("Server=192.168.3.33") + assert zabbix_agent_conf.contains("ServerActive=192.168.3.33") + assert zabbix_agent_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(zabbix_agent_include_dir): + assert zabbix_agent_include_dir.is_directory + assert zabbix_agent_include_dir.user == "root" + assert zabbix_agent_include_dir.group == "zabbix" + + +def test_socket(host): + # Find out why this is not working for linuxmint and opensus + if host.system_info.distribution not in ["linuxmint", "opensuse"]: + assert host.socket("tcp://0.0.0.0:10050").is_listening + + +def test_zabbix_package(host, zabbix_agent_package): + assert zabbix_agent_package.is_installed + + if host.system_info.distribution == "debian": + if host.system_info.codename in ["bullseye", "focal"]: + assert zabbix_agent_package.version.startswith("1:6.4") + else: + assert zabbix_agent_package.version.startswith("1:6.0") + if host.system_info.distribution == "centos": + assert zabbix_agent_package.version.startswith("6.4") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/no_auto_psk/test_no_auto_psk.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/no_auto_psk/test_no_auto_psk.py new file mode 100644 index 000000000..6fbbbb226 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/no_auto_psk/test_no_auto_psk.py @@ -0,0 +1,24 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.contains("TLSAccept=psk") + assert zabbix_agent_conf.contains("TLSPSKIdentity=my_Identity") + assert zabbix_agent_conf.contains("TLSPSKFile=/data/certs/zabbix.psk") + + +def test_zabbix_agent_psk(host): + psk_file = host.file("/data/certs/zabbix.psk") + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.contains( + "97defd6bd126d5ba7fa5f296595f82eac905d5eda270207a580ab7c0cb9e8eab" + ) diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/test_docker.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/test_docker.py new file mode 100644 index 000000000..e8fe39f39 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/test_docker.py @@ -0,0 +1,23 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("docker") + + +def test_docker_running(host): + zabbixagent = host.docker("zabbix-agent") + zabbixagent.is_running + + +def test_zabbix_include_dir(host): + zabbixagent = host.file("/etc/zabbix/zabbix_agentd.d") + assert zabbixagent.is_directory + assert zabbixagent.user == "root" + assert zabbixagent.group == "zabbix" + + +def test_socket(host): + assert host.socket("tcp://0.0.0.0:10050").is_listening diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/molecule.yml new file mode 100644 index 000000000..76edc902e --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/molecule.yml @@ -0,0 +1,19 @@ +--- +scenario: + name: agent2 +provisioner: + name: ansible + inventory: + group_vars: + all: + zabbix_agent2: true + zabbix_agent2_tlsconnect: psk + zabbix_agent2_tlsaccept: psk + zabbix_agent2_tlspskidentity: my_Identity + zabbix_agent2_tlspskfile: /data/certs/zabbix.psk + zabbix_agent2_tlspsk_secret: 97defd6bd126d5ba7fa5f296595f82eac905d5eda270207a580ab7c0cb9e8eab + zabbix_agent2_plugins: + - name: SystemRun + options: + - parameter: LogRemoteCommands + value: 0
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/agent2_common/test_agent2.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/agent2_common/test_agent2.py new file mode 100644 index 000000000..f1b3b0534 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/agent2_common/test_agent2.py @@ -0,0 +1,12 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent2") + + +def test_zabbix_agent2_dot_conf(host, zabbix_agent_file): + assert zabbix_agent_file.contains("Plugins.SystemRun.LogRemoteCommands=0") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py new file mode 100644 index 000000000..96d4a1716 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py @@ -0,0 +1,49 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbixagent_running_and_enabled(host, zabbix_agent_service): + # Find out why this is not working for linuxmint and opensuse + if host.system_info.distribution not in ["linuxmint", "opensuse", "ubuntu"]: + assert zabbix_agent_service.is_running + assert zabbix_agent_service.is_enabled + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.user == "root" + assert zabbix_agent_conf.group == "root" + assert zabbix_agent_conf.mode == 0o644 + + assert zabbix_agent_conf.contains("Server=192.168.3.33") + assert zabbix_agent_conf.contains("ServerActive=192.168.3.33") + assert zabbix_agent_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(zabbix_agent_include_dir): + assert zabbix_agent_include_dir.is_directory + assert zabbix_agent_include_dir.user == "root" + assert zabbix_agent_include_dir.group == "zabbix" + + +def test_socket(host): + # Find out why this is not working for linuxmint and opensus + if host.system_info.distribution not in ["linuxmint", "opensuse"]: + assert host.socket("tcp://0.0.0.0:10050").is_listening + + +def test_zabbix_package(host, zabbix_agent_package): + assert zabbix_agent_package.is_installed + + if host.system_info.distribution == "debian": + if host.system_info.codename in ["bullseye", "focal"]: + assert zabbix_agent_package.version.startswith("1:6.4") + else: + assert zabbix_agent_package.version.startswith("1:6.0") + if host.system_info.distribution == "centos": + assert zabbix_agent_package.version.startswith("6.4") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/conftest.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/conftest.py new file mode 100644 index 000000000..5d7087ab2 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/conftest.py @@ -0,0 +1,33 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +@pytest.fixture +def zabbix_agent_conf(host): + if host.system_info.distribution in ["opensuse"]: + passwd = host.file("/etc/zabbix/zabbix-agentd.conf") + else: + passwd = host.file("/etc/zabbix/zabbix_agent2.conf") + + return passwd + + +@pytest.fixture +def zabbix_agent_service(host): + return host.service("zabbix-agent2") + + +@pytest.fixture +def zabbix_agent_include_dir(host): + return host.file("/etc/zabbix/zabbix_agent2.d") + + +@pytest.fixture +def zabbix_agent_package(host): + return host.package("zabbix-agent2") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/no_auto_psk/test_no_auto_psk.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/no_auto_psk/test_no_auto_psk.py new file mode 100644 index 000000000..6fbbbb226 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/no_auto_psk/test_no_auto_psk.py @@ -0,0 +1,24 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.contains("TLSAccept=psk") + assert zabbix_agent_conf.contains("TLSPSKIdentity=my_Identity") + assert zabbix_agent_conf.contains("TLSPSKFile=/data/certs/zabbix.psk") + + +def test_zabbix_agent_psk(host): + psk_file = host.file("/data/certs/zabbix.psk") + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.contains( + "97defd6bd126d5ba7fa5f296595f82eac905d5eda270207a580ab7c0cb9e8eab" + ) diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/molecule.yml new file mode 100644 index 000000000..a63909406 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/molecule.yml @@ -0,0 +1,17 @@ +--- +scenario: + name: agent2autopsk +provisioner: + name: ansible + inventory: + group_vars: + all: + zabbix_agent2: true + zabbix_agent2_tlsconnect: psk + zabbix_agent2_tlsaccept: psk + zabbix_agent2_tlspsk_auto: True + zabbix_agent2_plugins: + - name: SystemRun + options: + - parameter: LogRemoteCommands + value: 0
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/agent2_common/test_agent2.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/agent2_common/test_agent2.py new file mode 100644 index 000000000..f1b3b0534 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/agent2_common/test_agent2.py @@ -0,0 +1,12 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent2") + + +def test_zabbix_agent2_dot_conf(host, zabbix_agent_file): + assert zabbix_agent_file.contains("Plugins.SystemRun.LogRemoteCommands=0") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/autopsk/test_auto_psk.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/autopsk/test_auto_psk.py new file mode 100644 index 000000000..859f2a255 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/autopsk/test_auto_psk.py @@ -0,0 +1,24 @@ +import pytest +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbix_agent_dot_conf(host, zabbix_agent_conf): + assert zabbix_agent_conf.contains("TLSAccept=psk") + assert zabbix_agent_conf.contains( + f"TLSPSKIdentity={host.ansible.get_variables()['inventory_hostname']}" + ) + assert zabbix_agent_conf.contains("TLSPSKFile=/etc/zabbix/tls_psk_auto.secret") + + +def test_zabbix_agent_autopsk(host): + psk_file = host.file("/etc/zabbix/tls_psk_auto.secret") + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.size == 64 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py new file mode 100644 index 000000000..96d4a1716 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py @@ -0,0 +1,49 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbixagent_running_and_enabled(host, zabbix_agent_service): + # Find out why this is not working for linuxmint and opensuse + if host.system_info.distribution not in ["linuxmint", "opensuse", "ubuntu"]: + assert zabbix_agent_service.is_running + assert zabbix_agent_service.is_enabled + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.user == "root" + assert zabbix_agent_conf.group == "root" + assert zabbix_agent_conf.mode == 0o644 + + assert zabbix_agent_conf.contains("Server=192.168.3.33") + assert zabbix_agent_conf.contains("ServerActive=192.168.3.33") + assert zabbix_agent_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(zabbix_agent_include_dir): + assert zabbix_agent_include_dir.is_directory + assert zabbix_agent_include_dir.user == "root" + assert zabbix_agent_include_dir.group == "zabbix" + + +def test_socket(host): + # Find out why this is not working for linuxmint and opensus + if host.system_info.distribution not in ["linuxmint", "opensuse"]: + assert host.socket("tcp://0.0.0.0:10050").is_listening + + +def test_zabbix_package(host, zabbix_agent_package): + assert zabbix_agent_package.is_installed + + if host.system_info.distribution == "debian": + if host.system_info.codename in ["bullseye", "focal"]: + assert zabbix_agent_package.version.startswith("1:6.4") + else: + assert zabbix_agent_package.version.startswith("1:6.0") + if host.system_info.distribution == "centos": + assert zabbix_agent_package.version.startswith("6.4") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/conftest.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/conftest.py new file mode 100644 index 000000000..5d7087ab2 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/conftest.py @@ -0,0 +1,33 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +@pytest.fixture +def zabbix_agent_conf(host): + if host.system_info.distribution in ["opensuse"]: + passwd = host.file("/etc/zabbix/zabbix-agentd.conf") + else: + passwd = host.file("/etc/zabbix/zabbix_agent2.conf") + + return passwd + + +@pytest.fixture +def zabbix_agent_service(host): + return host.service("zabbix-agent2") + + +@pytest.fixture +def zabbix_agent_include_dir(host): + return host.file("/etc/zabbix/zabbix_agent2.d") + + +@pytest.fixture +def zabbix_agent_package(host): + return host.package("zabbix-agent2") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/molecule.yml new file mode 100644 index 000000000..a4bf295c1 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/molecule.yml @@ -0,0 +1,9 @@ +--- +scenario: + name: autopsk +provisioner: + name: ansible + inventory: + group_vars: + all: + zabbix_agent_tlspsk_auto: True
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/autopsk/test_auto_psk.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/autopsk/test_auto_psk.py new file mode 100644 index 000000000..859f2a255 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/autopsk/test_auto_psk.py @@ -0,0 +1,24 @@ +import pytest +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbix_agent_dot_conf(host, zabbix_agent_conf): + assert zabbix_agent_conf.contains("TLSAccept=psk") + assert zabbix_agent_conf.contains( + f"TLSPSKIdentity={host.ansible.get_variables()['inventory_hostname']}" + ) + assert zabbix_agent_conf.contains("TLSPSKFile=/etc/zabbix/tls_psk_auto.secret") + + +def test_zabbix_agent_autopsk(host): + psk_file = host.file("/etc/zabbix/tls_psk_auto.secret") + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.size == 64 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py new file mode 100644 index 000000000..96d4a1716 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py @@ -0,0 +1,49 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbixagent_running_and_enabled(host, zabbix_agent_service): + # Find out why this is not working for linuxmint and opensuse + if host.system_info.distribution not in ["linuxmint", "opensuse", "ubuntu"]: + assert zabbix_agent_service.is_running + assert zabbix_agent_service.is_enabled + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.user == "root" + assert zabbix_agent_conf.group == "root" + assert zabbix_agent_conf.mode == 0o644 + + assert zabbix_agent_conf.contains("Server=192.168.3.33") + assert zabbix_agent_conf.contains("ServerActive=192.168.3.33") + assert zabbix_agent_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(zabbix_agent_include_dir): + assert zabbix_agent_include_dir.is_directory + assert zabbix_agent_include_dir.user == "root" + assert zabbix_agent_include_dir.group == "zabbix" + + +def test_socket(host): + # Find out why this is not working for linuxmint and opensus + if host.system_info.distribution not in ["linuxmint", "opensuse"]: + assert host.socket("tcp://0.0.0.0:10050").is_listening + + +def test_zabbix_package(host, zabbix_agent_package): + assert zabbix_agent_package.is_installed + + if host.system_info.distribution == "debian": + if host.system_info.codename in ["bullseye", "focal"]: + assert zabbix_agent_package.version.startswith("1:6.4") + else: + assert zabbix_agent_package.version.startswith("1:6.0") + if host.system_info.distribution == "centos": + assert zabbix_agent_package.version.startswith("6.4") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/conftest.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/conftest.py new file mode 100644 index 000000000..1ddde968c --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/conftest.py @@ -0,0 +1,33 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +@pytest.fixture +def zabbix_agent_conf(host): + if host.system_info.distribution in ["opensuse"]: + conf_file = host.file("/etc/zabbix/zabbix-agentd.conf") + else: + conf_file = host.file("/etc/zabbix/zabbix_agentd.conf") + + return conf_file + + +@pytest.fixture +def zabbix_agent_service(host): + return host.service("zabbix-agent") + + +@pytest.fixture +def zabbix_agent_include_dir(host): + return host.file("/etc/zabbix/zabbix_agentd.d") + + +@pytest.fixture +def zabbix_agent_package(host): + return host.package("zabbix-agent") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/molecule.yml new file mode 100644 index 000000000..8f053f0da --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/molecule.yml @@ -0,0 +1,11 @@ +--- +scenario: + name: default +provisioner: + name: ansible + inventory: + group_vars: + all: + zabbix_agent_tlspskidentity: my_Identity + zabbix_agent_tlspskfile: /data/certs/zabbix.psk + zabbix_agent_tlspsk_secret: 97defd6bd126d5ba7fa5f296595f82eac905d5eda270207a580ab7c0cb9e8eab diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py new file mode 100644 index 000000000..96d4a1716 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py @@ -0,0 +1,49 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbixagent_running_and_enabled(host, zabbix_agent_service): + # Find out why this is not working for linuxmint and opensuse + if host.system_info.distribution not in ["linuxmint", "opensuse", "ubuntu"]: + assert zabbix_agent_service.is_running + assert zabbix_agent_service.is_enabled + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.user == "root" + assert zabbix_agent_conf.group == "root" + assert zabbix_agent_conf.mode == 0o644 + + assert zabbix_agent_conf.contains("Server=192.168.3.33") + assert zabbix_agent_conf.contains("ServerActive=192.168.3.33") + assert zabbix_agent_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(zabbix_agent_include_dir): + assert zabbix_agent_include_dir.is_directory + assert zabbix_agent_include_dir.user == "root" + assert zabbix_agent_include_dir.group == "zabbix" + + +def test_socket(host): + # Find out why this is not working for linuxmint and opensus + if host.system_info.distribution not in ["linuxmint", "opensuse"]: + assert host.socket("tcp://0.0.0.0:10050").is_listening + + +def test_zabbix_package(host, zabbix_agent_package): + assert zabbix_agent_package.is_installed + + if host.system_info.distribution == "debian": + if host.system_info.codename in ["bullseye", "focal"]: + assert zabbix_agent_package.version.startswith("1:6.4") + else: + assert zabbix_agent_package.version.startswith("1:6.0") + if host.system_info.distribution == "centos": + assert zabbix_agent_package.version.startswith("6.4") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/conftest.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/conftest.py new file mode 100644 index 000000000..1ddde968c --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/conftest.py @@ -0,0 +1,33 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +@pytest.fixture +def zabbix_agent_conf(host): + if host.system_info.distribution in ["opensuse"]: + conf_file = host.file("/etc/zabbix/zabbix-agentd.conf") + else: + conf_file = host.file("/etc/zabbix/zabbix_agentd.conf") + + return conf_file + + +@pytest.fixture +def zabbix_agent_service(host): + return host.service("zabbix-agent") + + +@pytest.fixture +def zabbix_agent_include_dir(host): + return host.file("/etc/zabbix/zabbix_agentd.d") + + +@pytest.fixture +def zabbix_agent_package(host): + return host.package("zabbix-agent") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/no_auto_psk/test_no_auto_psk.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/no_auto_psk/test_no_auto_psk.py new file mode 100644 index 000000000..6fbbbb226 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/no_auto_psk/test_no_auto_psk.py @@ -0,0 +1,24 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("agent") + + +def test_zabbix_agent_dot_conf(zabbix_agent_conf): + assert zabbix_agent_conf.contains("TLSAccept=psk") + assert zabbix_agent_conf.contains("TLSPSKIdentity=my_Identity") + assert zabbix_agent_conf.contains("TLSPSKFile=/data/certs/zabbix.psk") + + +def test_zabbix_agent_psk(host): + psk_file = host.file("/data/certs/zabbix.psk") + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.contains( + "97defd6bd126d5ba7fa5f296595f82eac905d5eda270207a580ab7c0cb9e8eab" + ) diff --git a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/converge.yml b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/converge.yml new file mode 100644 index 000000000..ae76d6ee8 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/converge.yml @@ -0,0 +1,6 @@ +--- +- name: Converge + hosts: all + roles: + - role: zabbix_javagateway + javagateway_pidfile: /tmp/zabbix_java.pid diff --git a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml new file mode 100644 index 000000000..f56745b9b --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml @@ -0,0 +1,27 @@ +--- +driver: + name: docker + +platforms: + - name: zabbix-javagateway-${MY_MOLECULE_CONTAINER:-centos} + image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"} + command: ${MY_MOLECULE_DOCKER_COMMAND:-""} + privileged: true + pre_build_image: true + networks: + - name: zabbix + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + +provisioner: + name: ansible + lint: + name: ansible-lint + env: + ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix + ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml new file mode 100644 index 000000000..9d24c9f7e --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml @@ -0,0 +1,62 @@ +--- +- name: Prepare + hosts: all + pre_tasks: + + - name: "Set short version name" + set_fact: + zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}" + + - name: "Installing packages on CentOS" + yum: + name: + - net-tools + - which + - sudo + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + + - name: "Make sure the docs can be installed. (Debian)" + lineinfile: + path: /etc/dpkg/dpkg.cfg.d/excludes + state: absent + regexp: 'path-exclude=/usr/share/doc/*' + when: + - ansible_os_family != 'RedHat' + + - name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + + # https://github.com/geerlingguy/ansible-role-java/issues/64 + - name: "Apt update" + shell: "apt-get update && mkdir -p /usr/share/man/man1" + args: + warn: "{{ produce_warn | default(omit) }}" + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' + + - name: "Installing packages on NON-CentOS" + apt: + name: + - net-tools + - apt-utils + - procps + - "{{ zabbix_python_prefix }}-pip" + - gpg-agent + - "{{ zabbix_python_prefix }}-apt" + - sudo + - software-properties-common + - openjdk-11-jdk + update_cache: true + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' diff --git a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/tests/test_default.py new file mode 100644 index 000000000..57ff0e129 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/tests/test_default.py @@ -0,0 +1,23 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_zabbix_running_and_enabled(host): + zabbix = host.service("zabbix-java-gateway") + assert zabbix.is_running + + +def test_zabbix_java_gateway_dot_conf(host): + zabbix_proxy_conf = host.file("/etc/zabbix/zabbix_java_gateway.conf") + assert zabbix_proxy_conf.user == "zabbix" + assert zabbix_proxy_conf.group == "zabbix" + assert zabbix_proxy_conf.mode == 0o644 + + assert zabbix_proxy_conf.contains("LISTEN_IP=0.0.0.0") + assert zabbix_proxy_conf.contains("LISTEN_PORT=10052") + assert zabbix_proxy_conf.contains("PID_FILE=/run/zabbix/zabbix_java_gateway.pid") + assert zabbix_proxy_conf.contains("START_POLLERS=5") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/converge.yml b/ansible_collections/community/zabbix/molecule/zabbix_proxy/converge.yml new file mode 100644 index 000000000..d5413e2a4 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/converge.yml @@ -0,0 +1,4 @@ +--- +- hosts: all + roles: + - role: zabbix_proxy diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/destroy.yml b/ansible_collections/community/zabbix/molecule/zabbix_proxy/destroy.yml new file mode 100644 index 000000000..54771a5a1 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/destroy.yml @@ -0,0 +1,25 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + vars: + molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}" + molecule_yml: "{{ lookup('file', molecule_file) | from_yaml }}" + tasks: + - name: Destroy molecule instance(s) + docker_container: + name: "{{ item.name }}" + state: absent + force_kill: "{{ item.force_kill | default(True) }}" + with_items: "{{ molecule_yml.platforms }}" + + - name: Destroy 3rd party instance(s) + docker_container: + name: '{{ item }}' + state: absent + force_kill: true + with_items: + - mysql-host + - postgresql-host diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml new file mode 100644 index 000000000..21ab813c4 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml @@ -0,0 +1,56 @@ +--- + +driver: + name: docker +platforms: + - name: zabbix-proxy-${MY_MOLECULE_CONTAINER:-mysql-centos} + image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"} + command: ${MY_MOLECULE_DOCKER_COMMAND:-""} + privileged: true + pre_build_image: true + networks: + - name: zabbix + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + groups: + - ${MY_MOLECULE_GROUP:-mysql} + +provisioner: + name: ansible + lint: + name: ansible-lint + env: + ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix + ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles + inventory: + group_vars: + mysql: + zabbix_proxy_database: mysql + zabbix_proxy_database_long: mysql + zabbix_proxy_dbport: 3306 + zabbix_proxy_dbhost: mysql-host + zabbix_proxy_dbhost_run_install: false + zabbix_proxy_privileged_host: '%' + zabbix_proxy_mysql_login_host: mysql-host + zabbix_proxy_mysql_login_user: root + zabbix_proxy_mysql_login_password: changeme + zabbix_proxy_mysql_login_port: 3306 + postgresql: + zabbix_proxy_database: pgsql + zabbix_proxy_database_long: postgresql + zabbix_proxy_dbport: 5432 + zabbix_proxy_dbhost: postgresql-host + zabbix_proxy_dbhost_run_install: false + zabbix_proxy_pgsql_login_host: postgresql-host + zabbix_proxy_pgsql_login_user: postgres + zabbix_proxy_pgsql_login_password: changeme + zabbix_proxy_pgsql_login_port: 5432 + sqlite3: + zabbix_proxy_database: sqlite3 + zabbix_proxy_database_long: sqlite3 + zabbix_proxy_dbname: /path/to/sqlite3.db + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml new file mode 100644 index 000000000..0fc4ef320 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml @@ -0,0 +1,134 @@ +--- +- name: Prepare + hosts: localhost + connection: local + pre_tasks: + + - name: "Create MySQL Container" + docker_container: + name: mysql-host + image: mysql:8.0 + state: started + recreate: true + networks: + - name: zabbix + env: + MYSQL_ROOT_PASSWORD: changeme + no_log: true + with_items: "{{ molecule_yml.platforms }}" + when: + - '"mysql" in item.groups' + + - name: "Create postgresql Container" + docker_container: + name: postgresql-host + image: postgres:13 + state: started + recreate: true + networks: + - name: zabbix + env: + POSTGRES_PASSWORD: changeme + no_log: true + with_items: "{{ molecule_yml.platforms }}" + when: + - '"postgresql" in item.groups' + +- name: Prepare + hosts: all + tasks: + + - name: "Set short version name" + set_fact: + zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}" + + - name: "Create group for imaginary host" + add_host: + name: imaginary-host + groups: + - mysql + - postgresql + changed_when: false + + - name: "Installing packages on CentOS" + yum: + name: + - net-tools + - which + - sudo + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + + - name: "Installing packages on CentOS" + yum: + name: + - mysql + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + - inventory_hostname in groups['mysql'] + + - name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + + - name: "Apt update" + shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d" + args: + warn: "{{ produce_warn | default(omit) }}" + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' + + - name: "Installing packages on NON-CentOS" + apt: + name: + - net-tools + - apt-utils + - "{{ zabbix_python_prefix }}-pip" + - gpg-agent + - sudo + - doc-base + update_cache: true + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' + + - name: "Configure SUDO." + lineinfile: + dest: /etc/sudoers + line: "Defaults !requiretty" + state: present + + - name: "Make sure the docs can be installed. (RedHat)" + lineinfile: + dest: /etc/yum.conf + line: "tsflags=nodocs" + state: absent + when: + - ansible_os_family == 'RedHat' + + - name: "Make sure the docs can be installed. (Debian)" + lineinfile: + path: /etc/dpkg/dpkg.cfg.d/excludes + state: absent + regexp: 'path-exclude=/usr/share/doc/*' + when: + - ansible_os_family != 'RedHat' + + - name: PyMySQL + pip: + name: PyMySQL + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - inventory_hostname in groups['mysql'] diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py new file mode 100644 index 000000000..4ccbfeb4e --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py @@ -0,0 +1,64 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +def test_zabbixproxy_running_and_enabled(host): + zabbix = host.service("zabbix-proxy") + if host.system_info.distribution == "centos": + assert zabbix.is_enabled + assert zabbix.is_running + else: + assert zabbix.is_running + + +@pytest.mark.parametrize( + "proxy", [("zabbix-proxy-pgsql"), ("zabbix-proxy-mysql"), ("zabbix-proxy-sqlite3")] +) +def test_zabbix_package(host, proxy): + ansible_data = host.ansible.get_variables() + zabbixhost = ansible_data["inventory_hostname"] + + zabbixhost = zabbixhost.replace("-centos", "") + zabbixhost = zabbixhost.replace("-debian", "") + zabbixhost = zabbixhost.replace("-ubuntu", "") + + if zabbixhost == proxy: + zabbix_proxy = host.package(proxy) + if host.system_info.distribution in ["debian", "ubuntu"]: + assert zabbix_proxy.version.startswith("1:6.4") + elif host.system_info.distribution == "centos": + assert zabbix_proxy.version.startswith("6.4") + assert zabbix_proxy.is_installed + + +def test_zabbix_proxy_dot_conf(host): + zabbix_proxy_conf = host.file("/etc/zabbix/zabbix_proxy.conf") + assert zabbix_proxy_conf.user == "zabbix" + assert zabbix_proxy_conf.group == "zabbix" + assert zabbix_proxy_conf.mode == 0o644 + + assert zabbix_proxy_conf.contains("ListenPort=10051") + assert zabbix_proxy_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(host): + zabbix_include_dir = host.file("/etc/zabbix/zabbix_proxy.conf.d") + assert zabbix_include_dir.is_directory + assert zabbix_include_dir.user == "zabbix" + assert zabbix_include_dir.group == "zabbix" + # assert zabbix_include_dir.mode == 0o644 + + +def test_zabbix_proxy_logfile(host): + zabbix_logfile = host.file("/var/log/zabbix/zabbix_proxy.log") + + assert not zabbix_logfile.contains("Access denied for user") + assert not zabbix_logfile.contains("database is down: reconnecting") + assert zabbix_logfile.contains("current database version") + assert zabbix_logfile.contains(r"proxy #0 started \[main process\]") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/converge.yml b/ansible_collections/community/zabbix/molecule/zabbix_server/converge.yml new file mode 100644 index 000000000..cff36c579 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_server/converge.yml @@ -0,0 +1,5 @@ +--- +- hosts: all + become: true + roles: + - role: zabbix_server diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/destroy.yml b/ansible_collections/community/zabbix/molecule/zabbix_server/destroy.yml new file mode 100644 index 000000000..54771a5a1 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_server/destroy.yml @@ -0,0 +1,25 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + vars: + molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}" + molecule_yml: "{{ lookup('file', molecule_file) | from_yaml }}" + tasks: + - name: Destroy molecule instance(s) + docker_container: + name: "{{ item.name }}" + state: absent + force_kill: "{{ item.force_kill | default(True) }}" + with_items: "{{ molecule_yml.platforms }}" + + - name: Destroy 3rd party instance(s) + docker_container: + name: '{{ item }}' + state: absent + force_kill: true + with_items: + - mysql-host + - postgresql-host diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml new file mode 100644 index 000000000..4fa0a8daa --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml @@ -0,0 +1,52 @@ +--- + +driver: + name: docker +platforms: + - name: zabbix-server-${MY_MOLECULE_CONTAINER:-mysql-centos} + image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"} + command: ${MY_MOLECULE_DOCKER_COMMAND:-""} + privileged: true + pre_build_image: true + networks: + - name: zabbix + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + groups: + - ${MY_MOLECULE_GROUP:-mysql} + +provisioner: + name: ansible + lint: + name: ansible-lint + env: + ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix + ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles + inventory: + group_vars: + mysql: + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + zabbix_server_dbhost: mysql-host + zabbix_server_dbhost_run_install: false + zabbix_server_privileged_host: '%' + zabbix_server_mysql_login_host: mysql-host + zabbix_server_mysql_login_user: root + zabbix_server_mysql_login_password: changeme + zabbix_server_mysql_login_port: 3306 + postgresql: + zabbix_server_database: pgsql + zabbix_server_database_long: postgresql + zabbix_server_dbport: 5432 + zabbix_server_dbhost: postgresql-host + zabbix_server_dbhost_run_install: false + zabbix_server_pgsql_login_host: postgresql-host + zabbix_server_pgsql_login_user: postgres + zabbix_server_pgsql_login_password: changeme + zabbix_server_pgsql_login_port: 5432 + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml new file mode 100644 index 000000000..51945c066 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml @@ -0,0 +1,121 @@ +--- +- name: Prepare + hosts: localhost + connection: local + pre_tasks: + + - name: "Create MySQL Container" + docker_container: + name: mysql-host + image: mysql:8.0 + state: started + recreate: true + networks: + - name: zabbix + env: + MYSQL_ROOT_PASSWORD: changeme + no_log: true + with_items: "{{ molecule_yml.platforms }}" + when: + - '"mysql" in item.groups' + + - name: "Create postgresql Container" + docker_container: + name: postgresql-host + image: postgres:13 + state: started + recreate: true + networks: + - name: zabbix + env: + POSTGRES_PASSWORD: changeme + no_log: true + with_items: "{{ molecule_yml.platforms }}" + when: + - '"postgresql" in item.groups' + +- name: Prepare + hosts: all + tasks: + + - name: "Create group for imaginary host" + add_host: + name: imaginary-host + groups: + - mysql + - postgresql + changed_when: false + + - name: "Installing packages on CentOS" + yum: + name: + - net-tools + - which + - sudo + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + + - name: "Installing packages on CentOS" + yum: + name: + - mysql + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + - inventory_hostname in groups['mysql'] + + - name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + + - name: "Apt update" + shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d" + args: + warn: "{{ produce_warn | default(omit) }}" + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' + + - name: "Installing packages on NON-CentOS" + apt: + name: + - net-tools + - apt-utils + - python3-pip + - gpg-agent + - sudo + update_cache: true + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' + + - name: "Configure SUDO." + lineinfile: + dest: /etc/sudoers + line: "Defaults !requiretty" + state: present + + - name: "Make sure the docs are installed." + lineinfile: + dest: /etc/yum.conf + line: "tsflags=nodocs" + state: absent + when: + - ansible_os_family == 'RedHat' + + - name: PyMySQL + pip: + name: PyMySQL + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - inventory_hostname in groups['mysql'] diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py new file mode 100644 index 000000000..9a119d5ac --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py @@ -0,0 +1,62 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +def test_zabbiserver_running_and_enabled(host): + zabbix = host.service("zabbix-server") + if host.system_info.distribution == "centos": + assert zabbix.is_enabled + assert zabbix.is_running + else: + assert zabbix.is_running + + +@pytest.mark.parametrize("server", [("zabbix-server-pgsql"), ("zabbix-server-mysql")]) +def test_zabbix_package(host, server): + ansible_data = host.ansible.get_variables() + zabbixhost = ansible_data["inventory_hostname"] + + zabbixhost = zabbixhost.replace("-centos", "") + zabbixhost = zabbixhost.replace("-debian", "") + zabbixhost = zabbixhost.replace("-ubuntu", "") + + if zabbixhost == server: + zabbix_server = host.package(server) + if host.system_info.distribution in ["debian", "ubuntu"]: + assert zabbix_server.version.startswith("1:6.4") + elif host.system_info.distribution == "centos": + assert zabbix_server.version.startswith("6.4") + assert zabbix_server.is_installed + + +def test_zabbix_server_dot_conf(host): + zabbix_server_conf = host.file("/etc/zabbix/zabbix_server.conf") + assert zabbix_server_conf.user == "zabbix" + assert zabbix_server_conf.group == "zabbix" + assert zabbix_server_conf.mode == 0o640 + + assert zabbix_server_conf.contains("ListenPort=10051") + assert zabbix_server_conf.contains("DebugLevel=3") + + +def test_zabbix_include_dir(host): + zabbix_include_dir = host.file("/etc/zabbix/zabbix_server.conf.d") + assert zabbix_include_dir.is_directory + assert zabbix_include_dir.user == "zabbix" + assert zabbix_include_dir.group == "zabbix" + # assert zabbix_include_dir.mode == 0o644 + + +def test_zabbix_server_logfile(host): + zabbix_logfile = host.file("/var/log/zabbix/zabbix_server.log") + + assert not zabbix_logfile.contains("Access denied for user") + assert not zabbix_logfile.contains("database is down: reconnecting") + assert zabbix_logfile.contains("current database version") + assert zabbix_logfile.contains(r"server #0 started \[main process\]") diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/converge.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/converge.yml new file mode 100644 index 000000000..bd70be664 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_web/converge.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: zabbix_web diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/destroy.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/destroy.yml new file mode 100644 index 000000000..54771a5a1 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_web/destroy.yml @@ -0,0 +1,25 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + vars: + molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}" + molecule_yml: "{{ lookup('file', molecule_file) | from_yaml }}" + tasks: + - name: Destroy molecule instance(s) + docker_container: + name: "{{ item.name }}" + state: absent + force_kill: "{{ item.force_kill | default(True) }}" + with_items: "{{ molecule_yml.platforms }}" + + - name: Destroy 3rd party instance(s) + docker_container: + name: '{{ item }}' + state: absent + force_kill: true + with_items: + - mysql-host + - postgresql-host diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml new file mode 100644 index 000000000..baffecc47 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml @@ -0,0 +1,95 @@ +--- +dependency: + name: galaxy + enabled: true + options: + ignore-certs: true + ignore-errors: true + role-file: molecule/zabbix_web/requirements.yml + +driver: + name: docker +platforms: + - name: zabbix-web-${MY_MOLECULE_CONTAINER:-mysql-centos8} + image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"} + command: ${MY_MOLECULE_DOCKER_COMMAND:-""} + privileged: true + pre_build_image: true + networks: + - name: zabbix + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + groups: + - ${MY_MOLECULE_GROUP:-mysql} + +provisioner: + name: ansible + lint: + name: ansible-lint + env: + ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix + ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles + inventory: + group_vars: + mysql: + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + zabbix_server_dbhost: mysql-host + zabbix_server_dbhost_run_install: false + zabbix_server_privileged_host: "%" + zabbix_server_mysql_login_host: mysql-host + zabbix_server_mysql_login_user: root + zabbix_server_mysql_login_password: changeme + zabbix_server_mysql_login_port: 3306 + postgresql: + zabbix_server_database: pgsql + zabbix_server_database_long: postgresql + zabbix_server_dbport: 5432 + zabbix_server_dbhost: postgresql-host + zabbix_server_dbhost_run_install: false + zabbix_server_pgsql_login_host: postgresql-host + zabbix_server_pgsql_login_user: postgres + zabbix_server_pgsql_login_password: changeme + zabbix_server_pgsql_login_port: 5432 + host_vars: + zabbix-web-pgsql-debian: + zabbix_websrv: apache + zabbix_php_fpm_conf_listen: false + zabbix_api_server_url: zabbix-web-pgsql-debian + zabbix_websrv_servername: zabbix-web-pgsql-debian + zabbix-web-mysql-debian: + zabbix_websrv: apache + zabbix_php_fpm_conf_listen: false + zabbix_api_server_url: zabbix-web-mysql-debian + zabbix_websrv_servername: zabbix-web-mysql-debian + zabbix-web-pgsql-centos8: + ansible_rhn_repo_disable_gpg_check: true + zabbix_websrv: apache + zabbix_php_fpm_conf_listen: false + zabbix_api_server_url: zabbix-web-pgsql-centos8 + zabbix_websrv_servername: zabbix-web-pgsql-centos8 + zabbix-web-mysql-centos8: + ansible_rhn_repo_disable_gpg_check: true + php_fpm_pool_user: nginx + php_fpm_pool_group: nginx + zabbix_websrv: nginx + zabbix_php_fpm_conf_listen: false + zabbix_api_server_url: zabbix-web-mysql-centos8 + zabbix_websrv_servername: zabbix-web-mysql-centos8 + zabbix-web-mysql-ubuntu18: + zabbix_websrv: nginx + zabbix_php_fpm_conf_listen: false + zabbix_api_server_url: zabbix-web-mysql-ubuntu18 + zabbix_websrv_servername: zabbix-web-mysql-ubuntu18 + php_webserver_daemon: nginx + zabbix-web-pgsql-ubuntu20: + zabbix_php_fpm_conf_listen: false + zabbix_websrv: apache + zabbix_api_server_url: zabbix-web-pgsql-ubuntu20 + zabbix_websrv_servername: zabbix-web-pgsql-ubuntu20 + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml new file mode 100644 index 000000000..3c0c6db86 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml @@ -0,0 +1,150 @@ +--- +- name: Prepare + hosts: localhost + connection: local + pre_tasks: + - name: "Create MySQL Container" + docker_container: + name: mysql-host + image: mysql:8.0 + state: started + recreate: true + networks: + - name: zabbix + env: + MYSQL_ROOT_PASSWORD: changeme + no_log: true + with_items: "{{ molecule_yml.platforms }}" + when: + - '"mysql" in item.groups' + + - name: "Create postgresql Container" + docker_container: + name: postgresql-host + image: postgres:13 + state: started + recreate: true + networks: + - name: zabbix + env: + POSTGRES_PASSWORD: changeme + no_log: true + with_items: "{{ molecule_yml.platforms }}" + when: + - '"postgresql" in item.groups' + +- name: Prepare + hosts: all + pre_tasks: + - name: "Create group for imaginary host" + add_host: + name: imaginary-host + groups: + - mysql + - postgresql + changed_when: false + + - name: "Installing packages on CentOS" + yum: + name: + - net-tools + - which + - curl + - sudo + - "{{ 'python3-pip' if ansible_distribution_major_version == '8' else 'python-pip' }}" + - "{{ 'python3-libselinux' if ansible_distribution_major_version == '8' else 'libselinux-python' }}" + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + + - name: "Installing packages (CentOS7)" + yum: + name: + - centos-release-scl + state: present + register: installation_dependencies + when: + - ansible_os_family == 'RedHat' + - ansible_distribution_major_version == '7' + + - name: "Installing MySQL on CentOS" + yum: + name: + - mysql + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family == 'RedHat' + - inventory_hostname in groups['mysql'] + + - name: "Installing packages on NON-CentOS" + apt: + name: + - net-tools + - curl + - apt-utils + - apt-transport-https + - ca-certificates + - gnupg2 + - gpg-agent + - sudo + - vim + - "{{ 'python3-apt' if ansible_distribution_major_version in ['10', '11', '18', '20'] else 'python-apt' }}" + - "{{ 'python3-pip' if ansible_distribution_major_version in ['10', '11', '18', '20'] else 'python-pip' }}" + update_cache: true + state: present + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - ansible_os_family != 'RedHat' + + - name: "Configure SUDO." + lineinfile: + dest: /etc/sudoers + line: "Defaults !requiretty" + state: present + + - name: "Make sure the docs are installed." + lineinfile: + dest: /etc/yum.conf + line: "tsflags=nodocs" + state: absent + when: + - ansible_os_family == 'RedHat' + + - name: PyMySQL + pip: + name: PyMySQL + register: installation_dependencies + until: installation_dependencies is succeeded + when: + - inventory_hostname in groups['mysql'] + + - name: Enabeling PHP 7.4 + command: dnf module enable php:7.4 -y + when: + - ansible_os_family == 'RedHat' + - ansible_distribution_major_version == "8" + + roles: + - role: geerlingguy.apache + when: + - zabbix_websrv == "apache" + - role: geerlingguy.nginx + when: + - zabbix_websrv == "nginx" + - role: geerlingguy.php + when: + - ansible_os_family != 'RedHat' or (ansible_os_family == 'RedHat' and ansible_distribution_major_version == "8") + - role: zabbix_server + + post_tasks: + - name: "Remove file" + file: + path: "{{ item }}" + state: absent + with_items: + - /var/www/html/index.html diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/requirements.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/requirements.yml new file mode 100644 index 000000000..e08ac4c1f --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_web/requirements.yml @@ -0,0 +1,4 @@ +--- +- src: geerlingguy.apache +- src: geerlingguy.nginx +- src: geerlingguy.php diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py new file mode 100644 index 000000000..a6f7527b0 --- /dev/null +++ b/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py @@ -0,0 +1,70 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +@pytest.mark.parametrize( + "server, redhat, debian", + [ + ("zabbix-server-pgsql", "zabbix-web-pgsql", "zabbix-frontend-php"), + ("zabbix-server-mysql", "zabbix-web-mysql", "zabbix-frontend-php"), + ], +) +def test_zabbix_package(host, server, redhat, debian): + host = host.backend.get_hostname() + host = host.replace("-centos7", "") + host = host.replace("-centos8", "") + host = host.replace("-debian", "") + host = host.replace("-ubuntu", "") + + if host == server: + if host.system_info.distribution in ["debian", "ubuntu"]: + zabbix_web = host.package(debian) + assert zabbix_web.version.startswith("1:6.4") + elif host.system_info.distribution == "centos": + zabbix_web = host.package(redhat) + assert zabbix_web.version.startswith("6.4") + assert zabbix_web.is_installed + + +def test_zabbix_web(host): + zabbix_web = host.file("/etc/zabbix/web/zabbix.conf.php") + ansible_variables = host.ansible.get_variables() + zabbix_websrv = str(ansible_variables["zabbix_websrv"]) + + if host.system_info.distribution in ["debian", "ubuntu"]: + assert zabbix_web.user == "www-data" + assert zabbix_web.group == "www-data" + elif host.system_info.distribution == "centos": + if zabbix_websrv == "apache": + assert zabbix_web.user == "apache" + assert zabbix_web.group == "apache" + elif zabbix_websrv == "nginx": + assert zabbix_web.user == "nginx" + assert zabbix_web.group == "nginx" + assert zabbix_web.mode == 0o640 + + +def test_zabbix_api(host): + my_host = host.ansible.get_variables() + zabbix_api_server_url = str(my_host["zabbix_api_server_url"]) + hostname = "http://" + zabbix_api_server_url + "/api_jsonrpc.php" + post_data = '{"jsonrpc": "2.0", "method": "user.login", "params": { "username": "Admin", "password": "zabbix" }, "id": 1, "auth": null}' + headers = "Content-Type: application/json-rpc" + command = ( + "curl -XPOST -H '" + + str(headers) + + "' -d '" + + str(post_data) + + "' '" + + hostname + + "'" + ) + + cmd = host.run(command) + assert '"jsonrpc":"2.0","result":"' in cmd.stdout diff --git a/ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py b/ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py new file mode 100644 index 000000000..6d9a82a8e --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +class ModuleDocFragment(object): + + # Standard files documentation fragment + DOCUMENTATION = r""" +options: + persistent_connect_timeout: + type: int + description: + - Configures, in seconds, the amount of time to wait when trying to initially + establish a persistent connection. If this value expires before the connection + to the remote device is completed, the connection will fail. + default: 30 + ini: + - section: persistent_connection + key: connect_timeout + env: + - name: ANSIBLE_PERSISTENT_CONNECT_TIMEOUT + vars: + - name: ansible_connect_timeout + persistent_command_timeout: + type: int + description: + - Configures, in seconds, the amount of time to wait for a command to + return from the remote device. If this timer is exceeded before the + command returns, the connection plugin will raise an exception and + close. + default: 30 + ini: + - section: persistent_connection + key: command_timeout + env: + - name: ANSIBLE_PERSISTENT_COMMAND_TIMEOUT + vars: + - name: ansible_command_timeout + persistent_log_messages: + type: boolean + description: + - This flag will enable logging the command executed and response received from + target device in the ansible log file. For this option to work 'log_path' ansible + configuration option is required to be set to a file path with write access. + - Be sure to fully understand the security implications of enabling this + option as it could create a security vulnerability by logging sensitive information in log file. + default: False + ini: + - section: persistent_connection + key: log_messages + env: + - name: ANSIBLE_PERSISTENT_LOG_MESSAGES + vars: + - name: ansible_persistent_log_messages +""" diff --git a/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py b/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py new file mode 100644 index 000000000..2cd64b00f --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Ansible, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +class ModuleDocFragment(object): + + # Standard documentation fragment + DOCUMENTATION = r''' +options: + server_url: + description: + - URL of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + - If not set the environment variable C(ZABBIX_SERVER) will be used. + - This option is deprecated with the move to httpapi connection and will be removed in the next release + required: false + type: str + aliases: [ url ] + login_user: + description: + - Zabbix user name. + - If not set the environment variable C(ZABBIX_USERNAME) will be used. + - This option is deprecated with the move to httpapi connection and will be removed in the next release + type: str + required: false + login_password: + description: + - Zabbix user password. + - If not set the environment variable C(ZABBIX_PASSWORD) will be used. + - This option is deprecated with the move to httpapi connection and will be removed in the next release + type: str + required: false + http_login_user: + description: + - Basic Auth login + type: str + required: false + http_login_password: + description: + - Basic Auth password + type: str + required: false + timeout: + description: + - The timeout of API request (seconds). + - This option is deprecated with the move to httpapi connection and will be removed in the next release + - The default value is C(10) + type: int + validate_certs: + description: + - If set to False, SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates. + - If not set the environment variable C(ZABBIX_VALIDATE_CERTS) will be used. + - This option is deprecated with the move to httpapi connection and will be removed in the next release + - The default value is C(true) + type: bool +notes: + - If you use I(login_password=zabbix), the word "zabbix" is replaced by "********" in all module output, because I(login_password) uses C(no_log). + See L(this FAQ,https://docs.ansible.com/ansible/latest/network/user_guide/faq.html#why-is-my-output-sometimes-replaced-with) for more information. +''' diff --git a/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py b/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py new file mode 100644 index 000000000..3db65532c --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py @@ -0,0 +1,227 @@ +# (c) 2021, Markus Fischbacher (fischbacher.markus@gmail.com) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Quick Link to Zabbix API docs: https://www.zabbix.com/documentation/current/manual/api + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +--- +name: zabbix +author: + - Markus Fischbacher (@rockaut) + - Evgeny Yurchenko (@BGmot) +short_description: HttpApi Plugin for Zabbix +description: + - This HttpApi plugin provides methods to connect to Zabbix over their HTTP(S)-based api. +version_added: 1.8.0 +options: + zabbix_auth_key: + type: str + description: + - Specifies API authentication key + env: + - name: ANSIBLE_ZABBIX_AUTH_KEY + vars: + - name: ansible_zabbix_auth_key + zabbix_url_path: + type: str + description: + - Specifies path portion in Zabbix WebUI URL, e.g. for https://myzabbixfarm.com/zabbixeu zabbix_url_path=zabbixeu + default: zabbix + env: + - name: ANSIBLE_ZABBIX_URL_PATH + vars: + - name: ansible_zabbix_url_path + http_login_user: + type: str + description: + - The http user to access zabbix url with Basic Auth + vars: + - name: http_login_user + http_login_password: + type: str + description: + - The http password to access zabbix url with Basic Auth + vars: + - name: http_login_password +""" + +import json +import base64 + +from uuid import uuid4 + +from ansible.module_utils.basic import to_text +from ansible.errors import AnsibleConnectionFailure +from ansible.plugins.httpapi import HttpApiBase +from ansible.module_utils.connection import ConnectionError + + +class HttpApi(HttpApiBase): + zbx_api_version = None + auth_key = None + url_path = '/zabbix' # By default Zabbix WebUI is on http(s)://FQDN/zabbix + + def set_become(self, become_context): + """As this is an http rpc call there is no elevation available + """ + pass + + def update_auth(self, response, response_text): + return None + + def login(self, username, password): + self.auth_key = self.get_option('zabbix_auth_key') + if self.auth_key: + self.connection._auth = {'auth': self.auth_key} + return + + if not self.auth_key: + # Provide "fake" auth so netcommon.connection does not replace our headers + self.connection._auth = {'auth': 'fake'} + + # login() method is called "somehow" as a very first call to the REST API. + # This collection's code first of all executes api_version() but login() anyway + # is called first (I suspect due to complicated (for me) httpapi modules inheritance/communication + # model). Bottom line: at the time of login() execution we are not aware of Zabbix version. + # Proposed approach: first execute "user.login" with "user" parameter and if it fails then + # execute "user.login" with "username" parameter. + # Zabbix < 5.0 supports only "user" parameter. + # Zabbix >= 6.0 and <= 6.2 support both "user" and "username" parameters. + # Zabbix >= 6.4 supports only "username" parameter. + try: + # Zabbix <= 6.2 + payload = self.payload_builder("user.login", user=username, password=password) + code, response = self.send_request(data=payload) + except ConnectionError: + # Zabbix >= 6.4 + payload = self.payload_builder("user.login", username=username, password=password) + code, response = self.send_request(data=payload) + + if code == 200 and response != '': + # Replace auth with real api_key we got from Zabbix after successful login + self.connection._auth = {'auth': response} + + def logout(self): + if self.connection._auth and not self.auth_key: + payload = self.payload_builder("user.logout") + self.send_request(data=payload) + + def api_version(self): + url_path = self.get_option('zabbix_url_path') + if isinstance(url_path, str): + # zabbix_url_path provided (even if it is an empty string) + if url_path == '': + self.url_path = '' + else: + self.url_path = '/' + url_path + if not self.zbx_api_version: + if not hasattr(self.connection, 'zbx_api_version'): + code, version = self.send_request(data=self.payload_builder('apiinfo.version')) + if code == 200 and len(version) != 0: + self.connection.zbx_api_version = version + else: + raise ConnectionError("Could not get API version from Zabbix. Got HTTP code %s. Got version %s" % (code, version)) + self.zbx_api_version = self.connection.zbx_api_version + return self.zbx_api_version + + def send_request(self, data=None, request_method="POST", path="/api_jsonrpc.php"): + path = self.url_path + path + if not data: + data = {} + + if self.connection._auth: + data['auth'] = self.connection._auth['auth'] + + hdrs = { + 'Content-Type': 'application/json-rpc', + 'Accept': 'application/json', + } + http_login_user = self.get_option('http_login_user') + http_login_password = self.get_option('http_login_password') + if http_login_user and http_login_user != '-42': + # Need to add Basic auth header + credentials = (http_login_user + ':' + http_login_password).encode('ascii') + hdrs['Authorization'] = 'Basic ' + base64.b64encode(credentials).decode("ascii") + + if data['method'] in ['user.login', 'apiinfo.version']: + # user.login and apiinfo.version do not need "auth" in data + # we provided fake one in login() method to correctly handle HTTP basic auth header + data.pop('auth', None) + + data = json.dumps(data) + try: + self._display_request(request_method, path) + response, response_data = self.connection.send( + path, + data, + method=request_method, + headers=hdrs + ) + value = to_text(response_data.getvalue()) + + try: + json_data = json.loads(value) if value else {} + if "result" in json_data: + json_data = json_data["result"] + # JSONDecodeError only available on Python 3.5+ + except ValueError: + raise ConnectionError("Invalid JSON response: %s" % value) + + try: + # Some methods return bool not a dict in "result" + iter(json_data) + except TypeError: + # Do not try to find "error" if it is not a dict + return response.getcode(), json_data + + if "error" in json_data: + raise ConnectionError("REST API returned %s when sending %s" % (json_data["error"], data)) + + return response.getcode(), json_data + except AnsibleConnectionFailure as e: + self.connection.queue_message("vvv", "AnsibleConnectionFailure: %s" % e) + if to_text("Could not connect to") in to_text(e): + raise + if to_text("401") in to_text(e): + return 401, "Authentication failure" + else: + return 404, "Object not found" + except Exception as e: + raise e + + def _display_request(self, request_method, path): + self.connection.queue_message( + "vvvv", + "Web Services: %s %s/%s" % (request_method, self.connection._url, path), + ) + + def _get_response_value(self, response_data): + return to_text(response_data.getvalue()) + + def _response_to_json(self, response_text): + try: + return json.loads(response_text) if response_text else {} + # JSONDecodeError only available on Python 3.5+ + except ValueError: + raise ConnectionError("Invalid JSON response: %s" % response_text) + + @staticmethod + def payload_builder(method_, auth_=None, **kwargs): + reqid = str(uuid4()) + req = {'jsonrpc': '2.0', 'method': method_, 'id': reqid} + req['params'] = (kwargs) + + return req + + def handle_httperror(self, exc): + # The method defined in ansible.plugins.httpapi + # We need to override it to avoid endless re-tries if HTTP authentication fails + + if exc.code == 401: + return False + + return exc diff --git a/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py b/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py new file mode 100644 index 000000000..437d34227 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py @@ -0,0 +1,387 @@ +# +# Copyright: (c), Ansible Project +# +# (c) 2013, Greg Buehler +# (c) 2018, Filippo Ferrazini +# (c) 2021, Timothy Test +# Modified from ServiceNow Inventory Plugin and Zabbix inventory Script +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r''' +name: zabbix_inventory +author: + - Timothy Test (@ttestscripting) +short_description: Zabbix Inventory Plugin +version_added: 1.4.0 +description: + - Zabbix Inventory plugin + - All vars from zabbix are prefixed with zbx_ +requirements: + - "python >= 2.6" + - "zabbix-api >= 0.5.4" +options: + server_url: + description: + - URL of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + required: true + type: str + aliases: [ url ] + env: + - name: ZABBIX_SERVER + proxy: + description: Proxy server to use for reaching zabbix API + type: string + default: '' + host_zapi_query: + description: + - API query for hosts - see zabbix documentation for more details U(https://www.zabbix.com/documentation/current/manual/api/reference/host/get) + type: dict + default: {} + suboptions: + selectApplications: + type: str + description: + - query + - Return an applications property with host applications. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/application/object) for more details on field names + selectDiscoveries: + type: str + description: + - query + - Return a discoveries property with host low-level discovery rules. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/discoveryrule/object) for more details on field names + selectDiscoveryRule: + type: str + description: + - query + - Return a discoveryRule property with the low-level discovery rule that created the host (from host prototype in VMware monitoring). + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - please see U(https://www.zabbix.com/documentation/current/manual/api/reference/discoveryrule/object) for more details on field names + selectGraphs: + type: str + description: + - query + - Return a discoveries property with host low-level discovery rules. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/graph/object) for more details on field names + selectGroups: + type: str + description: + - query + - Return a groups property with host groups data that the host belongs to. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/hostgroup/object) for more details on field names + selectHostDiscovery: + type: str + description: + - query + - Return a hostDiscovery property with host discovery object data. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/host/get) for more details on field names + selectHttpTests: + type: str + description: + - query + - Return an httpTests property with host web scenarios. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/httptest/object) for more details on field names + selectInterfaces: + type: str + description: + - query + - Return an interfaces property with host interfaces. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/hostinterface/object) for more details on field names + selectInventory: + type: str + description: + - query + - Return an inventory property with host inventory data. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/host/object#host_inventory) for more details on field names + selectItems: + type: str + description: + - query + - Return an items property with host items. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/item/object) for more details on field names + selectMacros: + type: str + description: + - query + - Return a macros property with host macros. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/usermacro/object) for more details on field names + selectParentTemplates: + type: str + description: + - query + - Return a parentTemplates property with templates that the host is linked to + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/template/object) for more details on field names + selectDashboards: + type: str + description: + - query + - Return a dashboards property. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/templatedashboard/object) for more details on field names + selectTags: + type: str + description: + - query + - Return a tags property with host tags. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/host/object#host_tag) for more details on field names + selectInheritedTags: + type: str + description: + - query + - Return an inheritedTags property with tags that are on all templates which are linked to host. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/host/object#host_tag) for more details on field names + selectTriggers: + type: str + description: + - query + - Return a triggers property with host triggers. + - To return all values specify 'extend' + - Can be limited to different fields for example setting the vaule to ['name'] will only return the name + - Additional fields can be specified by comma seperated value ['name', 'field2'] + - Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/host/object#host_tag) for more details on field names + login_user: + description: + - Zabbix user name. + type: str + required: true + env: + - name: ZABBIX_USERNAME + login_password: + description: + - Zabbix user password. + type: str + required: true + env: + - name: ZABBIX_PASSWORD + http_login_user: + description: + - Basic Auth login + type: str + http_login_password: + description: + - Basic Auth password + type: str + timeout: + description: + - The timeout of API request (seconds). + type: int + default: 10 + validate_certs: + description: + - If set to False, SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates. + type: bool + default: true + env: + - name: ZABBIX_VALIDATE_CERTS + add_zabbix_groups: + description: + - If set to True, hosts will be added to groups based on their zabbix groups + type: bool + default: false +extends_documentation_fragment: + - constructed + - inventory_cache +''' + +EXAMPLES = r''' +# Simple Inventory Plugin example +# This will create an inventory with details from zabbix such as applications name, applicaitonids, Parent Template Name, and group membership name +#It will also create 2 ansible inventory groups for enabled and disabled hosts in zabbix based on the status field. +plugin: community.zabbix.zabbix_inventory +server_url: https://zabbix.com +login_user: Admin +login_password: password +host_zapi_query: + selectApplications: ['name', 'applicationid'] + selectParentTemplates: ['name'] + selectGroups: ['name'] +validate_certs: false +groups: + enabled: zbx_status == "0" + disabled: zbx_status == "1" + + +#Using Keyed Groups +plugin: community.zabbix.zabbix_inventory +server_url: https://zabbix.com +login_user: Admin +login_password: password +validate_certs: false +keyed_groups: + - key: zbx_status | lower + prefix: 'env' + - key: zbx_description | lower + prefix: 'test' + separator: '' + +#Using proxy format of proxy is 'http://<user>:<pass>@<proxy>:<port>' or 'http://<proxy>:<port>' +plugin: community.zabbix.zabbix_inventory +server_url: https://zabbix.com +proxy: http://someproxy:8080 +login_user: Admin +login_password: password +validate_certs: false + +#Organize inventory groups based on zabbix host groups +plugin: community.zabbix.zabbix_inventory +server_url: https://zabbix.com +add_zabbix_groups: true +login_user: Admin +login_password: password +validate_certs: false + +#Using compose to modify vars +plugin: community.zabbix.zabbix_inventory +server_url: https://zabbix.com +login_user: Admin +login_password: password +validate_certs: false +compose: + zbx_testvar: zbx_status.replace("1", "Disabled") + + +''' + +from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable, to_safe_group_name +import os +import atexit +import traceback + +try: + from zabbix_api import ZabbixAPI + HAS_ZABBIX_API = True +except ImportError: + ZBX_IMP_ERR = traceback.format_exc() + HAS_ZABBIX_API = False + + +class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): + + NAME = 'community.zabbix.zabbix_inventory' + + def login_zabbix(self): + # set proxy information if required + proxy = self.get_option('proxy') + os.environ['http_proxy'] = proxy + os.environ['HTTP_PROXY'] = proxy + os.environ['https_proxy'] = proxy + os.environ['HTTPS_PROXY'] = proxy + + server_url = self.get_option('server_url') + http_login_user = self.get_option('login_user') + http_login_password = self.get_option('login_password') + validate_certs = self.get_option('validate_certs') + timeout = self.get_option('timeout') + self._zapi = ZabbixAPI(server_url, timeout=timeout, user=http_login_user, passwd=http_login_password, validate_certs=validate_certs) + self.login() + self._zbx_api_version = self._zapi.api_version()[:5] + + def login(self): + # check if api already logged in + if not self._zapi.auth != '': + try: + login_user = self.get_option('login_user') + login_password = self.get_option('login_password') + self._zapi.login(login_user, login_password) + atexit.register(self._zapi.logout) + except Exception as e: + self.display.vvv(msg="Failed to connect to Zabbix server: %s" % e) + + def verify_file(self, path): + valid = False + if super(InventoryModule, self).verify_file(path): + if path.endswith(('zabbix_inventory.yaml', 'zabbix_inventory.yml')): + valid = True + else: + self.display.vvv( + 'Skipping due to inventory source not ending in "zabbix_inventory.yaml" nor "zabbix_inventory.yml"') + return valid + + def parse(self, inventory, loader, path, + cache=True): # Plugin interface (2) + super(InventoryModule, self).parse(inventory, loader, path) + + self._read_config_data(path) + self.cache_key = self.get_cache_key(path) + + self.use_cache = self.get_option('cache') and cache + self.update_cache = self.get_option('cache') and not cache + + self.login_zabbix() + zapi_query = self.get_option('host_zapi_query') + content = self._zapi.host.get(zapi_query) + + strict = self.get_option('strict') + + for record in content: + # add host to inventory + host_name = self.inventory.add_host(record['host']) + # set variables for host + for k in record.keys(): + self.inventory.set_variable(host_name, 'zbx_%s' % k, record[k]) + + # added for compose vars and keyed groups + self._set_composite_vars( + self.get_option('compose'), + self.inventory.get_host(host_name).get_vars(), host_name, strict) + + self._add_host_to_composed_groups(self.get_option('groups'), dict(), host_name, strict) + self._add_host_to_keyed_groups(self.get_option('keyed_groups'), dict(), host_name, strict) + + # organize inventory by zabbix groups + if self.get_option('add_zabbix_groups'): + content = self._zapi.host.get({'selectGroups': ['name']}) + for record in content: + host_name = record['host'] + if len(record['groups']) >= 1: + for group in record['groups']: + group_name = to_safe_group_name(group['name']) + self.inventory.add_group(group_name) + self.inventory.add_child(group_name, host_name) diff --git a/ansible_collections/community/zabbix/plugins/module_utils/__init__.py b/ansible_collections/community/zabbix/plugins/module_utils/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/module_utils/__init__.py diff --git a/ansible_collections/community/zabbix/plugins/module_utils/_version.py b/ansible_collections/community/zabbix/plugins/module_utils/_version.py new file mode 100644 index 000000000..ce027171c --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/module_utils/_version.py @@ -0,0 +1,343 @@ +# Vendored copy of distutils/version.py from CPython 3.9.5 +# +# Implements multiple version numbering conventions for the +# Python Module Distribution Utilities. +# +# PSF License (see PSF-license.txt or https://opensource.org/licenses/Python-2.0) +# + +"""Provides classes to represent module version numbers (one class for +each style of version numbering). There are currently two such classes +implemented: StrictVersion and LooseVersion. + +Every version number class implements the following interface: + * the 'parse' method takes a string and parses it to some internal + representation; if the string is an invalid version number, + 'parse' raises a ValueError exception + * the class constructor takes an optional string argument which, + if supplied, is passed to 'parse' + * __str__ reconstructs the string that was passed to 'parse' (or + an equivalent string -- ie. one that will generate an equivalent + version number instance) + * __repr__ generates Python code to recreate the version number instance + * _cmp compares the current instance with either another instance + of the same class or a string (which will be parsed to an instance + of the same class, thus must follow the same rules) +""" + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import re + +try: + RE_FLAGS = re.VERBOSE | re.ASCII +except AttributeError: + RE_FLAGS = re.VERBOSE + + +class Version: + """Abstract base class for version numbering classes. Just provides + constructor (__init__) and reproducer (__repr__), because those + seem to be the same for all version numbering classes; and route + rich comparisons to _cmp. + """ + + def __init__(self, vstring=None): + if vstring: + self.parse(vstring) + + def __repr__(self): + return "%s ('%s')" % (self.__class__.__name__, str(self)) + + def __eq__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c == 0 + + def __lt__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c < 0 + + def __le__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c <= 0 + + def __gt__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c > 0 + + def __ge__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c >= 0 + + +# Interface for version-number classes -- must be implemented +# by the following classes (the concrete ones -- Version should +# be treated as an abstract class). +# __init__ (string) - create and take same action as 'parse' +# (string parameter is optional) +# parse (string) - convert a string representation to whatever +# internal representation is appropriate for +# this style of version numbering +# __str__ (self) - convert back to a string; should be very similar +# (if not identical to) the string supplied to parse +# __repr__ (self) - generate Python code to recreate +# the instance +# _cmp (self, other) - compare two version numbers ('other' may +# be an unparsed version string, or another +# instance of your version class) + + +class StrictVersion(Version): + """Version numbering for anal retentives and software idealists. + Implements the standard interface for version number classes as + described above. A version number consists of two or three + dot-separated numeric components, with an optional "pre-release" tag + on the end. The pre-release tag consists of the letter 'a' or 'b' + followed by a number. If the numeric components of two version + numbers are equal, then one with a pre-release tag will always + be deemed earlier (lesser) than one without. + + The following are valid version numbers (shown in the order that + would be obtained by sorting according to the supplied cmp function): + + 0.4 0.4.0 (these two are equivalent) + 0.4.1 + 0.5a1 + 0.5b3 + 0.5 + 0.9.6 + 1.0 + 1.0.4a3 + 1.0.4b1 + 1.0.4 + + The following are examples of invalid version numbers: + + 1 + 2.7.2.2 + 1.3.a4 + 1.3pl1 + 1.3c4 + + The rationale for this version numbering system will be explained + in the distutils documentation. + """ + + version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', + RE_FLAGS) + + def parse(self, vstring): + match = self.version_re.match(vstring) + if not match: + raise ValueError("invalid version number '%s'" % vstring) + + (major, minor, patch, prerelease, prerelease_num) = \ + match.group(1, 2, 4, 5, 6) + + if patch: + self.version = tuple(map(int, [major, minor, patch])) + else: + self.version = tuple(map(int, [major, minor])) + (0,) + + if prerelease: + self.prerelease = (prerelease[0], int(prerelease_num)) + else: + self.prerelease = None + + def __str__(self): + if self.version[2] == 0: + vstring = '.'.join(map(str, self.version[0:2])) + else: + vstring = '.'.join(map(str, self.version)) + + if self.prerelease: + vstring = vstring + self.prerelease[0] + str(self.prerelease[1]) + + return vstring + + def _cmp(self, other): + if isinstance(other, str): + other = StrictVersion(other) + elif not isinstance(other, StrictVersion): + return NotImplemented + + if self.version != other.version: + # numeric versions don't match + # prerelease stuff doesn't matter + if self.version < other.version: + return -1 + else: + return 1 + + # have to compare prerelease + # case 1: neither has prerelease; they're equal + # case 2: self has prerelease, other doesn't; other is greater + # case 3: self doesn't have prerelease, other does: self is greater + # case 4: both have prerelease: must compare them! + + if (not self.prerelease and not other.prerelease): + return 0 + elif (self.prerelease and not other.prerelease): + return -1 + elif (not self.prerelease and other.prerelease): + return 1 + elif (self.prerelease and other.prerelease): + if self.prerelease == other.prerelease: + return 0 + elif self.prerelease < other.prerelease: + return -1 + else: + return 1 + else: + raise AssertionError("never get here") + +# end class StrictVersion + +# The rules according to Greg Stein: +# 1) a version number has 1 or more numbers separated by a period or by +# sequences of letters. If only periods, then these are compared +# left-to-right to determine an ordering. +# 2) sequences of letters are part of the tuple for comparison and are +# compared lexicographically +# 3) recognize the numeric components may have leading zeroes +# +# The LooseVersion class below implements these rules: a version number +# string is split up into a tuple of integer and string components, and +# comparison is a simple tuple comparison. This means that version +# numbers behave in a predictable and obvious way, but a way that might +# not necessarily be how people *want* version numbers to behave. There +# wouldn't be a problem if people could stick to purely numeric version +# numbers: just split on period and compare the numbers as tuples. +# However, people insist on putting letters into their version numbers; +# the most common purpose seems to be: +# - indicating a "pre-release" version +# ('alpha', 'beta', 'a', 'b', 'pre', 'p') +# - indicating a post-release patch ('p', 'pl', 'patch') +# but of course this can't cover all version number schemes, and there's +# no way to know what a programmer means without asking him. +# +# The problem is what to do with letters (and other non-numeric +# characters) in a version number. The current implementation does the +# obvious and predictable thing: keep them as strings and compare +# lexically within a tuple comparison. This has the desired effect if +# an appended letter sequence implies something "post-release": +# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002". +# +# However, if letters in a version number imply a pre-release version, +# the "obvious" thing isn't correct. Eg. you would expect that +# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison +# implemented here, this just isn't so. +# +# Two possible solutions come to mind. The first is to tie the +# comparison algorithm to a particular set of semantic rules, as has +# been done in the StrictVersion class above. This works great as long +# as everyone can go along with bondage and discipline. Hopefully a +# (large) subset of Python module programmers will agree that the +# particular flavour of bondage and discipline provided by StrictVersion +# provides enough benefit to be worth using, and will submit their +# version numbering scheme to its domination. The free-thinking +# anarchists in the lot will never give in, though, and something needs +# to be done to accommodate them. +# +# Perhaps a "moderately strict" version class could be implemented that +# lets almost anything slide (syntactically), and makes some heuristic +# assumptions about non-digits in version number strings. This could +# sink into special-case-hell, though; if I was as talented and +# idiosyncratic as Larry Wall, I'd go ahead and implement a class that +# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is +# just as happy dealing with things like "2g6" and "1.13++". I don't +# think I'm smart enough to do it right though. +# +# In any case, I've coded the test suite for this module (see +# ../test/test_version.py) specifically to fail on things like comparing +# "1.2a2" and "1.2". That's not because the *code* is doing anything +# wrong, it's because the simple, obvious design doesn't match my +# complicated, hairy expectations for real-world version numbers. It +# would be a snap to fix the test suite to say, "Yep, LooseVersion does +# the Right Thing" (ie. the code matches the conception). But I'd rather +# have a conception that matches common notions about version numbers. + + +class LooseVersion(Version): + """Version numbering for anarchists and software realists. + Implements the standard interface for version number classes as + described above. A version number consists of a series of numbers, + separated by either periods or strings of letters. When comparing + version numbers, the numeric components will be compared + numerically, and the alphabetic components lexically. The following + are all valid version numbers, in no particular order: + + 1.5.1 + 1.5.2b2 + 161 + 3.10a + 8.02 + 3.4j + 1996.07.12 + 3.2.pl0 + 3.1.1.6 + 2g6 + 11g + 0.960923 + 2.2beta29 + 1.13++ + 5.5.kw + 2.0b1pl0 + + In fact, there is no such thing as an invalid version number under + this scheme; the rules for comparison are simple and predictable, + but may not always give the results you want (for some definition + of "want"). + """ + + component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) + + def __init__(self, vstring=None): + if vstring: + self.parse(vstring) + + def parse(self, vstring): + # I've given up on thinking I can reconstruct the version string + # from the parsed tuple -- so I just store the string here for + # use by __str__ + self.vstring = vstring + components = [x for x in self.component_re.split(vstring) if x and x != '.'] + for i, obj in enumerate(components): + try: + components[i] = int(obj) + except ValueError: + pass + + self.version = components + + def __str__(self): + return self.vstring + + def __repr__(self): + return "LooseVersion ('%s')" % str(self) + + def _cmp(self, other): + if isinstance(other, str): + other = LooseVersion(other) + elif not isinstance(other, LooseVersion): + return NotImplemented + + if self.version == other.version: + return 0 + if self.version < other.version: + return -1 + if self.version > other.version: + return 1 + +# end class LooseVersion diff --git a/ansible_collections/community/zabbix/plugins/module_utils/api_request.py b/ansible_collections/community/zabbix/plugins/module_utils/api_request.py new file mode 100644 index 000000000..a29f492de --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/module_utils/api_request.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# (c) 2021, Markus Fischbacher (fischbacher.markus@gmail.com) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Quick Link to Zabbix API docs: https://www.zabbix.com/documentation/current/manual/api + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from uuid import uuid4 + +from ansible.module_utils.urls import CertificateError +from ansible.module_utils.connection import ConnectionError +from ansible.module_utils.connection import Connection +from ansible.module_utils._text import to_text + + +class ZabbixApiRequest(object): + + def __init__(self, module): + self.module = module + self.connection = Connection(self.module._socket_path) + + def _httpapi_error_handle(self, payload=None): + try: + code, response = self.connection.send_request(data=payload) + except ConnectionError as e: + self.module.fail_json(msg="connection error occurred: {0}".format(e)) + except CertificateError as e: + self.module.fail_json(msg="certificate error occurred: {0}".format(e)) + except ValueError as e: + self.module.fail_json(msg="certificate not found: {0}".format(e)) + + if code == 404: + if to_text(u"Object not found") in to_text(response) or to_text( + u"Could not find object" + ) in to_text(response): + return {} + + if not (code >= 200 and code < 300): + self.module.fail_json( + msg="Zabbix httpapi returned error {0} with message {1}".format( + code, response + ) + ) + + return response + + def api_version(self): + return self.connection.api_version() + + @staticmethod + def payload_builder(method_, params, jsonrpc_version='2.0', reqid=str(uuid4()), **kwargs): + req = {'jsonrpc': jsonrpc_version, 'method': method_, 'id': reqid} + req['params'] = params + return req + + def __getattr__(self, name): + return ZabbixApiSection(self, name) + + +class ZabbixApiSection(object): + parent = None + name = None + + def __init__(self, parent, name): + self.name = name + self.parent = parent + + def __getattr__(self, name): + def method(opts=None): + if self.name == "configuration" and name == "import_": + _method = "configuration.import" + else: + _method = "%s.%s" % (self.name, name) + if not opts: + opts = {} + payload = ZabbixApiRequest.payload_builder(_method, opts) + return self.parent._httpapi_error_handle(payload=payload) + + return method diff --git a/ansible_collections/community/zabbix/plugins/module_utils/base.py b/ansible_collections/community/zabbix/plugins/module_utils/base.py new file mode 100644 index 000000000..8858a02e1 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/module_utils/base.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible_collections.community.zabbix.plugins.module_utils.wrappers import ZapiWrapper +from ansible_collections.community.zabbix.plugins.module_utils.api_request import ZabbixApiRequest + + +class ZabbixBase(object): + """ + The base class for deriving off module classes + """ + def __init__(self, module, zbx=None, zapi_wrapper=None): + self._module = module + + if module._socket_path is None: + # ansible_connection = local + if zapi_wrapper is None: + self._zapi_wrapper = ZapiWrapper(module, zbx) + else: + self._zapi_wrapper = zapi_wrapper + + self._zapi = self._zapi_wrapper._zapi + self._zbx_api_version = self._zapi_wrapper._zbx_api_version + else: + # ansible_connection = httpapi + self._zapi = ZabbixApiRequest(module) + self._zbx_api_version = self._zapi.api_version() diff --git a/ansible_collections/community/zabbix/plugins/module_utils/helpers.py b/ansible_collections/community/zabbix/plugins/module_utils/helpers.py new file mode 100644 index 000000000..6c9c0fca5 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/module_utils/helpers.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible.module_utils.basic import env_fallback + + +def require_creds_params(module): + if module._socket_path is None: + # ansible_connection = local + if ((not module.params.get('server_url', None)) or (not module.params.get('login_user', None)) or (not module.params.get('login_password', None))): + module.fail_json(msg="server_url, login_user, login_password are mandatory parameters when httpapi connection is not used") + + +def zabbix_common_argument_spec(): + """ + Return a dictionary with connection options. + The options are commonly used by most of Zabbix modules. + """ + return dict( + server_url=dict( + type='str', + required=False, + aliases=['url'], + fallback=(env_fallback, ['ZABBIX_SERVER']) + ), + login_user=dict( + type='str', required=False, + fallback=(env_fallback, ['ZABBIX_USERNAME']) + ), + login_password=dict( + type='str', + required=False, + no_log=True, + fallback=(env_fallback, ['ZABBIX_PASSWORD']) + ), + http_login_user=dict( + type='str', + required=False, + default=None + ), + http_login_password=dict( + type='str', + required=False, + default=None, + no_log=True + ), + timeout=dict( + type='int' + ), + validate_certs=dict( + type='bool', + required=False, + fallback=(env_fallback, ['ZABBIX_VALIDATE_CERTS']) + ), + ) + + +def helper_cleanup_data(obj): + """ + Removes the None values from the object and returns the object + Args: + obj: object to cleanup + + Returns: + object: cleaned object + """ + if isinstance(obj, (list, tuple, set)): + return type(obj)(helper_cleanup_data(x) for x in obj if x is not None) + elif isinstance(obj, dict): + return type(obj)((helper_cleanup_data(k), helper_cleanup_data(v)) + for k, v in obj.items() if k is not None and v is not None) + else: + return obj + + +def helper_to_numeric_value(elements, value): + """Converts string values to integers + + Parameters: + elements: list of elements to enumerate + value: string value + + Returns: + int: converted integer + """ + if value is None: + return None + for index, element in enumerate(elements): + if isinstance(element, str) and element.lower() == value.lower(): + return index + if isinstance(element, list): + for deep_element in element: + if isinstance(deep_element, str) and deep_element.lower() == value.lower(): + return index + + +def helper_convert_unicode_to_str(data): + """Converts unicode objects to strings in dictionary + + Parameters: + data: unicode object + + Returns: + dict: strings in dictionary + """ + if isinstance(data, dict): + return dict(map(helper_convert_unicode_to_str, data.items())) + elif isinstance(data, (list, tuple, set)): + return type(data)(map(helper_convert_unicode_to_str, data)) + elif data is None: + return data + else: + return str(data) + + +def helper_compare_lists(l1, l2, diff_dict): + """ + Compares l1 and l2 lists and adds the items that are different + to the diff_dict dictionary. + Used in recursion with helper_compare_dictionaries() function. + + Parameters: + l1: first list to compare + l2: second list to compare + diff_dict: dictionary to store the difference + + Returns: + dict: items that are different + """ + if len(l1) != len(l2): + diff_dict.append(l1) + return diff_dict + for i, item in enumerate(l1): + if isinstance(item, dict): + for item2 in l2: + diff_dict2 = {} + diff_dict2 = helper_compare_dictionaries(item, item2, diff_dict2) + if len(diff_dict2) == 0: + break + if len(diff_dict2) != 0: + diff_dict.insert(i, item) + else: + if item != l2[i]: + diff_dict.append(item) + while {} in diff_dict: + diff_dict.remove({}) + return diff_dict + + +def helper_compare_dictionaries(d1, d2, diff_dict): + """ + Compares d1 and d2 dictionaries and adds the items that are different + to the diff_dict dictionary. + Used in recursion with helper_compare_lists() function. + + Parameters: + d1: first dictionary to compare + d2: second dictionary to compare + diff_dict: dictionary to store the difference + + Returns: + dict: items that are different + """ + for k, v in d1.items(): + if k not in d2: + diff_dict[k] = v + continue + if isinstance(v, dict): + diff_dict[k] = {} + helper_compare_dictionaries(v, d2[k], diff_dict[k]) + if diff_dict[k] == {}: + del diff_dict[k] + else: + diff_dict[k] = v + elif isinstance(v, list): + diff_dict[k] = [] + helper_compare_lists(v, d2[k], diff_dict[k]) + if diff_dict[k] == []: + del diff_dict[k] + else: + diff_dict[k] = v + else: + if v != d2[k]: + diff_dict[k] = v + return diff_dict + + +def helper_normalize_data(data, del_keys=None): + """ + Delete None parameter or specified keys from data. + + Parameters: + data: dictionary + + Returns: + data: falsene parameter removed data + del_keys: deleted keys + """ + if del_keys is None: + del_keys = [] + + for key, value in data.items(): + if value is None: + del_keys.append(key) + + for key in del_keys: + if key in data.keys(): + del data[key] + + return data, del_keys diff --git a/ansible_collections/community/zabbix/plugins/module_utils/wrappers.py b/ansible_collections/community/zabbix/plugins/module_utils/wrappers.py new file mode 100644 index 000000000..a982108f8 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/module_utils/wrappers.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import atexit +import traceback + +from ansible.module_utils.basic import missing_required_lib + +try: + from zabbix_api import ZabbixAPI, Already_Exists, ZabbixAPIException + + HAS_ZABBIX_API = True + ZBX_IMP_ERR = Exception() +except ImportError: + ZBX_IMP_ERR = traceback.format_exc() + HAS_ZABBIX_API = False + + +class ZapiWrapper(object): + """ + A simple wrapper over the Zabbix API + """ + def __init__(self, module, zbx=None): + self._module = module + + if not HAS_ZABBIX_API: + module.fail_json(msg=missing_required_lib('zabbix-api', url='https://pypi.org/project/zabbix-api/'), exception=ZBX_IMP_ERR) + + # check if zbx is already instantiated or not + if zbx is not None and isinstance(zbx, ZabbixAPI): + self._zapi = zbx + else: + server_url = module.params['server_url'] + + if module.params['validate_certs'] is None: + validate_certs = True + else: + validate_certs = module.params['validate_certs'] + + if module.params['timeout'] is None: + timeout = 10 + else: + timeout = module.params['timeout'] + + self._zapi = ZabbixAPI(server_url, timeout=timeout, validate_certs=validate_certs) + + self.login() + + self._zbx_api_version = self._zapi.api_version() + + def login(self): + # check if api already logged in + if not self._zapi.auth != '': + try: + login_user = self._module.params['login_user'] + login_password = self._module.params['login_password'] + self._zapi.login(login_user, login_password) + atexit.register(self._zapi.logout) + except Exception as e: + self._module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) + + +class ScreenItem(object): + @staticmethod + def create(zapi_wrapper, data, ignoreExists=False): + try: + zapi_wrapper._zapi.screenitem.create(data) + except Already_Exists as ex: + if not ignoreExists: + raise ex + + @staticmethod + def delete(zapi_wrapper, id_list=None): + try: + if id_list is None: + id_list = [] + zapi_wrapper._zapi.screenitem.delete(id_list) + except ZabbixAPIException as ex: + raise ex diff --git a/ansible_collections/community/zabbix/plugins/modules/__init__.py b/ansible_collections/community/zabbix/plugins/modules/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/__init__.py diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py new file mode 100644 index 000000000..8e130de69 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py @@ -0,0 +1,2106 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: zabbix_action + +short_description: Create/Delete/Update Zabbix actions + + +description: + - This module allows you to create, modify and delete Zabbix actions. + +author: + - Ruben Tsirunyan (@rubentsirunyan) + - Ruben Harutyunov (@K-DOT) + +requirements: + - "python >= 2.6" + +options: + name: + description: + - Name of the action + required: true + event_source: + description: + - Type of events that the action will handle. + - Required when C(state=present). + required: false + choices: ['trigger', 'discovery', 'auto_registration', 'internal'] + state: + description: + - State of the action. + - On C(present), it will create an action if it does not exist or update the action if the associated data is different. + - On C(absent), it will remove the action if it exists. + choices: ['present', 'absent'] + default: 'present' + status: + description: + - Status of the action. + choices: ['enabled', 'disabled'] + default: 'enabled' + pause_in_maintenance: + description: + - Whether to pause escalation during maintenance periods or not. + - Can be used when I(event_source=trigger). + type: 'bool' + default: true + esc_period: + description: + - Default operation step duration. Must be greater than 60 seconds. + - Accepts only seconds in int for <= Zabbix 3.2 + - Accepts seconds, time unit with suffix and user macro since => Zabbix 3.4 + - Required when C(state=present). + required: false + conditions: + type: list + elements: dict + description: + - List of conditions to use for filtering results. + - For more information about suboptions of this option please + check out Zabbix API documentation U(https://www.zabbix.com/documentation/5.0/manual/api/reference/action/object#action_filter_condition) + suboptions: + type: + description: + - Type (label) of the condition. + - C(application) is available only with <= Zabbix 5.2. + - 'Possible values when I(event_source=trigger):' + - ' - C(host_group)' + - ' - C(host)' + - ' - C(trigger)' + - ' - C(trigger_name)' + - ' - C(trigger_severity)' + - ' - C(time_period)' + - ' - C(host_template)' + - ' - C(application)' + - ' - C(maintenance_status) known in Zabbix 4.0 and above as "Problem is suppressed"' + - ' - C(event_tag)' + - ' - C(event_tag_value)' + - 'Possible values when I(event_source=discovery):' + - ' - C(host_IP)' + - ' - C(discovered_service_type)' + - ' - C(discovered_service_port)' + - ' - C(discovery_status)' + - ' - C(uptime_or_downtime_duration)' + - ' - C(received_value)' + - ' - C(discovery_rule)' + - ' - C(discovery_check)' + - ' - C(proxy)' + - ' - C(discovery_object)' + - 'Possible values when I(event_source=auto_registration):' + - ' - C(proxy)' + - ' - C(host_name)' + - ' - C(host_metadata)' + - 'Possible values when I(event_source=internal):' + - ' - C(host_group)' + - ' - C(host)' + - ' - C(host_template)' + - ' - C(application)' + - ' - C(event_type)' + value: + description: + - Value to compare with. + - 'When I(type=discovery_status), the choices are:' + - ' - C(up)' + - ' - C(down)' + - ' - C(discovered)' + - ' - C(lost)' + - 'When I(type=discovery_object), the choices are:' + - ' - C(host)' + - ' - C(service)' + - 'When I(type=event_type), the choices are:' + - ' - C(item in not supported state)' + - ' - C(item in normal state)' + - ' - C(LLD rule in not supported state)' + - ' - C(LLD rule in normal state)' + - ' - C(trigger in unknown state)' + - ' - C(trigger in normal state)' + - 'When I(type=trigger_severity), the choices are (case-insensitive):' + - ' - C(not classified)' + - ' - C(information)' + - ' - C(warning)' + - ' - C(average)' + - ' - C(high)' + - ' - C(disaster)' + - Irrespective of user-visible names being changed in Zabbix. Defaults to C(not classified) if omitted. + - Besides the above options, this is usually either the name + of the object or a string to compare with. + value2: + description: + - Secondary value to compare with. + - Required for trigger actions when condition I(type=event_tag_value). + operator: + description: + - Condition operator. + - When I(type) is set to C(time_period), the choices are C(in), C(not in). + - C(matches), C(does not match), C(Yes) and C(No) condition operators work only with >= Zabbix 4.0 + - When I(type) is set to C(maintenance_status), the choices are C(Yes) and C(No) for Zabbix >= 6.0 + choices: + - C(equals) or C(=) + - C(does not equal) or C(<>) + - C(contains) or C(like) + - C(does not contain) or C(not like) + - C(in) + - C(is greater than or equals) or C(>=) + - C(is less than or equals) or C(<=) + - C(not in) + - C(matches) + - C(does not match) + - C(Yes) + - C(No) + formulaid: + description: + - Arbitrary unique ID that is used to reference the condition from a custom expression. + - Can only contain upper-case letters. + - Required for custom expression filters and ignored otherwise. + eval_type: + description: + - Filter condition evaluation method. + - Defaults to C(andor) if conditions are less then 2 or if + I(formula) is not specified. + - Defaults to C(custom_expression) when formula is specified. + choices: + - 'andor' + - 'and' + - 'or' + - 'custom_expression' + formula: + description: + - User-defined expression to be used for evaluating conditions with a custom expression. + - The expression must contain IDs that reference each condition by its formulaid. + - The IDs used in the expression must exactly match the ones + defined in the I(conditions). No condition can remain unused or omitted. + - Required when I(eval_type=custom_expression). + - Use sequential IDs that start at "A". If non-sequential IDs are used, Zabbix re-indexes them. + This makes each module run notice the difference in IDs and update the action. + default_message: + description: + - Problem message default text. + - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module. + - Works only with < Zabbix 5.0 + default_subject: + description: + - Problem message default subject. + - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module. + - Works only with < Zabbix 5.0 + recovery_default_message: + description: + - Recovery message text. + - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module. + - Works only with >= Zabbix 3.2 and < Zabbix 5.0 + recovery_default_subject: + description: + - Recovery message subject. + - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module. + - Works only with >= Zabbix 3.2 and < Zabbix 5.0 + acknowledge_default_message: + description: + - Update operation (known as "Acknowledge operation" before Zabbix 4.0) message text. + - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module. + - Works only with >= Zabbix 3.4 and < Zabbix 5.0 + acknowledge_default_subject: + description: + - Update operation (known as "Acknowledge operation" before Zabbix 4.0) message subject. + - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module. + - Works only with >= Zabbix 3.4 and < Zabbix 5.0 + operations: + type: list + description: + - List of action operations + suboptions: + type: + description: + - Type of operation. + - 'Valid choices when setting type for I(recovery_operations) and I(acknowledge_operations):' + - ' - C(send_message)' + - ' - C(remote_command)' + - ' - C(notify_all_involved)' + - Choice C(notify_all_involved) only supported in I(recovery_operations) and I(acknowledge_operations). + choices: + - send_message + - remote_command + - add_host + - remove_host + - add_to_host_group + - remove_from_host_group + - link_to_template + - unlink_from_template + - enable_host + - disable_host + - set_host_inventory_mode + - notify_all_involved + esc_period: + description: + - Duration of an escalation step in seconds. + - Must be greater than 60 seconds. + - Accepts only seconds in int for <= Zabbix 3.2 + - Accepts seconds, time unit with suffix and user macro since => Zabbix 3.4 + - If set to 0 or 0s, the default action escalation period will be used. + default: 0s + esc_step_from: + description: + - Step to start escalation from. + default: 1 + esc_step_to: + description: + - Step to end escalation at. + - Specify 0 for infinitely. + default: 1 + send_to_groups: + type: list + description: + - User groups to send messages to. + send_to_users: + type: list + description: + - Users (usernames or aliases) to send messages to. + message: + description: + - Operation message text. + - Will check the 'default message' and use the text from I(default_message) if this and I(default_subject) are not specified + subject: + description: + - Operation message subject. + - Will check the 'default message' and use the text from I(default_subject) if this and I(default_subject) are not specified + media_type: + description: + - Media type that will be used to send the message. + - Can be used with I(type=send_message) or I(type=notify_all_involved) inside I(acknowledge_operations). + - Set to C(all) for all media types + default: 'all' + operation_condition: + type: 'str' + description: + - The action operation condition object defines a condition that must be met to perform the current operation. + choices: + - acknowledged + - not_acknowledged + host_groups: + type: list + description: + - List of host groups host should be added to. + - Required when I(type=add_to_host_group) or I(type=remove_from_host_group). + templates: + type: list + description: + - List of templates host should be linked to. + - Required when I(type=link_to_template) or I(type=unlink_from_template). + inventory: + description: + - Host inventory mode. + - Required when I(type=set_host_inventory_mode). + choices: + - manual + - automatic + command_type: + description: + - Type of operation command. + - Required when I(type=remote_command). + choices: + - custom_script + - ipmi + - ssh + - telnet + - global_script + command: + description: + - Command to run. + - Required when I(type=remote_command) and I(command_type!=global_script). + execute_on: + description: + - Target on which the custom script operation command will be executed. + - Required when I(type=remote_command) and I(command_type=custom_script). + choices: + - agent + - server + - proxy + run_on_groups: + description: + - Host groups to run remote commands on. + - Required when I(type=remote_command) and I(run_on_hosts) is not set. + run_on_hosts: + description: + - Hosts to run remote commands on. + - Required when I(type=remote_command) and I(run_on_groups) is not set. + - If set to 0 the command will be run on the current host. + ssh_auth_type: + description: + - Authentication method used for SSH commands. + - Required when I(type=remote_command) and I(command_type=ssh). + choices: + - password + - public_key + ssh_privatekey_file: + description: + - Name of the private key file used for SSH commands with public key authentication. + - Required when I(ssh_auth_type=public_key). + - Can be used when I(type=remote_command). + ssh_publickey_file: + description: + - Name of the public key file used for SSH commands with public key authentication. + - Required when I(ssh_auth_type=public_key). + - Can be used when I(type=remote_command). + username: + description: + - User name used for authentication. + - Required when I(ssh_auth_type in [public_key, password]) or I(command_type=telnet). + - Can be used when I(type=remote_command). + password: + description: + - Password used for authentication. + - Required when I(ssh_auth_type=password) or I(command_type=telnet). + - Can be used when I(type=remote_command). + port: + description: + - Port number used for authentication. + - Can be used when I(command_type in [ssh, telnet]) and I(type=remote_command). + script_name: + description: + - The name of script used for global script commands. + - Required when I(command_type=global_script). + - Can be used when I(type=remote_command). + recovery_operations: + type: list + description: + - List of recovery operations. + - C(Suboptions) are the same as for I(operations). + - Works only with >= Zabbix 3.2 + acknowledge_operations: + type: list + description: + - List of acknowledge operations. + - Action acknowledge operations are known as update operations since Zabbix 4.0. + - C(Suboptions) are the same as for I(operations). + - Works only with >= Zabbix 3.4 + aliases: [ update_operations ] + pause_symptoms: + type: bool + description: + - Whether to pause escalation if event is a symptom event. + - I(supported) if C(event_source) is set to C(trigger) + - Works only with >= Zabbix 6.4 + default: true + +notes: + - Only Zabbix >= 3.0 is supported. + + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Trigger action with only one condition +- name: Deploy trigger action + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_action: + name: "Send alerts to Admin" + event_source: 'trigger' + state: present + status: enabled + esc_period: 60 + conditions: + - type: 'trigger_severity' + operator: '>=' + value: 'Information' + operations: + - type: send_message + subject: "Something bad is happening" + message: "Come on, guys do something" + media_type: 'Email' + send_to_users: + - 'Admin' + +# Trigger action with multiple conditions and operations +- name: Deploy trigger action + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_action: + name: "Send alerts to Admin" + event_source: 'trigger' + state: present + status: enabled + esc_period: 1m + conditions: + - type: 'trigger_name' + operator: 'like' + value: 'Zabbix agent is unreachable' + formulaid: A + - type: 'trigger_severity' + operator: '>=' + value: 'disaster' + formulaid: B + formula: A or B + operations: + - type: send_message + media_type: 'Email' + send_to_users: + - 'Admin' + - type: remote_command + command: 'systemctl restart zabbix-agent' + command_type: custom_script + execute_on: server + run_on_hosts: + - 0 + +# Trigger action with recovery and acknowledge operations +- name: Deploy trigger action + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_action: + name: "Send alerts to Admin" + event_source: 'trigger' + state: present + status: enabled + esc_period: 1h + conditions: + - type: 'trigger_severity' + operator: '>=' + value: 'Information' + operations: + - type: send_message + subject: "Something bad is happening" + message: "Come on, guys do something" + media_type: 'Email' + send_to_users: + - 'Admin' + recovery_operations: + - type: send_message + subject: "Host is down" + message: "Come on, guys do something" + media_type: 'Email' + send_to_users: + - 'Admin' + acknowledge_operations: + - type: send_message + media_type: 'Email' + send_to_users: + - 'Admin' +''' + +RETURN = ''' +msg: + description: The result of the operation + returned: success + type: str + sample: 'Action Deleted: Register webservers, ID: 0001' +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Zapi(ZabbixBase): + def __init__(self, module, zbx=None): + super(Zapi, self).__init__(module, zbx) + self._zapi_wrapper = self + + def check_if_action_exists(self, name): + """Check if action exists. + + Args: + name: Name of the action. + + Returns: + The return value. True for success, False otherwise. + + """ + try: + _params = { + "selectOperations": "extend", + "selectRecoveryOperations": "extend", + "selectAcknowledgeOperations": "extend", + "selectFilter": "extend", + 'filter': {'name': [name]} + } + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + _params['selectUpdateOperations'] = _params.pop('selectAcknowledgeOperations', 'extend') + _action = self._zapi.action.get(_params) + if len(_action) > 0 and LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + _action[0]['recovery_operations'] = _action[0].pop('recoveryOperations', []) + _action[0]['acknowledge_operations'] = _action[0].pop('acknowledgeOperations', []) + return _action + except Exception as e: + self._module.fail_json(msg="Failed to check if action '%s' exists: %s" % (name, e)) + + def get_action_by_name(self, name): + """Get action by name + + Args: + name: Name of the action. + + Returns: + dict: Zabbix action + + """ + try: + action_list = self._zapi.action.get({ + 'output': 'extend', + 'filter': {'name': [name]} + }) + if len(action_list) < 1: + self._module.fail_json(msg="Action not found: %s" % name) + else: + return action_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get ID of '%s': %s" % (name, e)) + + def get_host_by_host_name(self, host_name): + """Get host by host name + + Args: + host_name: host name. + + Returns: + host matching host name + + """ + try: + host_list = self._zapi.host.get({ + 'output': 'extend', + 'selectInventory': 'extend', + 'filter': {'host': [host_name]} + }) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + return host_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get host '%s': %s" % (host_name, e)) + + def get_hostgroup_by_hostgroup_name(self, hostgroup_name): + """Get host group by host group name + + Args: + hostgroup_name: host group name. + + Returns: + host group matching host group name + + """ + try: + hostgroup_list = self._zapi.hostgroup.get({ + 'output': 'extend', + 'filter': {'name': [hostgroup_name]} + }) + if len(hostgroup_list) < 1: + self._module.fail_json(msg="Host group not found: %s" % hostgroup_name) + else: + return hostgroup_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get host group '%s': %s" % (hostgroup_name, e)) + + def get_template_by_template_name(self, template_name): + """Get template by template name + + Args: + template_name: template name. + + Returns: + template matching template name + + """ + try: + template_list = self._zapi.template.get({ + 'output': 'extend', + 'filter': {'host': [template_name]} + }) + if len(template_list) < 1: + self._module.fail_json(msg="Template not found: %s" % template_name) + else: + return template_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get template '%s': %s" % (template_name, e)) + + def get_trigger_by_trigger_name(self, trigger_name): + """Get trigger by trigger name + + Args: + trigger_name: trigger name. + + Returns: + trigger matching trigger name + + """ + try: + trigger_list = self._zapi.trigger.get({ + 'output': 'extend', + 'filter': {'description': [trigger_name]} + }) + if len(trigger_list) < 1: + self._module.fail_json(msg="Trigger not found: %s" % trigger_name) + else: + return trigger_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get trigger '%s': %s" % (trigger_name, e)) + + def get_discovery_rule_by_discovery_rule_name(self, discovery_rule_name): + """Get discovery rule by discovery rule name + + Args: + discovery_rule_name: discovery rule name. + + Returns: + discovery rule matching discovery rule name + + """ + try: + discovery_rule_list = self._zapi.drule.get({ + 'output': 'extend', + 'filter': {'name': [discovery_rule_name]} + }) + if len(discovery_rule_list) < 1: + self._module.fail_json(msg="Discovery rule not found: %s" % discovery_rule_name) + else: + return discovery_rule_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get discovery rule '%s': %s" % (discovery_rule_name, e)) + + def get_discovery_check_by_discovery_check_name(self, discovery_check_name): + """Get discovery check by discovery check name + + Args: + discovery_check_name: discovery check name. + + Returns: + discovery check matching discovery check name + + """ + try: + discovery_rule_name, dcheck_type = discovery_check_name.split(': ') + dcheck_type_to_number = { + 'SSH': '0', + 'LDAP': '1', + 'SMTP': '2', + 'FTP': '3', + 'HTTP': '4', + 'POP': '5', + 'NNTP': '6', + 'IMAP': '7', + 'TCP': '8', + 'Zabbix agent': '9', + 'SNMPv1 agent': '10', + 'SNMPv2 agent': '11', + 'ICMP ping': '12', + 'SNMPv3 agent': '13', + 'HTTPS': '14', + 'Telnet': '15' + } + if dcheck_type not in dcheck_type_to_number: + self._module.fail_json(msg="Discovery check type: %s does not exist" % dcheck_type) + + discovery_rule_list = self._zapi.drule.get({ + 'output': ['dchecks'], + 'filter': {'name': [discovery_rule_name]}, + 'selectDChecks': 'extend' + }) + if len(discovery_rule_list) < 1: + self._module.fail_json(msg="Discovery check not found: %s" % discovery_check_name) + + for dcheck in discovery_rule_list[0]['dchecks']: + if dcheck_type_to_number[dcheck_type] == dcheck['type']: + return dcheck + self._module.fail_json(msg="Discovery check not found: %s" % discovery_check_name) + except Exception as e: + self._module.fail_json(msg="Failed to get discovery check '%s': %s" % (discovery_check_name, e)) + + def get_proxy_by_proxy_name(self, proxy_name): + """Get proxy by proxy name + + Args: + proxy_name: proxy name. + + Returns: + proxy matching proxy name + + """ + try: + proxy_list = self._zapi.proxy.get({ + 'output': 'extend', + 'filter': {'host': [proxy_name]} + }) + if len(proxy_list) < 1: + self._module.fail_json(msg="Proxy not found: %s" % proxy_name) + else: + return proxy_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get proxy '%s': %s" % (proxy_name, e)) + + def get_mediatype_by_mediatype_name(self, mediatype_name): + """Get mediatype by mediatype name + + Args: + mediatype_name: mediatype name + + Returns: + mediatype matching mediatype name + + """ + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'): + filter = {'name': [mediatype_name]} + else: + filter = {'description': [mediatype_name]} + + try: + if str(mediatype_name).lower() == 'all': + return '0' + mediatype_list = self._zapi.mediatype.get({ + 'output': 'extend', + 'filter': filter + }) + if len(mediatype_list) < 1: + self._module.fail_json(msg="Media type not found: %s" % mediatype_name) + else: + return mediatype_list[0]['mediatypeid'] + except Exception as e: + self._module.fail_json(msg="Failed to get mediatype '%s': %s" % (mediatype_name, e)) + + def get_user_by_user_name(self, user_name): + """Get user by user name + + Args: + user_name: user name + + Returns: + user matching user name + + """ + try: + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4'): + filter = {'username': [user_name]} + else: + filter = {'alias': [user_name]} + user_list = self._zapi.user.get({ + 'output': 'extend', + 'filter': filter, + }) + if len(user_list) < 1: + self._module.fail_json(msg="User not found: %s" % user_name) + else: + return user_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get user '%s': %s" % (user_name, e)) + + def get_usergroup_by_usergroup_name(self, usergroup_name): + """Get usergroup by usergroup name + + Args: + usergroup_name: usergroup name + + Returns: + usergroup matching usergroup name + + """ + try: + usergroup_list = self._zapi.usergroup.get({ + 'output': 'extend', + 'filter': {'name': [usergroup_name]} + }) + if len(usergroup_list) < 1: + self._module.fail_json(msg="User group not found: %s" % usergroup_name) + else: + return usergroup_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get user group '%s': %s" % (usergroup_name, e)) + + # get script by script name + def get_script_by_script_name(self, script_name): + """Get script by script name + + Args: + script_name: script name + + Returns: + script matching script name + + """ + try: + if script_name is None: + return {} + script_list = self._zapi.script.get({ + 'output': 'extend', + 'filter': {'name': [script_name]} + }) + if len(script_list) < 1: + self._module.fail_json(msg="Script not found: %s" % script_name) + else: + return script_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get script '%s': %s" % (script_name, e)) + + +class Action(Zapi): + def __init__(self, module, zbx=None): + super(Action, self).__init__(module, zbx) + self.existing_data = None + + def _construct_parameters(self, **kwargs): + """Construct parameters. + + Args: + **kwargs: Arbitrary keyword parameters. + + Returns: + dict: dictionary of specified parameters + """ + + _params = { + 'name': kwargs['name'], + 'eventsource': zabbix_utils.helper_to_numeric_value([ + 'trigger', + 'discovery', + 'auto_registration', + 'internal'], kwargs['event_source']), + 'esc_period': kwargs.get('esc_period'), + 'filter': kwargs['conditions'], + 'def_longdata': kwargs['default_message'], + 'def_shortdata': kwargs['default_subject'], + 'r_longdata': kwargs['recovery_default_message'], + 'r_shortdata': kwargs['recovery_default_subject'], + 'ack_longdata': kwargs['acknowledge_default_message'], + 'ack_shortdata': kwargs['acknowledge_default_subject'], + 'operations': kwargs['operations'], + 'recovery_operations': kwargs.get('recovery_operations'), + 'acknowledge_operations': kwargs.get('acknowledge_operations'), + 'status': zabbix_utils.helper_to_numeric_value([ + 'enabled', + 'disabled'], kwargs['status']) + } + + if kwargs['event_source'] == 'trigger': + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.0'): + _params['pause_suppressed'] = '1' if kwargs['pause_in_maintenance'] else '0' + else: + _params['maintenance_mode'] = '1' if kwargs['pause_in_maintenance'] else '0' + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.4'): + _params['pause_symptoms'] = '1' if kwargs['pause_symptoms'] else '0' + + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'): + # remove some fields regarding + # https://www.zabbix.com/documentation/5.0/manual/api/reference/action/object + _params.pop('def_longdata', None) + _params.pop('def_shortdata', None) + _params.pop('r_longdata', None) + _params.pop('r_shortdata', None) + + if (LooseVersion(self._zbx_api_version) < LooseVersion('3.4') + or LooseVersion(self._zbx_api_version) >= LooseVersion('5.0')): + _params.pop('ack_longdata', None) + _params.pop('ack_shortdata', None) + + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + _params['update_operations'] = kwargs.get('update_operations') + if 'update_operations' in _params and not isinstance(_params.get('update_operations', None), type(None)): + _params.pop('acknowledge_operations', None) + elif isinstance(_params.get('acknowledge_operations', None), list): + _params['update_operations'] = _params.pop('acknowledge_operations', []) + else: + _params['update_operations'] = [] + _params.pop('acknowledge_operations', None) + + if 'esc_period' in _params and isinstance(_params.get('esc_period', None), type(None)): + _params.pop('esc_period') + + if 'recovery_operations' in _params: + if isinstance(_params.get('recovery_operations', None), type(None)) or len(_params.get('recovery_operations', [])) == 0: + _params.pop('recovery_operations') + + if 'update_operations' in _params: + if isinstance(_params.get('update_operations', None), type(None)) or len(_params.get('update_operations', [])) == 0: + _params.pop('update_operations') + + if _params['eventsource'] not in [0, 3]: + _params.pop('esc_period') + + return _params + + def check_difference(self, **kwargs): + """Check difference between action and user specified parameters. + + Args: + **kwargs: Arbitrary keyword parameters. + + Returns: + dict: dictionary of differences + """ + existing_action = zabbix_utils.helper_convert_unicode_to_str(self.check_if_action_exists(kwargs['name'])[0]) + parameters = zabbix_utils.helper_convert_unicode_to_str(self._construct_parameters(**kwargs)) + change_parameters = {} + _diff = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(parameters, existing_action, change_parameters)) + return _diff + + def update_action(self, **kwargs): + """Update action. + + Args: + **kwargs: Arbitrary keyword parameters. + + Returns: + action: updated action + """ + try: + if self._module.check_mode: + self._module.exit_json(msg="Action would be updated if check mode was not specified: %s" % kwargs, changed=True) + kwargs['actionid'] = kwargs.pop('action_id') + return self._zapi.action.update(kwargs) + except Exception as e: + self._module.fail_json(msg="Failed to update action '%s': %s" % (kwargs['actionid'], e)) + + def add_action(self, **kwargs): + """Add action. + + Args: + **kwargs: Arbitrary keyword parameters. + + Returns: + action: added action + """ + try: + if self._module.check_mode: + self._module.exit_json(msg="Action would be added if check mode was not specified", changed=True) + parameters = self._construct_parameters(**kwargs) + action_list = self._zapi.action.create(parameters) + return action_list['actionids'][0] + except Exception as e: + self._module.fail_json(msg="Failed to create action '%s': %s" % (kwargs['name'], e)) + + def delete_action(self, action_id): + """Delete action. + + Args: + action_id: Action id + + Returns: + action: deleted action + """ + try: + if self._module.check_mode: + self._module.exit_json(msg="Action would be deleted if check mode was not specified", changed=True) + return self._zapi.action.delete([action_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete action '%s': %s" % (action_id, e)) + + +class Operations(Zapi): + def _construct_operationtype(self, operation): + """Construct operation type. + + Args: + operation: operation to construct + + Returns: + str: constructed operation + """ + try: + return zabbix_utils.helper_to_numeric_value([ + "send_message", + "remote_command", + "add_host", + "remove_host", + "add_to_host_group", + "remove_from_host_group", + "link_to_template", + "unlink_from_template", + "enable_host", + "disable_host", + "set_host_inventory_mode"], operation['type'] + ) + except Exception: + self._module.fail_json(msg="Unsupported value '%s' for operation type." % operation['type']) + + def _construct_opmessage(self, operation): + """Construct operation message. + + Args: + operation: operation to construct the message + + Returns: + dict: constructed operation message + """ + try: + return { + 'default_msg': '0' if operation.get('message') is not None or operation.get('subject') is not None else '1', + 'mediatypeid': self._zapi_wrapper.get_mediatype_by_mediatype_name( + operation.get('media_type') + ) if operation.get('media_type') is not None else '0', + 'message': operation.get('message'), + 'subject': operation.get('subject'), + } + except Exception as e: + self._module.fail_json(msg="Failed to construct operation message. The error was: %s" % e) + + def _construct_opmessage_usr(self, operation): + """Construct operation message user. + + Args: + operation: operation to construct the message user + + Returns: + list: constructed operation message user or None if operation not found + """ + if operation.get('send_to_users') is None: + return None + return [{ + 'userid': self._zapi_wrapper.get_user_by_user_name(_user)['userid'] + } for _user in operation.get('send_to_users')] + + def _construct_opmessage_grp(self, operation): + """Construct operation message group. + + Args: + operation: operation to construct the message group + + Returns: + list: constructed operation message group or None if operation not found + """ + if operation.get('send_to_groups') is None: + return None + return [{ + 'usrgrpid': self._zapi_wrapper.get_usergroup_by_usergroup_name(_group)['usrgrpid'] + } for _group in operation.get('send_to_groups')] + + def _construct_opcommand(self, operation): + """Construct operation command. + + Args: + operation: operation to construct command + + Returns: + list: constructed operation command + """ + try: + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + opcommand = { + 'type': zabbix_utils.helper_to_numeric_value([ + 'custom_script', + 'ipmi', + 'ssh', + 'telnet', + 'global_script'], operation.get('command_type', 'custom_script')), + 'command': operation.get('command'), + 'execute_on': zabbix_utils.helper_to_numeric_value([ + 'agent', + 'server', + 'proxy'], operation.get('execute_on', 'server')), + 'scriptid': self._zapi_wrapper.get_script_by_script_name( + operation.get('script_name') + ).get('scriptid'), + 'authtype': zabbix_utils.helper_to_numeric_value([ + 'password', + 'public_key' + ], operation.get('ssh_auth_type')), + 'privatekey': operation.get('ssh_privatekey_file'), + 'publickey': operation.get('ssh_publickey_file'), + 'username': operation.get('username'), + 'password': operation.get('password'), + 'port': operation.get('port') + } + else: + # In 6.0 opcommand is an opbject with just one key 'scriptid' + opcommand = { + 'scriptid': self._zapi_wrapper.get_script_by_script_name( + operation.get('script_name') + ).get('scriptid') + } + + return opcommand + + except Exception as e: + self._module.fail_json(msg="Failed to construct operation command. The error was: %s" % e) + + def _construct_opcommand_hst(self, operation): + """Construct operation command host. + + Args: + operation: operation to construct command host + + Returns: + list: constructed operation command host + """ + if operation.get('run_on_hosts') is None: + return None + return [{ + 'hostid': self._zapi_wrapper.get_host_by_host_name(_host)['hostid'] + } if str(_host) != '0' else {'hostid': '0'} for _host in operation.get('run_on_hosts')] + + def _construct_opcommand_grp(self, operation): + """Construct operation command group. + + Args: + operation: operation to construct command group + + Returns: + list: constructed operation command group + """ + if operation.get('run_on_groups') is None: + return None + return [{ + 'groupid': self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)['groupid'] + } for _group in operation.get('run_on_groups')] + + def _construct_opgroup(self, operation): + """Construct operation group. + + Args: + operation: operation to construct group + + Returns: + list: constructed operation group + """ + return [{ + 'groupid': self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)['groupid'] + } for _group in operation.get('host_groups', [])] + + def _construct_optemplate(self, operation): + """Construct operation template. + + Args: + operation: operation to construct template + + Returns: + list: constructed operation template + """ + return [{ + 'templateid': self._zapi_wrapper.get_template_by_template_name(_template)['templateid'] + } for _template in operation.get('templates', [])] + + def _construct_opinventory(self, operation): + """Construct operation inventory. + + Args: + operation: operation to construct inventory + + Returns: + dict: constructed operation inventory + """ + return { + 'inventory_mode': zabbix_utils.helper_to_numeric_value([ + 'manual', + 'automatic' + ], operation.get('inventory')) + } + + def _construct_opconditions(self, operation): + """Construct operation conditions. + + Args: + operation: operation to construct the conditions + + Returns: + list: constructed operation conditions + """ + _opcond = operation.get('operation_condition') + if _opcond is not None: + if _opcond == 'acknowledged': + _value = '1' + elif _opcond == 'not_acknowledged': + _value = '0' + return [{ + 'conditiontype': '14', + 'operator': '0', + 'value': _value + }] + return [] + + def construct_the_data(self, operations, event_source): + """Construct the operation data using helper methods. + + Args: + operation: operation to construct + + Returns: + list: constructed operation data + """ + constructed_data = [] + for op in operations: + operation_type = self._construct_operationtype(op) + constructed_operation = { + 'operationtype': operation_type, + 'esc_period': op.get('esc_period'), + 'esc_step_from': op.get('esc_step_from'), + 'esc_step_to': op.get('esc_step_to') + } + # Send Message type + if constructed_operation['operationtype'] == 0: + constructed_operation['opmessage'] = self._construct_opmessage(op) + constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op) + constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op) + if event_source == 'trigger': + # opconditions valid only for 'trigger' action + constructed_operation['opconditions'] = self._construct_opconditions(op) + + # Send Command type + if constructed_operation['operationtype'] == 1: + constructed_operation['opcommand'] = self._construct_opcommand(op) + constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op) + constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op) + if event_source == 'trigger': + # opconditions valid only for 'trigger' action + constructed_operation['opconditions'] = self._construct_opconditions(op) + + # Add to/Remove from host group + if constructed_operation['operationtype'] in (4, 5): + constructed_operation['opgroup'] = self._construct_opgroup(op) + + # Link/Unlink template + if constructed_operation['operationtype'] in (6, 7): + constructed_operation['optemplate'] = self._construct_optemplate(op) + + # Set inventory mode + if constructed_operation['operationtype'] == 10: + constructed_operation['opinventory'] = self._construct_opinventory(op) + + # Remove escalation params when for event sources where they are not applicable + if event_source in ['trigger', 'internal']: + if isinstance(constructed_operation.get('esc_period'), type(None)): + constructed_operation['esc_period'] = 0 + else: + constructed_operation.pop('esc_period') + constructed_operation.pop('esc_step_from') + constructed_operation.pop('esc_step_to') + + constructed_data.append(constructed_operation) + + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class RecoveryOperations(Operations): + """ + Restructures the user defined recovery operations data to fit the Zabbix API requirements + """ + def _construct_operationtype(self, operation): + """Construct operation type. + + Args: + operation: operation to construct type + + Returns: + str: constructed operation type + """ + try: + return zabbix_utils.helper_to_numeric_value([ + "send_message", + "remote_command", + None, + None, + None, + None, + None, + None, + None, + None, + None, + "notify_all_involved"], operation['type'] + ) + except Exception: + self._module.fail_json(msg="Unsupported value '%s' for recovery operation type." % operation['type']) + + def construct_the_data(self, operations): + """Construct the recovery operations data using helper methods. + + Args: + operation: operation to construct + + Returns: + list: constructed recovery operations data + """ + constructed_data = [] + for op in operations: + operation_type = self._construct_operationtype(op) + constructed_operation = { + 'operationtype': operation_type, + } + + # Send Message type + if constructed_operation['operationtype'] == 0: + constructed_operation['opmessage'] = self._construct_opmessage(op) + constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op) + constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op) + + if constructed_operation['operationtype'] == 11: + constructed_operation['opmessage'] = self._construct_opmessage(op) + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + constructed_operation['opmessage'].pop('mediatypeid') + + # Send Command type + if constructed_operation['operationtype'] == 1: + constructed_operation['opcommand'] = self._construct_opcommand(op) + constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op) + constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op) + + constructed_data.append(constructed_operation) + + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class AcknowledgeOperations(Operations): + """ + Restructures the user defined acknowledge operations data to fit the Zabbix API requirements + """ + def _construct_operationtype(self, operation): + """Construct operation type. + + Args: + operation: operation to construct type + + Returns: + str: constructed operation type + """ + try: + return zabbix_utils.helper_to_numeric_value([ + "send_message", + "remote_command", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "notify_all_involved"], operation['type'] + ) + except Exception: + self._module.fail_json(msg="Unsupported value '%s' for acknowledge operation type." % operation['type']) + + def construct_the_data(self, operations): + """Construct the acknowledge operations data using helper methods. + + Args: + operation: operation to construct + + Returns: + list: constructed acknowledge operations data + """ + constructed_data = [] + for op in operations: + operation_type = self._construct_operationtype(op) + constructed_operation = { + 'operationtype': operation_type, + } + + # Send Message type + if constructed_operation['operationtype'] == 0: + constructed_operation['opmessage'] = self._construct_opmessage(op) + constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op) + constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op) + + if constructed_operation['operationtype'] == 12: + constructed_operation['opmessage'] = self._construct_opmessage(op) + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + constructed_operation['opmessage'].pop('mediatypeid') + + # Send Command type + if constructed_operation['operationtype'] == 1: + constructed_operation['opcommand'] = self._construct_opcommand(op) + constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op) + constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op) + + constructed_data.append(constructed_operation) + + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class Filter(Zapi): + def _construct_evaltype(self, _eval_type, _formula, _conditions): + """Construct the eval type + + Args: + _formula: zabbix condition evaluation formula + _conditions: list of conditions to check + + Returns: + dict: constructed acknowledge operations data + """ + if len(_conditions) <= 1: + return { + 'evaltype': '0', + 'formula': None + } + if _eval_type == 'andor': + return { + 'evaltype': '0', + 'formula': None + } + if _eval_type == 'and': + return { + 'evaltype': '1', + 'formula': None + } + if _eval_type == 'or': + return { + 'evaltype': '2', + 'formula': None + } + if _eval_type == 'custom_expression': + if _formula is not None: + return { + 'evaltype': '3', + 'formula': _formula + } + else: + self._module.fail_json(msg="'formula' is required when 'eval_type' is set to 'custom_expression'") + if _formula is not None: + return { + 'evaltype': '3', + 'formula': _formula + } + return { + 'evaltype': '0', + 'formula': None + } + + def _construct_conditiontype(self, _condition): + """Construct the condition type + + Args: + _condition: condition to check + + Returns: + str: constructed condition type data + """ + # application is disabled is disabled for condition type since 5.4 version. + if (LooseVersion(self._zbx_api_version) >= LooseVersion('5.4') + and _condition['type'] == 'application'): + self._module.fail_json(msg="'%s' is disabled for condition type since 5.4 version." % _condition['type']) + + try: + return zabbix_utils.helper_to_numeric_value([ + "host_group", + "host", + "trigger", + "trigger_name", + "trigger_severity", + "trigger_value", + "time_period", + "host_ip", + "discovered_service_type", + "discovered_service_port", + "discovery_status", + "uptime_or_downtime_duration", + "received_value", + "host_template", + None, + "application", + "maintenance_status", + None, + "discovery_rule", + "discovery_check", + "proxy", + "discovery_object", + "host_name", + "event_type", + "host_metadata", + "event_tag", + "event_tag_value"], _condition['type'] + ) + except Exception: + self._module.fail_json(msg="Unsupported value '%s' for condition type." % _condition['type']) + + def _construct_operator(self, _condition): + """Construct operator + + Args: + _condition: condition to construct + + Returns: + str: constructed operator + """ + try: + return zabbix_utils.helper_to_numeric_value([ + ["equals", "="], + ["does not equal", "<>"], + ["contains", "like"], + ["does not contain", "not like"], + "in", + ["is greater than or equals", ">="], + ["is less than or equals", "<="], + "not in", + "matches", + "does not match", + "Yes", + "No"], _condition['operator'] + ) + except Exception: + self._module.fail_json(msg="Unsupported value '%s' for operator." % _condition['operator']) + + def _construct_value(self, conditiontype, value): + """Construct operator + + Args: + conditiontype: type of condition to construct + value: value to construct + + Returns: + str: constructed value + """ + try: + # Host group + if conditiontype == 0: + return self._zapi_wrapper.get_hostgroup_by_hostgroup_name(value)['groupid'] + # Host + if conditiontype == 1: + return self._zapi_wrapper.get_host_by_host_name(value)['hostid'] + # Trigger + if conditiontype == 2: + return self._zapi_wrapper.get_trigger_by_trigger_name(value)['triggerid'] + # Trigger name: return as is + # Trigger severity + if conditiontype == 4: + return zabbix_utils.helper_to_numeric_value([ + "not classified", + "information", + "warning", + "average", + "high", + "disaster"], value or "not classified" + ) + + # Trigger value + if conditiontype == 5: + return zabbix_utils.helper_to_numeric_value([ + "ok", + "problem"], value or "ok" + ) + # Time period: return as is + # Host IP: return as is + # Discovered service type + if conditiontype == 8: + return zabbix_utils.helper_to_numeric_value([ + "SSH", + "LDAP", + "SMTP", + "FTP", + "HTTP", + "POP", + "NNTP", + "IMAP", + "TCP", + "Zabbix agent", + "SNMPv1 agent", + "SNMPv2 agent", + "ICMP ping", + "SNMPv3 agent", + "HTTPS", + "Telnet"], value + ) + # Discovered service port: return as is + # Discovery status + if conditiontype == 10: + return zabbix_utils.helper_to_numeric_value([ + "up", + "down", + "discovered", + "lost"], value + ) + if conditiontype == 13: + return self._zapi_wrapper.get_template_by_template_name(value)['templateid'] + if LooseVersion(self._zapi_wrapper._zbx_api_version) >= LooseVersion('6.0'): + # maintenance_status + if conditiontype == 16: + return zabbix_utils.helper_to_numeric_value([ + "Yes", + "No"], value + ) + if conditiontype == 18: + return self._zapi_wrapper.get_discovery_rule_by_discovery_rule_name(value)['druleid'] + if conditiontype == 19: + return self._zapi_wrapper.get_discovery_check_by_discovery_check_name(value)['dcheckid'] + if conditiontype == 20: + return self._zapi_wrapper.get_proxy_by_proxy_name(value)['proxyid'] + if conditiontype == 21: + return zabbix_utils.helper_to_numeric_value([ + "pchldrfor0", + "host", + "service"], value + ) + if conditiontype == 23: + return zabbix_utils.helper_to_numeric_value([ + "item in not supported state", + "item in normal state", + "LLD rule in not supported state", + "LLD rule in normal state", + "trigger in unknown state", + "trigger in normal state"], value + ) + return value + except Exception: + self._module.fail_json( + msg="""Unsupported value '%s' for specified condition type. + Check out Zabbix API documentation for supported values for + condition type '%s' at + https://www.zabbix.com/documentation/3.4/manual/api/reference/action/object#action_filter_condition""" % (value, conditiontype) + ) + + def construct_the_data(self, _eval_type, _formula, _conditions): + """Construct the user defined filter conditions to fit the Zabbix API + requirements operations data using helper methods. + + Args: + _formula: zabbix condition evaluation formula + _conditions: conditions to construct + + Returns: + dict: user defined filter conditions + """ + if _conditions is None: + return None + constructed_data = {} + constructed_data['conditions'] = [] + for cond in _conditions: + condition_type = self._construct_conditiontype(cond) + constructed_data['conditions'].append({ + "conditiontype": condition_type, + "value": self._construct_value(condition_type, cond.get("value")), + "value2": cond.get("value2"), + "formulaid": cond.get("formulaid"), + "operator": self._construct_operator(cond) + }) + _constructed_evaltype = self._construct_evaltype( + _eval_type, + _formula, + constructed_data['conditions'] + ) + constructed_data['evaltype'] = _constructed_evaltype['evaltype'] + constructed_data['formula'] = _constructed_evaltype['formula'] + return zabbix_utils.helper_cleanup_data(constructed_data) + + +def main(): + """Main ansible module function + """ + + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + esc_period=dict(type='str', required=False), + name=dict(type='str', required=True), + event_source=dict(type='str', required=False, choices=['trigger', 'discovery', 'auto_registration', 'internal']), + state=dict(type='str', required=False, default='present', choices=['present', 'absent']), + status=dict(type='str', required=False, default='enabled', choices=['enabled', 'disabled']), + pause_in_maintenance=dict(type='bool', required=False, default=True), + default_message=dict(type='str', required=False, default=''), + default_subject=dict(type='str', required=False, default=''), + recovery_default_message=dict(type='str', required=False, default=''), + recovery_default_subject=dict(type='str', required=False, default=''), + acknowledge_default_message=dict(type='str', required=False, default=''), + acknowledge_default_subject=dict(type='str', required=False, default=''), + conditions=dict( + type='list', + required=False, + default=[], + elements='dict', + options=dict( + formulaid=dict(type='str', required=False), + operator=dict(type='str', required=True), + type=dict(type='str', required=True), + value=dict(type='str', required=False), + value2=dict(type='str', required=False) + ), + required_if=[ + ['type', 'event_tag_value', ['value2']], + ] + ), + formula=dict(type='str', required=False, default=None), + eval_type=dict(type='str', required=False, default=None, choices=['andor', 'and', 'or', 'custom_expression']), + operations=dict( + type='list', + required=False, + default=[], + elements='dict', + options=dict( + type=dict( + type='str', + required=True, + choices=[ + 'send_message', + 'remote_command', + 'add_host', + 'remove_host', + 'add_to_host_group', + 'remove_from_host_group', + 'link_to_template', + 'unlink_from_template', + 'enable_host', + 'disable_host', + 'set_host_inventory_mode', + ] + ), + esc_period=dict(type='str', required=False), + esc_step_from=dict(type='int', required=False, default=1), + esc_step_to=dict(type='int', required=False, default=1), + operation_condition=dict( + type='str', + required=False, + default=None, + choices=['acknowledged', 'not_acknowledged'] + ), + # when type is remote_command + command_type=dict( + type='str', + required=False, + choices=[ + 'custom_script', + 'ipmi', + 'ssh', + 'telnet', + 'global_script' + ] + ), + command=dict(type='str', required=False), + execute_on=dict( + type='str', + required=False, + choices=['agent', 'server', 'proxy'] + ), + password=dict(type='str', required=False, no_log=True), + port=dict(type='int', required=False), + run_on_groups=dict(type='list', required=False), + run_on_hosts=dict(type='list', required=False), + script_name=dict(type='str', required=False), + ssh_auth_type=dict(type='str', required=False, choices=['password', 'public_key']), + ssh_privatekey_file=dict(type='str', required=False), + ssh_publickey_file=dict(type='str', required=False), + username=dict(type='str', required=False), + # when type is send_message + media_type=dict(type='str', required=False), + subject=dict(type='str', required=False), + message=dict(type='str', required=False), + send_to_groups=dict(type='list', required=False), + send_to_users=dict(type='list', required=False), + # when type is add_to_host_group or remove_from_host_group + host_groups=dict(type='list', required=False), + # when type is set_host_inventory_mode + inventory=dict(type='str', required=False, choices=['manual', 'automatic']), + # when type is link_to_template or unlink_from_template + templates=dict(type='list', required=False) + ), + required_if=[ + ['type', 'remote_command', ['command_type']], + ['type', 'remote_command', ['run_on_groups', 'run_on_hosts'], True], + ['command_type', 'custom_script', ['command', 'execute_on']], + ['command_type', 'ipmi', ['command']], + ['command_type', 'ssh', ['command', 'ssh_auth_type']], + ['ssh_auth_type', 'password', ['username', 'password']], + ['ssh_auth_type', 'public_key', ['username', 'ssh_privatekey_file', 'ssh_publickey_file']], + ['command_type', 'telnet', ['command', 'username', 'password']], + ['command_type', 'global_script', ['script_name']], + ['type', 'add_to_host_group', ['host_groups']], + ['type', 'remove_from_host_group', ['host_groups']], + ['type', 'link_to_template', ['templates']], + ['type', 'unlink_from_template', ['templates']], + ['type', 'set_host_inventory_mode', ['inventory']], + ['type', 'send_message', ['send_to_users', 'send_to_groups'], True] + ] + ), + recovery_operations=dict( + type='list', + required=False, + default=[], + elements='dict', + options=dict( + type=dict( + type='str', + required=True, + choices=[ + 'send_message', + 'remote_command', + 'notify_all_involved' + ] + ), + # when type is remote_command + command_type=dict( + type='str', + required=False, + choices=[ + 'custom_script', + 'ipmi', + 'ssh', + 'telnet', + 'global_script' + ] + ), + command=dict(type='str', required=False), + execute_on=dict( + type='str', + required=False, + choices=['agent', 'server', 'proxy'] + ), + password=dict(type='str', required=False, no_log=True), + port=dict(type='int', required=False), + run_on_groups=dict(type='list', required=False), + run_on_hosts=dict(type='list', required=False), + script_name=dict(type='str', required=False), + ssh_auth_type=dict(type='str', required=False, choices=['password', 'public_key']), + ssh_privatekey_file=dict(type='str', required=False), + ssh_publickey_file=dict(type='str', required=False), + username=dict(type='str', required=False), + # when type is send_message + media_type=dict(type='str', required=False), + subject=dict(type='str', required=False), + message=dict(type='str', required=False), + send_to_groups=dict(type='list', required=False), + send_to_users=dict(type='list', required=False), + ), + required_if=[ + ['type', 'remote_command', ['command_type']], + ['type', 'remote_command', [ + 'run_on_groups', + 'run_on_hosts' + ], True], + ['command_type', 'custom_script', [ + 'command', + 'execute_on' + ]], + ['command_type', 'ipmi', ['command']], + ['command_type', 'ssh', ['command', 'ssh_auth_type']], + ['ssh_auth_type', 'password', ['username', 'password']], + ['ssh_auth_type', 'public_key', ['username', 'ssh_privatekey_file', 'ssh_publickey_file']], + ['command_type', 'telnet', ['command', 'username', 'password']], + ['command_type', 'global_script', ['script_name']], + ['type', 'send_message', ['send_to_users', 'send_to_groups'], True] + ] + ), + acknowledge_operations=dict( + type='list', + required=False, + default=[], + elements='dict', + aliases=['update_operations'], + options=dict( + type=dict( + type='str', + required=True, + choices=[ + 'send_message', + 'remote_command', + 'notify_all_involved' + ] + ), + # when type is remote_command + command_type=dict( + type='str', + required=False, + choices=[ + 'custom_script', + 'ipmi', + 'ssh', + 'telnet', + 'global_script' + ] + ), + command=dict(type='str', required=False), + execute_on=dict( + type='str', + required=False, + choices=['agent', 'server', 'proxy'] + ), + password=dict(type='str', required=False, no_log=True), + port=dict(type='int', required=False), + run_on_groups=dict(type='list', required=False), + run_on_hosts=dict(type='list', required=False), + script_name=dict(type='str', required=False), + ssh_auth_type=dict(type='str', required=False, choices=['password', 'public_key']), + ssh_privatekey_file=dict(type='str', required=False), + ssh_publickey_file=dict(type='str', required=False), + username=dict(type='str', required=False), + # when type is send_message + media_type=dict(type='str', required=False), + subject=dict(type='str', required=False), + message=dict(type='str', required=False), + send_to_groups=dict(type='list', required=False), + send_to_users=dict(type='list', required=False), + ), + required_if=[ + ['type', 'remote_command', ['command_type']], + ['type', 'remote_command', [ + 'run_on_groups', + 'run_on_hosts' + ], True], + ['command_type', 'custom_script', [ + 'command', + 'execute_on' + ]], + ['command_type', 'ipmi', ['command']], + ['command_type', 'ssh', ['command', 'ssh_auth_type']], + ['ssh_auth_type', 'password', ['username', 'password']], + ['ssh_auth_type', 'public_key', ['username', 'ssh_privatekey_file', 'ssh_publickey_file']], + ['command_type', 'telnet', ['command', 'username', 'password']], + ['command_type', 'global_script', ['script_name']], + ['type', 'send_message', ['send_to_users', 'send_to_groups'], True] + ] + ), + pause_symptoms=dict(type='bool', required=False, default=True) + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ['state', 'present', [ + 'event_source' + ]] + ], + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + name = module.params['name'] + esc_period = module.params['esc_period'] + event_source = module.params['event_source'] + state = module.params['state'] + status = module.params['status'] + pause_in_maintenance = module.params['pause_in_maintenance'] + default_message = module.params['default_message'] + default_subject = module.params['default_subject'] + recovery_default_message = module.params['recovery_default_message'] + recovery_default_subject = module.params['recovery_default_subject'] + acknowledge_default_message = module.params['acknowledge_default_message'] + acknowledge_default_subject = module.params['acknowledge_default_subject'] + conditions = module.params['conditions'] + formula = module.params['formula'] + eval_type = module.params['eval_type'] + operations = module.params['operations'] + recovery_operations = module.params['recovery_operations'] + acknowledge_operations = module.params['acknowledge_operations'] + pause_symptoms = module.params['pause_symptoms'] + + zapi_wrapper = Zapi(module) + action = Action(module) + + action_exists = zapi_wrapper.check_if_action_exists(name) + ops = Operations(module, zapi_wrapper) + recovery_ops = RecoveryOperations(module, zapi_wrapper) + acknowledge_ops = AcknowledgeOperations(module, zapi_wrapper) + fltr = Filter(module, zapi_wrapper) + + if action_exists: + action_id = zapi_wrapper.get_action_by_name(name)['actionid'] + if state == "absent": + result = action.delete_action(action_id) + module.exit_json(changed=True, msg="Action Deleted: %s, ID: %s" % (name, result)) + else: + kwargs = dict( + action_id=action_id, + name=name, + event_source=event_source, + esc_period=esc_period, + status=status, + pause_in_maintenance=pause_in_maintenance, + default_message=default_message, + default_subject=default_subject, + recovery_default_message=recovery_default_message, + recovery_default_subject=recovery_default_subject, + acknowledge_default_message=acknowledge_default_message, + acknowledge_default_subject=acknowledge_default_subject, + operations=ops.construct_the_data(operations, event_source), + recovery_operations=recovery_ops.construct_the_data(recovery_operations), + conditions=fltr.construct_the_data(eval_type, formula, conditions) + ) + + if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.4'): + kwargs['pause_symptoms'] = pause_symptoms + + if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.0'): + kwargs[argument_spec['acknowledge_operations']['aliases'][0]] = acknowledge_ops.construct_the_data(acknowledge_operations) + else: + kwargs['acknowledge_operations'] = acknowledge_ops.construct_the_data(acknowledge_operations) + + difference = action.check_difference(**kwargs) + + if difference == {}: + module.exit_json(changed=False, msg="Action is up to date: %s" % (name)) + else: + result = action.update_action( + action_id=action_id, + **difference + ) + module.exit_json(changed=True, msg="Action Updated: %s, ID: %s" % (name, result)) + else: + if state == "absent": + module.exit_json(changed=False) + else: + kwargs = dict( + name=name, + event_source=event_source, + esc_period=esc_period, + status=status, + pause_in_maintenance=pause_in_maintenance, + default_message=default_message, + default_subject=default_subject, + recovery_default_message=recovery_default_message, + recovery_default_subject=recovery_default_subject, + acknowledge_default_message=acknowledge_default_message, + acknowledge_default_subject=acknowledge_default_subject, + operations=ops.construct_the_data(operations, event_source), + recovery_operations=recovery_ops.construct_the_data(recovery_operations), + conditions=fltr.construct_the_data(eval_type, formula, conditions) + ) + + if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.0'): + kwargs[argument_spec['acknowledge_operations']['aliases'][0]] = acknowledge_ops.construct_the_data(acknowledge_operations) + else: + kwargs['acknowledge_operations'] = acknowledge_ops.construct_the_data(acknowledge_operations) + + if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.4'): + kwargs['pause_symptoms'] = pause_symptoms + + action_id = action.add_action(**kwargs) + module.exit_json(changed=True, msg="Action created: %s, ID: %s" % (name, action_id)) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py new file mode 100644 index 000000000..51fb3e5b9 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py @@ -0,0 +1,812 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright: (c) 2022, ONODERA Masaru <masaru-onodera@ieee.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: zabbix_authentication + +short_description: Update Zabbix authentication + +description: + - This module allows you to modify Zabbix authentication setting. + +author: + - ONODERA Masaru(@masa-orca) + +requirements: + - "python >= 2.6" + +version_added: 1.6.0 + +options: + authentication_type: + description: + - Choose default authentication type. + required: false + type: str + choices: [ "internal", "ldap" ] + http_auth_enabled: + description: + - HTTP authentication will be enabled if C(true). + required: false + type: bool + http_login_form: + description: + - Choose default login form. + required: false + type: str + choices: [ "zabbix_login_form", "http_login_form" ] + http_strip_domains: + description: + - A list of domain names that should be removed from the username. + required: false + type: list + elements: str + http_case_sensitive: + description: + - Case sensitive login for HTTP authentication will be enabled if C(true). + required: false + type: bool + ldap_configured: + description: + - LDAP authentication will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + - Removed in Zabbix 6.4 + required: false + type: bool + ldap_auth_enabled: + description: + - LDAP authentication will be enabled if C(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + ldap_host: + description: + - LDAP server name. + - e.g. C(ldap://ldap.zabbix.com) + - This setting is required if current value of I(ldap_configured) is C(false). + - Works only with Zabbix <= 6.0 and is silently ignored in higher versions. + required: false + type: str + ldap_port: + description: + - A port number of LDAP server. + - This setting is required if current value of I(ldap_configured) is C(false). + - Works only with Zabbix <= 6.0 and is silently ignored in higher versions. + required: false + type: int + ldap_base_dn: + description: + - Base DN of LDAP. + - This setting is required if current value of I(ldap_configured) is C(false). + - Works only with Zabbix <= 6.0 and is silently ignored in higher versions. + required: false + type: str + ldap_search_attribute: + description: + - Search attribute of LDAP. + - This setting is required if current value of I(ldap_configured) is C(false). + - Works only with Zabbix <= 6.0 and is silently ignored in higher versions. + required: false + type: str + ldap_bind_dn: + description: + - Bind DN of LDAP. + - Works only with Zabbix <= 6.0 and is silently ignored in higher versions. + required: false + type: str + ldap_case_sensitive: + description: + - case sensitive login for LDAP authentication will be enabled if C(true). + required: false + type: bool + ldap_bind_password: + description: + - Bind password of LDAP. + - Works only with Zabbix <= 6.0 and is silently ignored in higher versions. + required: false + type: str + ldap_userdirectory: + description: + - LDAP authentication default user directory name for user groups with gui_access set to LDAP or System default. + - Required to be set when C(ldap_configured) / C(ldap_auth_enabled) is set to 1. + required: false + type: str + ldap_jit_status: + description: + - Status of LDAP provisioning. + - This parameter is available since Zabbix 6.4. + required: false + type: bool + jit_provision_interval: + description: + - Time interval between JIT provision requests for logged-in user. + - Accepts seconds and time unit with suffix with month and year support (3600s,60m,1h,1d,1M,1y). Minimum value 1h. + - Available only for LDAP provisioning. + - This parameter is available since Zabbix 6.4. + required: false + type: str + default: 1h + disabled_usrgroup: + description: + - User group name to assign the deprovisioned user to. + - The user group must be disabled and cannot be enabled or deleted when configured. + - Required if C(ldap_jit_status) for C(saml_jit_status) enabled. + - This parameter is available since Zabbix 6.4. + required: false + type: str + saml_auth_enabled: + description: + - SAML authentication will be enabled if C(true). + required: false + type: bool + saml_idp_entityid: + description: + - SAML identify provider's entity ID. + - This setting is required if current value of I(saml_auth_enabled) is C(false). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: str + saml_sso_url: + description: + - URL for single sign on service of SAML. + - This setting is required if current value of I(saml_auth_enabled) is C(false). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: str + saml_slo_url: + description: + - URL for SAML single logout service. + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: str + saml_username_attribute: + description: + - User name attribute of SAML. + - This setting is required if current value of I(saml_auth_enabled) is C(false). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: str + saml_sp_entityid: + description: + - Entity ID of SAML service provider. + - This setting is required if current value of I(saml_auth_enabled) is C(false). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: str + saml_nameid_format: + description: + - Name identifier format of SAML service provider. + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: str + saml_sign_messages: + description: + - SAML sign messages will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_sign_assertions: + description: + - SAML sign assertions will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_sign_authn_requests: + description: + - SAML sign AuthN requests will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_sign_logout_requests: + description: + - SAML sign logout requests will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_sign_logout_responses: + description: + - SAML sign logout responses will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_encrypt_nameid: + description: + - SAML encrypt name ID will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_encrypt_assertions: + description: + - SAML encrypt assertions will be enabled if C(true). + - Works only with Zabbix <= 6.2 and is silently ignored in higher versions. + required: false + type: bool + saml_case_sensitive: + description: + - Case sensitive login for SAML authentication will be enabled if C(true). + required: false + type: bool + saml_jit_status: + description: + - Status of SAML provisioning. + - This parameter is available since Zabbix 6.4. + required: false + type: bool + passwd_min_length: + description: + - Minimal length of password. + - Choose from 1-70. + - This parameter is available since Zabbix 6.0. + required: false + type: int + passwd_check_rules: + description: + - Checking password rules. + - Select multiple from C(contain_uppercase_and_lowercase_letters), + C(contain_digits). C(contain_special_characters) and C(avoid_easy_to_guess). + - This parameter is available since Zabbix 6.0. + required: false + type: list + elements: str + +notes: + - Zabbix 5.4 version and higher are supported. + +extends_documentation_fragment: + - community.zabbix.zabbix +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Update all authentication setting (Zabbix <= 6.0) + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: + - comp + - any + http_case_sensitive: true + ldap_configured: true + ldap_host: 'ldap://localhost' + ldap_port: 389 + ldap_base_dn: 'ou=Users,ou=system' + ldap_search_attribute: 'uid' + ldap_bind_dn: 'uid=ldap_search,ou=system' + ldap_case_sensitive: true + ldap_bind_password: 'password' + saml_auth_enabled: true + saml_idp_entityid: '' + saml_sso_url: 'https://localhost/SAML2/SSO' + saml_slo_url: 'https://localhost/SAML2/SLO' + saml_username_attribute: 'uid' + saml_sp_entityid: 'https://localhost' + saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' + saml_sign_messages: true + saml_sign_assertions: true + saml_sign_authn_requests: true + saml_sign_logout_requests: true + saml_sign_logout_responses: true + saml_encrypt_nameid: true + saml_encrypt_assertions: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + +- name: Update all authentication setting (Zabbix = 6.2) + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: + - comp + - any + http_case_sensitive: true + ldap_configured: true + ldap_case_sensitive: true + saml_auth_enabled: true + saml_idp_entityid: '' + saml_sso_url: 'https://localhost/SAML2/SSO' + saml_slo_url: 'https://localhost/SAML2/SLO' + saml_username_attribute: 'uid' + saml_sp_entityid: 'https://localhost' + saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' + saml_sign_messages: true + saml_sign_assertions: true + saml_sign_authn_requests: true + saml_sign_logout_requests: true + saml_sign_logout_responses: true + saml_encrypt_nameid: true + saml_encrypt_assertions: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + +- name: Update all authentication setting (Zabbix >= 6.4) + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: + - comp + - any + http_case_sensitive: true + ldap_auth_enabled: true + ldap_case_sensitive: true + saml_auth_enabled: true + saml_case_sensitive: true + ldap_jit_status: true + saml_jit_status: true + jit_provision_interval: 1h + disabled_usrgrp: Disabled + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess +''' + +RETURN = ''' +msg: + description: The result of the operation + returned: success + type: str + sample: 'Successfully update authentication setting' +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Authentication(ZabbixBase): + def __init__(self, module, zbx=None, zapi_wrapper=None): + super(Authentication, self).__init__(module, zbx, zapi_wrapper) + if LooseVersion(self._zbx_api_version) < LooseVersion('5.4.0'): + module.fail_json(msg="This module doesn't support Zabbix versions lower than 5.4.0") + + # get authentication setting + def get_authentication(self): + try: + return self._zapi.authentication.get({'output': 'extend'}) + except Exception as e: + self._module.fail_json(msg="Failed to get authentication setting: %s" % e) + + # update authentication setting + def update_authentication( + self, + current_authentication, + authentication_type, + http_auth_enabled, + http_login_form, + http_strip_domains, + http_case_sensitive, + ldap_configured, + ldap_auth_enabled, + ldap_host, + ldap_port, + ldap_base_dn, + ldap_search_attribute, + ldap_bind_dn, + ldap_case_sensitive, + ldap_bind_password, + ldap_userdirectory, + saml_auth_enabled, + saml_idp_entityid, + saml_sso_url, + saml_slo_url, + saml_username_attribute, + saml_sp_entityid, + saml_nameid_format, + saml_sign_messages, + saml_sign_assertions, + saml_sign_authn_requests, + saml_sign_logout_requests, + saml_sign_logout_responses, + saml_encrypt_nameid, + saml_encrypt_assertions, + saml_case_sensitive, + passwd_min_length, + passwd_check_rules, + ldap_jit_status, + saml_jit_status, + jit_provision_interval, + disabled_usrgroup): + try: + params = {} + + if authentication_type: + params['authentication_type'] = str(zabbix_utils.helper_to_numeric_value( + ['internal', 'ldap'], + authentication_type + )) + + if isinstance(http_auth_enabled, bool): + params['http_auth_enabled'] = str(int(http_auth_enabled)) + + if http_login_form: + params['http_login_form'] = str(zabbix_utils.helper_to_numeric_value( + ['zabbix_login_form', 'http_login_form'], + http_login_form + )) + + if http_strip_domains: + params['http_strip_domains'] = ','.join(http_strip_domains) + + if isinstance(http_case_sensitive, bool): + params['http_case_sensitive'] = str(int(http_case_sensitive)) + + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + if isinstance(ldap_configured, bool): + params['ldap_configured'] = str(int(ldap_configured)) + else: + if isinstance(ldap_auth_enabled, bool): + params['ldap_auth_enabled'] = str(int(ldap_auth_enabled)) + + if LooseVersion(self._zbx_api_version) < LooseVersion('6.2.0'): + if ldap_host: + params['ldap_host'] = ldap_host + + if ldap_port: + params['ldap_port'] = str(ldap_port) + + if ldap_base_dn: + params['ldap_base_dn'] = ldap_base_dn + + if ldap_search_attribute: + params['ldap_search_attribute'] = ldap_search_attribute + + if ldap_bind_dn: + params['ldap_bind_dn'] = ldap_bind_dn + + if ldap_bind_password: + params['ldap_bind_password'] = ldap_bind_password + else: + if ldap_userdirectory: + directory = self._zapi.userdirectory.get({'search': {'name': ldap_userdirectory}}) + if not directory: + self._module.fail_json(msg="Canot find user directory with name: %s" % ldap_userdirectory) + params['ldap_userdirectoryid'] = directory[0]['userdirectoryid'] + + if isinstance(ldap_case_sensitive, bool): + params['ldap_case_sensitive'] = str(int(ldap_case_sensitive)) + + if isinstance(saml_auth_enabled, bool): + params['saml_auth_enabled'] = str(int(saml_auth_enabled)) + + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + if saml_idp_entityid: + params['saml_idp_entityid'] = saml_idp_entityid + + if saml_sso_url: + params['saml_sso_url'] = saml_sso_url + + if saml_slo_url: + params['saml_slo_url'] = saml_slo_url + + if saml_username_attribute: + params['saml_username_attribute'] = saml_username_attribute + + if saml_sp_entityid: + params['saml_sp_entityid'] = saml_sp_entityid + + if saml_nameid_format: + params['saml_nameid_format'] = saml_nameid_format + + if isinstance(saml_sign_messages, bool): + params['saml_sign_messages'] = str(int(saml_sign_messages)) + + if isinstance(saml_sign_assertions, bool): + params['saml_sign_assertions'] = str(int(saml_sign_assertions)) + + if isinstance(saml_sign_authn_requests, bool): + params['saml_sign_authn_requests'] = str(int(saml_sign_authn_requests)) + + if isinstance(saml_sign_logout_requests, bool): + params['saml_sign_logout_requests'] = str(int(saml_sign_logout_requests)) + + if isinstance(saml_sign_logout_responses, bool): + params['saml_sign_logout_responses'] = str(int(saml_sign_logout_responses)) + + if isinstance(saml_encrypt_nameid, bool): + params['saml_encrypt_nameid'] = str(int(saml_encrypt_nameid)) + + if isinstance(saml_encrypt_assertions, bool): + params['saml_encrypt_assertions'] = str(int(saml_encrypt_assertions)) + + if isinstance(saml_case_sensitive, bool): + params['saml_case_sensitive'] = str(int(saml_case_sensitive)) + else: + if isinstance(ldap_jit_status, bool): + params['ldap_jit_status'] = str(int(ldap_jit_status)) + + if isinstance(saml_jit_status, bool): + params['saml_jit_status'] = str(int(saml_jit_status)) + + if isinstance(jit_provision_interval, str): + params['jit_provision_interval'] = jit_provision_interval + + if isinstance(disabled_usrgroup, str): + usrgrpids = self._zapi.usergroup.get({'filter': {'name': disabled_usrgroup}}) + if not usrgrpids: + self._module.fail_json('User group "%s" cannot be found' % disabled_usrgroup) + params['disabled_usrgrpid'] = str(int(usrgrpids[0]['usrgrpid'])) + + if (ldap_jit_status or saml_jit_status) and not disabled_usrgroup: + self._module.fail_json('"disabled_usrgroup" must be provided if "ldap_jit_status" or "saml_jit_status" enabled') + + if passwd_min_length: + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + self._module.warn('passwd_min_length is ignored with Zabbix 5.4.') + elif passwd_min_length < 1 or passwd_min_length > 70: + self._module.fail_json(msg="Please set 0-70 to passwd_min_length.") + else: + params['passwd_min_length'] = str(passwd_min_length) + + if passwd_check_rules: + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + self._module.warn('passwd_check_rules is ignored with Zabbix 5.4.') + else: + passwd_check_rules_values = [ + 'contain_uppercase_and_lowercase_letters', + 'contain_digits', + 'contain_special_characters', + 'avoid_easy_to_guess' + ] + params['passwd_check_rules'] = 0 + if isinstance(passwd_check_rules, str): + if passwd_check_rules not in passwd_check_rules_values: + self._module.fail_json(msg="%s is invalid value for passwd_check_rules." % passwd_check_rules) + params['passwd_check_rules'] += 2 ** zabbix_utils.helper_to_numeric_value( + passwd_check_rules_values, passwd_check_rules + ) + elif isinstance(passwd_check_rules, list): + for _passwd_check_rules_value in passwd_check_rules: + if _passwd_check_rules_value not in passwd_check_rules_values: + self._module.fail_json(msg="%s is invalid value for passwd_check_rules." % _passwd_check_rules_value) + params['passwd_check_rules'] += 2 ** zabbix_utils.helper_to_numeric_value( + passwd_check_rules_values, _passwd_check_rules_value + ) + + params['passwd_check_rules'] = str(params['passwd_check_rules']) + + future_authentication = current_authentication.copy() + future_authentication.update(params) + + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + if (current_authentication['ldap_configured'] == '0' + and future_authentication['ldap_configured'] == '1'): + if LooseVersion(self._zbx_api_version) < LooseVersion('6.2.0'): + if (not ldap_host + or not ldap_port + or not ldap_search_attribute + or not ldap_base_dn): + self._module.fail_json( + msg="Please set ldap_host, ldap_search_attribute and ldap_base_dn when you change a value of ldap_configured to true." + ) + else: + if not ldap_userdirectory: + self._module.fail_json(msg="Please set ldap_userdirectory when you change a value of ldap_configured to true.") + else: + if (current_authentication['ldap_auth_enabled'] == "0" + and future_authentication['ldap_auth_enabled'] == "1"): + if not ldap_userdirectory: + self._module.fail_json(msg="Please set ldap_userdirectory when you change a value of ldap_auth_enabled to true.") + + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + if (current_authentication['saml_auth_enabled'] == '0' + and future_authentication['saml_auth_enabled'] == '1' + and not saml_idp_entityid + and not saml_sso_url + and not saml_username_attribute + and not saml_sp_entityid): + self._module.fail_json( + msg=' '.join([ + "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid", + "when you change a value of saml_auth_enabled to true." + ]) + ) + + if future_authentication != current_authentication: + if self._module.check_mode: + self._module.exit_json(changed=True) + + self._zapi.authentication.update(params) + self._module.exit_json(changed=True, result="Successfully update authentication setting") + else: + self._module.exit_json(changed=False, result="Authentication setting is already up to date") + except Exception as e: + self._module.fail_json(msg="Failed to update authentication setting, Exception: %s" % e) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + authentication_type=dict(type='str', choices=['internal', 'ldap']), + http_auth_enabled=dict(type='bool'), + http_login_form=dict(type='str', choices=['zabbix_login_form', 'http_login_form']), + http_strip_domains=dict(type='list', elements='str'), + http_case_sensitive=dict(type='bool'), + ldap_configured=dict(type='bool'), + ldap_auth_enabled=dict(type='bool'), + ldap_host=dict(type='str'), + ldap_port=dict(type='int'), + ldap_base_dn=dict(type='str'), + ldap_search_attribute=dict(type='str'), + ldap_bind_dn=dict(type='str'), + ldap_case_sensitive=dict(type='bool'), + ldap_bind_password=dict(type='str', no_log=True), + ldap_userdirectory=dict(type='str'), + ldap_jit_status=dict(type='bool'), + saml_auth_enabled=dict(type='bool'), + saml_idp_entityid=dict(type='str'), + saml_sso_url=dict(type='str'), + saml_slo_url=dict(type='str'), + saml_username_attribute=dict(type='str'), + saml_sp_entityid=dict(type='str'), + saml_nameid_format=dict(type='str'), + saml_sign_messages=dict(type='bool'), + saml_sign_assertions=dict(type='bool'), + saml_sign_authn_requests=dict(type='bool'), + saml_sign_logout_requests=dict(type='bool'), + saml_sign_logout_responses=dict(type='bool'), + saml_encrypt_nameid=dict(type='bool'), + saml_encrypt_assertions=dict(type='bool'), + saml_case_sensitive=dict(type='bool'), + saml_jit_status=dict(type='bool'), + jit_provision_interval=dict(type='str', default='1h'), + disabled_usrgroup=dict(type='str'), + passwd_min_length=dict(type='int', no_log=False), + passwd_check_rules=dict(type='list', elements='str', no_log=False) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + authentication_type = module.params['authentication_type'] + http_auth_enabled = module.params['http_auth_enabled'] + http_login_form = module.params['http_login_form'] + http_strip_domains = module.params['http_strip_domains'] + http_case_sensitive = module.params['http_case_sensitive'] + ldap_configured = module.params['ldap_configured'] + ldap_auth_enabled = module.params['ldap_auth_enabled'] + ldap_host = module.params['ldap_host'] + ldap_port = module.params['ldap_port'] + ldap_base_dn = module.params['ldap_base_dn'] + ldap_search_attribute = module.params['ldap_search_attribute'] + ldap_bind_dn = module.params['ldap_bind_dn'] + ldap_case_sensitive = module.params['ldap_case_sensitive'] + ldap_bind_password = module.params['ldap_bind_password'] + ldap_userdirectory = module.params['ldap_userdirectory'] + saml_auth_enabled = module.params['saml_auth_enabled'] + saml_idp_entityid = module.params['saml_idp_entityid'] + saml_sso_url = module.params['saml_sso_url'] + saml_slo_url = module.params['saml_slo_url'] + saml_username_attribute = module.params['saml_username_attribute'] + saml_sp_entityid = module.params['saml_sp_entityid'] + saml_nameid_format = module.params['saml_nameid_format'] + saml_sign_messages = module.params['saml_sign_messages'] + saml_sign_assertions = module.params['saml_sign_assertions'] + saml_sign_authn_requests = module.params['saml_sign_authn_requests'] + saml_sign_logout_requests = module.params['saml_sign_logout_requests'] + saml_sign_logout_responses = module.params['saml_sign_logout_responses'] + saml_encrypt_nameid = module.params['saml_encrypt_nameid'] + saml_encrypt_assertions = module.params['saml_encrypt_assertions'] + saml_case_sensitive = module.params['saml_case_sensitive'] + passwd_min_length = module.params['passwd_min_length'] + passwd_check_rules = module.params['passwd_check_rules'] + ldap_jit_status = module.params['ldap_jit_status'] + saml_jit_status = module.params['saml_jit_status'] + jit_provision_interval = module.params['jit_provision_interval'] + disabled_usrgroup = module.params['disabled_usrgroup'] + + authentication = Authentication(module) + + current_authentication = authentication.get_authentication() + authentication.update_authentication( + current_authentication, + authentication_type, + http_auth_enabled, + http_login_form, + http_strip_domains, + http_case_sensitive, + ldap_configured, + ldap_auth_enabled, + ldap_host, + ldap_port, + ldap_base_dn, + ldap_search_attribute, + ldap_bind_dn, + ldap_case_sensitive, + ldap_bind_password, + ldap_userdirectory, + saml_auth_enabled, + saml_idp_entityid, + saml_sso_url, + saml_slo_url, + saml_username_attribute, + saml_sp_entityid, + saml_nameid_format, + saml_sign_messages, + saml_sign_assertions, + saml_sign_authn_requests, + saml_sign_logout_requests, + saml_sign_logout_responses, + saml_encrypt_nameid, + saml_encrypt_assertions, + saml_case_sensitive, + passwd_min_length, + passwd_check_rules, + ldap_jit_status, + saml_jit_status, + jit_provision_interval, + disabled_usrgroup + ) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py new file mode 100644 index 000000000..c8bf35538 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py @@ -0,0 +1,223 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: zabbix_autoregister + +short_description: Update Zabbix autoregistration + + +description: + - This module allows you to modify Zabbix autoregistration. + +author: + - ONODERA Masaru(@masa-orca) + +requirements: + - "python >= 2.6" + +version_added: 1.6.0 + +options: + tls_accept: + description: + - Type of allowed incoming connections for autoregistration. + - Choose from C(unsecure), C(tls_with_psk) or both. + type: list + elements: str + required: true + tls_psk_identity: + description: + - TLS connection uses this PSK identity string. + - The PSK identity string will be transmitted unencrypted over the network. Therefore, you should not put any sensitive information here. + - This setting requires I(tls_accept=tls_with_psk) if current value of I(tls_accept) is C(unsecure). + type: str + tls_psk: + description: + - TLS connection uses this PSK value. + - This setting requires I(tls_accept=tls_with_psk) if current value of I(tls_accept) is C(unsecure). + type: str + +notes: + - Only Zabbix >= 4.4 is supported. + - This module returns changed=true when any value is set in I(tls_psk_identity) or I(tls_psk) as Zabbix API + will not return any sensitive information back for module to compare. + - Please note that this module configures B(global Zabbix Server settings). + If you want to create autoregistration action so your hosts can automatically add themselves + to the monitoring have a look at M(community.zabbix.zabbix_action). + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Update autoregistration + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_autoregister: + server_url: "http://zabbix.example.com/zabbix/" + login_user: Admin + login_password: secret + tls_accept: + - unsecure + - tls_with_psk + tls_psk_identity: 'PSK 001' + tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478" + +- name: Set unsecure to tls_accept + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_autoregister: + server_url: "http://zabbix.example.com/zabbix/" + login_user: Admin + login_password: secret + tls_accept: unsecure +''' + +RETURN = ''' +msg: + description: The result of the operation + returned: success + type: str + sample: 'Successfully updated global autoregistration setting' +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Autoregistration(ZabbixBase): + def __init__(self, module, zbx=None, zapi_wrapper=None): + super(Autoregistration, self).__init__(module, zbx, zapi_wrapper) + if LooseVersion(self._zbx_api_version) < LooseVersion('4.4.0'): + module.fail_json(msg="This module doesn't support Zabbix versions lower than 4.4.0") + + # get autoregistration + def get_autoregistration(self): + try: + return self._zapi.autoregistration.get({"output": 'extend'}) + except Exception as e: + self._module.fail_json(msg="Failed to get autoregistration: %s" % e) + + # update autoregistration + def update_autoregistration(self, current_setting, tls_accept, tls_psk_identity, tls_psk): + tls_accept_values = [ + None, + 'unsecure', + 'tls_with_psk' + ] + params = {} + try: + if isinstance(tls_accept, str): + params['tls_accept'] = zabbix_utils.helper_to_numeric_value( + tls_accept_values, tls_accept + ) + elif isinstance(tls_accept, list): + params['tls_accept'] = 0 + for _tls_accept_value in tls_accept: + params['tls_accept'] += zabbix_utils.helper_to_numeric_value( + tls_accept_values, _tls_accept_value + ) + else: + self._module.fail_json(msg="Value of tls_accept must be list or string.") + + if tls_psk_identity: + params['tls_psk_identity'] = tls_psk_identity + + if tls_psk: + params['tls_psk'] = tls_psk + + current_tls_accept = int(current_setting['tls_accept']) + if (current_tls_accept == tls_accept_values.index('unsecure') + and params['tls_accept'] >= tls_accept_values.index('tls_with_psk')): + if not tls_psk_identity or not tls_psk: + self._module.fail_json(msg="Please set tls_psk_identity and tls_psk.") + + if (not tls_psk_identity and not tls_psk + and params['tls_accept'] == current_tls_accept): + self._module.exit_json(changed=False, result="Autoregistration is already up to date") + + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.autoregistration.update(params) + self._module.exit_json(changed=True, result="Successfully updated global autoregistration setting") + except Exception as e: + self._module.fail_json(msg="Failed to update autoregistration: %s" % e) + + +def main(): + """Main ansible module function + """ + + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + tls_accept=dict( + type='list', + elements='str', + required=True + ), + tls_psk_identity=dict(type='str', required=False, no_log=True), + tls_psk=dict(type='str', required=False, no_log=True), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + tls_accept = module.params['tls_accept'] + tls_psk_identity = module.params['tls_psk_identity'] + tls_psk = module.params['tls_psk'] + + autoregistration_class_obj = Autoregistration(module) + current_setting = autoregistration_class_obj.get_autoregistration() + autoregistration_class_obj.update_autoregistration(current_setting, tls_accept, tls_psk_identity, tls_psk) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py new file mode 100644 index 000000000..11b2f7c7f --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py @@ -0,0 +1,728 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Tobias Birkefeld (@tcraxs) <t@craxs.de> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: zabbix_discovery_rule +short_description: Create/delete/update Zabbix discovery rules +description: + - Create discovery rule. + - Delete existing discovery rule. + - Update existing discovery rule with new options. +author: + - "Tobias Birkefeld (@tcraxs)" +requirements: + - "python >= 2.6" +options: + state: + description: + - Create or delete discovery rules. + type: str + default: "present" + choices: [ "present", "absent" ] + name: + description: + - Name of the discovery rule. + required: true + type: str + iprange: + description: + - One or several IP ranges to check separated by commas. + type: list + elements: str + dchecks: + description: + - List of dictionaries of discovery check objects. + - For more information, review discovery check object documentation at + U(https://www.zabbix.com/documentation/current/manual/api/reference/dcheck/object) + suboptions: + type: + description: + - Type of check. + type: str + choices: ['SSH', + 'LDAP', + 'SMTP', + 'FTP', + 'HTTP', + 'POP', + 'NNTP', + 'IMAP', + 'TCP', + 'Zabbix', + 'SNMPv1', + 'SNMPv2', + 'ICMP', + 'SNMPv3', + 'HTTPS', + 'Telnet'] + ports: + description: + - One or several port ranges to check separated by commas. Used for all checks except for ICMP. + type: str + key: + description: + - "The value of this property differs depending on the type of the check:" + - "- key to query for Zabbix agent checks" + - "- SNMP OID for SNMPv1, SNMPv2 and SNMPv3 checks" + type: str + snmp_community: + description: + - SNMP community. + - Required for SNMPv1 and SNMPv2 agent checks. + type: str + snmpv3_authpassphrase: + description: + - Authentication passphrase used for SNMPv3 agent checks with security level set to authNoPriv or authPriv. + type: str + snmpv3_authprotocol: + description: + - Authentication protocol used for SNMPv3 agent checks with security level set to authNoPriv or authPriv. + - "Possible values:" + - MD5 + - SHA + type: str + choices: ["MD5", "SHA"] + snmpv3_contextname: + description: + - SNMPv3 context name. Used only by SNMPv3 checks. + type: str + snmpv3_privpassphrase: + description: + - Privacy passphrase used for SNMPv3 agent checks with security level set to authPriv. + type: str + snmpv3_privprotocol: + description: + - Privacy protocol used for SNMPv3 agent checks with security level set to authPriv. + - "Possible values:" + - DES + - AES + type: str + choices: ["DES", "AES"] + snmpv3_securitylevel: + description: + - Security level used for SNMPv3 agent checks. + - "Possible values:" + - noAuthNoPriv + - authNoPriv + - authPriv + type: str + choices: ["noAuthNoPriv", "authNoPriv", "authPriv"] + snmpv3_securityname: + description: + - Security name used for SNMPv3 agent checks. + type: str + uniq: + description: + - Whether to use this check as a device uniqueness criteria. + - Only a single unique check can be configured for a discovery rule. + - Used for Zabbix agent, SNMPv1, SNMPv2 and SNMPv3 agent checks. + - "Possible values:" + - "no - (default) do not use this check as a uniqueness criteria" + - "yes - use this check as a uniqueness criteria" + type: bool + default: no + host_source: + description: + - Source for host name. + - "Possible values:" + - "DNS (default)" + - "IP" + - "discovery - discovery value of this check" + - Options is available since Zabbix 4.4 + type: str + default: "DNS" + choices: ["DNS", "IP", "discovery"] + name_source: + description: + - Source for visible name. + - "Possible values:" + - "none - (default) not specified" + - "DNS" + - "IP" + - "discovery - discovery value of this check" + - Options is available since Zabbix 4.4 + type: str + default: "None" + choices: ["None", "DNS", "IP", "discovery"] + type: list + elements: dict + aliases: [ "dcheck" ] + delay: + description: + - Execution interval of the discovery rule. + - Accepts seconds, time unit with suffix and user macro. + type: str + default: "1h" + proxy: + description: + - Name of the proxy used for discovery. + type: str + status: + description: + - Whether the discovery rule is enabled. + - "Possible values:" + - enabled (default) + - disabled + type: str + default: "enabled" + choices: ["enabled", "disabled"] +notes: + - Only Zabbix >= 4.0 is supported. +extends_documentation_fragment: + - community.zabbix.zabbix +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Base create discovery rule example +- name: Create discovery rule with ICMP and zabbix agent checks + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discovery_rule: + name: ACME + state: present + iprange: 192.168.1.1-255 + dchecks: + - type: ICMP + - type: Zabbix + key: "system.hostname" + ports: 10050 + uniq: yes + host_source: "discovery" + +# Base update (add new dcheck) discovery rule example +- name: Create discovery rule with ICMP and zabbix agent checks + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discovery_rule: + name: ACME + state: present + iprange: 192.168.1.1-255 + dchecks: + - type: SNMPv3 + snmp_community: CUSTOMER@snmp3-readonly + ports: "161" + key: iso.3.6.1.2.1.1.1.0 + snmpv3_contextname: "ContextName" + snmpv3_securityname: "SecurityName" + snmpv3_securitylevel: "authPriv" + snmpv3_authprotocol: "SHA" + snmpv3_authpassphrase: "SeCrEt" + snmpv3_privprotocol: "AES" + snmpv3_privpassphrase: "TopSecret" + uniq: no + host_source: "DNS" + name_source: "None" + +# Base delete discovery rule example +- name: Delete discovery rule + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discovery_rule: + name: ACME + state: absent +''' + +RETURN = r''' +state: + description: Discovery rule state at the end of execution. + returned: on success + type: str + sample: 'present' +drule: + description: Discovery rule name. + returned: on success + type: str + sample: 'ACME' +druleid: + description: Discovery rule id. + returned: on success + type: str + sample: '42' +msg: + description: The result of the operation + returned: always + type: str + sample: 'Discovery rule created: ACME, ID: 42' +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Dchecks(ZabbixBase): + """ + Restructures the user defined discovery checks to fit the Zabbix API requirements + """ + + def construct_the_data(self, _dchecks): + """Construct the user defined discovery check to fit the Zabbix API + requirements + Args: + _dchecks: discovery checks to construct + Returns: + dict: user defined discovery checks + """ + if _dchecks is None: + return None + constructed_data = [] + for check in _dchecks: + constructed_check = { + 'type': zabbix_utils.helper_to_numeric_value([ + 'SSH', + 'LDAP', + 'SMTP', + 'FTP', + 'HTTP', + 'POP', + 'NNTP', + 'IMAP', + 'TCP', + 'Zabbix', + 'SNMPv1', + 'SNMPv2', + 'ICMP', + 'SNMPv3', + 'HTTPS', + 'Telnet'], check.get('type') + ), + 'uniq': int(check.get('uniq')) + } + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'): + constructed_check.update({ + 'host_source': zabbix_utils.helper_to_numeric_value([ + 'None', + 'DNS', + 'IP', + 'discovery'], check.get('host_source') + ), + 'name_source': zabbix_utils.helper_to_numeric_value([ + 'None', + 'DNS', + 'IP', + 'discovery'], check.get('name_source') + ) + }) + if constructed_check['type'] in (0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15): + constructed_check['ports'] = check.get('ports') + if constructed_check['type'] == 9: + constructed_check['ports'] = check.get('ports') + constructed_check['key_'] = check.get('key') + if constructed_check['type'] in (10, 11): + constructed_check['ports'] = check.get('ports') + constructed_check['snmp_community'] = check.get('snmp_community') + constructed_check['key_'] = check.get('key') + if constructed_check['type'] == 13: + constructed_check['ports'] = check.get('ports') + constructed_check['key_'] = check.get('key') + constructed_check['snmpv3_contextname'] = check.get('snmpv3_contextname') + constructed_check['snmpv3_securityname'] = check.get('snmpv3_securityname') + constructed_check['snmpv3_securitylevel'] = zabbix_utils.helper_to_numeric_value([ + 'noAuthNoPriv', + 'authNoPriv', + 'authPriv'], check.get('snmpv3_securitylevel') + ) + if constructed_check['snmpv3_securitylevel'] in (1, 2): + constructed_check['snmpv3_authprotocol'] = zabbix_utils.helper_to_numeric_value([ + 'MD5', + 'SHA'], check.get('snmpv3_authprotocol') + ) + constructed_check['snmpv3_authpassphrase'] = check.get('snmpv3_authpassphrase') + if constructed_check['snmpv3_securitylevel'] == 2: + constructed_check['snmpv3_privprotocol'] = zabbix_utils.helper_to_numeric_value([ + 'DES', + 'AES'], check.get('snmpv3_privprotocol') + ) + constructed_check['snmpv3_privpassphrase'] = check.get('snmpv3_privpassphrase') + constructed_data.append(constructed_check) + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class DiscoveryRule(ZabbixBase): + def check_if_drule_exists(self, name): + """Check if discovery rule exists. + Args: + name: Name of the discovery rule. + Returns: + The return value. True for success, False otherwise. + """ + try: + _drule = self._zapi.drule.get({ + 'output': 'extend', + 'selectDChecks': 'extend', + 'filter': {'name': [name]} + }) + if len(_drule) > 0: + return _drule + except Exception as e: + self._module.fail_json(msg="Failed to check if discovery rule '%s' exists: %s" + % (name, e)) + + def get_drule_by_drule_name(self, name): + """Get discovery rule by discovery rule name + Args: + name: discovery rule name. + Returns: + discovery rule matching discovery rule name + """ + try: + drule_list = self._zapi.drule.get({ + 'output': 'extend', + 'selectDChecks': 'extend', + 'filter': {'name': [name]} + }) + if len(drule_list) < 1: + self._module.fail_json(msg="Discovery rule not found: %s" % name) + else: + return drule_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get discovery rule '%s': %s" % (name, e)) + + def get_proxy_by_proxy_name(self, proxy_name): + """Get proxy by proxy name + Args: + proxy_name: proxy name. + Returns: + proxy matching proxy name + """ + try: + proxy_list = self._zapi.proxy.get({ + 'output': 'extend', + 'selectInterface': 'extend', + 'filter': {'host': [proxy_name]} + }) + if len(proxy_list) < 1: + self._module.fail_json(msg="Proxy not found: %s" % proxy_name) + else: + return proxy_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get proxy '%s': %s" % (proxy_name, e)) + + def _construct_parameters(self, **kwargs): + """Construct parameters. + Args: + **kwargs: Arbitrary keyword parameters. + Returns: + dict: dictionary of specified parameters + """ + _params = { + 'name': kwargs['name'], + 'iprange': ','.join(kwargs['iprange']), + 'delay': kwargs['delay'], + 'status': zabbix_utils.helper_to_numeric_value([ + 'enabled', + 'disabled'], kwargs['status'] + ), + 'dchecks': kwargs['dchecks'] + } + if kwargs['proxy']: + _params['proxy_hostid'] = self.get_proxy_by_proxy_name(kwargs['proxy'])['proxyid'] + return _params + + def check_difference(self, **kwargs): + """Check difference between discovery rule and user specified parameters. + Args: + **kwargs: Arbitrary keyword parameters. + Returns: + dict: dictionary of differences + """ + existing_drule = zabbix_utils.helper_convert_unicode_to_str(self.check_if_drule_exists(kwargs['name'])[0]) + parameters = zabbix_utils.helper_convert_unicode_to_str(self._construct_parameters(**kwargs)) + change_parameters = {} + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + if existing_drule['nextcheck']: + existing_drule.pop('nextcheck') + _diff = zabbix_utils.helper_cleanup_data(compare_dictionaries(parameters, existing_drule, change_parameters)) + return _diff + + def update_drule(self, **kwargs): + """Update discovery rule. + Args: + **kwargs: Arbitrary keyword parameters. + Returns: + drule: updated discovery rule + """ + try: + if self._module.check_mode: + self._module.exit_json(msg="Discovery rule would be updated if check mode was not specified: ID %s" % kwargs['drule_id'], changed=True) + kwargs['druleid'] = kwargs.pop('drule_id') + return self._zapi.drule.update(kwargs) + except Exception as e: + self._module.fail_json(msg="Failed to update discovery rule ID '%s': %s" % (kwargs['drule_id'], e)) + + def add_drule(self, **kwargs): + """Add discovery rule + Args: + **kwargs: Arbitrary keyword parameters + Returns: + drule: created discovery rule + """ + try: + if self._module.check_mode: + self._module.exit_json(msg="Discovery rule would be added if check mode was not specified", changed=True) + parameters = self._construct_parameters(**kwargs) + drule_list = self._zapi.drule.create(parameters) + return drule_list['druleids'][0] + except Exception as e: + self._module.fail_json(msg="Failed to create discovery rule %s: %s" % (kwargs['name'], e)) + + def delete_drule(self, drule_id): + """Delete discovery rule. + Args: + drule_id: Discovery rule id + Returns: + drule: deleted discovery rule + """ + try: + if self._module.check_mode: + self._module.exit_json(changed=True, msg="Discovery rule would be deleted if check mode was not specified") + return self._zapi.drule.delete([drule_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete discovery rule '%s': %s" % (drule_id, e)) + + +def compare_lists(l1, l2, diff_dict): + """ + Compares l1 and l2 lists and adds the items that are different + to the diff_dict dictionary. + Used in recursion with compare_dictionaries() function. + Args: + l1: first list to compare + l2: second list to compare + diff_dict: dictionary to store the difference + Returns: + dict: items that are different + """ + if len(l1) != len(l2): + diff_dict.append(l1) + return diff_dict + for i, item in enumerate(l1): + if isinstance(item, dict): + diff_dict.insert(i, {}) + diff_dict[i] = compare_dictionaries(item, l2[i], diff_dict[i]) + else: + if item != l2[i]: + diff_dict.append(item) + while {} in diff_dict: + diff_dict.remove({}) + return diff_dict + + +def compare_dictionaries(d1, d2, diff_dict): + """ + Compares d1 and d2 dictionaries and adds the items that are different + to the diff_dict dictionary. + Used in recursion with compare_lists() function. + Args: + d1: first dictionary to compare + d2: second dictionary to compare + diff_dict: dictionary to store the difference + Returns: + dict: items that are different + """ + for k, v in d1.items(): + if k not in d2: + diff_dict[k] = v + continue + if isinstance(v, dict): + diff_dict[k] = {} + compare_dictionaries(v, d2[k], diff_dict[k]) + if diff_dict[k] == {}: + del diff_dict[k] + else: + diff_dict[k] = v + elif isinstance(v, list): + diff_dict[k] = [] + compare_lists(v, d2[k], diff_dict[k]) + if diff_dict[k] == []: + del diff_dict[k] + else: + diff_dict[k] = v + else: + if v != d2[k]: + diff_dict[k] = v + return diff_dict + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update( + name=dict(type='str', required=True), + iprange=dict(type='list', required=False, elements='str'), + dchecks=dict( + type='list', + required=False, + aliases=['dcheck'], + elements='dict', + options=dict( + type=dict(type='str', choices=[ + 'SSH', + 'LDAP', + 'SMTP', + 'FTP', + 'HTTP', + 'POP', + 'NNTP', + 'IMAP', + 'TCP', + 'Zabbix', + 'SNMPv1', + 'SNMPv2', + 'ICMP', + 'SNMPv3', + 'HTTPS', + 'Telnet'] + ), + ports=dict(type='str'), + key=dict(type='str', no_log=False), + snmp_community=dict(type='str'), + snmpv3_authpassphrase=dict(type='str', no_log=True), + snmpv3_authprotocol=dict(type='str', choices=['MD5', 'SHA']), + snmpv3_contextname=dict(type='str'), + snmpv3_privpassphrase=dict(type='str', no_log=True), + snmpv3_privprotocol=dict(type='str', choices=['DES', 'AES']), + snmpv3_securitylevel=dict(type='str', choices=['noAuthNoPriv', 'authNoPriv', 'authPriv']), + snmpv3_securityname=dict(type='str'), + uniq=dict(type='bool', default=False), + host_source=dict(type='str', choices=['DNS', 'IP', 'discovery'], default='DNS'), + name_source=dict(type='str', choices=['None', 'DNS', 'IP', 'discovery'], default='None') + ), + required_if=[ + ['type', 'SSH', ['ports']], + ['type', 'LDAP', ['ports']], + ['type', 'SMTP', ['ports']], + ['type', 'FTP', ['ports']], + ['type', 'HTTP', ['ports']], + ['type', 'POP', ['ports']], + ['type', 'NNTP', ['ports']], + ['type', 'IMAP', ['ports']], + ['type', 'TCP', ['ports']], + ['type', 'Zabbix', ['ports', 'key']], + ['type', 'SNMPv1', ['ports', 'key', 'snmp_community']], + ['type', 'SNMPv2', ['ports', 'key', 'snmp_community']], + ['type', 'SNMPv3', ['ports', 'key']], + ['type', 'HTTPS', ['ports']], + ['type', 'Telnet', ['ports']], + ['snmpv3_securitylevel', 'authPriv', ['snmpv3_privpassphrase']] + ] + ), + delay=dict(type='str', required=False, default='1h'), + proxy=dict(type='str', required=False, default=None), + status=dict(type='str', default="enabled", choices=["enabled", "disabled"]), + state=dict(type='str', default='present', choices=['present', 'absent']) + ) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ['state', 'present', ['name', 'iprange', 'dchecks']], + ['state', 'absent', ['name']], + ], + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + state = module.params['state'] + name = module.params['name'] + iprange = module.params['iprange'] + dchecks = module.params['dchecks'] + delay = module.params['delay'] + proxy = module.params['proxy'] + status = module.params['status'] + + drule = DiscoveryRule(module) + zbx = drule._zapi + dcks = Dchecks(module, zbx) + + drule_exists = drule.check_if_drule_exists(name) + + if drule_exists: + drule_id = drule.get_drule_by_drule_name(name)['druleid'] + if state == "absent": + drule.delete_drule(drule_id) + module.exit_json(changed=True, state=state, drule=name, druleid=drule_id, msg="Discovery Rule deleted: %s, ID: %s" % (name, drule_id)) + else: + difference = drule.check_difference( + drule_id=drule_id, + name=name, + iprange=iprange, + dchecks=dcks.construct_the_data(dchecks), + delay=delay, + proxy=proxy, + status=status + ) + + if difference == {}: + module.exit_json(changed=False, state=state, drule=name, druleid=drule_id, msg="Discovery Rule is up to date: %s" % name) + else: + drule_id = drule.update_drule( + drule_id=drule_id, + **difference + ) + module.exit_json(changed=True, state=state, drule=name, druleid=drule_id, msg="Discovery Rule updated: %s, ID: %s" % (name, drule_id)) + else: + if state == "absent": + module.exit_json(changed=False, state=state, drule=name, msg="Discovery rule %s does not exist, nothing to delete" % name) + else: + drule_id = drule.add_drule( + name=name, + iprange=iprange, + dchecks=dcks.construct_the_data(dchecks), + delay=delay, + proxy=proxy, + status=status + ) + module.exit_json(changed=True, state=state, drule=name, druleid=drule_id, msg="Discovery Rule created: %s, ID: %s" % (name, drule_id)) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py new file mode 100644 index 000000000..d0221223b --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py @@ -0,0 +1,297 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_globalmacro +short_description: Create/update/delete Zabbix Global macros +version_added: 1.4.0 +description: + - manages Zabbix Global macros, it can create, update or delete them. + - For macro_type Secret the value field cannot be validated and will always be overwritten due to the secret nature of the Text. +author: + - "Cove (@cove)" + - Dean Hailin Song (!UNKNOWN) + - Timothy Test (@ttestscripting) +requirements: + - "python >= 2.6" +options: + macro_name: + description: + - Name of the global macro in zabbix native format C({$MACRO}) or simple format C(MACRO). + required: true + type: str + macro_value: + description: + - Value of the global macro. + - Required if I(state=present). + type: str + macro_type: + description: + - Type of the global macro Text or Secret Text. + - Required if I(state=present). + - text + - secret - Secret Text Works only with Zabbix >= 5.0 and will default to Text in lower versions + - vault - Vault Secret Works only with Zabbix >= 5.2 and will default to Text in lower versions + type: str + choices: [text, secret, vault] + default: text + macro_description: + description: + - Text Description of the global macro. + - Works only with Zabbix >= 4.4 and is silently ignored in lower versions + type: str + default: '' + state: + description: + - State of the macro. + - On C(present), it will create if macro does not exist or update the macro if the associated data is different. + - On C(absent) will remove a macro if it exists. + required: false + choices: ['present', 'absent'] + type: str + default: "present" + force: + description: + - Only updates an existing macro if set to C(yes). + default: 'yes' + type: bool + +notes: + - This module returns changed=true when I(macro_type=secret) with Zabbix >= 5.0. + +extends_documentation_fragment: +- community.zabbix.zabbix +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create new global macro or update an existing macro's value + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_globalmacro: + macro_name: EXAMPLE.MACRO + macro_value: Example value + macro_type: 0 + macro_description: Example description + state: present +# Values with curly brackets need to be quoted otherwise they will be interpreted as a dictionary +- name: Create new global macro in Zabbix native format with Secret Type + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_globalmacro: + macro_name: "{$EXAMPLE.MACRO}" + macro_value: Example value + macro_type: 1 + macro_description: Example description + state: present +- name: Delete existing global macro + community.zabbix.zabbix_globalmacro: + macro_name: "{$EXAMPLE.MACRO}" + state: absent +''' + +RETURN = r""" +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class GlobalMacro(ZabbixBase): + # get global macro + def get_global_macro(self, macro_name): + try: + all_global_macro_list = self._zapi.usermacro.get({"globalmacro": 'true'}) + global_macro_list = [d for d in all_global_macro_list if d['macro'] == macro_name] + if len(global_macro_list) > 0: + return global_macro_list[0] + return None + except Exception as e: + self._module.fail_json(msg="Failed to get global macro %s: %s" % (macro_name, e)) + + # create global macro + def create_global_macro(self, macro_name, macro_value, macro_type, macro_description): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + if LooseVersion(self._zbx_api_version) < LooseVersion('4.4.0'): + self._zapi.usermacro.createglobal({'macro': macro_name, 'value': macro_value}) + self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name) + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4.0'): + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0.0'): + if LooseVersion(self._zbx_api_version) < LooseVersion('5.2.0'): + if macro_type == '2': + macro_type = '0' + self._zapi.usermacro.createglobal({'macro': macro_name, 'value': macro_value, 'type': macro_type, 'description': macro_description}) + self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name) + else: + self._zapi.usermacro.createglobal({'macro': macro_name, 'value': macro_value, 'description': macro_description}) + self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name) + except Exception as e: + self._module.fail_json(msg="Failed to create global macro %s: %s" % (macro_name, e)) + + # update global macro + def update_global_macro(self, global_macro_obj, macro_name, macro_value, macro_type, macro_description): + global_macro_id = global_macro_obj['globalmacroid'] + try: + if LooseVersion(self._zbx_api_version) < LooseVersion('4.4.0'): + if global_macro_obj['macro'] == macro_name and global_macro_obj['value'] == macro_value: + self._module.exit_json(changed=False, result="Global macro %s already up to date" % macro_name) + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.updateglobal({'globalmacroid': global_macro_id, 'macro': macro_name, 'value': macro_value}) + self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name) + elif LooseVersion(self._zbx_api_version) >= LooseVersion('5.0.0'): + if LooseVersion(self._zbx_api_version) < LooseVersion('5.2.0'): + if macro_type == '2': + macro_type = '0' + if global_macro_obj['type'] == '0' or global_macro_obj['type'] == '2': + if (global_macro_obj['macro'] == macro_name and global_macro_obj['value'] == macro_value + and global_macro_obj['type'] == macro_type and global_macro_obj['description'] == macro_description): + self._module.exit_json(changed=False, result="Global macro %s already up to date" % macro_name) + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.updateglobal({'globalmacroid': global_macro_id, 'macro': macro_name, + 'value': macro_value, 'type': macro_type, 'description': macro_description}) + self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name) + else: + if (global_macro_obj['macro'] == macro_name and global_macro_obj['value'] == macro_value + and global_macro_obj['description'] == macro_description): + self._module.exit_json(changed=False, result="Global macro %s already up to date" % macro_name) + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.updateglobal({'globalmacroid': global_macro_id, 'macro': macro_name, + 'value': macro_value, 'description': macro_description}) + self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name) + except Exception as e: + self._module.fail_json(msg="Failed to update global macro %s: %s" % (macro_name, e)) + + # delete global macro + def delete_global_macro(self, global_macro_obj, macro_name): + global_macro_id = global_macro_obj['globalmacroid'] + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.deleteglobal([global_macro_id]) + self._module.exit_json(changed=True, result="Successfully deleted global macro %s" % macro_name) + except Exception as e: + self._module.fail_json(msg="Failed to delete global macro %s: %s" % (macro_name, e)) + + +def normalize_macro_name(macro_name): + # Zabbix handles macro names in upper case characters + if ':' in macro_name: + macro_name = ':'.join([macro_name.split(':')[0].upper(), ':'.join(macro_name.split(':')[1:])]) + else: + macro_name = macro_name.upper() + + # Valid format for macro is {$MACRO} + if not macro_name.startswith('{$'): + macro_name = '{$' + macro_name + if not macro_name.endswith('}'): + macro_name = macro_name + '}' + + return macro_name + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + macro_name=dict(type='str', required=True), + macro_value=dict(type='str', required=False, no_log=True), + macro_type=dict(type='str', default='text', choices=['text', 'secret', 'vault']), + macro_description=dict(type='str', default=''), + state=dict(type='str', default='present', choices=['present', 'absent']), + force=dict(type='bool', default=True) + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ['state', 'present', ['macro_value']] + ], + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + macro_name = normalize_macro_name(module.params['macro_name']) + macro_value = module.params['macro_value'] + macro_type = module.params['macro_type'] + macro_value = module.params['macro_value'] + macro_description = module.params['macro_description'] + state = module.params['state'] + force = module.params['force'] + + if macro_type == 'text': + macro_type = '0' + elif macro_type == 'secret': + macro_type = '1' + elif macro_type == 'vault': + macro_type = '2' + + global_macro_class_obj = GlobalMacro(module) + + if macro_name: + global_macro_obj = global_macro_class_obj.get_global_macro(macro_name) + + if state == 'absent': + if not global_macro_obj: + module.exit_json(changed=False, msg="Global Macro %s does not exist" % macro_name) + else: + # delete a macro + global_macro_class_obj.delete_global_macro(global_macro_obj, macro_name) + else: + if not global_macro_obj: + # create global macro + global_macro_class_obj.create_global_macro(macro_name, macro_value, macro_type, macro_description) + elif force: + # update global macro + global_macro_class_obj.update_global_macro(global_macro_obj, macro_name, macro_value, macro_type, macro_description) + else: + module.exit_json(changed=False, result="Global macro %s already exists and force is set to no" % macro_name) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py new file mode 100644 index 000000000..0426f9336 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py @@ -0,0 +1,201 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# (c) 2013-2014, Epic Games, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_group +short_description: Create/delete Zabbix host groups +description: + - Create host groups if they do not exist. + - Delete existing host groups if they exist. +author: + - "Cove (@cove)" + - "Tony Minfei Ding (!UNKNOWN)" + - "Harrison Gu (@harrisongu)" +requirements: + - "python >= 2.6" +options: + state: + description: + - Create or delete host group. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + host_groups: + description: + - List of host groups to create or delete. + required: true + type: list + elements: str + aliases: [ "host_group" ] + +extends_documentation_fragment: +- community.zabbix.zabbix + +notes: + - Too many concurrent updates to the same group may cause Zabbix to return errors, see examples for a workaround if needed. +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Base create host groups example +- name: Create host groups + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_group: + state: present + host_groups: + - Example group1 + - Example group2 + +# Limit the Zabbix group creations to one host since Zabbix can return an error when doing concurrent updates +- name: Create host groups + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_group: + state: present + host_groups: + - Example group1 + - Example group2 + when: inventory_hostname==groups['group_name'][0] +''' + + +import traceback + +try: + from zabbix_api import Already_Exists + + HAS_ZABBIX_API = True + ZBX_IMP_ERR = Exception() +except ImportError: + ZBX_IMP_ERR = traceback.format_exc() + HAS_ZABBIX_API = False + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class HostGroup(ZabbixBase): + # create host group(s) if not exists + def create_host_group(self, group_names): + try: + group_add_list = [] + for group_name in group_names: + result = self._zapi.hostgroup.get({'filter': {'name': group_name}}) + if not result: + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.hostgroup.create({'name': group_name}) + group_add_list.append(group_name) + except Already_Exists: + return group_add_list + return group_add_list + except Exception as e: + self._module.fail_json(msg="Failed to create host group(s): %s" % e) + + # delete host group(s) + def delete_host_group(self, group_ids): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.hostgroup.delete(group_ids) + except Exception as e: + self._module.fail_json(msg="Failed to delete host group(s), Exception: %s" % e) + + # get group ids by name + def get_group_ids(self, host_groups): + group_ids = [] + + group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': host_groups}}) + for group in group_list: + group_id = group['groupid'] + group_ids.append(group_id) + return group_ids, group_list + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + host_groups=dict(type='list', required=True, aliases=['host_group']), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password']: + if p in module.params and module.params[p] and module.params[p]: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + host_groups = module.params['host_groups'] + state = module.params['state'] + + hostGroup = HostGroup(module) + + group_ids = [] + group_list = [] + if host_groups: + group_ids, group_list = hostGroup.get_group_ids(host_groups) + + if state == "absent": + # delete host groups + if group_ids: + delete_group_names = [] + hostGroup.delete_host_group(group_ids) + for group in group_list: + delete_group_names.append(group['name']) + module.exit_json(changed=True, + result="Successfully deleted host group(s): %s." % ",".join(delete_group_names)) + else: + module.exit_json(changed=False, result="No host group(s) to delete.") + else: + # create host groups + group_add_list = hostGroup.create_host_group(host_groups) + if len(group_add_list) > 0: + module.exit_json(changed=True, result="Successfully created host group(s): %s" % group_add_list) + else: + module.exit_json(changed=False) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py new file mode 100644 index 000000000..b3f693052 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py @@ -0,0 +1,115 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) me@mimiko.me +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +RETURN = r''' +--- +host_groups: + description: List of Zabbix groups. + returned: success + type: dict + sample: [ { "flags": "0", "groupid": "33", "internal": "0", "name": "Hostgruup A" } ] +''' + +DOCUMENTATION = r''' +--- +module: zabbix_group_info +short_description: Gather information about Zabbix hostgroup +description: + - This module allows you to search for Zabbix hostgroup entries. + - This module was called C(zabbix_group_facts) before Ansible 2.9. The usage did not change. +author: + - "Michael Miko (@RedWhiteMiko)" +requirements: + - "python >= 2.6" +options: + hostgroup_name: + description: + - Name of the hostgroup in Zabbix. + - hostgroup is the unique identifier used and cannot be updated using this module. + required: true + type: list + elements: str + +extends_documentation_fragment: +- community.zabbix.zabbix +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get hostgroup info + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_group_info: + hostgroup_name: + - ExampleHostgroup + timeout: 10 +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Host(ZabbixBase): + def get_group_ids_by_group_names(self, group_names): + group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}}) + if len(group_list) < 1: + self._module.fail_json(msg="Hostgroup not found: %s" % group_names) + return group_list + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + hostgroup_name=dict(type='list', required=True), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + if module._name == 'zabbix_group_facts': + module.deprecate("The 'zabbix_group_facts' module has been renamed to 'zabbix_group_info'", + collection_name="community.zabbix", version='2.0.0') # was 2.13 + + hostgroup_name = module.params['hostgroup_name'] + + host = Host(module) + host_groups = host.get_group_ids_by_group_names(hostgroup_name) + module.exit_json(host_groups=host_groups) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py new file mode 100644 index 000000000..b3f693052 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py @@ -0,0 +1,115 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) me@mimiko.me +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +RETURN = r''' +--- +host_groups: + description: List of Zabbix groups. + returned: success + type: dict + sample: [ { "flags": "0", "groupid": "33", "internal": "0", "name": "Hostgruup A" } ] +''' + +DOCUMENTATION = r''' +--- +module: zabbix_group_info +short_description: Gather information about Zabbix hostgroup +description: + - This module allows you to search for Zabbix hostgroup entries. + - This module was called C(zabbix_group_facts) before Ansible 2.9. The usage did not change. +author: + - "Michael Miko (@RedWhiteMiko)" +requirements: + - "python >= 2.6" +options: + hostgroup_name: + description: + - Name of the hostgroup in Zabbix. + - hostgroup is the unique identifier used and cannot be updated using this module. + required: true + type: list + elements: str + +extends_documentation_fragment: +- community.zabbix.zabbix +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get hostgroup info + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_group_info: + hostgroup_name: + - ExampleHostgroup + timeout: 10 +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Host(ZabbixBase): + def get_group_ids_by_group_names(self, group_names): + group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}}) + if len(group_list) < 1: + self._module.fail_json(msg="Hostgroup not found: %s" % group_names) + return group_list + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + hostgroup_name=dict(type='list', required=True), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + if module._name == 'zabbix_group_facts': + module.deprecate("The 'zabbix_group_facts' module has been renamed to 'zabbix_group_info'", + collection_name="community.zabbix", version='2.0.0') # was 2.13 + + hostgroup_name = module.params['hostgroup_name'] + + host = Host(module) + host_groups = host.get_group_ids_by_group_names(hostgroup_name) + module.exit_json(host_groups=host_groups) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py new file mode 100644 index 000000000..c43742378 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py @@ -0,0 +1,1302 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_host +short_description: Create/update/delete Zabbix hosts +description: + - This module allows you to create, modify and delete Zabbix host entries and associated group and template data. +author: + - "Cove (@cove)" + - Tony Minfei Ding (!UNKNOWN) + - Harrison Gu (@harrisongu) + - Werner Dijkerman (@dj-wasabi) + - Eike Frost (@eikef) +requirements: + - "python >= 2.6" +options: + host_name: + description: + - Name of the host in Zabbix. + - I(host_name) is the unique identifier used and cannot be updated using this module. + required: true + type: str + visible_name: + description: + - Visible name of the host in Zabbix. + type: str + description: + description: + - Description of the host in Zabbix. + type: str + host_groups: + description: + - List of host groups the host is part of. + - Make sure the Zabbix user used for Ansible can read these groups. + type: list + elements: str + link_templates: + description: + - List of templates linked to the host. + type: list + elements: str + inventory_mode: + description: + - Configure the inventory mode. + choices: ['automatic', 'manual', 'disabled'] + type: str + inventory_zabbix: + description: + - Add Facts for a zabbix inventory (e.g. Tag) (see example below). + - Please review the interface documentation for more information on the supported properties + - U(https://www.zabbix.com/documentation/3.2/manual/api/reference/host/object#host_inventory) + type: dict + status: + description: + - Monitoring status of the host. + choices: ['enabled', 'disabled'] + default: 'enabled' + type: str + state: + description: + - State of the host. + - On C(present), it will create if host does not exist or update the host if the associated data is different. + - On C(absent) will remove a host if it exists. + choices: ['present', 'absent'] + default: 'present' + type: str + proxy: + description: + - The name of the Zabbix proxy to be used. + type: str + interfaces: + type: list + elements: dict + description: + - List of interfaces to be created for the host (see example below). + - For more information, review host interface documentation at + - U(https://www.zabbix.com/documentation/4.0/manual/api/reference/hostinterface/object) + default: [] + suboptions: + type: + type: str + description: + - Interface type to add + - Numerical values are also accepted for interface type + - 1 = agent + - 2 = snmp + - 3 = ipmi + - 4 = jmx + choices: ['agent', '1', 'snmp', '2', 'ipmi', '3', 'jmx', '4'] + required: true + main: + type: int + description: + - Whether the interface is used as default. + - If multiple interfaces with the same type are provided, only one can be default. + - 0 (not default), 1 (default) + default: 0 + choices: [0, 1] + useip: + type: int + description: + - Connect to host interface with IP address instead of DNS name. + - 0 (don't use ip), 1 (use ip) + default: 0 + choices: [0, 1] + ip: + type: str + description: + - IP address used by host interface. + - Required if I(useip=1). + dns: + type: str + description: + - DNS name of the host interface. + - Required if I(useip=0). + port: + type: str + description: + - Port used by host interface. + - If not specified, default port for each type of interface is used + - 10050 if I(type='agent') + - 161 if I(type='snmp') + - 623 if I(type='ipmi') + - 12345 if I(type='jmx') + bulk: + type: int + description: + - Whether to use bulk SNMP requests. + - Only valid when interface I(type='snmp'). + - 0 (don't use bulk requests), 1 (use bulk requests) + - Works only with Zabbix <= 4.4 and is silently ignored in higher versions. + - Use I(details) with Zabbix >= 5.0. + choices: [0, 1] + default: 1 + details: + type: dict + description: + - Additional details for SNMP host interfaces. + - Required when I(type='snmp'). + - Works only with Zabbix >= 5.0. + default: {} + suboptions: + version: + type: int + description: + - SNMP version. + - 1 (SNMPv1), 2 (SNMPv2c), 3 (SNMPv3) + choices: [1, 2, 3] + default: 2 + bulk: + type: int + description: + - Whether to use bulk SNMP requests. + - 0 (don't use bulk requests), 1 (use bulk requests) + choices: [0, 1] + default: 1 + community: + type: str + description: + - SNMPv1 and SNMPv2 community string. + - Required when I(version=1) or I(version=2). + default: '' + securityname: + type: str + description: + - SNMPv3 security name. + default: '' + contextname: + type: str + description: + - SNMPv3 context name. + default: '' + securitylevel: + type: int + description: + - SNMPv3 security level. + - 0 (noAuthNoPriv), 1 (authNoPriv), 2 (authPriv). + choices: [0, 1, 2] + default: 0 + authprotocol: + type: int + description: + - SNMPv3 authentication protocol. + - Used when I(securitylevel=1)(authNoPriv) or I(securitylevel=2)(AuthPriv). + - Variants 2,3,4,5 are supported only on Zabbix 5.4 or greater + - 0 (MD5), 1 (SHA1), 2 (SHA224), 3 (SHA256), 4 (SHA384), 5 (SHA512) + default: 0 + choices: [0, 1, 2, 3, 4, 5] + authpassphrase: + type: str + description: + - SNMPv3 authentication passphrase. + - Used when I(securitylevel=1)(authNoPriv) or I(securitylevel=2)(AuthPriv). + default: '' + privprotocol: + type: int + description: + - SNMPv3 privacy protocol. + - Used when I(securitylevel=2)(authPriv). + - Variants 2,3,4,5 are supported only on Zabbix 5.4 or greater + - 0 (DES), 1 (AES128), 2 (AES192), 3 (AES256), 4 (AES192C), 5 (AES256C) + default: 0 + choices: [0, 1, 2, 3, 4, 5] + privpassphrase: + type: str + description: + - SNMPv3 privacy passphrase. + - Used when I(securitylevel=2)(AuthPriv). + default: '' + tls_connect: + description: + - Specifies what encryption to use for outgoing connections. + - Possible values, 1 (no encryption), 2 (PSK), 4 (certificate). + - Works only with >= Zabbix 3.0 + type: int + tls_accept: + description: + - Specifies what types of connections are allowed for incoming connections. + - The tls_accept parameter accepts values of 1 to 7 + - Possible values, 1 (no encryption), 2 (PSK), 4 (certificate). + - Values can be combined. + - Works only with >= Zabbix 3.0 + type: int + tls_psk_identity: + description: + - It is a unique name by which this specific PSK is referred to by Zabbix components + - Do not put sensitive information in the PSK identity string, it is transmitted over the network unencrypted. + - Works only with >= Zabbix 3.0 + - Using this parameter with Zabbix >= 5.4 makes this module non-idempotent. + type: str + tls_psk: + description: + - PSK value is a hard to guess string of hexadecimal digits. + - The preshared key, at least 32 hex digits. Required if either I(tls_connect) or I(tls_accept) has PSK enabled. + - Works only with >= Zabbix 3.0 + - Using this parameter with Zabbix >= 5.4 makes this module non-idempotent. + type: str + ca_cert: + description: + - Required certificate issuer. + - Works only with >= Zabbix 3.0 + aliases: [ tls_issuer ] + type: str + tls_subject: + description: + - Required certificate subject. + - Works only with >= Zabbix 3.0 + type: str + ipmi_authtype: + description: + - IPMI authentication algorithm. + - Please review the Host object documentation for more information on the supported properties + - 'https://www.zabbix.com/documentation/3.4/manual/api/reference/host/object' + - Possible values are, C(0) (none), C(1) (MD2), C(2) (MD5), C(4) (straight), C(5) (OEM), C(6) (RMCP+), + with -1 being the API default. + - Please note that the Zabbix API will treat absent settings as default when updating + any of the I(ipmi_)-options; this means that if you attempt to set any of the four + options individually, the rest will be reset to default values. + type: int + ipmi_privilege: + description: + - IPMI privilege level. + - Please review the Host object documentation for more information on the supported properties + - 'https://www.zabbix.com/documentation/3.4/manual/api/reference/host/object' + - Possible values are C(1) (callback), C(2) (user), C(3) (operator), C(4) (admin), C(5) (OEM), with C(2) + being the API default. + - also see the last note in the I(ipmi_authtype) documentation + type: int + ipmi_username: + description: + - IPMI username. + - also see the last note in the I(ipmi_authtype) documentation + type: str + ipmi_password: + description: + - IPMI password. + - also see the last note in the I(ipmi_authtype) documentation + type: str + force: + description: + - Overwrite the host configuration, even if already present. + type: bool + default: 'yes' + macros: + description: + - List of user macros to assign to the zabbix host. + - Providing I(macros=[]) with I(force=yes) will clean all of the existing user macros from the host. + type: list + elements: dict + suboptions: + macro: + description: + - Name of the user macro. + - Can be in zabbix native format "{$MACRO}" or short format "MACRO". + type: str + required: true + value: + description: + - Value of the user macro. + type: str + required: true + description: + description: + - Description of the user macro. + - Works only with >= Zabbix 4.4. + type: str + required: false + default: '' + type: + description: + - Type of the macro. + - Works only with >= Zabbix 5.0. + - Since value is not returned by API for secret macros, there is no reliable way to + detect changes in the content of secret macro value. + - To update secret macro value, please update description alongside it so it passes + the check. + choices: [text, secret] + type: str + required: false + default: text + aliases: [ user_macros ] + tags: + description: + - List of host tags to assign to the zabbix host. + - Works only with >= Zabbix 4.2. + - Providing I(tags=[]) with I(force=yes) will clean all of the tags from the host. + type: list + elements: dict + suboptions: + tag: + description: + - Name of the host tag. + type: str + required: true + value: + description: + - Value of the host tag. + type: str + default: '' + aliases: [ host_tags ] + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create a new host or rewrite an existing host's info +# Set task level following variables for Zabbix Server host in task + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + become: false + delegate_to: zabbix-example-fqdn.org# you can use delegate_to or task level ansible_host like next example + community.zabbix.zabbix_host: + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Example group1 + - Example group2 + link_templates: + - Example template1 + - Example template2 + status: enabled + state: present + inventory_mode: manual + inventory_zabbix: + tag: "{{ your_tag }}" + alias: "{{ your_alias }}" + notes: "Special Informations: {{ your_informations | default('None') }}" + location: "{{ your_location }}" + site_rack: "{{ your_site_rack }}" + os: "{{ your_os }}" + hardware: "{{ your_hardware }}" + ipmi_authtype: 2 + ipmi_privilege: 4 + ipmi_username: username + ipmi_password: password + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.xx.xx.xx + dns: "" + port: "10050" + - type: 4 + main: 1 + useip: 1 + ip: 10.xx.xx.xx + dns: "" + port: "12345" + proxy: a.zabbix.proxy + macros: + - macro: '{$EXAMPLEMACRO}' + value: ExampleMacroValue + - macro: EXAMPLEMACRO2 + value: ExampleMacroValue2 + description: Example desc that work only with Zabbix 4.4 and higher + tags: + - tag: ExampleHostsTag + - tag: ExampleHostsTag2 + value: ExampleTagValue + +- name: Update an existing host's TLS settings +# Set current task level variables for Zabbix Server host in task + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org # you can use task level ansible_host or delegate_to like in previous example + become: false + community.zabbix.zabbix_host: + host_name: ExampleHost + visible_name: ExampleName + host_groups: + - Example group1 + tls_psk_identity: test + tls_connect: 2 + tls_psk: 123456789abcdef123456789abcdef12 + force: false +''' + + +import copy + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Host(ZabbixBase): + # exist host + def is_host_exist(self, host_name): + result = self._zapi.host.get({'filter': {'host': host_name}}) + return result + + # check if host group exists + def check_host_group_exist(self, group_names): + for group_name in group_names: + result = self._zapi.hostgroup.get({'filter': {'name': group_name}}) + if not result: + self._module.fail_json(msg="Hostgroup not found: %s" % group_name) + return True + + def get_template_ids(self, template_list): + template_ids = [] + if template_list is None or len(template_list) == 0: + return template_ids + for template in template_list: + template_list = self._zapi.template.get({'output': 'extend', 'filter': {'host': template}}) + if len(template_list) < 1: + self._module.fail_json(msg="Template not found: %s" % template) + else: + template_id = template_list[0]['templateid'] + template_ids.append(template_id) + return template_ids + + def add_host(self, host_name, group_ids, status, interfaces, proxy_id, visible_name, description, tls_connect, + tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, + ipmi_username, ipmi_password, macros, tags): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + parameters = {'host': host_name, 'interfaces': interfaces, 'groups': group_ids, 'status': status} + if proxy_id: + parameters['proxy_hostid'] = proxy_id + if visible_name: + parameters['name'] = visible_name + if tls_connect: + parameters['tls_connect'] = tls_connect + if tls_accept: + parameters['tls_accept'] = tls_accept + if tls_psk_identity is not None: + parameters['tls_psk_identity'] = tls_psk_identity + if tls_psk is not None: + parameters['tls_psk'] = tls_psk + if tls_issuer is not None: + parameters['tls_issuer'] = tls_issuer + if tls_subject is not None: + parameters['tls_subject'] = tls_subject + if description: + parameters['description'] = description + if ipmi_authtype is not None: + parameters['ipmi_authtype'] = ipmi_authtype + if ipmi_privilege is not None: + parameters['ipmi_privilege'] = ipmi_privilege + if ipmi_username is not None: + parameters['ipmi_username'] = ipmi_username + if ipmi_password is not None: + parameters['ipmi_password'] = ipmi_password + if macros is not None: + parameters['macros'] = macros + if tags is not None: + parameters['tags'] = tags + + host_list = self._zapi.host.create(parameters) + if len(host_list) >= 1: + return host_list['hostids'][0] + except Exception as e: + self._module.fail_json(msg="Failed to create host %s: %s" % (host_name, e)) + + def update_host(self, host_name, group_ids, status, host_id, interfaces, exist_interface_list, proxy_id, + visible_name, description, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, + tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, macros, tags): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + parameters = {'hostid': host_id, 'groups': group_ids, 'status': status} + if proxy_id >= 0: + parameters['proxy_hostid'] = proxy_id + if visible_name: + parameters['name'] = visible_name + if tls_connect: + parameters['tls_connect'] = tls_connect + if tls_accept: + parameters['tls_accept'] = tls_accept + if tls_psk_identity: + parameters['tls_psk_identity'] = tls_psk_identity + if tls_psk: + parameters['tls_psk'] = tls_psk + if tls_issuer: + parameters['tls_issuer'] = tls_issuer + if tls_subject: + parameters['tls_subject'] = tls_subject + if description: + parameters['description'] = description + if ipmi_authtype: + parameters['ipmi_authtype'] = ipmi_authtype + if ipmi_privilege: + parameters['ipmi_privilege'] = ipmi_privilege + if ipmi_username: + parameters['ipmi_username'] = ipmi_username + if ipmi_password: + parameters['ipmi_password'] = ipmi_password + if macros is not None: + parameters['macros'] = macros + if tags is not None: + parameters['tags'] = tags + if interfaces: + parameters['interfaces'] = interfaces + + self._zapi.host.update(parameters) + except Exception as e: + self._module.fail_json(msg="Failed to update host %s: %s" % (host_name, e)) + + def delete_host(self, host_id, host_name): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.delete([host_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete host %s: %s" % (host_name, e)) + + # get host by host name + def get_host_by_host_name(self, host_name): + params = { + 'output': 'extend', + 'selectInventory': 'extend', + 'selectMacros': 'extend', + 'filter': { + 'host': [host_name] + } + } + + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.2.0'): + params.update({'selectTags': ['tag', 'value']}) + + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4.0'): + params.update({ + 'output': [ + "inventory_mode", + "hostid", + "proxy_hostid", + "host", + "status", + "lastaccess", + "ipmi_authtype", + "ipmi_privilege", + "ipmi_username", + "ipmi_password", + "maintenanceid", + "maintenance_status", + "maintenance_type", + "maintenance_from", + "name", + "flags", + "templateid", + "description", + "tls_connect", + "tls_accept", + "tls_issuer", + "tls_subject", + "proxy_address", + "auto_compress", + "custom_interfaces", + "uuid" + ] + }) + + host_list = self._zapi.host.get(params) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + return host_list[0] + + # get proxyid by proxy name + def get_proxyid_by_proxy_name(self, proxy_name): + proxy_list = self._zapi.proxy.get({'output': 'extend', 'filter': {'host': [proxy_name]}}) + if len(proxy_list) < 1: + self._module.fail_json(msg="Proxy not found: %s" % proxy_name) + else: + return int(proxy_list[0]['proxyid']) + + # get group ids by group names + def get_group_ids_by_group_names(self, group_names): + if self.check_host_group_exist(group_names): + return self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}}) + + # get host groups ids by host id + def get_group_ids_by_host_id(self, host_id): + return self._zapi.hostgroup.get({'output': 'extend', 'hostids': host_id}) + + # get host templates by host id + def get_host_templates_by_host_id(self, host_id): + template_ids = [] + template_list = self._zapi.template.get({'output': 'extend', 'hostids': host_id}) + for template in template_list: + template_ids.append(template['templateid']) + return template_ids + + def construct_host_interfaces(self, interfaces): + """Ensures interfaces object is properly formatted before submitting it to API. + + Args: + interfaces (list): list of dictionaries for each interface present on the host. + + Returns: + (interfaces, ip) - where interfaces is original list reformated into a valid format + and ip is any IP address found on interface of type agent (printing purposes only). + """ + ip = "" + interface_types = {'agent': 1, 'snmp': 2, 'ipmi': 3, 'jmx': 4} + type_to_port = {1: '10050', 2: '161', 3: '623', 4: '12345'} + + for interface in interfaces: + if interface['type'] in list(interface_types.keys()): + interface['type'] = interface_types[interface['type']] + else: + interface['type'] = int(interface['type']) + + if interface['type'] == 1: + ip = interface.get('ip', '') + + for key in ['ip', 'dns']: + if key not in interface or interface[key] is None: + interface[key] = '' + + if 'port' not in interface or interface['port'] is None: + interface['port'] = type_to_port.get(interface['type'], '') + + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0.0'): + if 'bulk' in interface: + del interface['bulk'] + + # Not handled in argument_spec with required_if since only SNMP interfaces are using details + if interface['type'] == 2: + if not interface['details']: + self._module.fail_json(msg='Option "details" required for SNMP interface {0}'.format(interface)) + + i_details = interface['details'] + if i_details['version'] < 3 and not i_details.get('community', False): + self._module.fail_json( + msg='Option "community" is required in "details" for SNMP interface {0}'.format(interface)) + + else: + interface['details'] = {} + + else: + if 'details' in interface: + del interface['details'] + + return (interfaces, ip) + + # check the exist_interfaces whether it equals the interfaces or not + def check_interface_properties(self, exist_interfaces, interfaces): + # Find already configured interfaces in requested interfaces + if len(exist_interfaces) != len(interfaces): + return True + + for iface in interfaces: + found = False + for e_int in exist_interfaces: + diff_dict = {} + zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(iface, e_int, diff_dict)) + if diff_dict == {}: + found = True + break + + if interfaces and not found: + return True + + return False + + # get the status of host by host + def get_host_status_by_host(self, host): + return host['status'] + + # check all the properties before link or clear template + def check_all_properties(self, host_id, group_ids, status, interfaces, template_ids, + exist_interfaces, host, proxy_id, visible_name, description, host_name, + inventory_mode, inventory_zabbix, tls_accept, tls_psk_identity, tls_psk, + tls_issuer, tls_subject, tls_connect, ipmi_authtype, ipmi_privilege, + ipmi_username, ipmi_password, macros, tags): + # get the existing host's groups + exist_host_groups = sorted(self.get_group_ids_by_host_id(host_id), key=lambda k: k['groupid']) + if sorted(group_ids, key=lambda k: k['groupid']) != exist_host_groups: + return True + + # get the existing status + exist_status = self.get_host_status_by_host(host) + if int(status) != int(exist_status): + return True + + # check the exist_interfaces whether it equals the interfaces or not + if self.check_interface_properties(exist_interfaces, interfaces): + return True + + # get the existing templates + exist_template_ids = self.get_host_templates_by_host_id(host_id) + if set(list(template_ids)) != set(exist_template_ids): + return True + + if int(host['proxy_hostid']) != int(proxy_id): + return True + + # Check whether the visible_name has changed; Zabbix defaults to the technical hostname if not set. + if visible_name: + if host['name'] != visible_name: + return True + + # Only compare description if it is given as a module parameter + if description: + if host['description'] != description: + return True + + if inventory_mode: + if LooseVersion(self._zbx_api_version) <= LooseVersion('4.4.0'): + if host['inventory']: + if int(host['inventory']['inventory_mode']) != self.inventory_mode_numeric(inventory_mode): + return True + elif inventory_mode != 'disabled': + return True + else: + if int(host['inventory_mode']) != self.inventory_mode_numeric(inventory_mode): + return True + + if inventory_zabbix: + proposed_inventory = copy.deepcopy(host['inventory']) + proposed_inventory.update(inventory_zabbix) + if proposed_inventory != host['inventory']: + return True + + if tls_accept is not None and 'tls_accept' in host: + if int(host['tls_accept']) != tls_accept: + return True + + if LooseVersion(self._zbx_api_version) < LooseVersion('5.4'): + if tls_psk_identity is not None and 'tls_psk_identity' in host: + if host['tls_psk_identity'] != tls_psk_identity: + return True + if tls_psk is not None and 'tls_psk' in host: + if host['tls_psk'] != tls_psk: + return True + else: + # in Zabbix >= 5.4 these parameters are write-only and are not returned in host.get response + if tls_psk_identity is not None or tls_psk is not None: + return True + + if tls_issuer is not None and 'tls_issuer' in host: + if host['tls_issuer'] != tls_issuer: + return True + + if tls_subject is not None and 'tls_subject' in host: + if host['tls_subject'] != tls_subject: + return True + + if tls_connect is not None and 'tls_connect' in host: + if int(host['tls_connect']) != tls_connect: + return True + if ipmi_authtype is not None: + if int(host['ipmi_authtype']) != ipmi_authtype: + return True + if ipmi_privilege is not None: + if int(host['ipmi_privilege']) != ipmi_privilege: + return True + if ipmi_username is not None: + if host['ipmi_username'] != ipmi_username: + return True + if ipmi_password is not None: + if host['ipmi_password'] != ipmi_password: + return True + + # hostmacroid and hostid are present in every item of host['macros'] and need to be removed + if macros is not None and 'macros' in host: + t_macros = copy.deepcopy(macros) # make copy to prevent change in original data + for macro in host['macros']: + macro.pop('hostid', False) + macro.pop('hostmacroid', False) + + diff = [] + zabbix_utils.helper_compare_lists(t_macros, host['macros'], diff) + if diff != []: + return True + + if tags is not None and 'tags' in host: + if sorted(tags, key=lambda k: k['tag']) != sorted(host['tags'], key=lambda k: k['tag']): + return True + + return False + + # link or clear template of the host + def link_or_clear_template(self, host_id, template_id_list, tls_connect, tls_accept, tls_psk_identity, tls_psk, + tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password): + # get host's exist template ids + exist_template_id_list = self.get_host_templates_by_host_id(host_id) + + exist_template_ids = set(exist_template_id_list) + template_ids = set(template_id_list) + template_id_list = list(template_ids) + + # get unlink and clear templates + templates_clear = exist_template_ids.difference(template_ids) + templates_clear_list = list(templates_clear) + request_str = {'hostid': host_id, 'templates': template_id_list, 'templates_clear': templates_clear_list, + 'ipmi_authtype': ipmi_authtype, 'ipmi_privilege': ipmi_privilege, 'ipmi_username': ipmi_username, 'ipmi_password': ipmi_password} + if tls_connect: + request_str['tls_connect'] = tls_connect + if tls_accept: + request_str['tls_accept'] = tls_accept + if tls_psk_identity is not None: + request_str['tls_psk_identity'] = tls_psk_identity + if tls_psk is not None: + request_str['tls_psk'] = tls_psk + if tls_issuer is not None: + request_str['tls_issuer'] = tls_issuer + if tls_subject is not None: + request_str['tls_subject'] = tls_subject + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.update(request_str) + except Exception as e: + self._module.fail_json(msg="Failed to link template to host: %s" % e) + + def inventory_mode_numeric(self, inventory_mode): + if inventory_mode == "automatic": + return int(1) + elif inventory_mode == "manual": + return int(0) + elif inventory_mode == "disabled": + return int(-1) + return inventory_mode + + # Update the host inventory_mode + def update_inventory_mode(self, host_id, inventory_mode): + + # nothing was set, do nothing + if not inventory_mode: + return + + inventory_mode = self.inventory_mode_numeric(inventory_mode) + + # watch for - https://support.zabbix.com/browse/ZBX-6033 + request_str = {'hostid': host_id, 'inventory_mode': inventory_mode} + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.update(request_str) + except Exception as e: + self._module.fail_json(msg="Failed to set inventory_mode to host: %s" % e) + + def update_inventory_zabbix(self, host_id, inventory): + + if not inventory: + return + + request_str = {'hostid': host_id, 'inventory': inventory} + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.update(request_str) + except Exception as e: + self._module.fail_json(msg="Failed to set inventory to host: %s" % e) + + +# Add all default values to all missing parameters for existing interfaces +def update_exist_interfaces_with_defaults(exist_interfaces): + + new_exist_interfaces = [] + default_interface = { + 'main': '0', + 'useip': '0', + 'ip': '', + 'dns': '', + 'port': '' + } + default_interface_details = { + 'version': 2, + 'bulk': 1, + 'community': '', + 'securityname': '', + 'contextname': '', + 'securitylevel': 0, + 'authprotocol': 0, + 'authpassphrase': '', + 'privprotocol': 0, + 'privpassphrase': '' + } + for interface in exist_interfaces: + new_interface = default_interface.copy() + new_interface.update(interface) + new_interface['details'] = default_interface_details.copy() + if 'details' in interface: + new_interface['details'].update(interface['details']) + new_exist_interfaces.append(new_interface) + + return new_exist_interfaces + + +def normalize_macro_name(macro_name): + # Zabbix handles macro names in upper case characters + if ':' in macro_name: + macro_name = ':'.join([macro_name.split(':')[0].upper(), ':'.join(macro_name.split(':')[1:])]) + else: + macro_name = macro_name.upper() + + # Valid format for macro is {$MACRO} + if not macro_name.startswith('{$'): + macro_name = '{$' + macro_name + if not macro_name.endswith('}'): + macro_name = macro_name + '}' + + return macro_name + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + host_name=dict(type='str', required=True), + host_groups=dict(type='list', required=False), + link_templates=dict(type='list', required=False), + status=dict(type='str', default="enabled", choices=['enabled', 'disabled']), + state=dict(type='str', default="present", choices=['present', 'absent']), + inventory_mode=dict(type='str', required=False, choices=['automatic', 'manual', 'disabled']), + ipmi_authtype=dict(type='int', default=None), + ipmi_privilege=dict(type='int', default=None), + ipmi_username=dict(type='str', required=False, default=None), + ipmi_password=dict(type='str', required=False, default=None, no_log=True), + tls_connect=dict(type='int', required=False), + tls_accept=dict(type='int', required=False), + tls_psk_identity=dict(type='str', required=False), + tls_psk=dict(type='str', required=False, no_log=True), + ca_cert=dict(type='str', required=False, aliases=['tls_issuer']), + tls_subject=dict(type='str', required=False), + inventory_zabbix=dict(type='dict', required=False), + interfaces=dict( + type='list', + elements='dict', + default=[], + options=dict( + type=dict(type='str', required=True, choices=['agent', '1', 'snmp', '2', 'ipmi', '3', 'jmx', '4']), + main=dict(type='int', choices=[0, 1], default=0), + useip=dict(type='int', choices=[0, 1], default=0), + ip=dict(type='str'), + dns=dict(type='str'), + port=dict(type='str'), + bulk=dict(type='int', choices=[0, 1], default=1), + details=dict( + type='dict', + default={}, + options=dict( + version=dict(type='int', choices=[1, 2, 3], default=2), + bulk=dict(type='int', choices=[0, 1], default=1), + community=dict(type='str', default=''), + securityname=dict(type='str', default=''), + contextname=dict(type='str', default=''), + securitylevel=dict(type='int', choices=[0, 1, 2], default=0), + authprotocol=dict(type='int', choices=[0, 1, 2, 3, 4, 5], default=0), + authpassphrase=dict(type='str', default='', no_log=True), + privprotocol=dict(type='int', choices=[0, 1, 2, 3, 4, 5], default=0), + privpassphrase=dict(type='str', default='', no_log=True) + ) + ) + ), + required_if=[ + ['useip', 0, ['dns']], + ['useip', 1, ['ip']] + ] + ), + force=dict(type='bool', default=True), + proxy=dict(type='str', required=False), + visible_name=dict(type='str', required=False), + description=dict(type='str', required=False), + macros=dict( + type='list', + elements='dict', + aliases=['user_macros'], + options=dict( + macro=dict(type='str', required=True), + value=dict(type='str', required=True), + description=dict(type='str', default=''), + type=dict(type='str', default='text', choices=['text', 'secret']) + ) + ), + tags=dict( + type='list', + elements='dict', + aliases=['host_tags'], + options=dict( + tag=dict(type='str', required=True), + value=dict(type='str', default='') + ) + ) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + host_name = module.params['host_name'] + visible_name = module.params['visible_name'] + description = module.params['description'] + host_groups = module.params['host_groups'] + link_templates = module.params['link_templates'] + inventory_mode = module.params['inventory_mode'] + ipmi_authtype = module.params['ipmi_authtype'] + ipmi_privilege = module.params['ipmi_privilege'] + ipmi_username = module.params['ipmi_username'] + ipmi_password = module.params['ipmi_password'] + tls_connect = module.params['tls_connect'] + tls_accept = module.params['tls_accept'] + tls_psk_identity = module.params['tls_psk_identity'] + tls_psk = module.params['tls_psk'] + tls_issuer = module.params['ca_cert'] + tls_subject = module.params['tls_subject'] + inventory_zabbix = module.params['inventory_zabbix'] + status = module.params['status'] + state = module.params['state'] + interfaces = module.params['interfaces'] + force = module.params['force'] + proxy = module.params['proxy'] + macros = module.params['macros'] + tags = module.params['tags'] + + # convert enabled to 0; disabled to 1 + status = 1 if status == "disabled" else 0 + + host = Host(module) + + template_ids = [] + if link_templates: + template_ids = host.get_template_ids(link_templates) + + group_ids = [] + + if host_groups: + group_ids = host.get_group_ids_by_group_names(host_groups) + + interfaces, ip = host.construct_host_interfaces(interfaces) + + if macros: + # convert macros to zabbix native format - {$MACRO} + for macro in macros: + macro['macro'] = normalize_macro_name(macro['macro']) + + if LooseVersion(host._zbx_api_version) <= LooseVersion('4.4.0'): + if 'description' in macro: + macro.pop('description', False) + + if 'type' in macro: + if LooseVersion(host._zbx_api_version) < LooseVersion('5.0.0'): + macro.pop('type') + else: + if macro['type'] == 'text': + macro['type'] = '0' + elif macro['type'] == 'secret': + macro['type'] = '1' + + # Use proxy specified, or set to 0 + if proxy: + proxy_id = host.get_proxyid_by_proxy_name(proxy) + else: + proxy_id = 0 + + # check if host exist + is_host_exist = host.is_host_exist(host_name) + + if is_host_exist: + # get host id by host name + zabbix_host_obj = host.get_host_by_host_name(host_name) + host_id = zabbix_host_obj['hostid'] + + # If proxy is not specified as a module parameter, use the existing setting + if proxy is None: + proxy_id = int(zabbix_host_obj['proxy_hostid']) + + if state == "absent": + # remove host + host.delete_host(host_id, host_name) + module.exit_json(changed=True, result="Successfully delete host %s" % host_name) + else: + if not host_groups: + # if host_groups have not been specified when updating an existing host, just + # get the group_ids from the existing host without updating them. + group_ids = host.get_group_ids_by_host_id(host_id) + + # get existing host's interfaces + exist_interfaces = host._zapi.hostinterface.get({'output': 'extend', 'hostids': host_id}) + exist_interfaces.sort(key=lambda x: int(x['interfaceid'])) + exist_interfaces = update_exist_interfaces_with_defaults(exist_interfaces) + + # Convert integer parameters from strings to ints + for idx, interface in enumerate(copy.deepcopy(exist_interfaces)): + for key in tuple(interface.keys()): + # fix values for properties + if key in ['useip', 'main', 'type', 'bulk']: + exist_interfaces[idx][key] = int(interface[key]) + elif key == 'details': + if not interface[key]: + exist_interfaces[idx][key] = {} + else: + for d_key in interface[key].keys(): + if d_key in ['version', 'bulk', 'securitylevel', 'authprotocol', 'privprotocol']: + exist_interfaces[idx][key][d_key] = int(interface[key][d_key]) + + interfaces_copy = copy.deepcopy(interfaces) + found_in_interfaces = [] + for idx, interface in enumerate(copy.deepcopy(exist_interfaces)): + interfaceid = interface['interfaceid'] + hostid = interface['hostid'] + + if not interfaces_copy: + # Whe no interfaces specified, copy existing interfaces + interfaces.append(interface) + continue + + # Find already configured interfaces in requested interfaces and compile final list of + # interfaces in 'interfaces' variable. Every element of the list defines one interface. + # If an element has 'interfaceid' field then Zabbix will update existing interface otherwise + # a new interface will be added. + found = False + for idx1, iface in enumerate(interfaces_copy): + diff_dict = {} + zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(iface, interface, diff_dict)) + if diff_dict == {}: + found = True + found_in_interfaces.append(iface) + interfaces[idx1]['interfaceid'] = interfaceid + interfaces[idx1]['hostid'] = hostid + break + + if not found: + if not force: + interfaces.append(interface) + else: + # if force == True overwrite existing interfaces with provided interfaces with the same type + for idx1, iface in enumerate(interfaces_copy): + if interface['type'] == iface['type'] and iface not in found_in_interfaces: + found_in_interfaces.append(iface) + interfaces[idx1]['interfaceid'] = interfaceid + interfaces[idx1]['hostid'] = hostid + break + + if not force or link_templates is None: + template_ids = list(set(template_ids + host.get_host_templates_by_host_id(host_id))) + + if not force: + for group_id in host.get_group_ids_by_host_id(host_id): + if group_id not in group_ids: + group_ids.append(group_id) + + # Macros not present in host.update will be removed if we dont copy them when force=no + if macros is not None and 'macros' in zabbix_host_obj.keys(): + existing_macros = zabbix_host_obj['macros'] + for macro in existing_macros: + macro.pop('hostmacroid', None) + macro.pop('hostid', None) + macro.pop('automatic', None) + found = False + for idx1, prov_macro in enumerate(macros): + diff_dict = {} + zabbix_utils.helper_compare_dictionaries(prov_macro, macro, diff_dict) + if diff_dict == {}: + found = True + break + if found: + macros[idx1] = macro + else: + macros.append(macro) + + # Tags not present in host.update will be removed if we dont copy them when force=no + if tags is not None and 'tags' in zabbix_host_obj.keys(): + provided_tags = [t['tag'] for t in tags] + existing_tags = zabbix_host_obj['tags'] + for tag in existing_tags: + if tag['tag'] not in provided_tags: + tags.append(tag) + + # update host + if host.check_all_properties( + host_id, group_ids, status, interfaces, template_ids, exist_interfaces, zabbix_host_obj, proxy_id, + visible_name, description, host_name, inventory_mode, inventory_zabbix, tls_accept, tls_psk_identity, tls_psk, + tls_issuer, tls_subject, tls_connect, ipmi_authtype, ipmi_privilege, + ipmi_username, ipmi_password, macros, tags): + + host.update_host( + host_name, group_ids, status, host_id, interfaces, exist_interfaces, proxy_id, visible_name, + description, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, + ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, macros, tags) + + host.link_or_clear_template( + host_id, template_ids, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, + tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password) + + host.update_inventory_mode(host_id, inventory_mode) + host.update_inventory_zabbix(host_id, inventory_zabbix) + + module.exit_json(changed=True, + result="Successfully update host %s (%s) and linked with template '%s'" + % (host_name, ip, link_templates)) + else: + module.exit_json(changed=False) + + else: + if state == "absent": + # the host is already deleted. + module.exit_json(changed=False) + + if not group_ids: + module.fail_json(msg="Specify at least one group for creating host '%s'." % host_name) + + if not interfaces or (interfaces and len(interfaces) == 0): + if LooseVersion(host._zbx_api_version) < LooseVersion('5.2.0'): + module.fail_json(msg="Specify at least one interface for creating host '%s'." % host_name) + + # create host + host_id = host.add_host( + host_name, group_ids, status, interfaces, proxy_id, visible_name, description, tls_connect, tls_accept, + tls_psk_identity, tls_psk, tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, + ipmi_password, macros, tags) + + host.link_or_clear_template( + host_id, template_ids, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, + ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password) + + host.update_inventory_mode(host_id, inventory_mode) + host.update_inventory_zabbix(host_id, inventory_zabbix) + + module.exit_json(changed=True, result="Successfully added host %s (%s) and linked with template '%s'" % ( + host_name, ip, link_templates)) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py new file mode 100644 index 000000000..eb22ce23c --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py @@ -0,0 +1,319 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) stephane.travassac@fr.clara.net +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +RETURN = ''' +--- +triggers_ok: + description: Host Zabbix Triggers in OK state + returned: On success + type: complex + contains: + comments: + description: Additional description of the trigger + type: str + description: + description: Name of the trigger + type: str + error: + description: Error text if there have been any problems when updating the state of the trigger + type: str + expression: + description: Reduced trigger expression + type: str + flags: + description: Origin of the trigger + type: int + lastchange: + description: Time when the trigger last changed its state (timestamp) + type: int + priority: + description: Severity of the trigger + type: int + state: + description: State of the trigger + type: int + status: + description: Whether the trigger is enabled or disabled + type: int + templateid: + description: ID of the parent template trigger + type: int + triggerid: + description: ID of the trigger + type: int + type: + description: Whether the trigger can generate multiple problem events + type: int + url: + description: URL associated with the trigger + type: str + value: + description: Whether the trigger is in OK or problem state + type: int +triggers_problem: + description: Host Zabbix Triggers in problem state. See trigger and event objects in API documentation of your zabbix version for more + returned: On success + type: complex + contains: + comments: + description: Additional description of the trigger + type: str + description: + description: Name of the trigger + type: str + error: + description: Error text if there have been any problems when updating the state of the trigger + type: str + expression: + description: Reduced trigger expression + type: str + flags: + description: Origin of the trigger + type: int + last_event: + description: last event informations + type: complex + contains: + acknowledged: + description: If set to true return only acknowledged events + type: int + acknowledges: + description: acknowledges informations + type: complex + contains: + alias: + description: Account who acknowledge + type: str + clock: + description: Time when the event was created (timestamp) + type: int + message: + description: Text of the acknowledgement message + type: str + clock: + description: Time when the event was created (timestamp) + type: int + eventid: + description: ID of the event + type: int + value: + description: State of the related object + type: int + lastchange: + description: Time when the trigger last changed its state (timestamp) + type: int + priority: + description: Severity of the trigger + type: int + state: + description: State of the trigger + type: int + status: + description: Whether the trigger is enabled or disabled + type: int + templateid: + description: ID of the parent template trigger + type: int + triggerid: + description: ID of the trigger + type: int + type: + description: Whether the trigger can generate multiple problem events + type: int + url: + description: URL associated with the trigger + type: str + value: + description: Whether the trigger is in OK or problem state + type: int +''' + +DOCUMENTATION = ''' +--- +module: zabbix_host_events_info +short_description: Get all triggers about a Zabbix host +description: + - This module allows you to see if a Zabbix host have no active alert to make actions on it. + For this case use module Ansible 'fail' to exclude host in trouble. + - Length of "triggers_ok" allow if template's triggers exist for Zabbix Host +author: + - "Stéphane Travassac (@stravassac)" +requirements: + - "python >= 2.7" +options: + host_identifier: + description: + - Identifier of Zabbix Host + required: true + type: str + host_id_type: + description: + - Type of host_identifier + choices: + - hostname + - visible_name + - hostid + required: false + default: hostname + type: str + trigger_severity: + description: + - Zabbix severity for search filter + default: average + required: false + choices: + - not_classified + - information + - warning + - average + - high + - disaster + type: str +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: exclude machine if alert active on it + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_host_events_info: + host_identifier: "{{inventory_hostname}}" + host_id_type: "hostname" + timeout: 120 + register: zbx_host + delegate_to: localhost +- fail: + msg: "machine alert in zabbix" + when: zbx_host['triggers_problem']|length > 0 +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Host(ZabbixBase): + def get_host(self, host_identifier, host_inventory, search_key): + """ Get host by hostname|visible_name|hostid """ + host = self._zapi.host.get( + {'output': 'extend', 'selectParentTemplates': ['name'], 'filter': {search_key: host_identifier}, + 'selectInventory': host_inventory}) + if len(host) < 1: + self._module.fail_json(msg="Host not found: %s" % host_identifier) + else: + return host[0] + + def get_triggers_by_host_id_in_problem_state(self, host_id, trigger_severity): + """ Get triggers in problem state from a hostid""" + # https://www.zabbix.com/documentation/3.4/manual/api/reference/trigger/get + output = 'extend' + triggers_list = self._zapi.trigger.get({'output': output, 'hostids': host_id, + 'min_severity': trigger_severity}) + return triggers_list + + def get_last_event_by_trigger_id(self, triggers_id): + """ Get the last event from triggerid""" + output = ['eventid', 'clock', 'acknowledged', 'value'] + select_acknowledges = ['clock', 'alias', 'message'] + event = self._zapi.event.get({'output': output, 'objectids': triggers_id, + 'select_acknowledges': select_acknowledges, "limit": 1, "sortfield": "clock", + "sortorder": "DESC"}) + return event[0] + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + host_identifier=dict(type='str', required=True), + host_id_type=dict( + default='hostname', + type='str', + choices=['hostname', 'visible_name', 'hostid']), + trigger_severity=dict( + type='str', + required=False, + default='average', + choices=['not_classified', 'information', 'warning', 'average', 'high', 'disaster']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + trigger_severity_map = {'not_classified': 0, 'information': 1, 'warning': 2, 'average': 3, 'high': 4, 'disaster': 5} + host_id = module.params['host_identifier'] + host_id_type = module.params['host_id_type'] + trigger_severity = trigger_severity_map[module.params['trigger_severity']] + + host_inventory = 'hostid' + + host = Host(module) + + if host_id_type == 'hostname': + zabbix_host = host.get_host(host_id, host_inventory, 'host') + host_id = zabbix_host['hostid'] + + elif host_id_type == 'visible_name': + zabbix_host = host.get_host(host_id, host_inventory, 'name') + host_id = zabbix_host['hostid'] + + elif host_id_type == 'hostid': + ''' check hostid exist''' + zabbix_host = host.get_host(host_id, host_inventory, 'hostid') + + triggers = host.get_triggers_by_host_id_in_problem_state(host_id, trigger_severity) + + triggers_ok = [] + triggers_problem = [] + for trigger in triggers: + # tGet last event for trigger with problem value = 1 + # https://www.zabbix.com/documentation/3.4/manual/api/reference/trigger/object + if int(trigger['value']) == 1: + event = host.get_last_event_by_trigger_id(trigger['triggerid']) + trigger['last_event'] = event + triggers_problem.append(trigger) + else: + triggers_ok.append(trigger) + + module.exit_json(ok=True, triggers_ok=triggers_ok, triggers_problem=triggers_problem) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py new file mode 100644 index 000000000..58e3343ab --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py @@ -0,0 +1,239 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) me@mimiko.me +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +RETURN = r''' +--- +hosts: + description: List of Zabbix hosts. See https://www.zabbix.com/documentation/4.0/manual/api/reference/host/get for list of host values. + returned: success + type: dict + sample: [ { "available": "1", "description": "", "disable_until": "0", "error": "", "flags": "0", "groups": ["1"], "host": "Host A", ... } ] +''' + +DOCUMENTATION = r''' +--- +module: zabbix_host_info +short_description: Gather information about Zabbix host +description: + - This module allows you to search for Zabbix host entries. + - This module was called C(zabbix_host_facts) before Ansible 2.9. The usage did not change. +author: + - "Michael Miko (@RedWhiteMiko)" +requirements: + - "python >= 2.6" +options: + host_name: + description: + - Name of the host in Zabbix. + - host_name is the unique identifier used and cannot be updated using this module. + - Required when I(host_ip) is not used. + required: false + type: str + default: '' + host_ip: + description: + - Host interface IP of the host in Zabbix. + - Required when I(host_name) is not used. + required: false + type: list + elements: str + default: [] + exact_match: + description: + - Find the exact match + type: bool + default: no + remove_duplicate: + description: + - Remove duplicate host from host result + type: bool + default: yes + host_inventory: + description: + - List of host inventory keys to display in result. + - Whole host inventory is retrieved if keys are not specified. + type: list + elements: str + required: false + default: [] +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get host info + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_host_info: + host_name: ExampleHost + host_ip: 127.0.0.1 + timeout: 10 + exact_match: no + remove_duplicate: yes + +- name: Reduce host inventory information to provided keys + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_host_info: + host_name: ExampleHost + host_inventory: + - os + - tag + host_ip: 127.0.0.1 + timeout: 10 + exact_match: no + remove_duplicate: yes +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Host(ZabbixBase): + def get_hosts_by_host_name(self, host_name, exact_match, host_inventory): + """ Get host by host name """ + search_key = 'search' + if exact_match: + search_key = 'filter' + host_list = self._zapi.host.get({ + 'output': 'extend', + 'selectParentTemplates': ['name'], + search_key: {'host': [host_name]}, + 'selectInventory': host_inventory, + 'selectGroups': 'extend', + 'selectTags': 'extend', + 'selectMacros': 'extend' + }) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + return host_list + + def get_hosts_by_ip(self, host_ips, host_inventory): + """ Get host by host ip(s) """ + hostinterfaces = self._zapi.hostinterface.get({ + 'output': 'extend', + 'filter': { + 'ip': host_ips + } + }) + if len(hostinterfaces) < 1: + self._module.fail_json(msg="Host not found: %s" % host_ips) + host_list = [] + for hostinterface in hostinterfaces: + host = self._zapi.host.get({ + 'output': 'extend', + 'selectGroups': 'extend', + 'selectParentTemplates': ['name'], + 'hostids': hostinterface['hostid'], + 'selectInventory': host_inventory, + 'selectTags': 'extend', + 'selectMacros': 'extend' + }) + host[0]['hostinterfaces'] = hostinterface + host_list.append(host[0]) + return host_list + + def delete_duplicate_hosts(self, hosts): + """ Delete duplicated hosts """ + unique_hosts = [] + listed_hostnames = [] + for zabbix_host in hosts: + if zabbix_host['name'] in listed_hostnames: + continue + unique_hosts.append(zabbix_host) + listed_hostnames.append(zabbix_host['name']) + return unique_hosts + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + host_name=dict(type='str', default='', required=False), + host_ip=dict(type='list', default=[], required=False), + exact_match=dict(type='bool', required=False, default=False), + remove_duplicate=dict(type='bool', required=False, default=True), + host_inventory=dict(type='list', default=[], required=False) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + if module._name == 'zabbix_host_facts': + module.deprecate("The 'zabbix_host_facts' module has been renamed to 'zabbix_host_info'", + collection_name="community.zabbix", version='2.0.0') # was 2.13 + + zabbix_utils.require_creds_params(module) + + host_name = module.params['host_name'] + host_ips = module.params['host_ip'] + exact_match = module.params['exact_match'] + is_remove_duplicate = module.params['remove_duplicate'] + host_inventory = module.params['host_inventory'] + + if not host_inventory: + host_inventory = 'extend' + + host = Host(module) + + if host_name: + hosts = host.get_hosts_by_host_name(host_name, exact_match, host_inventory) + if is_remove_duplicate: + hosts = host.delete_duplicate_hosts(hosts) + extended_hosts = [] + for zabbix_host in hosts: + zabbix_host['hostinterfaces'] = host._zapi.hostinterface.get({ + 'output': 'extend', 'hostids': zabbix_host['hostid'] + }) + extended_hosts.append(zabbix_host) + module.exit_json(ok=True, hosts=extended_hosts) + + elif host_ips: + extended_hosts = host.get_hosts_by_ip(host_ips, host_inventory) + if is_remove_duplicate: + hosts = host.delete_duplicate_hosts(extended_hosts) + module.exit_json(ok=True, hosts=extended_hosts) + else: + module.exit_json(ok=False, hosts=[], result="No Host present") + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py new file mode 100644 index 000000000..58e3343ab --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py @@ -0,0 +1,239 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) me@mimiko.me +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +RETURN = r''' +--- +hosts: + description: List of Zabbix hosts. See https://www.zabbix.com/documentation/4.0/manual/api/reference/host/get for list of host values. + returned: success + type: dict + sample: [ { "available": "1", "description": "", "disable_until": "0", "error": "", "flags": "0", "groups": ["1"], "host": "Host A", ... } ] +''' + +DOCUMENTATION = r''' +--- +module: zabbix_host_info +short_description: Gather information about Zabbix host +description: + - This module allows you to search for Zabbix host entries. + - This module was called C(zabbix_host_facts) before Ansible 2.9. The usage did not change. +author: + - "Michael Miko (@RedWhiteMiko)" +requirements: + - "python >= 2.6" +options: + host_name: + description: + - Name of the host in Zabbix. + - host_name is the unique identifier used and cannot be updated using this module. + - Required when I(host_ip) is not used. + required: false + type: str + default: '' + host_ip: + description: + - Host interface IP of the host in Zabbix. + - Required when I(host_name) is not used. + required: false + type: list + elements: str + default: [] + exact_match: + description: + - Find the exact match + type: bool + default: no + remove_duplicate: + description: + - Remove duplicate host from host result + type: bool + default: yes + host_inventory: + description: + - List of host inventory keys to display in result. + - Whole host inventory is retrieved if keys are not specified. + type: list + elements: str + required: false + default: [] +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get host info + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_host_info: + host_name: ExampleHost + host_ip: 127.0.0.1 + timeout: 10 + exact_match: no + remove_duplicate: yes + +- name: Reduce host inventory information to provided keys + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_host_info: + host_name: ExampleHost + host_inventory: + - os + - tag + host_ip: 127.0.0.1 + timeout: 10 + exact_match: no + remove_duplicate: yes +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Host(ZabbixBase): + def get_hosts_by_host_name(self, host_name, exact_match, host_inventory): + """ Get host by host name """ + search_key = 'search' + if exact_match: + search_key = 'filter' + host_list = self._zapi.host.get({ + 'output': 'extend', + 'selectParentTemplates': ['name'], + search_key: {'host': [host_name]}, + 'selectInventory': host_inventory, + 'selectGroups': 'extend', + 'selectTags': 'extend', + 'selectMacros': 'extend' + }) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + return host_list + + def get_hosts_by_ip(self, host_ips, host_inventory): + """ Get host by host ip(s) """ + hostinterfaces = self._zapi.hostinterface.get({ + 'output': 'extend', + 'filter': { + 'ip': host_ips + } + }) + if len(hostinterfaces) < 1: + self._module.fail_json(msg="Host not found: %s" % host_ips) + host_list = [] + for hostinterface in hostinterfaces: + host = self._zapi.host.get({ + 'output': 'extend', + 'selectGroups': 'extend', + 'selectParentTemplates': ['name'], + 'hostids': hostinterface['hostid'], + 'selectInventory': host_inventory, + 'selectTags': 'extend', + 'selectMacros': 'extend' + }) + host[0]['hostinterfaces'] = hostinterface + host_list.append(host[0]) + return host_list + + def delete_duplicate_hosts(self, hosts): + """ Delete duplicated hosts """ + unique_hosts = [] + listed_hostnames = [] + for zabbix_host in hosts: + if zabbix_host['name'] in listed_hostnames: + continue + unique_hosts.append(zabbix_host) + listed_hostnames.append(zabbix_host['name']) + return unique_hosts + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + host_name=dict(type='str', default='', required=False), + host_ip=dict(type='list', default=[], required=False), + exact_match=dict(type='bool', required=False, default=False), + remove_duplicate=dict(type='bool', required=False, default=True), + host_inventory=dict(type='list', default=[], required=False) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + if module._name == 'zabbix_host_facts': + module.deprecate("The 'zabbix_host_facts' module has been renamed to 'zabbix_host_info'", + collection_name="community.zabbix", version='2.0.0') # was 2.13 + + zabbix_utils.require_creds_params(module) + + host_name = module.params['host_name'] + host_ips = module.params['host_ip'] + exact_match = module.params['exact_match'] + is_remove_duplicate = module.params['remove_duplicate'] + host_inventory = module.params['host_inventory'] + + if not host_inventory: + host_inventory = 'extend' + + host = Host(module) + + if host_name: + hosts = host.get_hosts_by_host_name(host_name, exact_match, host_inventory) + if is_remove_duplicate: + hosts = host.delete_duplicate_hosts(hosts) + extended_hosts = [] + for zabbix_host in hosts: + zabbix_host['hostinterfaces'] = host._zapi.hostinterface.get({ + 'output': 'extend', 'hostids': zabbix_host['hostid'] + }) + extended_hosts.append(zabbix_host) + module.exit_json(ok=True, hosts=extended_hosts) + + elif host_ips: + extended_hosts = host.get_hosts_by_ip(host_ips, host_inventory) + if is_remove_duplicate: + hosts = host.delete_duplicate_hosts(extended_hosts) + module.exit_json(ok=True, hosts=extended_hosts) + else: + module.exit_json(ok=False, hosts=[], result="No Host present") + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py new file mode 100644 index 000000000..1fed5d889 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py @@ -0,0 +1,286 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_hostmacro +short_description: Create/update/delete Zabbix host macros +description: + - manages Zabbix host macros, it can create, update or delete them. +author: + - "Cove (@cove)" + - Dean Hailin Song (!UNKNOWN) +requirements: + - "python >= 2.6" +options: + host_name: + description: + - Name of the host. + required: true + type: str + macro_name: + description: + - Name of the host macro in zabbix native format C({$MACRO}) or simple format C(MACRO). + required: true + type: str + macro_value: + description: + - Value of the host macro. + - Required if I(state=present). + type: str + macro_type: + type: str + description: + - Type of the host macro. + - text (default) + - secret (Works only with Zabbix >= 5.0) + - vault (Works only with Zabbix >= 5.2) + required: false + choices: ['text', 'secret', 'vault'] + default: 'text' + state: + description: + - State of the macro. + - On C(present), it will create if macro does not exist or update the macro if the associated data is different. + - On C(absent) will remove a macro if it exists. + required: false + choices: ['present', 'absent'] + type: str + default: "present" + force: + description: + - Only updates an existing macro if set to C(yes). + default: 'yes' + type: bool + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create new host macro or update an existing macro's value + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_hostmacro: + host_name: ExampleHost + macro_name: EXAMPLE.MACRO + macro_value: Example value + state: present + +# Values with curly brackets need to be quoted otherwise they will be interpreted as a dictionary +- name: Create new host macro in Zabbix native format + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_hostmacro: + host_name: ExampleHost + macro_name: "{$EXAMPLE.MACRO}" + macro_value: Example value + state: present + +- name: Delete existing host macro + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_hostmacro: + host_name: ExampleHost + macro_name: "{$EXAMPLE.MACRO}" + state: absent +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class HostMacro(ZabbixBase): + # get host id by host name + def get_host_id(self, host_name): + try: + host_list = self._zapi.host.get({'output': 'extend', 'filter': {'host': host_name}}) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + host_id = host_list[0]['hostid'] + return host_id + except Exception as e: + self._module.fail_json(msg="Failed to get the host %s id: %s." % (host_name, e)) + + # get host macro + def get_host_macro(self, macro_name, host_id): + try: + host_macro_list = self._zapi.usermacro.get( + {"output": "extend", "selectSteps": "extend", 'hostids': [host_id], 'filter': {'macro': macro_name}}) + if len(host_macro_list) > 0: + return host_macro_list[0] + return None + except Exception as e: + self._module.fail_json(msg="Failed to get host macro %s: %s" % (macro_name, e)) + + # create host macro + def create_host_macro(self, macro_name, macro_value, macro_type, host_id): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'): + self._zapi.usermacro.create({'hostid': host_id, 'macro': macro_name, 'value': macro_value, 'type': macro_type}) + else: + self._zapi.usermacro.create({'hostid': host_id, 'macro': macro_name, 'value': macro_value}) + self._module.exit_json(changed=True, result="Successfully added host macro %s" % macro_name) + except Exception as e: + self._module.fail_json(msg="Failed to create host macro %s: %s" % (macro_name, e)) + + # update host macro + def update_host_macro(self, host_macro_obj, macro_name, macro_value, macro_type): + host_macro_id = host_macro_obj['hostmacroid'] + if host_macro_obj['macro'] == macro_name: + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'): + # no change only when macro type == 0. when type = 1 or 2 zabbix will not output value of it. + if host_macro_obj['type'] == '0' and macro_type == '0' and host_macro_obj['value'] == macro_value: + self._module.exit_json(changed=False, result="Host macro %s already up to date" % macro_name) + else: + if host_macro_obj['value'] == macro_value: + self._module.exit_json(changed=False, result="Host macro %s already up to date" % macro_name) + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'): + self._zapi.usermacro.update({'hostmacroid': host_macro_id, 'value': macro_value, 'type': macro_type}) + else: + self._zapi.usermacro.update({'hostmacroid': host_macro_id, 'value': macro_value}) + self._module.exit_json(changed=True, result="Successfully updated host macro %s" % macro_name) + except Exception as e: + self._module.fail_json(msg="Failed to update host macro %s: %s" % (macro_name, e)) + + # delete host macro + def delete_host_macro(self, host_macro_obj, macro_name): + host_macro_id = host_macro_obj['hostmacroid'] + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.delete([host_macro_id]) + self._module.exit_json(changed=True, result="Successfully deleted host macro %s" % macro_name) + except Exception as e: + self._module.fail_json(msg="Failed to delete host macro %s: %s" % (macro_name, e)) + + +def normalize_macro_name(macro_name): + # Zabbix handles macro names in upper case characters + if ':' in macro_name: + macro_name = ':'.join([macro_name.split(':')[0].upper(), ':'.join(macro_name.split(':')[1:])]) + else: + macro_name = macro_name.upper() + + # Valid format for macro is {$MACRO} + if not macro_name.startswith('{$'): + macro_name = '{$' + macro_name + if not macro_name.endswith('}'): + macro_name = macro_name + '}' + + return macro_name + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + host_name=dict(type='str', required=True), + macro_name=dict(type='str', required=True), + macro_value=dict(type='str', required=False), + macro_type=dict(type='str', default='text', choices=['text', 'secret', 'vault']), + state=dict(type='str', default='present', choices=['present', 'absent']), + force=dict(type='bool', default=True) + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ['state', 'present', ['macro_value']] + ], + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + host_name = module.params['host_name'] + macro_name = normalize_macro_name(module.params['macro_name']) + macro_value = module.params['macro_value'] + state = module.params['state'] + force = module.params['force'] + if module.params['macro_type'] == 'secret': + macro_type = '1' + elif module.params['macro_type'] == 'vault': + macro_type = '2' + else: + macro_type = '0' + + host_macro_class_obj = HostMacro(module) + + if host_name: + host_id = host_macro_class_obj.get_host_id(host_name) + host_macro_obj = host_macro_class_obj.get_host_macro(macro_name, host_id) + + if state == 'absent': + if not host_macro_obj: + module.exit_json(changed=False, msg="Host Macro %s does not exist" % macro_name) + else: + # delete a macro + host_macro_class_obj.delete_host_macro(host_macro_obj, macro_name) + else: + if not host_macro_obj: + # create host macro + host_macro_class_obj.create_host_macro(macro_name, macro_value, macro_type, host_id) + elif force: + # update host macro + host_macro_class_obj.update_host_macro(host_macro_obj, macro_name, macro_value, macro_type) + else: + module.exit_json(changed=False, result="Host macro %s already exists and force is set to no" % macro_name) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py new file mode 100644 index 000000000..901ff965a --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py @@ -0,0 +1,423 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright: (c) 2022, ONODERA Masaru <masaru-onodera@ieee.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: zabbix_housekeeping + +short_description: Update Zabbix housekeeping + +description: + - This module allows you to modify Zabbix housekeeping setting. + +author: + - ONODERA Masaru(@masa-orca) + +requirements: + - "python >= 2.6" + +version_added: 1.6.0 + +options: + hk_events_mode: + description: + - Internal housekeeping for events and alerts will be enabled if C(true). + required: false + type: bool + hk_events_trigger: + description: + - Storage period of trigger data (e.g. 365d). + required: false + type: str + hk_events_service: + description: + - Storage period of service data (e.g. 365d). + - This parameter is available since Zabbix 6.0. + required: false + type: str + hk_events_internal: + description: + - Storage period of internal data (e.g. 365d). + required: false + type: str + hk_events_discovery: + description: + - Storage period of network discovery (e.g. 365d). + required: false + type: str + hk_events_autoreg: + description: + - Storage period of autoregistration data (e.g. 365d). + required: false + type: str + hk_services_mode: + description: + - Internal housekeeping for services will be enabled if C(true). + required: false + type: bool + hk_services: + description: + - Storage period of services data (e.g. 365d). + required: false + type: str + hk_audit_mode: + description: + - Internal housekeeping for audit will be enabled if C(true). + required: false + type: bool + hk_audit: + description: + - Storage period of audit data (e.g. 365d). + required: false + type: str + hk_sessions_mode: + description: + - Internal housekeeping for sessions will be enabled if C(true). + required: false + type: bool + hk_sessions: + description: + - Storage period of sessions data (e.g. 365d). + required: false + type: str + hk_history_mode: + description: + - Internal housekeeping for history will be enabled if C(true). + required: false + type: bool + hk_history_global: + description: + - Overriding history period of each items will be enabled if C(true). + required: false + type: bool + hk_history: + description: + - Storage priod of history data (e.g. 365d). + required: false + type: str + hk_trends_mode: + description: + - Internal housekeeping for trends will be enabled if C(true). + required: false + type: bool + hk_trends_global: + description: + - Overriding trend period of each items will be enabled if C(true). + required: false + type: bool + hk_trends: + description: + - Storage priod of trends data (e.g. 365d). + required: false + type: str + compression_status: + description: + - TimescaleDB compression for history and trends will be enabled if C(true). + required: false + type: bool + compress_older: + description: + - Compress history and trends records older than this period if I(compression_status=true). + required: false + type: str + +notes: + - Zabbix 5.2 version and higher are supported. + +extends_documentation_fragment: + - community.zabbix.zabbix +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Update housekeeping all parameter + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_housekeeping: + login_user: Admin + login_password: secret + hk_events_mode: yes + hk_events_trigger: 365d + hk_events_service: 365d + hk_events_internal: 365d + hk_events_discovery: 365d + hk_events_autoreg: 365d + hk_services_mode: yes + hk_services: 365d + hk_audit_mode: yes + hk_audit: 365d + hk_sessions_mode: yes + hk_sessions: 365d + hk_history_mode: yes + hk_history_global: yes + hk_history: 365d + hk_trends_mode: yes + hk_trends_global: yes + hk_trends: 365d + compression_status: off + compress_older: 7d +''' + +RETURN = ''' +msg: + description: The result of the operation + returned: success + type: str + sample: 'Successfully update housekeeping setting' +''' + +import re + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Housekeeping(ZabbixBase): + def __init__(self, module, zbx=None, zapi_wrapper=None): + super(Housekeeping, self).__init__(module, zbx, zapi_wrapper) + if LooseVersion(self._zbx_api_version) < LooseVersion('5.2.0'): + module.fail_json(msg="This module doesn't support Zabbix versions lower than 5.2.0") + + # get housekeeping setting + def get_housekeeping(self): + try: + return self._zapi.housekeeping.get({'output': 'extend'}) + except Exception as e: + self._module.fail_json(msg="Failed to get housekeeping setting: %s" % e) + + # Check parameter about time is valid. + def check_time_parameter(self, key_name, value): + match_result = re.match("^[0-9]+[smhdw]$", value) + if not match_result: + self._module.fail_json(msg="Invalid value for %s! Please set value like 365d." % key_name) + + # update housekeeping setting + def update_housekeeping( + self, + current_housekeeping, + hk_events_mode, + hk_events_trigger, + hk_events_service, + hk_events_internal, + hk_events_discovery, + hk_events_autoreg, + hk_services_mode, + hk_services, + hk_audit_mode, + hk_audit, + hk_sessions_mode, + hk_sessions, + hk_history_mode, + hk_history_global, + hk_history, + hk_trends_mode, + hk_trends_global, + hk_trends, + compression_status, + compress_older): + try: + params = {} + + if isinstance(hk_events_mode, bool): + params['hk_events_mode'] = str(int(hk_events_mode)) + + if hk_events_trigger: + self.check_time_parameter('hk_events_trigger', hk_events_trigger) + params['hk_events_trigger'] = hk_events_trigger + + if hk_events_service: + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + self._module.warn('hk_events_service is ignored with <= Zabbix 5.4.') + else: + self.check_time_parameter('hk_events_service', hk_events_service) + params['hk_events_service'] = hk_events_service + + if hk_events_internal: + self.check_time_parameter('hk_events_internal', hk_events_internal) + params['hk_events_internal'] = hk_events_internal + + if hk_events_discovery: + self.check_time_parameter('hk_events_discovery', hk_events_discovery) + params['hk_events_discovery'] = hk_events_discovery + + if hk_events_autoreg: + self.check_time_parameter('hk_events_autoreg', hk_events_autoreg) + params['hk_events_autoreg'] = hk_events_autoreg + + if isinstance(hk_services_mode, bool): + params['hk_services_mode'] = str(int(hk_services_mode)) + + if hk_services: + self.check_time_parameter('hk_services', hk_services) + params['hk_services'] = hk_services + + if isinstance(hk_audit_mode, bool): + params['hk_audit_mode'] = str(int(hk_audit_mode)) + + if hk_audit: + self.check_time_parameter('hk_audit', hk_audit) + params['hk_audit'] = hk_audit + + if isinstance(hk_sessions_mode, bool): + params['hk_sessions_mode'] = str(int(hk_sessions_mode)) + + if hk_sessions: + self.check_time_parameter('hk_sessions', hk_sessions) + params['hk_sessions'] = hk_sessions + + if isinstance(hk_history_mode, bool): + params['hk_history_mode'] = str(int(hk_history_mode)) + + if isinstance(hk_history_global, bool): + params['hk_history_global'] = str(int(hk_history_global)) + + if hk_history: + self.check_time_parameter('hk_history', hk_history) + params['hk_history'] = hk_history + + if isinstance(hk_trends_mode, bool): + params['hk_trends_mode'] = str(int(hk_trends_mode)) + + if isinstance(hk_trends_global, bool): + params['hk_trends_global'] = str(int(hk_trends_global)) + + if hk_trends: + self.check_time_parameter('hk_trends', hk_trends) + params['hk_trends'] = hk_trends + + if isinstance(compression_status, bool): + params['compression_status'] = str(int(compression_status)) + + if compress_older: + self.check_time_parameter('compress_older', compress_older) + params['compress_older'] = compress_older + + future_housekeeping = current_housekeeping.copy() + future_housekeeping.update(params) + + if future_housekeeping != current_housekeeping: + if self._module.check_mode: + self._module.exit_json(changed=True) + + self._zapi.housekeeping.update(params) + self._module.exit_json(changed=True, result="Successfully update housekeeping setting") + else: + self._module.exit_json(changed=False, result="Housekeeping setting is already up to date") + except Exception as e: + self._module.fail_json(msg="Failed to update housekeeping setting, Exception: %s" % e) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + hk_events_mode=dict(type='bool'), + hk_events_trigger=dict(type='str'), + hk_events_service=dict(type='str'), + hk_events_internal=dict(type='str'), + hk_events_discovery=dict(type='str'), + hk_events_autoreg=dict(type='str'), + hk_services_mode=dict(type='bool'), + hk_services=dict(type='str'), + hk_audit_mode=dict(type='bool'), + hk_audit=dict(type='str'), + hk_sessions_mode=dict(type='bool'), + hk_sessions=dict(type='str'), + hk_history_mode=dict(type='bool'), + hk_history_global=dict(type='bool'), + hk_history=dict(type='str'), + hk_trends_mode=dict(type='bool'), + hk_trends_global=dict(type='bool'), + hk_trends=dict(type='str'), + compression_status=dict(type='bool'), + compress_older=dict(type='str') + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + hk_events_mode = module.params['hk_events_mode'] + hk_events_trigger = module.params['hk_events_trigger'] + hk_events_service = module.params['hk_events_service'] + hk_events_internal = module.params['hk_events_internal'] + hk_events_discovery = module.params['hk_events_discovery'] + hk_events_autoreg = module.params['hk_events_autoreg'] + hk_services_mode = module.params['hk_services_mode'] + hk_services = module.params['hk_services'] + hk_audit_mode = module.params['hk_audit_mode'] + hk_audit = module.params['hk_audit'] + hk_sessions_mode = module.params['hk_sessions_mode'] + hk_sessions = module.params['hk_sessions'] + hk_history_mode = module.params['hk_history_mode'] + hk_history_global = module.params['hk_history_global'] + hk_history = module.params['hk_history'] + hk_trends_mode = module.params['hk_trends_mode'] + hk_trends_global = module.params['hk_trends_global'] + hk_trends = module.params['hk_trends'] + compression_status = module.params['compression_status'] + compress_older = module.params['compress_older'] + + housekeeping = Housekeeping(module) + + current_housekeeping = housekeeping.get_housekeeping() + housekeeping.update_housekeeping( + current_housekeeping, + hk_events_mode, + hk_events_trigger, + hk_events_service, + hk_events_internal, + hk_events_discovery, + hk_events_autoreg, + hk_services_mode, + hk_services, + hk_audit_mode, + hk_audit, + hk_sessions_mode, + hk_sessions, + hk_history_mode, + hk_history_global, + hk_history, + hk_trends_mode, + hk_trends_global, + hk_trends, + compression_status, + compress_older + ) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py new file mode 100644 index 000000000..139db5057 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py @@ -0,0 +1,498 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013, Alexander Bulimov <lazywolf0@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_maintenance +short_description: Create Zabbix maintenance windows +description: + - This module will let you create Zabbix maintenance windows. +author: "Alexander Bulimov (@abulimov)" +requirements: + - "python >= 2.6" +options: + state: + description: + - Create or remove a maintenance window. Maintenance window to remove is identified by name. + default: present + choices: [ "present", "absent" ] + type: str + host_names: + description: + - Hosts to manage maintenance window for. + - B(Required) option when I(state=present) and I(host_groups) is not used. + aliases: [ "host_name" ] + type: list + elements: str + host_groups: + description: + - Host groups to manage maintenance window for. + - B(Required) option when I(state=present) and I(host_names) is not used. + aliases: [ "host_group" ] + type: list + elements: str + minutes: + description: + - Length of maintenance window in minutes. + default: 10 + type: int + name: + description: + - Unique name of maintenance window. + required: true + type: str + desc: + description: + - Short description of maintenance window. + default: Created by Ansible + type: str + collect_data: + description: + - Type of maintenance. With data collection, or without. + type: bool + default: 'yes' + visible_name: + description: + - Type of zabbix host name to use for identifying hosts to include in the maintenance. + - I(visible_name=yes) to search by visible name, I(visible_name=no) to search by technical name. + type: bool + default: 'yes' + version_added: '2.0.0' + tags: + description: + - List of tags to assign to the hosts in maintenance. + - Requires I(collect_data=yes). + type: list + elements: dict + suboptions: + tag: + description: + - Name of the tag. + type: str + required: true + value: + description: + - Value of the tag. + type: str + default: '' + operator: + description: + - Condition operator. + - Possible values is + - 0 - Equals + - 2 - Contains + type: int + default: 2 + +extends_documentation_fragment: +- community.zabbix.zabbix + + +notes: + - Useful for setting hosts in maintenance mode before big update, + and removing maintenance window after update. + - Module creates maintenance window from now() to now() + minutes, + so if Zabbix server's time and host's time are not synchronized, + you will get strange results. +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create a named maintenance window for host www1 for 90 minutes + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_maintenance: + name: Update of www1 + host_name: www1.example.com + state: present + minutes: 90 + +- name: Create a named maintenance window for host www1 and host groups Office and Dev + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_maintenance: + name: Update of www1 + host_name: www1.example.com + host_groups: + - Office + - Dev + state: present + tags: + - tag: ExampleHostsTag + - tag: ExampleHostsTag2 + value: ExampleTagValue + - tag: ExampleHostsTag3 + value: ExampleTagValue + operator: 0 + +- name: Create a named maintenance window for hosts www1 and db1, without data collection. + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_maintenance: + name: update + host_names: + - www1.example.com + - db1.example.com + state: present + collect_data: false + +- name: Remove maintenance window by name + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_maintenance: + name: Test1 + state: absent +''' + +import datetime +import time + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils +from ansible.module_utils.compat.version import LooseVersion + + +class MaintenanceModule(ZabbixBase): + def create_maintenance(self, group_ids, host_ids, start_time, + maintenance_type, period, name, desc, tags): + end_time = start_time + period + try: + parameters = { + "groupids": group_ids, + "hostids": host_ids, + "name": name, + "maintenance_type": maintenance_type, + "active_since": str(start_time), + "active_till": str(end_time), + "description": desc, + "timeperiods": [{ + "timeperiod_type": "0", + "start_date": str(start_time), + "period": str(period), + }] + } + if tags is not None: + parameters['tags'] = tags + self._zapi.maintenance.create(parameters) + # zabbix_api can call sys.exit() so we need to catch SystemExit here + except (Exception, SystemExit) as e: + return 1, None, str(e) + return 0, None, None + + def update_maintenance(self, maintenance_id, group_ids, host_ids, + start_time, maintenance_type, period, desc, tags): + end_time = start_time + period + try: + parameters = { + "maintenanceid": maintenance_id, + "groupids": group_ids, + "hostids": host_ids, + "maintenance_type": maintenance_type, + "active_since": str(start_time), + "active_till": str(end_time), + "description": desc, + "timeperiods": [{ + "timeperiod_type": "0", + "start_date": str(start_time), + "period": str(period), + }] + } + if tags is not None: + parameters['tags'] = tags + else: + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + parameters['tags'] = [] + self._zapi.maintenance.update(parameters) + # zabbix_api can call sys.exit() so we need to catch SystemExit here + except (Exception, SystemExit) as e: + return 1, None, str(e) + return 0, None, None + + def get_maintenance(self, name): + try: + maintenances = self._zapi.maintenance.get( + { + "filter": + { + "name": name, + }, + "selectGroups": "extend", + "selectHosts": "extend", + "selectTags": "extend" + } + ) + # zabbix_api can call sys.exit() so we need to catch SystemExit here + except (Exception, SystemExit) as e: + return 1, None, str(e) + + for maintenance in maintenances: + maintenance["groupids"] = [group["groupid"] for group + in maintenance["groups"]] if "groups" in maintenance else [] + maintenance["hostids"] = [host["hostid"] for host + in maintenance["hosts"]] if "hosts" in maintenance else [] + return 0, maintenance, None + + return 0, None, None + + def delete_maintenance(self, maintenance_id): + try: + self._zapi.maintenance.delete([maintenance_id]) + # zabbix_api can call sys.exit() so we need to catch SystemExit here + except (Exception, SystemExit) as e: + return 1, None, str(e) + return 0, None, None + + def get_group_ids(self, host_groups): + group_ids = [] + for group in host_groups: + try: + result = self._zapi.hostgroup.get( + { + "output": "extend", + "filter": + { + "name": group + } + } + ) + # zabbix_api can call sys.exit() so we need to catch SystemExit here + except (Exception, SystemExit) as e: + return 1, None, str(e) + + if not result: + return 1, None, "Group id for group %s not found" % group + + group_ids.append(result[0]["groupid"]) + + return 0, group_ids, None + + def get_host_ids(self, host_names, zabbix_host): + host_ids = [] + for host in host_names: + try: + result = self._zapi.host.get( + { + "output": "extend", + "filter": + { + zabbix_host: host + } + } + ) + # zabbix_api can call sys.exit() so we need to catch SystemExit here + except (Exception, SystemExit) as e: + return 1, None, str(e) + + if not result: + return 1, None, "Host id for host %s not found" % host + + host_ids.append(result[0]["hostid"]) + + return 0, host_ids, None + + def check_maint_properties(self, maintenance, group_ids, host_ids, maintenance_type, + start_time, period, desc, tags): + if sorted(group_ids) != sorted(maintenance["groupids"]): + return True + if sorted(host_ids) != sorted(maintenance["hostids"]): + return True + if str(maintenance_type) != maintenance["maintenance_type"]: + return True + if str(int(start_time)) != maintenance["active_since"]: + return True + if str(int(start_time + period)) != maintenance["active_till"]: + return True + if str(desc) != maintenance['description']: + return True + if tags is not None and 'tags' in maintenance: + if sorted(tags, key=lambda k: k['tag']) != sorted(maintenance['tags'], key=lambda k: k['tag']): + return True + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + state=dict(type='str', required=False, default='present', + choices=['present', 'absent']), + host_names=dict(type='list', required=False, + default=None, aliases=['host_name']), + minutes=dict(type='int', required=False, default=10), + host_groups=dict(type='list', required=False, + default=None, aliases=['host_group']), + name=dict(type='str', required=True), + desc=dict(type='str', required=False, default="Created by Ansible"), + collect_data=dict(type='bool', required=False, default=True), + visible_name=dict(type='bool', required=False, default=True), + tags=dict( + type='list', + elements='dict', + required=False, + options=dict( + tag=dict(type='str', required=True), + operator=dict(type='int', default=2), + value=dict(type='str', default='') + ) + ) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + maint = MaintenanceModule(module) + + host_names = module.params['host_names'] + host_groups = module.params['host_groups'] + state = module.params['state'] + minutes = module.params['minutes'] + name = module.params['name'] + desc = module.params['desc'] + collect_data = module.params['collect_data'] + visible_name = module.params['visible_name'] + tags = module.params['tags'] + + if collect_data: + maintenance_type = 0 + else: + maintenance_type = 1 + if tags is not None: + module.fail_json(msg="Tags cannot be provided for maintenance without data collection.") + + if visible_name: + zabbix_host = "name" + else: + zabbix_host = "host" + + changed = False + + if state == "present": + if not host_names and not host_groups: + module.fail_json( + msg="At least one host_name or host_group must be defined for each created maintenance.") + + now = datetime.datetime.now().replace(second=0) + start_time = int(time.mktime(now.timetuple())) + period = 60 * int(minutes) # N * 60 seconds + + if host_groups: + (rc, group_ids, error) = maint.get_group_ids(host_groups) + if rc != 0: + module.fail_json(msg="Failed to get group_ids: %s" % error) + else: + group_ids = [] + + if host_names: + (rc, host_ids, error) = maint.get_host_ids(host_names, zabbix_host) + if rc != 0: + module.fail_json(msg="Failed to get host_ids: %s" % error) + else: + host_ids = [] + + (rc, maintenance, error) = maint.get_maintenance(name) + if rc != 0: + module.fail_json( + msg="Failed to check maintenance %s existence: %s" % (name, error)) + + if maintenance and maint.check_maint_properties(maintenance, group_ids, host_ids, maintenance_type, + start_time, period, desc, tags): + if module.check_mode: + changed = True + else: + (rc, data, error) = maint.update_maintenance( + maintenance["maintenanceid"], group_ids, host_ids, start_time, maintenance_type, period, desc, tags) + if rc == 0: + changed = True + else: + module.fail_json( + msg="Failed to update maintenance: %s" % error) + + if not maintenance: + if module.check_mode: + changed = True + else: + (rc, data, error) = maint.create_maintenance( + group_ids, host_ids, start_time, maintenance_type, period, name, desc, tags) + if rc == 0: + changed = True + else: + module.fail_json( + msg="Failed to create maintenance: %s" % error) + + if state == "absent": + + (rc, maintenance, error) = maint.get_maintenance(name) + if rc != 0: + module.fail_json( + msg="Failed to check maintenance %s existence: %s" % (name, error)) + + if maintenance: + if module.check_mode: + changed = True + else: + (rc, data, error) = maint.delete_maintenance( + maintenance["maintenanceid"]) + if rc == 0: + changed = True + else: + module.fail_json( + msg="Failed to remove maintenance: %s" % error) + + module.exit_json(changed=changed) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py new file mode 100644 index 000000000..175b96df6 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py @@ -0,0 +1,818 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017-2018, Antony Alekseyev <antony.alekseyev@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: zabbix_map +author: + - "Antony Alekseyev (@Akint)" +short_description: Create/update/delete Zabbix maps +description: + - "This module allows you to create, modify and delete Zabbix map entries, + using Graphviz binaries and text description written in DOT language. + Nodes of the graph will become map elements and edges will become links between map elements. + See U(https://en.wikipedia.org/wiki/DOT_(graph_description_language)) and U(https://www.graphviz.org/) for details. + Inspired by U(http://blog.zabbix.com/maps-for-the-lazy/)." + - "The following extra node attributes are supported: + C(zbx_host) contains name of the host in Zabbix. Use this if desired type of map element is C(host). + C(zbx_group) contains name of the host group in Zabbix. Use this if desired type of map element is C(host group). + C(zbx_sysmap) contains name of the map in Zabbix. Use this if desired type of map element is C(map). + C(zbx_label) contains label of map element. + C(zbx_image) contains name of the image used to display the element in default state. + C(zbx_image_disabled) contains name of the image used to display disabled map element. + C(zbx_image_maintenance) contains name of the image used to display map element in maintenance. + C(zbx_image_problem) contains name of the image used to display map element with problems. + C(zbx_url) contains map element URL in C(name:url) format. + More than one URL could be specified by adding a postfix (e.g., C(zbx_url1), C(zbx_url2))." + - "The following extra link attributes are supported: + C(zbx_draw_style) contains link line draw style. Possible values: C(line), C(bold), C(dotted), C(dashed). + C(zbx_trigger) contains name of the trigger used as a link indicator in C(host_name:trigger_name) format. + More than one trigger could be specified by adding a postfix (e.g., C(zbx_trigger1), C(zbx_trigger2)). + C(zbx_trigger_color) contains indicator color specified either as CSS3 name or as a hexadecimal code starting with C(#). + C(zbx_trigger_draw_style) contains indicator draw style. Possible values are the same as for C(zbx_draw_style)." +requirements: + - "python >= 2.6" + - pydotplus + - webcolors + - Pillow + - Graphviz +options: + name: + description: + - Name of the map. + required: true + aliases: [ "map_name" ] + type: str + data: + description: + - Graph written in DOT language. + required: false + aliases: [ "dot_data" ] + type: str + state: + description: + - State of the map. + - On C(present), it will create if map does not exist or update the map if the associated data is different. + - On C(absent) will remove the map if it exists. + required: false + choices: ['present', 'absent'] + default: "present" + type: str + width: + description: + - Width of the map. + required: false + default: 800 + type: int + height: + description: + - Height of the map. + required: false + default: 600 + type: int + margin: + description: + - Size of white space between map's borders and its elements. + required: false + default: 40 + type: int + expand_problem: + description: + - Whether the problem trigger will be displayed for elements with a single problem. + required: false + type: bool + default: true + highlight: + description: + - Whether icon highlighting is enabled. + required: false + type: bool + default: true + label_type: + description: + - Map element label type. + required: false + choices: ['label', 'ip', 'name', 'status', 'nothing', 'custom'] + default: "name" + type: str + default_image: + description: + - Name of the Zabbix image used to display the element if this element doesn't have the C(zbx_image) attribute defined. + required: false + aliases: [ "image" ] + type: str + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +RETURN = r''' # ''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +### +### Example inventory: +# [web] +# web[01:03].example.com ansible_host=127.0.0.1 +# [db] +# db.example.com ansible_host=127.0.0.1 +# [backup] +# backup.example.com ansible_host=127.0.0.1 +### +### Each inventory host is present in Zabbix with a matching name. +### +### Contents of 'map.j2': +# digraph G { +# graph [layout=dot splines=false overlap=scale] +# INTERNET [zbx_url="Google:https://google.com" zbx_image="Cloud_(96)"] +# {% for web_host in groups.web %} +# {% set web_loop = loop %} +# web{{ '%03d' % web_loop.index }} [zbx_host="{{ web_host }}"] +# INTERNET -> web{{ '%03d' % web_loop.index }} [zbx_trigger="{{ web_host }}:Zabbix agent on {HOST.NAME} is unreachable for 5 minutes"] +# {% for db_host in groups.db %} +# {% set db_loop = loop %} +# web{{ '%03d' % web_loop.index }} -> db{{ '%03d' % db_loop.index }} +# {% endfor %} +# {% endfor %} +# { rank=same +# {% for db_host in groups.db %} +# {% set db_loop = loop %} +# db{{ '%03d' % db_loop.index }} [zbx_host="{{ db_host }}"] +# {% for backup_host in groups.backup %} +# {% set backup_loop = loop %} +# db{{ '%03d' % db_loop.index }} -> backup{{ '%03d' % backup_loop.index }} [color="blue"] +# {% endfor %} +# {% endfor %} +# {% for backup_host in groups.backup %} +# {% set backup_loop = loop %} +# backup{{ '%03d' % backup_loop.index }} [zbx_host="{{ backup_host }}"] +# {% endfor %} +# } +# } +### +### Create Zabbix map "Demo Map" made of template 'map.j2' +- name: Create Zabbix map + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_map: + name: Demo map + state: present + data: "{{ lookup('template', 'map.j2') }}" + default_image: Server_(64) + expand_problem: no + highlight: no + label_type: label + delegate_to: localhost + run_once: yes +''' + + +import base64 +import traceback + +from io import BytesIO +from operator import itemgetter + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +try: + import pydotplus + HAS_PYDOTPLUS = True + PYDOT_IMP_ERR = Exception() +except ImportError: + PYDOT_IMP_ERR = traceback.format_exc() + HAS_PYDOTPLUS = False + +try: + import webcolors + HAS_WEBCOLORS = True + WEBCOLORS_IMP_ERR = Exception() +except ImportError: + WEBCOLORS_IMP_ERR = traceback.format_exc() + HAS_WEBCOLORS = False + +try: + from PIL import Image + HAS_PIL = True + PIL_IMP_ERR = Exception() +except ImportError: + PIL_IMP_ERR = traceback.format_exc() + HAS_PIL = False + + +class Map(ZabbixBase): + def __init__(self, module, zbx=None, zapi_wrapper=None): + super(Map, self).__init__(module, zbx, zapi_wrapper) + self.map_name = module.params['name'] + self.dot_data = module.params['data'] + self.width = module.params['width'] + self.height = module.params['height'] + self.state = module.params['state'] + self.default_image = module.params['default_image'] + self.map_id = self._get_sysmap_id(self.map_name) + self.margin = module.params['margin'] + self.expand_problem = module.params['expand_problem'] + self.highlight = module.params['highlight'] + self.label_type = module.params['label_type'] + self.selements_sort_keys = self._get_selements_sort_keys() + + def _build_graph(self): + try: + graph_without_positions = pydotplus.graph_from_dot_data(self.dot_data) + dot_data_with_positions = graph_without_positions.create_dot() + graph_with_positions = pydotplus.graph_from_dot_data(dot_data_with_positions) + if graph_with_positions: + return graph_with_positions + except Exception as e: + self._module.fail_json(msg="Failed to build graph from DOT data: %s" % e) + + def get_map_config(self): + if not self.dot_data: + self._module.fail_json(msg="'data' is mandatory with state 'present'") + graph = self._build_graph() + nodes = self._get_graph_nodes(graph) + edges = self._get_graph_edges(graph) + icon_ids = self._get_icon_ids() + map_config = { + 'name': self.map_name, + 'label_type': self._get_label_type_id(self.label_type), + 'expandproblem': int(self.expand_problem), + 'highlight': int(self.highlight), + 'width': self.width, + 'height': self.height, + 'selements': self._get_selements(graph, nodes, icon_ids), + 'links': self._get_links(nodes, edges), + } + return map_config + + def _get_label_type_id(self, label_type): + label_type_ids = { + 'label': 0, + 'ip': 1, + 'name': 2, + 'status': 3, + 'nothing': 4, + 'custom': 5, + } + try: + label_type_id = label_type_ids[label_type] + except Exception as e: + self._module.fail_json(msg="Failed to find id for label type '%s': %s" % (label_type, e)) + return label_type_id + + def _get_images_info(self, data, icon_ids): + images = [ + { + 'dot_tag': 'zbx_image', + 'zbx_property': 'iconid_off', + 'mandatory': True + }, + { + 'dot_tag': 'zbx_image_disabled', + 'zbx_property': 'iconid_disabled', + 'mandatory': False + }, + { + 'dot_tag': 'zbx_image_maintenance', + 'zbx_property': 'iconid_maintenance', + 'mandatory': False + }, + { + 'dot_tag': 'zbx_image_problem', + 'zbx_property': 'iconid_on', + 'mandatory': False + } + ] + images_info = {} + default_image = self.default_image if self.default_image else sorted(icon_ids.items())[0][0] + for image in images: + image_name = data.get(image['dot_tag'], None) + if not image_name: + if image['mandatory']: + image_name = default_image + else: + continue + image_name = remove_quotes(image_name) + if image_name in icon_ids: + images_info[image['zbx_property']] = icon_ids[image_name] + if not image['mandatory']: + images_info['use_iconmap'] = 0 + else: + self._module.fail_json(msg="Failed to find id for image '%s'" % image_name) + return images_info + + def _get_element_type(self, data): + types = { + 'host': 0, + 'sysmap': 1, + 'trigger': 2, + 'group': 3, + 'image': 4 + } + element_type = { + 'elementtype': types['image'], + } + if LooseVersion(self._zbx_api_version) < LooseVersion('3.4'): + element_type.update({ + 'elementid': "0", + }) + for type_name, type_id in sorted(types.items()): + field_name = 'zbx_' + type_name + if field_name in data: + method_name = '_get_' + type_name + '_id' + element_name = remove_quotes(data[field_name]) + get_element_id = getattr(self, method_name, None) + if get_element_id: + elementid = get_element_id(element_name) + if elementid and int(elementid) > 0: + element_type.update({ + 'elementtype': type_id, + 'label': element_name + }) + if LooseVersion(self._zbx_api_version) < LooseVersion('3.4'): + element_type.update({ + 'elementid': elementid, + }) + else: + element_type.update({ + 'elements': [{ + type_name + 'id': elementid, + }], + }) + break + else: + self._module.fail_json(msg="Failed to find id for %s '%s'" % (type_name, element_name)) + return element_type + + # get list of map elements (nodes) + def _get_selements(self, graph, nodes, icon_ids): + selements = [] + icon_sizes = {} + scales = self._get_scales(graph) + for selementid, (node, data) in enumerate(nodes.items(), start=1): + selement = { + 'selementid': selementid + } + data['selementid'] = selementid + + images_info = self._get_images_info(data, icon_ids) + selement.update(images_info) + image_id = images_info['iconid_off'] + if image_id not in icon_sizes: + icon_sizes[image_id] = self._get_icon_size(image_id) + + pos = self._convert_coordinates(data['pos'], scales, icon_sizes[image_id]) + selement.update(pos) + + selement['label'] = remove_quotes(node) + element_type = self._get_element_type(data) + selement.update(element_type) + + label = self._get_label(data) + if label: + selement['label'] = label + + urls = self._get_urls(data) + if urls: + selement['urls'] = urls + + selements.append(selement) + return selements + + def _get_links(self, nodes, edges): + links = {} + for edge in edges: + link_id = tuple(sorted(edge.obj_dict['points'])) + node1, node2 = link_id + data = edge.obj_dict['attributes'] + + if "style" in data and data['style'] == "invis": + continue + + if link_id not in links: + links[link_id] = { + 'selementid1': min(nodes[node1]['selementid'], nodes[node2]['selementid']), + 'selementid2': max(nodes[node1]['selementid'], nodes[node2]['selementid']), + } + link = links[link_id] + + if "color" not in link: + link['color'] = self._get_color_hex(remove_quotes(data.get('color', 'green'))) + + if "zbx_draw_style" not in link: + link['drawtype'] = self._get_link_draw_style_id(remove_quotes(data.get('zbx_draw_style', 'line'))) + + label = self._get_label(data) + if label and "label" not in link: + link['label'] = label + + triggers = self._get_triggers(data) + if triggers: + if "linktriggers" not in link: + link['linktriggers'] = [] + link['linktriggers'] += triggers + + return list(links.values()) + + def _get_urls(self, data): + urls = [] + for url_raw in [remove_quotes(value) for key, value in data.items() if key.startswith("zbx_url")]: + try: + name, url = url_raw.split(':', 1) + except Exception as e: + self._module.fail_json(msg="Failed to parse zbx_url='%s': %s" % (url_raw, e)) + urls.append({ + 'name': name, + 'url': url, + }) + return urls + + def _get_triggers(self, data): + triggers = [] + for trigger_definition in [remove_quotes(value) for key, value in data.items() if key.startswith("zbx_trigger")]: + triggerid = self._get_trigger_id(trigger_definition) + if triggerid: + triggers.append({ + 'triggerid': triggerid, + 'color': self._get_color_hex(remove_quotes(data.get('zbx_trigger_color', 'red'))), + 'drawtype': self._get_link_draw_style_id(remove_quotes(data.get('zbx_trigger_draw_style', 'bold'))), + }) + else: + self._module.fail_json(msg="Failed to find trigger '%s'" % (trigger_definition)) + return triggers + + @staticmethod + def _get_label(data, default=None): + if "zbx_label" in data: + label = remove_quotes(data['zbx_label']).replace('\\n', '\n') + elif "label" in data: + label = remove_quotes(data['label']) + else: + label = default + return label + + def _get_sysmap_id(self, map_name): + exist_map = self._zapi.map.get({'filter': {'name': map_name}}) + if exist_map: + return exist_map[0]['sysmapid'] + return None + + def _get_group_id(self, group_name): + exist_group = self._zapi.hostgroup.get({'filter': {'name': group_name}}) + if exist_group: + return exist_group[0]['groupid'] + return None + + def map_exists(self): + return bool(self.map_id) + + def create_map(self, map_config): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + result = self._zapi.map.create(map_config) + if result: + return result + except Exception as e: + self._module.fail_json(msg="Failed to create map: %s" % e) + + def update_map(self, map_config): + if not self.map_id: + self._module.fail_json(msg="Failed to update map: map_id is unknown. Try to create_map instead.") + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + map_config['sysmapid'] = self.map_id + result = self._zapi.map.update(map_config) + if result: + return result + except Exception as e: + self._module.fail_json(msg="Failed to update map: %s" % e) + + def delete_map(self): + if not self.map_id: + self._module.fail_json(msg="Failed to delete map: map_id is unknown.") + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.map.delete([self.map_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete map, Exception: %s" % e) + + def is_exist_map_correct(self, generated_map_config): + exist_map_configs = self._zapi.map.get({ + 'sysmapids': self.map_id, + 'selectLinks': 'extend', + 'selectSelements': 'extend' + }) + exist_map_config = exist_map_configs[0] + if not self._is_dicts_equal(generated_map_config, exist_map_config): + return False + if not self._is_selements_equal(generated_map_config['selements'], exist_map_config['selements']): + return False + self._update_ids(generated_map_config, exist_map_config) + if not self._is_links_equal(generated_map_config['links'], exist_map_config['links']): + return False + return True + + def _get_selements_sort_keys(self): + keys_to_sort = ['label'] + if LooseVersion(self._zbx_api_version) < LooseVersion('3.4'): + keys_to_sort.insert(0, 'elementid') + return keys_to_sort + + def _is_selements_equal(self, generated_selements, exist_selements): + if len(generated_selements) != len(exist_selements): + return False + generated_selements_sorted = sorted(generated_selements, key=itemgetter(*self.selements_sort_keys)) + exist_selements_sorted = sorted(exist_selements, key=itemgetter(*self.selements_sort_keys)) + for (generated_selement, exist_selement) in zip(generated_selements_sorted, exist_selements_sorted): + if LooseVersion(self._zbx_api_version) >= LooseVersion('3.4'): + if not self._is_elements_equal(generated_selement.get('elements', []), exist_selement.get('elements', [])): + return False + if not self._is_dicts_equal(generated_selement, exist_selement, ['selementid']): + return False + if not self._is_urls_equal(generated_selement.get('urls', []), exist_selement.get('urls', [])): + return False + return True + + def _is_urls_equal(self, generated_urls, exist_urls): + if len(generated_urls) != len(exist_urls): + return False + generated_urls_sorted = sorted(generated_urls, key=itemgetter('name', 'url')) + exist_urls_sorted = sorted(exist_urls, key=itemgetter('name', 'url')) + for (generated_url, exist_url) in zip(generated_urls_sorted, exist_urls_sorted): + if not self._is_dicts_equal(generated_url, exist_url, ['selementid']): + return False + return True + + def _is_elements_equal(self, generated_elements, exist_elements): + if len(generated_elements) != len(exist_elements): + return False + generated_elements_sorted = sorted(generated_elements, key=lambda k: k.values()[0]) + exist_elements_sorted = sorted(exist_elements, key=lambda k: k.values()[0]) + for (generated_element, exist_element) in zip(generated_elements_sorted, exist_elements_sorted): + if not self._is_dicts_equal(generated_element, exist_element, ['selementid']): + return False + return True + + # since generated IDs differ from real Zabbix ones, make real IDs match generated ones + def _update_ids(self, generated_map_config, exist_map_config): + generated_selements_sorted = sorted(generated_map_config['selements'], key=itemgetter(*self.selements_sort_keys)) + exist_selements_sorted = sorted(exist_map_config['selements'], key=itemgetter(*self.selements_sort_keys)) + id_mapping = {} + for (generated_selement, exist_selement) in zip(generated_selements_sorted, exist_selements_sorted): + id_mapping[exist_selement['selementid']] = generated_selement['selementid'] + for link in exist_map_config['links']: + link['selementid1'] = id_mapping[link['selementid1']] + link['selementid2'] = id_mapping[link['selementid2']] + if link['selementid2'] < link['selementid1']: + link['selementid1'], link['selementid2'] = link['selementid2'], link['selementid1'] + + def _is_links_equal(self, generated_links, exist_links): + if len(generated_links) != len(exist_links): + return False + generated_links_sorted = sorted(generated_links, key=itemgetter('selementid1', 'selementid2', 'color', 'drawtype')) + exist_links_sorted = sorted(exist_links, key=itemgetter('selementid1', 'selementid2', 'color', 'drawtype')) + for (generated_link, exist_link) in zip(generated_links_sorted, exist_links_sorted): + if not self._is_dicts_equal(generated_link, exist_link, ['selementid1', 'selementid2']): + return False + if not self._is_triggers_equal(generated_link.get('linktriggers', []), exist_link.get('linktriggers', [])): + return False + return True + + def _is_triggers_equal(self, generated_triggers, exist_triggers): + if len(generated_triggers) != len(exist_triggers): + return False + generated_triggers_sorted = sorted(generated_triggers, key=itemgetter('triggerid')) + exist_triggers_sorted = sorted(exist_triggers, key=itemgetter('triggerid')) + for (generated_trigger, exist_trigger) in zip(generated_triggers_sorted, exist_triggers_sorted): + if not self._is_dicts_equal(generated_trigger, exist_trigger): + return False + return True + + @staticmethod + def _is_dicts_equal(d1, d2, exclude_keys=None): + if exclude_keys is None: + exclude_keys = [] + for key in d1.keys(): + if isinstance(d1[key], dict) or isinstance(d1[key], list): + continue + if key in exclude_keys: + continue + # compare as strings since Zabbix API returns everything as strings + if key not in d2 or str(d2[key]) != str(d1[key]): + return False + return True + + def _get_host_id(self, hostname): + hostid = self._zapi.host.get({'filter': {'host': hostname}}) + if hostid: + return str(hostid[0]['hostid']) + + def _get_trigger_id(self, trigger_definition): + try: + host, trigger = trigger_definition.split(':', 1) + except Exception as e: + self._module.fail_json(msg="Failed to parse zbx_trigger='%s': %s" % (trigger_definition, e)) + triggerid = self._zapi.trigger.get({ + 'host': host, + 'filter': { + 'description': trigger + } + }) + if triggerid: + return str(triggerid[0]['triggerid']) + + def _get_icon_ids(self): + icons_list = self._zapi.image.get({}) + icon_ids = {} + for icon in icons_list: + icon_ids[icon['name']] = icon['imageid'] + return icon_ids + + def _get_icon_size(self, icon_id): + icons_list = self._zapi.image.get({ + 'imageids': [ + icon_id + ], + 'select_image': True + }) + if len(icons_list) > 0: + icon_base64 = icons_list[0]['image'] + else: + self._module.fail_json(msg="Failed to find image with id %s" % icon_id) + image = Image.open(BytesIO(base64.b64decode(icon_base64))) + icon_width, icon_height = image.size + return icon_width, icon_height + + @staticmethod + def _get_node_attributes(node): + attr = {} + if "attributes" in node.obj_dict: + attr.update(node.obj_dict['attributes']) + pos = node.get_pos() + if pos is not None: + pos = remove_quotes(pos) + xx, yy = pos.split(",") + attr['pos'] = (float(xx), float(yy)) + return attr + + def _get_graph_nodes(self, parent): + nodes = {} + for node in parent.get_nodes(): + node_name = node.get_name() + if node_name in ('node', 'graph', 'edge'): + continue + nodes[node_name] = self._get_node_attributes(node) + for subgraph in parent.get_subgraphs(): + nodes.update(self._get_graph_nodes(subgraph)) + return nodes + + def _get_graph_edges(self, parent): + edges = [] + for edge in parent.get_edges(): + edges.append(edge) + for subgraph in parent.get_subgraphs(): + edges += self._get_graph_edges(subgraph) + return edges + + def _get_scales(self, graph): + bb = remove_quotes(graph.get_bb()) + min_x, min_y, max_x, max_y = bb.split(",") + scale_x = (self.width - self.margin * 2) / (float(max_x) - float(min_x)) if float(max_x) != float(min_x) else 0 + scale_y = (self.height - self.margin * 2) / (float(max_y) - float(min_y)) if float(max_y) != float(min_y) else 0 + return { + 'min_x': float(min_x), + 'min_y': float(min_y), + 'max_x': float(max_x), + 'max_y': float(max_y), + 'scale_x': float(scale_x), + 'scale_y': float(scale_y), + } + + # transform Graphviz coordinates to Zabbix's ones + def _convert_coordinates(self, pos, scales, icon_size): + return { + 'x': int((pos[0] - scales['min_x']) * scales['scale_x'] - icon_size[0] / 2 + self.margin), + 'y': int((scales['max_y'] - pos[1] + scales['min_y']) * scales['scale_y'] - icon_size[1] / 2 + self.margin), + } + + def _get_color_hex(self, color_name): + if color_name.startswith('#'): + color_hex = color_name + else: + try: + color_hex = webcolors.name_to_hex(color_name) + except Exception as e: + self._module.fail_json(msg="Failed to get RGB hex for color '%s': %s" % (color_name, e)) + color_hex = color_hex.strip('#').upper() + return color_hex + + def _get_link_draw_style_id(self, draw_style): + draw_style_ids = { + 'line': 0, + 'bold': 2, + 'dotted': 3, + 'dashed': 4 + } + try: + draw_style_id = draw_style_ids[draw_style] + except Exception as e: + self._module.fail_json(msg="Failed to find id for draw type '%s': %s" % (draw_style, e)) + return draw_style_id + + +# If a string has single or double quotes around it, remove them. +def remove_quotes(s): + if (s[0] == s[-1]) and s.startswith(("'", '"')): + s = s[1:-1] + return s + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True, aliases=['map_name']), + data=dict(type='str', required=False, aliases=['dot_data']), + width=dict(type='int', default=800), + height=dict(type='int', default=600), + state=dict(type='str', default="present", choices=['present', 'absent']), + default_image=dict(type='str', required=False, aliases=['image']), + margin=dict(type='int', default=40), + expand_problem=dict(type='bool', default=True), + highlight=dict(type='bool', default=True), + label_type=dict(type='str', default='name', choices=['label', 'ip', 'name', 'status', 'nothing', 'custom']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + if not HAS_PYDOTPLUS: + module.fail_json(msg=missing_required_lib('pydotplus', url='https://pypi.org/project/pydotplus/'), exception=PYDOT_IMP_ERR) + if not HAS_WEBCOLORS: + module.fail_json(msg=missing_required_lib('webcolors', url='https://pypi.org/project/webcolors/'), exception=WEBCOLORS_IMP_ERR) + if not HAS_PIL: + module.fail_json(msg=missing_required_lib('Pillow', url='https://pypi.org/project/Pillow/'), exception=PIL_IMP_ERR) + + sysmap = Map(module) + + if sysmap.state == "absent": + if sysmap.map_exists(): + sysmap.delete_map() + module.exit_json(changed=True, result="Successfully deleted map: %s" % sysmap.map_name) + else: + module.exit_json(changed=False) + else: + map_config = sysmap.get_map_config() + if sysmap.map_exists(): + if sysmap.is_exist_map_correct(map_config): + module.exit_json(changed=False) + else: + sysmap.update_map(map_config) + module.exit_json(changed=True, result="Successfully updated map: %s" % sysmap.map_name) + else: + sysmap.create_map(map_config) + module.exit_json(changed=True, result="Successfully created map: %s" % sysmap.map_name) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py new file mode 100644 index 000000000..c5693f467 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py @@ -0,0 +1,864 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_mediatype +short_description: Create/Update/Delete Zabbix media types +description: + - This module allows you to create, modify and delete Zabbix media types. +author: + - Ruben Tsirunyan (@rubentsirunyan) +requirements: + - "python >= 2.6" + +options: + name: + type: 'str' + description: + - Name of the media type. + required: true + description: + type: 'str' + description: + - Description of the media type. + - Works only with Zabbix versions 4.4 or newer. + default: '' + state: + type: 'str' + description: + - Desired state of the mediatype. + - On C(present), it will create a mediatype if it does not exist or update the mediatype if the associated data is different. + - On C(absent), it will remove the mediatype if it exists. + choices: + - present + - absent + default: 'present' + type: + type: 'str' + description: + - Type of the media type. + - Media types I(jabber) and I(ez_texting) works only with Zabbix versions 4.2 or older. + - Media type I(webhook) works only with Zabbix versions 4.4 or newer. + choices: + - email + - script + - sms + - webhook + - jabber + - ez_texting + required: true + status: + type: 'str' + description: + - Whether the media type is enabled or no. + choices: + - enabled + - disabled + default: 'enabled' + max_sessions: + type: 'int' + description: + - The maximum number of alerts that can be processed in parallel. + - Possible value is 1 when I(type=sms) and 0-100 otherwise. + - Works only with Zabbix versions 3.4 or newer. + default: 1 + max_attempts: + type: 'int' + description: + - The maximum number of attempts to send an alert. + - Possible range is 0-10. + - Works only with Zabbix versions 3.4 or newer. + default: 3 + attempt_interval: + type: 'str' + description: + - The interval between retry attempts. + - Possible range is 0-60s in Zabbix < 5.0 or 0-1h in Zabbix >= 5.0. + - Works only with Zabbix versions 3.4 or newer. + default: 10s + script_name: + type: 'str' + description: + - The name of the executed script. + - Required when I(type=script). + script_params: + type: 'list' + elements: str + description: + - List of script parameters. + - Required when I(type=script). + gsm_modem: + type: 'str' + description: + - Serial device name of the gsm modem. + - Required when I(type=sms). + username: + type: 'str' + description: + - Username or Jabber identifier. + - Required when I(type=jabber) or I(type=ez_texting). + - Required when I(type=email) and I(smtp_authentication=true). + password: + type: 'str' + description: + - Authentication password. + - Required when I(type=jabber) or I(type=ez_texting). + - Required when I(type=email) and I(smtp_authentication=true). + smtp_server: + type: 'str' + description: + - SMTP server host. + - Required when I(type=email). + default: 'localhost' + smtp_server_port: + type: 'int' + description: + - SMTP server port. + - Required when I(type=email). + default: 25 + smtp_helo: + type: 'str' + description: + - SMTP HELO. + - Required when I(type=email). + default: 'localhost' + smtp_email: + type: 'str' + description: + - Email address from which notifications will be sent. + - Required when I(type=email). + smtp_authentication: + type: 'bool' + description: + - Whether SMTP authentication with username and password should be enabled or not. + - If set to C(true), C(username) and C(password) should be specified. + default: false + smtp_security: + type: 'str' + description: + - SMTP connection security level to use. + choices: + - None + - STARTTLS + - SSL/TLS + smtp_verify_host: + type: 'bool' + description: + - SSL verify host for SMTP. + - Can be specified when I(smtp_security=STARTTLS) or I(smtp_security=SSL/TLS) + default: false + smtp_verify_peer: + type: 'bool' + description: + - SSL verify peer for SMTP. + - Can be specified when I(smtp_security=STARTTLS) or I(smtp_security=SSL/TLS) + default: false + message_text_limit: + type: 'str' + description: + - The message text limit. + - Required when I(type=ez_texting). + - 160 characters for USA and 136 characters for Canada. + choices: + - USA + - Canada + webhook_script: + type: 'str' + description: + - Required when I(type=webhook). + - JavaScript code that will perform webhook operation. + - This code has access to all parameters in I(webhook_params). + - It may perform HTTP GET, POST, PUT and DELETE requests and has control over HTTP headers and request body. + - It may return OK status along with an optional list of tags and tag values or an error string. + - Works only with Zabbix versions 4.4 or newer. + webhook_timeout: + type: 'str' + description: + - Can be used when I(type=webhook). + - Execution timeout for JavaScript code in I(webhook_script). + - Possible values are 1-60s. + default: 30s + process_tags: + type: 'bool' + description: + - Can be used when I(type=webhook). + - Process returned JSON property values as tags. + - These tags are added to the already existing (if any) problem event tags in Zabbix. + default: false + event_menu: + type: 'bool' + description: + - Can be used when I(type=webhook). + - Includes entry in Event menu with link to created external ticket. + default: false + event_menu_url: + type: 'str' + description: + - Requred when I(event_menu=true). + - Event menu entry underlying URL. + event_menu_name: + type: 'str' + description: + - Requred when I(event_menu=true). + - Event menu entry name. + webhook_params: + type: 'list' + elements: 'dict' + description: + - Can be used when I(type=webhook). + - Webhook variables that are passed to webhook script when executed. + default: [] + suboptions: + name: + type: 'str' + description: + - Name of the parameter. + required: true + value: + type: 'str' + description: + - Value of the parameter. + - All macros that are supported in problem notifications are supported in the parameters. + - Values are URL-encoded automatically. Values from macros are resolved and then URL-encoded automatically. + default: '' + message_templates: + type: 'list' + elements: 'dict' + description: + - Default notification messages for the event types. + - Works only with Zabbix versions 5.0 or newer. + default: [] + suboptions: + eventsource: + type: 'str' + description: + - Event source. + - Required when I(recovery) is used. + choices: + - triggers + - discovery + - autoregistration + - internal + recovery: + type: 'str' + description: + - Operation mode. + - Required when I(eventsource) is used. + choices: + - operations + - recovery_operations + - update_operations + subject: + type: 'str' + description: + - Subject of the default message. + - May contain macros and is limited to 255 characters. + default: '' + body: + type: 'str' + description: + - Body of the default message. + - May contain macros. + default: '' + +extends_documentation_fragment: +- community.zabbix.zabbix + + +''' + +RETURN = r''' # ''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: 'Create an email mediatype with SMTP authentication' + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_mediatype: + name: "Ops email" + type: 'email' + smtp_server: 'example.com' + smtp_server_port: 2000 + smtp_email: 'ops@example.com' + smtp_authentication: true + username: 'smtp_user' + password: 'smtp_pass' + +- name: 'Create a script mediatype' + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_mediatype: + name: "my script" + type: 'script' + script_name: 'my_script.py' + script_params: + - 'arg1' + - 'arg2' + +- name: 'Create a jabber mediatype' + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_mediatype: + name: "My jabber" + type: 'jabber' + username: 'jabber_id' + password: 'jabber_pass' + +- name: 'Create a SMS mediatype' + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_mediatype: + name: "My SMS Mediatype" + type: 'sms' + gsm_modem: '/dev/ttyS0' + +# Supported since Zabbix 4.4 +- name: 'Create a webhook mediatype' + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_mediatype: + name: "My webhook Mediatype" + type: 'webhook' + webhook_script: "{{ lookup('file', 'slack.js') }}" + webhook_params: + - name: alert_message + value: '{ALERT.MESSAGE}' + - name: zabbix_url + value: '{$ZABBIX.URL}' + process_tags: true + event_menu: true + event_menu_name: "Open in Slack: '{EVENT.TAGS.__channel_name}'" + event_menu_url: '{EVENT.TAGS.__message_link}' + +# Supported since Zabbix 5.0 +- name: 'Create an email mediatype with message templates' + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_mediatype: + name: "Ops email" + type: 'email' + smtp_email: 'ops@example.com' + message_templates: + - eventsource: triggers + recovery: operations + subject: "Problem: {EVENT.NAME}" + body: "Problem started at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: triggers + recovery: recovery_operations + subject: "Resolved: {EVENT.NAME}" + body: "Problem resolved at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: triggers + recovery: update_operations + subject: "Updated problem: {EVENT.NAME}" + body: "{USER.FULLNAME} {EVENT.UPDATE.ACTION} problem at {EVENT.UPDATE.DATE} {EVENT.UPDATE.TIME}.\r\n" + - eventsource: discovery + recovery: operations + subject: "Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}" + body: "Discovery rule: {DISCOVERY.RULE.NAME}\r\n\r\nDevice IP: {DISCOVERY.DEVICE.IPADDRESS}" + - eventsource: autoregistration + recovery: operations + subject: "Autoregistration: {HOST.HOST}" + body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}" +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +def diff(existing, new): + """Constructs the diff for Ansible's --diff option. + + Args: + existing (dict): Existing mediatype data. + new (dict): New mediatype data. + + Returns: + A dictionary like {'before': existing, 'after': new} + with filtered empty values. + """ + before = {} + after = {} + for key in new: + before[key] = existing[key] + if new[key] is None: + after[key] = '' + else: + after[key] = new[key] + return {'before': before, 'after': after} + + +class MediaTypeModule(ZabbixBase): + def check_if_mediatype_exists(self, name): + """Checks if mediatype exists. + + Args: + name: Zabbix mediatype name + + Returns: + Tuple of (True, `id of the mediatype`) if mediatype exists, (False, None) otherwise + """ + filter_key_name = 'description' + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'): + # description key changed to name key from zabbix 4.4 + filter_key_name = 'name' + + try: + mediatype_list = self._zapi.mediatype.get({ + 'output': 'extend', + 'filter': {filter_key_name: [name]} + }) + if len(mediatype_list) < 1: + return False, None + else: + return True, mediatype_list[0]['mediatypeid'] + except Exception as e: + self._module.fail_json(msg="Failed to get ID of the mediatype '{name}': {e}".format(name=name, e=e)) + + def construct_parameters(self): + """Translates data to a format suitable for Zabbix API and filters + the ones that are related to the specified mediatype type. + + Returns: + A dictionary of arguments that are related to transport type, + and are in a format that is understandable by Zabbix API. + """ + truths = {'False': '0', 'True': '1'} + parameters = dict( + status='0' if self._module.params['status'] == 'enabled' else '1', + type={ + 'email': '0', + 'script': '1', + 'sms': '2', + 'jabber': '3', + 'webhook': '4', + 'ez_texting': '100' + }.get(self._module.params['type']), + ) + + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'): + parameters.update(dict( + name=self._module.params['name'], + description=self._module.params['description'], + )) + else: + parameters.update(dict(description=self._module.params['name'])) + + if LooseVersion(self._zbx_api_version) >= LooseVersion('3.4'): + parameters.update(dict( + maxsessions=str(self._module.params['max_sessions']), + maxattempts=str(self._module.params['max_attempts']), + attempt_interval=str(self._module.params['attempt_interval']) + )) + + if self._module.params['message_templates'] and LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'): + msg_templates = [] + for template in self._module.params['message_templates']: + msg_templates.append(dict( + eventsource={ + 'triggers': '0', + 'discovery': '1', + 'autoregistration': '2', + 'internal': '3'}.get(template['eventsource']), + recovery={ + 'operations': '0', + 'recovery_operations': '1', + 'update_operations': '2'}.get(template['recovery']), + subject=template['subject'], + message=template['body'] + )) + parameters.update(dict(message_templates=msg_templates)) + + if self._module.params['type'] == 'email': + parameters.update(dict( + smtp_server=self._module.params['smtp_server'], + smtp_port=str(self._module.params['smtp_server_port']), + smtp_helo=self._module.params['smtp_helo'], + smtp_email=self._module.params['smtp_email'], + smtp_security={'None': '0', 'STARTTLS': '1', 'SSL/TLS': '2'}.get(str(self._module.params['smtp_security'])), + smtp_authentication=truths.get(str(self._module.params['smtp_authentication'])), + smtp_verify_host=truths.get(str(self._module.params['smtp_verify_host'])), + smtp_verify_peer=truths.get(str(self._module.params['smtp_verify_peer'])), + username=self._module.params['username'], + passwd=self._module.params['password'] + )) + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + if parameters['smtp_authentication'] == '0': + parameters.pop('username') + parameters.pop('passwd') + return parameters + + elif self._module.params['type'] == 'script': + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + if self._module.params['script_params'] is None: + _script_params = '' # ZBX-15706 + else: + _script_params = '\n'.join(str(i) for i in self._module.params['script_params']) + '\n' + parameters.update(dict( + exec_path=self._module.params['script_name'], + exec_params=_script_params + )) + else: + _script_params = [] + if self._module.params['script_params']: + for i, val in enumerate(self._module.params['script_params']): + _script_params.append({'sortorder': str(i), 'value': val}) + parameters.update(dict( + exec_path=self._module.params['script_name'], + parameters=_script_params + )) + return parameters + + elif self._module.params['type'] == 'sms': + parameters.update(dict(gsm_modem=self._module.params['gsm_modem'])) + return parameters + + elif self._module.params['type'] == 'webhook' and LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'): + parameters.update(dict( + script=self._module.params['webhook_script'], + timeout=self._module.params['webhook_timeout'], + process_tags=truths.get(str(self._module.params['process_tags'])), + show_event_menu=truths.get(str(self._module.params['event_menu'])), + parameters=self._module.params['webhook_params'] + )) + if self._module.params['event_menu']: + parameters.update(dict( + event_menu_url=self._module.params['event_menu_url'], + event_menu_name=self._module.params['event_menu_name'] + )) + return parameters + + elif self._module.params['type'] == 'jabber' and LooseVersion(self._zbx_api_version) <= LooseVersion('4.2'): + parameters.update(dict( + username=self._module.params['username'], + passwd=self._module.params['password'] + )) + return parameters + + elif self._module.params['type'] == 'ez_texting' and LooseVersion(self._zbx_api_version) <= LooseVersion('4.2'): + parameters.update(dict( + username=self._module.params['username'], + passwd=self._module.params['password'], + exec_path={'USA': '0', 'Canada': '1'}.get(self._module.params['message_text_limit']), + )) + return parameters + + self._module.fail_json(msg="%s is unsupported for Zabbix version %s" % (parameters['unsupported_parameter'], parameters['zbx_api_version'])) + + def validate_params(self, params): + """Validates arguments that are required together. + + Fails the module with the message that shows the missing + requirements if there are some. + + Args: + params (list): Each element of this list + is a list like + ['argument_key', 'argument_value', ['required_arg_1', + 'required_arg_2']]. + Format is the same as `required_if` parameter of AnsibleModule. + """ + for param in params: + if self._module.params[param[0]] == param[1]: + if None in [self._module.params[i] for i in param[2]]: + self._module.fail_json( + msg="Following arguments are required when {key} is {value}: {arguments}".format( + key=param[0], + value=param[1], + arguments=', '.join(param[2]) + ) + ) + + def get_update_params(self, mediatype_id, **kwargs): + """Filters only the parameters that are different and need to be updated. + + Args: + mediatype_id (int): ID of the mediatype to be updated. + **kwargs: Parameters for the new mediatype. + + Returns: + A tuple where the first element is a dictionary of parameters + that need to be updated and the second one is a dictionary + returned by diff() function with + existing mediatype data and new params passed to it. + """ + get_params = {'output': 'extend', 'mediatypeids': [mediatype_id]} + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'): + get_params.update({'selectMessageTemplates': 'extend'}) + + existing_mediatype = self._zapi.mediatype.get(get_params)[0] + + if existing_mediatype['type'] != kwargs['type']: + return kwargs, diff(existing_mediatype, kwargs) + else: + params_to_update = {} + for key in kwargs: + # sort list of parameters to prevent mismatch due to reordering + if key == 'parameters' and (kwargs[key] != [] or existing_mediatype[key] != []): + if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'): + kwargs[key] = sorted(kwargs[key], key=lambda x: x['name']) + existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['name']) + else: + if kwargs['type'] == '1': # script + kwargs[key] = sorted(kwargs[key], key=lambda x: x['sortorder']) + existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['sortorder']) + elif kwargs['type'] == '4': # webhook + kwargs[key] = sorted(kwargs[key], key=lambda x: x['name']) + existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['name']) + + if key == 'message_templates' and (kwargs[key] != [] or existing_mediatype[key] != []): + kwargs[key] = sorted(kwargs[key], key=lambda x: x['subject']) + existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['subject']) + + if (not (kwargs[key] is None and existing_mediatype[key] == '')) and kwargs[key] != existing_mediatype[key]: + params_to_update[key] = kwargs[key] + return params_to_update, diff(existing_mediatype, kwargs) + + def delete_mediatype(self, mediatype_id): + try: + return self._zapi.mediatype.delete([mediatype_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete mediatype '{_id}': {e}".format(_id=mediatype_id, e=e)) + + def update_mediatype(self, **kwargs): + try: + self._zapi.mediatype.update(kwargs) + except Exception as e: + self._module.fail_json(msg="Failed to update mediatype '{_id}': {e}".format(_id=kwargs['mediatypeid'], e=e)) + + def create_mediatype(self, **kwargs): + try: + self._zapi.mediatype.create(kwargs) + except Exception as e: + self._module.fail_json(msg="Failed to create mediatype '{name}': {e}".format(name=kwargs['name'], e=e)) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + description=dict(type='str', required=False, default=''), + state=dict(type='str', default='present', choices=['present', 'absent']), + type=dict(type='str', choices=['email', 'script', 'sms', 'webhook', 'jabber', 'ez_texting'], required=True), + status=dict(type='str', default='enabled', choices=['enabled', 'disabled'], required=False), + max_sessions=dict(type='int', default=1, required=False), + max_attempts=dict(type='int', default=3, required=False), + attempt_interval=dict(type='str', default='10s', required=False), + # Script + script_name=dict(type='str', required=False), + script_params=dict(type='list', required=False), + # SMS + gsm_modem=dict(type='str', required=False), + # Jabber + username=dict(type='str', required=False), + password=dict(type='str', required=False, no_log=True), + # Email + smtp_server=dict(type='str', default='localhost', required=False), + smtp_server_port=dict(type='int', default=25, required=False), + smtp_helo=dict(type='str', default='localhost', required=False), + smtp_email=dict(type='str', required=False), + smtp_security=dict(type='str', required=False, choices=['None', 'STARTTLS', 'SSL/TLS']), + smtp_authentication=dict(type='bool', default=False, required=False), + smtp_verify_host=dict(type='bool', default=False, required=False), + smtp_verify_peer=dict(type='bool', default=False, required=False), + # EZ Text + message_text_limit=dict(type='str', required=False, choices=['USA', 'Canada']), + # Webhook + webhook_script=dict(type='str'), + webhook_timeout=dict(type='str', default='30s'), + process_tags=dict(type='bool', default=False), + event_menu=dict(type='bool', default=False), + event_menu_url=dict(type='str'), + event_menu_name=dict(type='str'), + webhook_params=dict( + type='list', + elements='dict', + default=[], + required=False, + options=dict( + name=dict(type='str', required=True), + value=dict(type='str', default='') + ) + ), + message_templates=dict( + type='list', + elements='dict', + default=[], + required=False, + options=dict( + eventsource=dict(type='str', choices=['triggers', 'discovery', 'autoregistration', 'internal']), + recovery=dict(type='str', choices=['operations', 'recovery_operations', 'update_operations']), + subject=dict(type='str', default=''), + body=dict(type='str', default='') + ), + required_together=[ + ['eventsource', 'recovery'] + ], + ) + )) + + # this is used to simulate `required_if` of `AnsibleModule`, but only when state=present + required_params = [ + ['type', 'email', ['smtp_email']], + ['type', 'script', ['script_name']], + ['type', 'sms', ['gsm_modem']], + ['type', 'jabber', ['username', 'password']], + ['type', 'ez_texting', ['username', 'password', 'message_text_limit']], + ['type', 'webhook', ['webhook_script']], + ['event_menu', True, ['event_menu_url', 'event_menu_name']], + ['smtp_authentication', True, ['username', 'password']] + ] + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + state = module.params['state'] + name = module.params['name'] + + mediatype = MediaTypeModule(module) + if module.params['state'] == 'present': + mediatype.validate_params(required_params) + mediatype_exists, mediatype_id = mediatype.check_if_mediatype_exists(name) + + parameters = mediatype.construct_parameters() + + if mediatype_exists: + if state == 'absent': + if module.check_mode: + module.exit_json( + changed=True, + msg="Mediatype would have been deleted. Name: {name}, ID: {_id}".format( + name=name, + _id=mediatype_id + ) + ) + mediatype_id = mediatype.delete_mediatype(mediatype_id) + module.exit_json( + changed=True, + msg="Mediatype deleted. Name: {name}, ID: {_id}".format( + name=name, + _id=mediatype_id + ) + ) + else: + params_to_update, diff = mediatype.get_update_params(mediatype_id, **parameters) + if params_to_update == {}: + module.exit_json( + changed=False, + msg="Mediatype is up to date: {name}".format(name=name) + ) + else: + if module.check_mode: + module.exit_json( + changed=True, + diff=diff, + msg="Mediatype would have been updated. Name: {name}, ID: {_id}".format( + name=name, + _id=mediatype_id + ) + ) + mediatype_id = mediatype.update_mediatype(mediatypeid=mediatype_id, **params_to_update) + module.exit_json( + changed=True, + diff=diff, + msg="Mediatype updated. Name: {name}, ID: {_id}".format( + name=name, + _id=mediatype_id + ) + ) + else: + if state == "absent": + module.exit_json(changed=False) + else: + if module.check_mode: + module.exit_json( + changed=True, + msg="Mediatype would have been created. Name: {name}, ID: {_id}".format( + name=name, + _id=mediatype_id + ) + ) + mediatype_id = mediatype.create_mediatype(**parameters) + module.exit_json( + changed=True, + msg="Mediatype created: {name}, ID: {_id}".format( + name=name, + _id=mediatype_id + ) + ) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py new file mode 100644 index 000000000..3fdfe42c1 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py @@ -0,0 +1,461 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2017, Alen Komic +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_proxy +short_description: Create/delete/get/update Zabbix proxies +description: + - This module allows you to create, modify, get and delete Zabbix proxy entries. +author: + - "Alen Komic (@akomic)" +requirements: + - "python >= 2.6" +options: + proxy_name: + description: + - Name of the proxy in Zabbix. + required: true + type: str + proxy_address: + description: + - Comma-delimited list of IP/CIDR addresses or DNS names to accept active proxy requests from. + - Requires I(status=active). + - Works only with >= Zabbix 4.0. ( remove option for <= 4.0 ) + required: false + type: str + description: + description: + - Description of the proxy. + required: false + type: str + status: + description: + - Type of proxy. (4 - active, 5 - passive) + required: false + choices: ['active', 'passive'] + default: "active" + type: str + tls_connect: + description: + - Connections to proxy. + required: false + choices: ['no_encryption','PSK','certificate'] + default: 'no_encryption' + type: str + tls_accept: + description: + - Connections from proxy. + required: false + choices: ['no_encryption','PSK','certificate'] + default: 'no_encryption' + type: str + ca_cert: + description: + - Certificate issuer. + required: false + aliases: [ tls_issuer ] + type: str + tls_subject: + description: + - Certificate subject. + required: false + type: str + tls_psk_identity: + description: + - PSK identity. Required if either I(tls_connect) or I(tls_accept) has PSK enabled. + required: false + type: str + tls_psk: + description: + - The preshared key, at least 32 hex digits. Required if either I(tls_connect) or I(tls_accept) has PSK enabled. + required: false + type: str + state: + description: + - State of the proxy. + - On C(present), it will create if proxy does not exist or update the proxy if the associated data is different. + - On C(absent) will remove a proxy if it exists. + required: false + choices: ['present', 'absent'] + default: "present" + type: str + interface: + description: + - Dictionary with params for the interface when proxy is in passive mode. + - For more information, review proxy interface documentation at + - U(https://www.zabbix.com/documentation/4.0/manual/api/reference/proxy/object#proxy_interface). + required: false + suboptions: + useip: + type: int + description: + - Connect to proxy interface with IP address instead of DNS name. + - 0 (don't use ip), 1 (use ip). + default: 0 + choices: [0, 1] + ip: + type: str + description: + - IP address used by proxy interface. + - Required if I(useip=1). + default: '' + dns: + type: str + description: + - DNS name of the proxy interface. + - Required if I(useip=0). + default: '' + port: + type: str + description: + - Port used by proxy interface. + default: '10051' + type: + type: int + description: + - Interface type to add. + - This suboption is currently ignored for Zabbix proxy. + - This suboption is deprecated since Ansible 2.10 and will eventually be removed in 2.14. + required: false + default: 0 + main: + type: int + description: + - Whether the interface is used as default. + - This suboption is currently ignored for Zabbix proxy. + - This suboption is deprecated since Ansible 2.10 and will eventually be removed in 2.14. + required: false + default: 0 + default: {} + type: dict + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create or update a proxy with proxy type active + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_proxy: + proxy_name: ExampleProxy + description: ExampleProxy + status: active + state: present + proxy_address: ExampleProxy.local + +- name: Create a new passive proxy using only it's IP + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_proxy: + proxy_name: ExampleProxy + description: ExampleProxy + status: passive + state: present + interface: + useip: 1 + ip: 10.1.1.2 + port: 10051 + +- name: Create a new passive proxy using only it's DNS + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_proxy: + proxy_name: ExampleProxy + description: ExampleProxy + status: passive + state: present + interface: + dns: proxy.example.com + port: 10051 +''' + +RETURN = r''' # ''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Proxy(ZabbixBase): + def __init__(self, module, zbx=None, zapi_wrapper=None): + super(Proxy, self).__init__(module, zbx, zapi_wrapper) + self.existing_data = None + + def proxy_exists(self, proxy_name): + result = self._zapi.proxy.get({'output': 'extend', + 'selectInterface': 'extend', + 'filter': {'host': proxy_name}}) + + if len(result) > 0 and 'proxyid' in result[0]: + self.existing_data = result[0] + return result[0]['proxyid'] + else: + return result + + def add_proxy(self, data): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + + parameters = {} + for item in data: + if data[item]: + parameters[item] = data[item] + + if 'proxy_address' in data and data['status'] != '5': + parameters.pop('proxy_address', False) + + if 'interface' in data and data['status'] != '6': + parameters.pop('interface', False) + else: + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + parameters['interface'].pop('type') + parameters['interface'].pop('main') + + proxy_ids_list = self._zapi.proxy.create(parameters) + self._module.exit_json(changed=True, + result="Successfully added proxy %s (%s)" % (data['host'], data['status'])) + if len(proxy_ids_list) >= 1: + return proxy_ids_list['proxyids'][0] + except Exception as e: + self._module.fail_json(msg="Failed to create proxy %s: %s" % (data['host'], e)) + + def delete_proxy(self, proxy_id, proxy_name): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.proxy.delete([proxy_id]) + self._module.exit_json(changed=True, result="Successfully deleted proxy %s" % proxy_name) + except Exception as e: + self._module.fail_json(msg="Failed to delete proxy %s: %s" % (proxy_name, str(e))) + + def update_proxy(self, proxy_id, data): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + + parameters = {} + for key in data: + if data[key]: + parameters[key] = data[key] + if 'interface' in parameters: + if parameters['status'] == '5': + # Active proxy + parameters.pop('interface', False) + else: + # Passive proxy + parameters['interface']['useip'] = str(parameters['interface']['useip']) + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0.0'): + parameters['interface'].pop('type', False) + parameters['interface'].pop('main', False) + else: + parameters['interface']['type'] = '0' + parameters['interface']['main'] = '1' + if ('interface' in self.existing_data + and isinstance(self.existing_data['interface'], dict)): + new_interface = self.existing_data['interface'].copy() + new_interface.update(parameters['interface']) + parameters['interface'] = new_interface + + if parameters['status'] == '5': + # Active proxy + parameters.pop('tls_connect', False) + else: + # Passive proxy + parameters.pop('tls_accept', False) + + parameters['proxyid'] = proxy_id + + change_parameters = {} + difference = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(parameters, self.existing_data, change_parameters)) + + if difference == {}: + self._module.exit_json(changed=False) + else: + difference['proxyid'] = proxy_id + self._zapi.proxy.update(parameters) + self._module.exit_json( + changed=True, + result="Successfully updated proxy %s (%s)" % + (data['host'], proxy_id) + ) + except Exception as e: + self._module.fail_json(msg="Failed to update proxy %s: %s" % + (data['host'], e)) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + proxy_name=dict(type='str', required=True), + proxy_address=dict(type='str', required=False), + status=dict(type='str', default="active", choices=['active', 'passive']), + state=dict(type='str', default="present", choices=['present', 'absent']), + description=dict(type='str', required=False), + tls_connect=dict(type='str', default='no_encryption', choices=['no_encryption', 'PSK', 'certificate']), + tls_accept=dict(type='str', default='no_encryption', choices=['no_encryption', 'PSK', 'certificate']), + ca_cert=dict(type='str', required=False, default=None, aliases=['tls_issuer']), + tls_subject=dict(type='str', required=False, default=None), + tls_psk_identity=dict(type='str', required=False, default=None), + tls_psk=dict(type='str', required=False, default=None, no_log=True), + interface=dict( + type='dict', + required=False, + default={}, + options=dict( + useip=dict(type='int', choices=[0, 1], default=0), + ip=dict(type='str', default=''), + dns=dict(type='str', default=''), + port=dict(type='str', default='10051'), + type=dict(type='int', default=0, removed_in_version="3.0.0", removed_from_collection='community.zabbix'), # was Ansible 2.14 + main=dict(type='int', default=0, removed_in_version="3.0.0", removed_from_collection='community.zabbix'), # was Ansible 2.14 + ), + ) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + proxy_name = module.params['proxy_name'] + proxy_address = module.params['proxy_address'] + description = module.params['description'] + status = module.params['status'] + tls_connect = module.params['tls_connect'] + tls_accept = module.params['tls_accept'] + tls_issuer = module.params['ca_cert'] + tls_subject = module.params['tls_subject'] + tls_psk_identity = module.params['tls_psk_identity'] + tls_psk = module.params['tls_psk'] + state = module.params['state'] + interface = module.params['interface'] + + # convert enabled to 0; disabled to 1 + status = 6 if status == "passive" else 5 + + if tls_connect == 'certificate': + tls_connect = 4 + elif tls_connect == 'PSK': + tls_connect = 2 + else: + tls_connect = 1 + + if tls_accept == 'certificate': + tls_accept = 4 + elif tls_accept == 'PSK': + tls_accept = 2 + else: + tls_accept = 1 + + proxy = Proxy(module) + + # check if proxy already exists + proxy_id = proxy.proxy_exists(proxy_name) + + if proxy_id: + if state == "absent": + # remove proxy + proxy.delete_proxy(proxy_id, proxy_name) + else: + proxy.update_proxy(proxy_id, { + 'host': proxy_name, + 'description': description, + 'status': str(status), + 'tls_connect': str(tls_connect), + 'tls_accept': str(tls_accept), + 'tls_issuer': tls_issuer, + 'tls_subject': tls_subject, + 'tls_psk_identity': tls_psk_identity, + 'tls_psk': tls_psk, + 'interface': interface, + 'proxy_address': proxy_address + }) + else: + if state == "absent": + # the proxy is already deleted. + module.exit_json(changed=False) + + proxy_id = proxy.add_proxy(data={ + 'host': proxy_name, + 'description': description, + 'status': str(status), + 'tls_connect': str(tls_connect), + 'tls_accept': str(tls_accept), + 'tls_issuer': tls_issuer, + 'tls_subject': tls_subject, + 'tls_psk_identity': tls_psk_identity, + 'tls_psk': tls_psk, + 'interface': interface, + 'proxy_address': proxy_address + }) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py new file mode 100644 index 000000000..b40022883 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py @@ -0,0 +1,182 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, D3DeFi +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +module: zabbix_proxy_info +short_description: Gather information about Zabbix proxy +version_added: 1.5.0 +author: + - Dusan Matejka (@D3DeFi) +description: + - This module allows you to obtain detailed information about configured zabbix proxies. +requirements: + - "python >= 2.6" +options: + proxy_name: + description: + - Name of the Zabbix proxy. + required: true + type: str + proxy_hosts: + description: + - Also return list of hosts monitored by the proxy. + required: false + default: false + type: bool +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get zabbix proxy info alongside the list of hosts monitored by the proxy + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_proxy_info: + server_url: "http://zabbix.example.com/zabbix/" + login_user: admin + login_password: secret + proxy_name: zbx01.example.com + proxy_hosts: true +''' + +RETURN = ''' +zabbix_proxy: + description: example + returned: always + type: dict + sample: { + "auto_compress": "1", + "custom_interfaces": "0", + "description": "ExampleProxy", + "discover": "0", + "flags": "0", + "host": "ExampleProxy", + "hosts": [ + { + "host": "ExampleHost", + "hostid": "10453" + } + ], + "interface": { + "available": "0", + "details": [], + "disable_until": "0", + "dns": "ExampleProxy.local", + "error": "", + "errors_from": "0", + "hostid": "10452", + "interfaceid": "10", + "ip": "10.1.1.2", + "main": "1", + "port": "10051", + "type": "0", + "useip": "1" + }, + "ipmi_authtype": "-1", + "ipmi_password": "", + "ipmi_privilege": "2", + "ipmi_username": "", + "lastaccess": "0", + "maintenance_from": "0", + "maintenance_status": "0", + "maintenance_type": "0", + "maintenanceid": "0", + "name": "", + "proxy_address": "", + "proxy_hostid": "0", + "proxyid": "10452", + "status": "6", + "templateid": "0", + "tls_accept": "1", + "tls_connect": "1", + "tls_issuer": "", + "tls_subject": "", + "uuid": "" + } +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Proxy(ZabbixBase): + + def get_proxy(self, name, hosts=False): + result = {} + params = { + 'filter': { + 'host': name + }, + 'output': 'extend', + 'selectInterface': 'extend', + } + + if hosts: + params['selectHosts'] = ['host', 'hostid'] + + try: + result = self._zapi.proxy.get(params) + except Exception as e: + self._module.fail_json(msg="Failed to get proxy information: %s" % e) + + return result[0] if result else {} + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + proxy_name=dict(type='str', required=True), + proxy_hosts=dict(type='bool', required=False, default=False), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + name = module.params['proxy_name'] + hosts = module.params['proxy_hosts'] + + proxy = Proxy(module) + result = proxy.get_proxy(name, hosts) + module.exit_json(changed=False, zabbix_proxy=result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py new file mode 100644 index 000000000..5e350fc80 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py @@ -0,0 +1,496 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_screen +short_description: Create/update/delete Zabbix screens +description: + - This module allows you to create, modify and delete Zabbix screens and associated graph data. +author: + - "Cove (@cove)" + - "Tony Minfei Ding (!UNKNOWN)" + - "Harrison Gu (@harrisongu)" +requirements: + - "python >= 2.6" + - "Zabbix <= 5.2" +options: + screens: + description: + - List of screens to be created/updated/deleted (see example). + type: list + elements: dict + required: true + suboptions: + screen_name: + description: + - Screen name will be used. + - If a screen has already been added, the screen name won't be updated. + type: str + required: true + host_group: + description: + - Host group(s) will be used for searching hosts. + - Required if I(state=present). + type: list + elements: str + aliases: [ 'host_groups' ] + state: + description: + - I(present) - Create a screen if it doesn't exist. If the screen already exists, the screen will be updated as needed. + - I(absent) - If a screen exists, the screen will be deleted. + type: str + default: present + choices: + - absent + - present + graph_names: + description: + - Graph names will be added to a screen. Case insensitive. + - Required if I(state=present). + type: list + elements: str + graph_width: + description: + - Graph width will be set in graph settings. + type: int + graph_height: + description: + - Graph height will be set in graph settings. + type: int + graphs_in_row: + description: + - Limit columns of a screen and make multiple rows. + type: int + default: 3 + sort: + description: + - Sort hosts alphabetically. + - If there are numbers in hostnames, leading zero should be used. + type: bool + default: no + +extends_documentation_fragment: +- community.zabbix.zabbix + + +notes: + - Too many concurrent updates to the same screen may cause Zabbix to return errors, see examples for a workaround if needed. + - Screens where removed from Zabbix with Version 5.4 +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Screens where removed from Zabbix with Version 5.4 + +# Create/update a screen. +- name: Create a new screen or update an existing screen's items 5 in a row + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_screen: + screens: + - screen_name: ExampleScreen1 + host_group: Example group1 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + graphs_in_row: 5 + +# Create/update multi-screen +- name: Create two of new screens or update the existing screens' items + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_screen: + screens: + - screen_name: ExampleScreen1 + host_group: Example group1 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + - screen_name: ExampleScreen2 + host_group: Example group2 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + +# Limit the Zabbix screen creations to one host since Zabbix can return an error when doing concurrent updates +- name: Create a new screen or update an existing screen's items + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_screen: + state: present + screens: + - screen_name: ExampleScreen + host_group: Example group + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + when: inventory_hostname==groups['group_name'][0] + +# Create/update using multiple hosts_groups. Hosts NOT present in all listed host_groups will be skipped. +- name: Create new screen or update the existing screen's items for hosts in both given groups + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_screen: + screens: + - screen_name: ExampleScreen1 + host_group: + - Example group1 + - Example group2 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible_collections.community.zabbix.plugins.module_utils.wrappers import ScreenItem +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Screen(ZabbixBase): + # get list of group ids by list of group names + def get_host_group_ids(self, group_names): + if not group_names: + self._module.fail_json(msg="group_name is required") + hostGroup_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}}) + if not hostGroup_list: + self._module.fail_json(msg="Host group not found: {0}".format(group_names)) + else: + hostGroup_ids = [g['groupid'] for g in hostGroup_list] + return hostGroup_ids + + # get monitored host_ids by host_group_ids + # (the hosts belonging to all given groups) + def get_host_ids_by_group_ids(self, group_ids, sort): + host_list = self._zapi.host.get({'output': 'extend', 'selectGroups': 'groupid', 'groupids': group_ids, 'monitored_hosts': 1}) + if not host_list: + self._module.fail_json(msg="No hosts in the all group(s) with ids {0}".format(group_ids)) + else: + if sort: + host_list = sorted(host_list, key=lambda name: name['name']) + host_ids = [] + for host in host_list: + host_group_ids = [g['groupid'] for g in host['groups']] + # Check if all search group ids are in hosts group ids + if set(group_ids).issubset(host_group_ids): + host_id = host['hostid'] + host_ids.append(host_id) + return host_ids + + # get screen + def get_screen_id(self, screen_name): + if screen_name == "": + self._module.fail_json(msg="screen_name is required") + try: + screen_id_list = self._zapi.screen.get({'output': 'extend', 'search': {"name": screen_name}}) + if len(screen_id_list) >= 1: + screen_id = screen_id_list[0]['screenid'] + return screen_id + return None + except Exception as e: + self._module.fail_json(msg="Failed to get screen %s from Zabbix: %s" % (screen_name, e)) + + # create screen + def create_screen(self, screen_name, h_size, v_size): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + screen = self._zapi.screen.create({'name': screen_name, 'hsize': h_size, 'vsize': v_size}) + return screen['screenids'][0] + except Exception as e: + self._module.fail_json(msg="Failed to create screen %s: %s" % (screen_name, e)) + + # update screen + def update_screen(self, screen_id, screen_name, h_size, v_size): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.screen.update({'screenid': screen_id, 'hsize': h_size, 'vsize': v_size}) + except Exception as e: + self._module.fail_json(msg="Failed to update screen %s: %s" % (screen_name, e)) + + # delete screen + def delete_screen(self, screen_id, screen_name): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.screen.delete([screen_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete screen %s: %s" % (screen_name, e)) + + # get graph ids + def get_graph_ids(self, hosts, graph_name_list): + graph_id_lists = [] + vsize = 1 + for host in hosts: + graph_id_list = self.get_graphs_by_host_id(graph_name_list, host) + size = len(graph_id_list) + if size > 0: + graph_id_lists.extend(graph_id_list) + if vsize < size: + vsize = size + return graph_id_lists, vsize + + # getGraphs + def get_graphs_by_host_id(self, graph_name_list, host_id): + graph_ids = [] + for graph_name in graph_name_list: + graphs_list = self._zapi.graph.get({'output': 'extend', 'search': {'name': graph_name}, 'hostids': host_id}) + graph_id_list = [] + if len(graphs_list) > 0: + for graph in graphs_list: + graph_id = graph['graphid'] + graph_id_list.append(graph_id) + if len(graph_id_list) > 0: + graph_ids.extend(graph_id_list) + return graph_ids + + # get screen items + def get_screen_items(self, screen_id): + screen_item_list = self._zapi.screenitem.get({'output': 'extend', 'screenids': screen_id}) + return screen_item_list + + # delete screen items + def delete_screen_items(self, screen_id, screen_item_id_list): + if len(screen_item_id_list) == 0: + return True + screen_item_list = self.get_screen_items(screen_id) + if len(screen_item_list) > 0: + if self._module.check_mode: + self._module.exit_json(changed=True) + ScreenItem.delete(self, screen_item_id_list) + return True + return False + + # get screen's hsize and vsize + def get_hsize_vsize(self, hosts, v_size, graphs_in_row): + h_size = len(hosts) + # when there is only one host, put all graphs in a row + if h_size == 1: + if v_size <= graphs_in_row: + h_size = v_size + else: + h_size = graphs_in_row + v_size = (v_size - 1) // h_size + 1 + # when len(hosts) is more then graphs_in_row + elif len(hosts) > graphs_in_row: + h_size = graphs_in_row + v_size = (len(hosts) // graphs_in_row + 1) * v_size + + return h_size, v_size + + # create screen_items + def create_screen_items(self, screen_id, hosts, graph_name_list, width, height, h_size, graphs_in_row): + if len(hosts) < 4: + if width is None or width < 0: + width = 500 + else: + if width is None or width < 0: + width = 200 + if height is None or height < 0: + height = 100 + + # when there're only one host, only one row is not good. + if len(hosts) == 1: + graph_id_list = self.get_graphs_by_host_id(graph_name_list, hosts[0]) + for i, graph_id in enumerate(graph_id_list): + if graph_id is not None: + ScreenItem.create(self, ignoreExists=True, data={'screenid': screen_id, 'resourcetype': 0, 'resourceid': graph_id, + 'width': width, 'height': height, + 'x': i % h_size, 'y': i // h_size, 'colspan': 1, 'rowspan': 1, + 'elements': 0, 'valign': 0, 'halign': 0, + 'style': 0, 'dynamic': 0, 'sort_triggers': 0}) + else: + for i, host in enumerate(hosts): + graph_id_list = self.get_graphs_by_host_id(graph_name_list, host) + for j, graph_id in enumerate(graph_id_list): + if graph_id is not None: + ScreenItem.create(self, ignoreExists=True, data={'screenid': screen_id, 'resourcetype': 0, 'resourceid': graph_id, + 'width': width, 'height': height, + 'x': i % graphs_in_row, 'y': len(graph_id_list) * (i // graphs_in_row) + j, + 'colspan': 1, 'rowspan': 1, + 'elements': 0, 'valign': 0, 'halign': 0, + 'style': 0, 'dynamic': 0, 'sort_triggers': 0}) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + screens=dict( + type='list', + elements='dict', + required=True, + options=dict( + screen_name=dict(type='str', required=True), + host_group=dict(type='list', aliases=['host_groups'], elements='str'), + state=dict(type='str', default='present', choices=['absent', 'present']), + graph_names=dict(type='list', elements='str'), + graph_width=dict(type='int', default=None), + graph_height=dict(type='int', default=None), + graphs_in_row=dict(type='int', default=3), + sort=dict(default=False, type='bool'), + ), + required_if=[ + ['state', 'present', ['host_group']] + ] + ) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + screens = module.params['screens'] + + screen = Screen(module) + if LooseVersion(screen._zbx_api_version) >= LooseVersion('5.4'): + module.fail_json(msg="Zabbix 5.4 removed the Screens feature see (%s)." % ( + "https://www.zabbix.com/documentation/current/en/manual/api/changes_5.2_-_5.4" + )) + + created_screens = [] + changed_screens = [] + deleted_screens = [] + + for zabbix_screen in screens: + screen_name = zabbix_screen['screen_name'] + screen_id = screen.get_screen_id(screen_name) + state = zabbix_screen['state'] + sort = zabbix_screen['sort'] + + if state == "absent": + if screen_id: + screen_item_list = screen.get_screen_items(screen_id) + screen_item_id_list = [] + for screen_item in screen_item_list: + screen_item_id = screen_item['screenitemid'] + screen_item_id_list.append(screen_item_id) + screen.delete_screen_items(screen_id, screen_item_id_list) + screen.delete_screen(screen_id, screen_name) + + deleted_screens.append(screen_name) + else: + host_group = zabbix_screen['host_group'] + graph_names = zabbix_screen['graph_names'] + graphs_in_row = zabbix_screen['graphs_in_row'] + graph_width = zabbix_screen['graph_width'] + graph_height = zabbix_screen['graph_height'] + host_group_ids = screen.get_host_group_ids(host_group) + hosts = screen.get_host_ids_by_group_ids(host_group_ids, sort) + if not hosts: + module.fail_json(msg="No hosts found belongin to all given groups: %s" % host_group) + screen_item_id_list = [] + resource_id_list = [] + + graph_ids, v_size = screen.get_graph_ids(hosts, graph_names) + h_size, v_size = screen.get_hsize_vsize(hosts, v_size, graphs_in_row) + + if not screen_id: + # create screen + screen_id = screen.create_screen(screen_name, h_size, v_size) + screen.create_screen_items(screen_id, hosts, graph_names, graph_width, graph_height, h_size, graphs_in_row) + created_screens.append(screen_name) + else: + screen_item_list = screen.get_screen_items(screen_id) + + for screen_item in screen_item_list: + screen_item_id = screen_item['screenitemid'] + resource_id = screen_item['resourceid'] + screen_item_id_list.append(screen_item_id) + resource_id_list.append(resource_id) + + # when the screen items changed, then update + if graph_ids != resource_id_list: + deleted = screen.delete_screen_items(screen_id, screen_item_id_list) + if deleted: + screen.update_screen(screen_id, screen_name, h_size, v_size) + screen.create_screen_items(screen_id, hosts, graph_names, graph_width, graph_height, h_size, graphs_in_row) + changed_screens.append(screen_name) + + if created_screens and changed_screens: + module.exit_json(changed=True, result="Successfully created screen(s): %s, and updated screen(s): %s" % (",".join(created_screens), + ",".join(changed_screens))) + elif created_screens: + module.exit_json(changed=True, result="Successfully created screen(s): %s" % ",".join(created_screens)) + elif changed_screens: + module.exit_json(changed=True, result="Successfully updated screen(s): %s" % ",".join(changed_screens)) + elif deleted_screens: + module.exit_json(changed=True, result="Successfully deleted screen(s): %s" % ",".join(deleted_screens)) + else: + module.exit_json(changed=False) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py new file mode 100644 index 000000000..15277b0fa --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py @@ -0,0 +1,464 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2022, BGmot +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +module: zabbix_script +short_description: Create/update/delete Zabbix scripts +version_added: 1.7.0 +author: + - Evgeny Yurchenko (@BGmot) +description: + - This module allows you to create, update and delete scripts. +requirements: + - "python >= 2.6" +options: + name: + description: + - Name of the script. + required: true + type: str + script_type: + description: + - Script type. + - Types C(ssh), C(telnet) and C(webhook) works only with Zabbix >= 5.4. + type: str + required: true + choices: ['script', 'ipmi', 'ssh', 'telnet', 'webhook'] + command: + description: + - Command to run. + type: str + required: true + scope: + description: + - Script scope. + - Works only with Zabbix >= 5.4. For lower versions is silently ignored which is equivalent of C(manual_host_action). + type: str + required: false + choices: ['action_operation', 'manual_host_action', 'manual_event_action'] + default: 'action_operation' + execute_on: + description: + - Where to run the script. + - Used if type is C(script). + type: str + required: false + choices: ['zabbix_agent', 'zabbix_server', 'zabbix_server_proxy'] + default: 'zabbix_server_proxy' + menu_path: + description: + - Folders separated by slash that form a menu like navigation in frontend when clicked on host or event. + - Used if scope is C(manual_host_action) or C(manual_event_action). + - Works only with Zabbix >= 5.4. For lower versions is silently ignored. Prepend menu path to name instead. + type: str + required: false + authtype: + description: + - Authentication method used for SSH script type. + - Used if type is C(ssh). + type: str + required: false + choices: ['password', 'public_key'] + username: + description: + - User name used for authentication. + - Used if type is C(ssh) or C(telnet) + type: str + required: false + password: + description: + - Password used for SSH scripts with password authentication and Telnet scripts. + - Used if type is C(ssh) and authtype is C(password) or type is C(telnet). + type: str + required: false + publickey: + description: + - Name of the public key file used for SSH scripts with public key authentication. + - Used if type is C(ssh) and authtype is C(public_key). + type: str + required: false + privatekey: + description: + - Name of the private key file used for SSH scripts with public key authentication. + - Used if type is C(ssh) and authtype is C(public_key). + type: str + required: false + port: + description: + - Port number used for SSH and Telnet scripts. + - Used if type is C(ssh) or C(telnet). + type: str + required: false + host_group: + description: + - host group name that the script can be run on. If set to 'all', the script will be available on all host groups. + type: str + required: false + default: 'all' + user_group: + description: + - user group name that will be allowed to run the script. If set to 'all', the script will be available for all user groups. + - Used if scope is C(manual_host_action) or C(manual_event_action). + type: str + required: false + default: 'all' + host_access: + description: + - Host permissions needed to run the script. + - Used if scope is C(manual_host_action) or C(manual_event_action). + type: str + required: false + choices: ['read', 'write'] + default: 'read' + confirmation: + description: + - Confirmation pop up text. The pop up will appear when trying to run the script from the Zabbix frontend. + - Used if scope is C(manual_host_action) or C(manual_event_action). + type: str + required: false + script_timeout: + description: + - Webhook script execution timeout in seconds. Time suffixes are supported, e.g. 30s, 1m. + - Required if type is C(webhook). + - 'Possible values: 1-60s.' + type: str + default: '30s' + required: false + parameters: + description: + - Array of webhook input parameters. + - Used if type is C(webhook). + type: list + elements: dict + suboptions: + name: + description: + - Parameter name. + type: str + required: true + value: + description: + - Parameter value. Supports macros. + type: str + required: false + default: '' + description: + description: + - Description of the script. + type: str + required: false + state: + description: + - State of the script. + type: str + required: false + choices: ['present', 'absent'] + default: 'present' +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: test - Create new action operation script to execute webhook + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + zabbix_script: + name: Test action operation script + scope: action_operation + script_type: webhook + command: 'return 0' + description: "Test action operation script" + state: present +''' + +RETURN = ''' +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Script(ZabbixBase): + def get_script_ids(self, script_name): + script_ids = [] + scripts = self._zapi.script.get({'filter': {'name': script_name}}) + for script in scripts: + script_ids.append(script['scriptid']) + return script_ids + + def create_script(self, name, script_type, command, scope, execute_on, menu_path, authtype, username, password, + publickey, privatekey, port, host_group, user_group, host_access, confirmation, script_timeout, parameters, description): + if self._module.check_mode: + self._module.exit_json(changed=True) + + self._zapi.script.create(self.generate_script_config(name, script_type, command, scope, execute_on, menu_path, + authtype, username, password, publickey, privatekey, port, host_group, user_group, host_access, confirmation, + script_timeout, parameters, description)) + + def delete_script(self, script_ids): + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.script.delete(script_ids) + + def generate_script_config(self, name, script_type, command, scope, execute_on, menu_path, authtype, username, password, + publickey, privatekey, port, host_group, user_group, host_access, confirmation, script_timeout, parameters, description): + if host_group == 'all': + groupid = '0' + else: + groups = self._zapi.hostgroup.get({'filter': {'name': host_group}}) + if not groups: + self._module.fail_json(changed=False, msg='Host group "%s" not found' % host_group) + groupid = groups[0]['groupid'] + + if user_group == 'all': + usrgrpid = '0' + else: + user_groups = self._zapi.usergroup.get({'filter': {'name': user_group}}) + if not user_groups: + self._module.fail_json(changed=False, msg='User group "%s" not found' % user_group) + usrgrpid = user_groups[0]['usrgrpid'] + + request = { + 'name': name, + 'type': str(zabbix_utils.helper_to_numeric_value([ + 'script', + 'ipmi', + 'ssh', + 'telnet', + '', + 'webhook'], script_type)), + 'command': command, + 'scope': str(zabbix_utils.helper_to_numeric_value([ + '', + 'action_operation', + 'manual_host_action', + '', + 'manual_event_action'], scope)), + 'groupid': groupid + } + + if description is not None: + request['description'] = description + + if script_type == 'script': + if execute_on is None: + execute_on = 'zabbix_server_proxy' + request['execute_on'] = str(zabbix_utils.helper_to_numeric_value([ + 'zabbix_agent', + 'zabbix_server', + 'zabbix_server_proxy'], execute_on)) + + if scope in ['manual_host_action', 'manual_event_action']: + if menu_path is None: + request['menu_path'] = '' + else: + request['menu_path'] = menu_path + request['usrgrpid'] = usrgrpid + request['host_access'] = str(zabbix_utils.helper_to_numeric_value([ + '', + '', + 'read', + 'write'], host_access)) + if confirmation is None: + request['confirmation'] = '' + else: + request['confirmation'] = confirmation + + if script_type == 'ssh': + if authtype is None: + self._module.fail_json(changed=False, msg='authtype must be provided for ssh script type') + request['authtype'] = str(zabbix_utils.helper_to_numeric_value([ + 'password', + 'public_key'], authtype)) + if authtype == 'public_key': + if publickey is None or privatekey is None: + self._module.fail_json(changed=False, msg='publickey and privatekey must be provided for ssh script type with publickey authtype') + request['publickey'] = publickey + request['privatekey'] = privatekey + + if script_type in ['ssh', 'telnet']: + if username is None: + self._module.fail_json(changed=False, msg='username must be provided for "ssh" and "telnet" script types') + request['username'] = username + if (script_type == 'ssh' and authtype == 'password') or script_type == 'telnet': + if password is None: + self._module.fail_json(changed=False, msg='password must be provided for telnet script type or ssh script type with password autheype') + request['password'] = password + if port is not None: + request['port'] = port + + if script_type == 'webhook': + request['timeout'] = script_timeout + if parameters: + request['parameters'] = parameters + + if LooseVersion(self._zbx_api_version) < LooseVersion('5.4'): + if script_type not in ['script', 'ipmi']: + self._module.fail_json(changed=False, msg='script_type must be script or ipmi in version <5.4') + if 'scope' in request: + del request['scope'] + if 'menu_path' in request: + del request['menu_path'] + + return request + + def update_script(self, script_id, name, script_type, command, scope, execute_on, menu_path, authtype, username, password, + publickey, privatekey, port, host_group, user_group, host_access, confirmation, script_timeout, parameters, description): + generated_config = self.generate_script_config(name, script_type, command, scope, execute_on, menu_path, authtype, username, + password, publickey, privatekey, port, host_group, user_group, host_access, + confirmation, script_timeout, parameters, description) + live_config = self._zapi.script.get({'filter': {'name': name}})[0] + + change_parameters = {} + difference = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(generated_config, live_config, change_parameters)) + + if not difference: + self._module.exit_json(changed=False, msg="Script %s up to date" % name) + + if self._module.check_mode: + self._module.exit_json(changed=True) + generated_config['scriptid'] = live_config['scriptid'] + self._zapi.script.update(generated_config) + self._module.exit_json(changed=True, msg="Script %s updated" % name) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + script_type=dict( + type='str', + required=True, + choices=['script', 'ipmi', 'ssh', 'telnet', 'webhook']), + command=dict(type='str', required=True), + scope=dict( + type='str', + required=False, + choices=['action_operation', 'manual_host_action', 'manual_event_action'], + default='action_operation'), + execute_on=dict( + type='str', + required=False, + choices=['zabbix_agent', 'zabbix_server', 'zabbix_server_proxy'], + default='zabbix_server_proxy'), + menu_path=dict(type='str', required=False), + authtype=dict( + type='str', + required=False, + choices=['password', 'public_key']), + username=dict(type='str', required=False), + password=dict(type='str', required=False, no_log=True), + publickey=dict(type='str', required=False), + privatekey=dict(type='str', required=False, no_log=True), + port=dict(type='str', required=False), + host_group=dict(type='str', required=False, default='all'), + user_group=dict(type='str', required=False, default='all'), + host_access=dict( + type='str', + required=False, + choices=['read', 'write'], + default='read'), + confirmation=dict(type='str', required=False), + script_timeout=dict(type='str', default='30s', required=False), + parameters=dict( + type='list', + elements='dict', + options=dict( + name=dict(type='str', required=True), + value=dict(type='str', required=False, default='') + ) + ), + description=dict(type='str', required=False), + state=dict( + type='str', + required=False, + default='present', + choices=['present', 'absent']) + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + name = module.params['name'] + script_type = module.params['script_type'] + command = module.params['command'] + scope = module.params['scope'] + execute_on = module.params['execute_on'] + menu_path = module.params['menu_path'] + authtype = module.params['authtype'] + username = module.params['username'] + password = module.params['password'] + publickey = module.params['publickey'] + privatekey = module.params['privatekey'] + port = module.params['port'] + host_group = module.params['host_group'] + user_group = module.params['user_group'] + host_access = module.params['host_access'] + confirmation = module.params['confirmation'] + script_timeout = module.params['script_timeout'] + parameters = module.params['parameters'] + description = module.params['description'] + state = module.params['state'] + + script = Script(module) + script_ids = script.get_script_ids(name) + + # Delete script + if state == "absent": + if not script_ids: + module.exit_json(changed=False, msg="Script not found, no change: %s" % name) + script.delete_script(script_ids) + module.exit_json(changed=True, result="Successfully deleted script(s) %s" % name) + + elif state == "present": + if not script_ids: + script.create_script(name, script_type, command, scope, execute_on, menu_path, authtype, username, password, + publickey, privatekey, port, host_group, user_group, host_access, confirmation, script_timeout, parameters, description) + module.exit_json(changed=True, msg="Script %s created" % name) + else: + script.update_script(script_ids[0], name, script_type, command, scope, execute_on, menu_path, authtype, username, + password, publickey, privatekey, port, host_group, user_group, host_access, confirmation, + script_timeout, parameters, description) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py new file mode 100644 index 000000000..9468ee49a --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py @@ -0,0 +1,723 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2019, OVH SAS +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: zabbix_service +short_description: Create/update/delete Zabbix service +description: + - Create/update/delete Zabbix service. +author: + - "Emmanuel Riviere (@emriver)" + - "Evgeny Yurchenko (@BGmot)" +requirements: + - "python >= 2.7" +options: + name: + description: + - Name of Zabbix service + required: true + type: str + parent: + description: + - Name of Zabbix service parent + - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module. + required: false + type: str + sla: + description: + - Sla value (i.e 99.99), goodsla in Zabbix API + - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module. + required: false + type: float + calculate_sla: + description: + - If yes, calculate the SLA value for this service, showsla in Zabbix API + - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module. + required: false + default: false + type: bool + algorithm: + description: + - Algorithm used to calculate the sla with < Zabbix 6.0 + - ' - C(no), sla is not calculated' + - ' - C(one_child), problem if at least one child has a problem' + - ' - C(all_children), problem if all children have problems' + - Status calculation rule. Only applicable if child services exists with >= Zabbix 6.0 + - ' - C(status_to_ok), set status to OK with' + - ' - C(most_crit_if_all_children), most critical if all children have problems' + - ' - C(most_crit_of_child_serv), most critical of child services with' + required: false + type: str + choices: ["no", "one_child", "all_children", "status_to_ok", "most_crit_if_all_children", "most_crit_of_child_serv"] + default: one_child + trigger_name: + description: + - Name of trigger linked to the service. + - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module. + required: false + type: str + trigger_host: + description: + - Name of host linked to the service. + - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module. + required: false + type: str + state: + description: + - 'State: present - create/update service; absent - delete service.' + required: false + choices: [present, absent] + default: "present" + type: str + sortorder: + description: + - Position of the service used for sorting. + required: true + type: str + weight: + description: + - Service weight. + - New field with >= Zabbix 6.0. + required: false + default: '0' + type: str + description: + description: + - Description of the service. + - New field with >= Zabbix 6.0. + required: false + type: str + tags: + description: + - Service tags to be created for the service. + - New field with >= Zabbix 6.0. + required: false + type: list + elements: dict + suboptions: + tag: + description: + - Service tag name. + required: true + type: str + value: + description: + - Service tag value. + required: false + type: str + problem_tags: + description: + - Problem tags to be created for the service. + - New field with >= Zabbix 6.0. + required: false + type: list + elements: dict + suboptions: + tag: + description: + - Problem tag name. + required: true + type: str + operator: + description: + - Mapping condition operator. + - C(equals) + - C(like) + choices: ['equals', 'like'] + required: false + default: "equals" + type: str + value: + description: + - Problem tag value. + required: false + default: "" + type: str + parents: + description: + - Parent services to be linked to the service. + - New field with >= Zabbix 6.0. + required: false + type: list + elements: str + children: + description: + - Child services to be linked to the service. + - New field with >= Zabbix 6.0. + required: false + type: list + elements: str + propagation_rule: + description: + - Status propagation value. Must be set together with propagation_rule. + - New field with >= Zabbix 6.0. + - C(as_is) propagate service status as is - without any changes + - C(increase) increase the propagated status by a given propagation_value (by 1 to 5 severities) + - C(decrease) decrease the propagated status by a given propagation_value (by 1 to 5 severities) + - C(ignore) ignore this service - the status is not propagated to the parent service at all + - C(fixed) set fixed service status using a given propagation_value + - Required with C(propagation_value) + required: false + type: str + default: as_is + propagation_value: + description: + - Status propagation value. Must be set together with propagation_rule. + - New field with >= Zabbix 6.0. + - 'Possible values when I(propagation_rule=as_is or ignore):' + - ' - C(not_classified)' + - 'Possible values when I(propagation_rule=increase or decrease):' + - ' - C(information)' + - ' - C(warning)' + - ' - C(average)' + - ' - C(high)' + - ' - C(disaster)' + - 'Possible values when I(propagation_rule=fixed):' + - ' - C(ok)' + - ' - C(not_classified)' + - ' - C(information)' + - ' - C(warning)' + - ' - C(average)' + - ' - C(high)' + - ' - C(disaster)' + - Required with C(propagation_rule) + required: false + type: str + status_rules: + description: + - Status rules for the service. + - New field with >= Zabbix 6.0. + required: false + type: list + elements: dict + suboptions: + type: + description: + - Condition for setting (New status) status. + - C(at_least_n_child_services_have_status_or_above) if at least (N) child services have (Status) status or above + - C(at_least_npct_child_services_have_status_or_above) if at least (N%) of child services have (Status) status or above + - C(less_than_n_child_services_have_status_or_below) if less than (N) child services have (Status) status or below + - C(less_than_npct_child_services_have_status_or_below) if less than (N%) of child services have (Status) status or below + - C(weight_child_services_with_status_or_above_at_least_w) if weight of child services with (Status) status or above is at least (W) + - C(weight_child_services_with_status_or_above_at_least_npct) if weight of child services with (Status) status or above is at least (N%) + - C(weight_child_services_with_status_or_below_less_w) if weight of child services with (Status) status or below is less than (W) + - C(weight_child_services_with_status_or_below_less_npct) if weight of child services with (Status) status or below is less than (N%) + required: true + type: str + limit_value: + description: + - 'Limit value: N, N% or W' + - 'Possible values: 1-100000 for N and W, 1-100 for N%' + required: true + type: int + limit_status: + description: + - Limit status. + - C(ok) OK + - C(not_classified) Not classified + - C(information) Information + - C(warning) Warning + - C(average) Average + - C(high) High + - C(disaster) Disaster + required: true + type: str + new_status: + description: + - New status value. + - C(not_classified) Not classified + - C(information) Information + - C(warning) Warning + - C(average) Average + - C(high) High + - C(disaster) Disaster + required: true + type: str + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +--- +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Creates a new Zabbix service with Zabbix < 6.0 +- name: Manage services + # set task level variables + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_service: + name: apache2 service + sla: 99.99 + calculate_sla: yes + algorithm: one_child + trigger_name: apache2 service status + trigger_host: webserver01 + state: present + +# Creates a new Zabbix service with Zabbix >= 6.0 +- name: Create Zabbix service monitoring Apache2 in DCs in Toronto area + # set task level variables + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_service: + name: 'apache2 service Toronto' + description: Apache2 services in Toronto area + sortorder: 0 + propagation_rule: increase + propagation_value: warning + weight: 1 + state: present + tags: + - tag: zabbix_service + value: apache2 + - tag: area + value: Toronto + problem_tags: + - tag: service_name + value: httpd + - tag: area + operator: like + value: toronto + status_rules: + - type: at_least_n_child_services_have_status_or_above + limit_value: 4242 + limit_status: ok + new_status: average + +- name: Create Zabbix service monitoring all Apache2 services + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_service: + name: apache2 service + description: Apache2 services + tags: + - tag: zabbix_service + value: apache2 + - tag: area + value: global + children: + - 'apache2 service Toronto' +''' + +RETURN = ''' +--- +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils +from ansible.module_utils.compat.version import LooseVersion + + +class Service(ZabbixBase): + def get_service_ids(self, service_name): + service_ids = [] + services = self._zapi.service.get({'filter': {'name': service_name}}) + for service in services: + service_ids.append(service['serviceid']) + return service_ids + + def delete_service(self, service_ids): + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.service.delete(service_ids) + + def dump_services(self, service_ids): + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + services = self._zapi.service.get({'output': 'extend', 'filter': {'serviceid': service_ids}, 'selectParent': '1'}) + else: + services = self._zapi.service.get({'output': 'extend', 'filter': {'serviceid': service_ids}, 'selectParents': 'extend', + 'selectTags': 'extend', 'selectProblemTags': 'extend', 'selectChildren': 'extend', + 'selectStatusRules': 'extend'}) + + return services + + def generate_service_config(self, name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, + algorithm, description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules): + algorithms = {'no': '0', 'one_child': '1', 'all_children': '2', + 'status_to_ok': '0', 'most_crit_if_all_children': '1', 'most_crit_of_child_serv': '2'} + algorithm = algorithms[algorithm] + + if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'): + if calculate_sla: + calculate_sla = 1 + else: + calculate_sla = 0 + else: + sla = 0 # Parameter does not exist in >= 6.0 but we needed for format() function constructing request + + # Zabbix api return when no trigger + trigger_id = 0 + if trigger_host and trigger_name: + # Retrieving the host to get the trigger + hosts = self._zapi.host.get({'filter': {'host': trigger_host}}) + if not hosts: + self._module.fail_json(msg="Target host %s not found" % trigger_host) + host_id = hosts[0]['hostid'] + + triggers = self._zapi.trigger.get({'filter': {'description': trigger_name}, 'hostids': [host_id]}) + if not triggers: + self._module.fail_json(msg="Trigger %s not found on host %s" % (trigger_name, trigger_host)) + trigger_id = triggers[0]['triggerid'] + + request = { + 'name': name, + 'algorithm': algorithm, + 'showsla': str(calculate_sla), + 'sortorder': sortorder, + 'goodsla': format(sla, '.4f'), # Sla has 4 decimals + 'triggerid': str(trigger_id) + } + + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + request.pop('showsla') + request.pop('triggerid') + request.pop('goodsla') + request['description'] = description + request['weight'] = weight + + if tags: + request['tags'] = tags + else: + request['tags'] = [] + + request['problem_tags'] = [] + if problem_tags: + p_operators = {'equals': '0', 'like': '2'} + for p_tag in problem_tags: + pt = {'tag': p_tag['tag'], 'operator': '0', 'value': ''} + if 'operator' in p_tag: + pt['operator'] = p_operators[p_tag['operator']] + if 'value' in p_tag: + pt['value'] = p_tag['value'] + request['problem_tags'].append(pt) + + if parents: + p_service_ids = [] + p_services = self._zapi.service.get({'filter': {'name': parents}}) + for p_service in p_services: + p_service_ids.append({'serviceid': p_service['serviceid']}) + request['parents'] = p_service_ids + else: + request['parents'] = [] + + if children: + c_service_ids = [] + c_services = self._zapi.service.get({'filter': {'name': children}}) + for c_service in c_services: + c_service_ids.append({'serviceid': c_service['serviceid']}) + request['children'] = c_service_ids + else: + request['children'] = [] + + request['status_rules'] = [] + if status_rules: + for s_rule in status_rules: + status_rule = {} + if 'type' in s_rule: + sr_type_map = {'at_least_n_child_services_have_status_or_above': '0', + 'at_least_npct_child_services_have_status_or_above': '1', + 'less_than_n_child_services_have_status_or_below': '2', + 'less_than_npct_child_services_have_status_or_below': '3', + 'weight_child_services_with_status_or_above_at_least_w': '4', + 'weight_child_services_with_status_or_above_at_least_npct': '5', + 'weight_child_services_with_status_or_below_less_w': '6', + 'weight_child_services_with_status_or_below_less_npct': '7'} + if s_rule['type'] not in sr_type_map: + self._module.fail_json(msg="Wrong value for 'type' parameter in status rule.") + status_rule['type'] = sr_type_map[s_rule['type']] + else: + self._module.fail_json(msg="'type' is mandatory paremeter for status rule.") + + if 'limit_value' in s_rule: + lv = s_rule['limit_value'] + if status_rule['type'] in ['0', '2', '4', '6']: + if int(lv) < 1 or int(lv) > 100000: + self._module.fail_json(msg="'limit_value' for N and W must be between 1 and 100000 but provided %s" % lv) + else: + if int(lv) < 1 or int(lv) > 100: + self._module.fail_json(msg="'limit_value' for N%% must be between 1 and 100 but provided %s" % lv) + status_rule['limit_value'] = str(lv) + else: + self._module.fail_json(msg="'limit_value' is mandatory paremeter for status rule.") + + if 'limit_status' in s_rule: + sr_ls_map = {'ok': '-1', 'not_classified': '0', 'information': '1', 'warning': '2', + 'average': '3', 'high': '4', 'disaster': 5} + if s_rule['limit_status'] not in sr_ls_map: + self._module.fail_json(msg="Wrong value for 'limit_status' parameter in status rule.") + status_rule['limit_status'] = sr_ls_map[s_rule['limit_status']] + else: + self._module.fail_json(msg="'limit_status' is mandatory paremeter for status rule.") + + if 'new_status' in s_rule: + sr_ns_map = {'not_classified': '0', 'information': '1', 'warning': '2', + 'average': '3', 'high': '4', 'disaster': '5'} + if s_rule['new_status'] not in sr_ns_map: + self._module.fail_json(msg="Wrong value for 'new_status' parameter in status rule.") + status_rule['new_status'] = sr_ns_map[s_rule['new_status']] + else: + self._module.fail_json(msg="'new_status' is mandatory paremeter for status rule.") + + request['status_rules'].append(status_rule) + + request['propagation_rule'] = '0' + if propagation_rule: + if propagation_value is None: + self._module.fail_json(msg="If 'propagation_rule' is provided then 'propagation_value' must be provided too.") + pr_map = {'as_is': '0', 'increase': '1', 'decrease': '2', 'ignore': '3', 'fixed': '4'} + if propagation_rule not in pr_map: + self._module.fail_json(msg="Wrong value for 'propagation_rule' parameter.") + else: + request['propagation_rule'] = pr_map[propagation_rule] + + request['propagation_value'] = '0' + if propagation_value: + if propagation_rule is None: + self._module.fail_json(msg="If 'propagation_value' is provided then 'propagation_rule' must be provided too.") + pv_map = {'ok': '-1', 'not_classified': '0', 'information': '1', 'warning': '2', + 'average': '3', 'high': '4', 'disaster': '5'} + if propagation_value not in pv_map: + self._module.fail_json(msg="Wrong value for 'propagation_value' parameter.") + else: + request['propagation_value'] = pv_map[propagation_value] + else: + if parent: + parent_ids = self.get_service_ids(parent) + if not parent_ids: + self._module.fail_json(msg="Parent %s not found" % parent) + request['parentid'] = parent_ids[0] + return request + + def create_service(self, name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm, + description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules): + if self._module.check_mode: + self._module.exit_json(changed=True) + + self._zapi.service.create(self.generate_service_config(name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, + algorithm, description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules)) + + def update_service(self, service_id, name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm, + description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules): + generated_config = self.generate_service_config(name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm, + description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules) + live_config = self.dump_services(service_id)[0] + + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'): + if len(live_config['parents']) > 0: + # Need to rewrite parents list to only service ids + new_parents = [] + for parent in live_config['parents']: + new_parents.append({'serviceid': parent['serviceid']}) + live_config['parents'] = new_parents + + if len(live_config['children']) > 0: + # Need to rewrite children list to only service ids + new_children = [] + for child in live_config['children']: + new_children.append({'serviceid': child['serviceid']}) + live_config['children'] = new_children + + else: + if 'goodsla' in live_config: + live_config['goodsla'] = format(float(live_config['goodsla']), '.4f') + + if 'parentid' in generated_config: + if 'serviceid' in live_config['parent']: + live_config['parentid'] = live_config['parent']['serviceid'] + + change_parameters = {} + difference = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(generated_config, live_config, change_parameters)) + + if difference == {}: + self._module.exit_json(changed=False, msg="Service %s up to date" % name) + + if self._module.check_mode: + self._module.exit_json(changed=True) + generated_config['serviceid'] = service_id + self._zapi.service.update(generated_config) + self._module.exit_json(changed=True, msg="Service %s updated" % name) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + parent=dict(type='str', required=False), + sla=dict(type='float', required=False), + calculate_sla=dict(type='bool', required=False, default=False), + algorithm=dict(default='one_child', required=False, choices=['no', 'one_child', 'all_children', + 'status_to_ok', 'most_crit_if_all_children', 'most_crit_of_child_serv']), + trigger_name=dict(type='str', required=False), + trigger_host=dict(type='str', required=False), + sortorder=dict(type='str', required=True), + weight=dict(default='0', type='str', required=False), + state=dict(default="present", choices=['present', 'absent']), + description=dict(type='str', required=False), + tags=dict( + type='list', + required=False, + elements='dict', + options=dict( + tag=dict( + type='str', + required=True + ), + value=dict( + type='str', + required=False + ) + ) + ), + problem_tags=dict( + type='list', + required=False, + elements='dict', + options=dict( + tag=dict( + type='str', + required=True + ), + operator=dict( + type='str', + required=False, + choices=[ + 'equals', + 'like' + ], + default='equals' + ), + value=dict( + type='str', + required=False, + default='' + ) + ) + ), + parents=dict(type='list', required=False, elements='str'), + children=dict(type='list', required=False, elements='str'), + propagation_rule=dict(default='as_is', type='str', required=False), + propagation_value=dict(type='str', required=False), + status_rules=dict( + type='list', + required=False, + elements='dict', + options=dict( + type=dict( + type='str', + required=True + ), + limit_value=dict( + type='int', + required=True + ), + limit_status=dict( + type='str', + required=True + ), + new_status=dict( + type='str', + required=True + ) + ) + ) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + name = module.params['name'] + parent = module.params['parent'] + sla = module.params['sla'] + calculate_sla = module.params['calculate_sla'] + algorithm = module.params['algorithm'] + trigger_name = module.params['trigger_name'] + trigger_host = module.params['trigger_host'] + sortorder = module.params['sortorder'] + weight = module.params['weight'] + state = module.params['state'] + description = module.params['description'] + tags = module.params['tags'] + problem_tags = module.params['problem_tags'] + parents = module.params['parents'] + children = module.params['children'] + propagation_rule = module.params['propagation_rule'] + propagation_value = module.params['propagation_value'] + status_rules = module.params['status_rules'] + + # Load service module + service = Service(module) + service_ids = service.get_service_ids(name) + + # Delete service + if state == "absent": + if not service_ids: + module.exit_json(changed=False, msg="Service not found, no change: %s" % name) + service.delete_service(service_ids) + module.exit_json(changed=True, result="Successfully deleted service(s) %s" % name) + + elif state == "present": + if (trigger_name and not trigger_host) or (trigger_host and not trigger_name): + module.fail_json(msg="Specify either both trigger_host and trigger_name or none to create or update a service") + # Does not exists going to create it + if not service_ids: + service.create_service(name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm, description, + tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules) + module.exit_json(changed=True, msg="Service %s created" % name) + # Else we update it if needed + else: + service.update_service(service_ids[0], name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, + algorithm, description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py new file mode 100644 index 000000000..7c4c098af --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py @@ -0,0 +1,928 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017, sookido +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_template +short_description: Create/update/delete/dump Zabbix template +description: + - This module allows you to create, modify, delete and dump Zabbix templates. + - Multiple templates can be created or modified at once if passing JSON or XML to module. +author: + - "sookido (@sookido)" + - "Logan Vig (@logan2211)" + - "Dusan Matejka (@D3DeFi)" +requirements: + - "python >= 2.6" +options: + template_name: + description: + - Name of Zabbix template. + - Required when I(template_json) or I(template_xml) are not used. + - Mutually exclusive with I(template_json) and I(template_xml). + required: false + type: str + template_json: + description: + - JSON dump of templates to import. + - Multiple templates can be imported this way. + - Mutually exclusive with I(template_name) and I(template_xml). + required: false + type: json + template_xml: + description: + - XML dump of templates to import. + - Multiple templates can be imported this way. + - You are advised to pass XML structure matching the structure used by your version of Zabbix server. + - Custom XML structure can be imported as long as it is valid, but may not yield consistent idempotent + results on subsequent runs. + - Mutually exclusive with I(template_name) and I(template_json). + required: false + type: str + template_groups: + description: + - List of template groups to add template to when template is created. + - Replaces the current template groups the template belongs to if the template is already present. + - Required when creating a new template with C(state=present) and I(template_name) is used. + Not required when updating an existing template. + required: false + type: list + elements: str + link_templates: + description: + - List of template names to be linked to the template. + - Templates that are not specified and are linked to the existing template will be only unlinked and not + cleared from the template. + required: false + type: list + elements: str + clear_templates: + description: + - List of template names to be unlinked and cleared from the template. + - This option is ignored if template is being created for the first time. + required: false + type: list + elements: str + macros: + description: + - List of user macros to create for the template. + - Macros that are not specified and are present on the existing template will be replaced. + - See examples on how to pass macros. + required: false + type: list + elements: dict + suboptions: + macro: + description: + - Name of the macro. + - Must be specified in {$NAME} format. + type: str + required: true + value: + description: + - Value of the macro. + type: str + required: true + tags: + description: + - List of tags to assign to the template. + - Works only with >= Zabbix 4.2. + - Providing I(tags=[]) with I(force=yes) will clean all of the tags from the template. + required: false + type: list + elements: dict + suboptions: + tag: + description: + - Name of the template tag. + type: str + required: true + value: + description: + - Value of the template tag. + type: str + default: '' + dump_format: + description: + - Format to use when dumping template with C(state=dump). + - This option is deprecated and will eventually be removed in 2.14. + required: false + choices: [json, xml] + default: "json" + type: str + omit_date: + description: + - Removes the date field for the exported/dumped template + - Requires C(state=dump) + required: false + type: bool + default: false + state: + description: + - Required state of the template. + - On C(state=present) template will be created/imported or updated depending if it is already present. + - On C(state=dump) template content will get dumped into required format specified in I(dump_format). + - On C(state=absent) template will be deleted. + - The C(state=dump) is deprecated and will be removed in 2.14. The M(community.zabbix.zabbix_template_info) module should be used instead. + required: false + choices: [present, absent, dump] + default: "present" + type: str + +extends_documentation_fragment: +- community.zabbix.zabbix + +notes: +- there where breaking changes in the Zabbix API with version 5.4 onwards (especially UUIDs) which may + require you to export the templates again (see version tag >= 5.4 in the resulting file/data). +''' + +EXAMPLES = r''' +--- +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create a new Zabbix template linked to groups, macros and templates + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: ExampleHost + template_groups: + - Role + - Role2 + link_templates: + - Example template1 + - Example template2 + macros: + - macro: '{$EXAMPLE_MACRO1}' + value: 30000 + - macro: '{$EXAMPLE_MACRO2}' + value: 3 + - macro: '{$EXAMPLE_MACRO3}' + value: 'Example' + state: present + +- name: Unlink and clear templates from the existing Zabbix template + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: ExampleHost + clear_templates: + - Example template3 + - Example template4 + state: present + +- name: Import Zabbix templates from JSON + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_json: "{{ lookup('file', 'zabbix_apache2.json') }}" + state: present + +- name: Import Zabbix templates from XML + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_xml: "{{ lookup('file', 'zabbix_apache2.xml') }}" + state: present + +- name: Import Zabbix template from Ansible dict variable + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_json: + zabbix_export: + version: '3.2' + templates: + - name: Template for Testing + description: 'Testing template import' + template: Test Template + groups: + - name: Templates + applications: + - name: Test Application + state: present + +- name: Configure macros on the existing Zabbix template + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: Template + macros: + - macro: '{$TEST_MACRO}' + value: 'Example' + state: present + +- name: Add tags to the existing Zabbix template + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: Template + tags: + - tag: class + value: application + state: present + +- name: Delete Zabbix template + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: Template + state: absent + +- name: Dump Zabbix template as JSON + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: Template + omit_date: yes + state: dump + register: template_dump + +- name: Dump Zabbix template as XML + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template: + template_name: Template + dump_format: xml + omit_date: false + state: dump + register: template_dump +''' + +RETURN = r''' +--- +template_json: + description: The JSON dump of the template + returned: when state is dump and omit_date is no + type: str + sample: { + "zabbix_export":{ + "date":"2017-11-29T16:37:24Z", + "templates":[{ + "templates":[], + "description":"", + "httptests":[], + "screens":[], + "applications":[], + "discovery_rules":[], + "groups":[{"name":"Templates"}], + "name":"Test Template", + "items":[], + "macros":[], + "template":"test" + }], + "version":"3.2", + "groups":[{ + "name":"Templates" + }] + } + } + +template_xml: + description: dump of the template in XML representation + returned: when state is dump, dump_format is xml and omit_date is yes + type: str + sample: |- + <?xml version="1.0" ?> + <zabbix_export> + <version>4.2</version> + <groups> + <group> + <name>Templates</name> + </group> + </groups> + <templates> + <template> + <template>test</template> + <name>Test Template</name> + <description/> + <groups> + <group> + <name>Templates</name> + </group> + </groups> + <applications/> + <items/> + <discovery_rules/> + <httptests/> + <macros/> + <templates/> + <screens/> + <tags/> + </template> + </templates> + </zabbix_export> +''' + + +import json +import traceback +import re +import xml.etree.ElementTree as ET + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_native +from ansible.module_utils.six import PY2 + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Template(ZabbixBase): + # get group ids by group names + def get_group_ids_by_group_names(self, group_names): + group_ids = [] + for group_name in group_names: + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.2'): + group = self._zapi.templategroup.get({'output': ['groupid'], 'filter': {'name': group_name}}) + else: + group = self._zapi.hostgroup.get({'output': ['groupid'], 'filter': {'name': group_name}}) + if group: + group_ids.append({'groupid': group[0]['groupid']}) + else: + self._module.fail_json(msg="Template group not found: %s" % group_name) + return group_ids + + def get_template_ids(self, template_list): + template_ids = [] + if template_list is None or len(template_list) == 0: + return template_ids + for template in template_list: + template_list = self._zapi.template.get({'output': 'extend', 'filter': {'host': template}}) + if len(template_list) < 1: + continue + else: + template_id = template_list[0]['templateid'] + template_ids.append({'templateid': template_id}) + return template_ids + + def add_template(self, template_name, group_ids, link_template_ids, macros, tags): + if self._module.check_mode: + self._module.exit_json(changed=True) + + new_template = {'host': template_name, 'groups': group_ids, 'templates': link_template_ids, 'macros': macros, 'tags': tags} + if macros is None: + new_template.update({'macros': []}) + if tags is None: + new_template.update({'tags': []}) + if link_template_ids is None: + new_template.update({'templates': []}) + + self._zapi.template.create(new_template) + + def check_template_changed(self, template_ids, template_groups, link_templates, clear_templates, + template_macros, template_tags, template_content, template_type): + """Compares template parameters to already existing values if any are found. + + template_json - JSON structures are compared as deep sorted dictionaries, + template_xml - XML structures are compared as strings, but filtered and formatted first, + If none above is used, all the other arguments are compared to their existing counterparts + retrieved from Zabbix API.""" + changed = False + # Compare filtered and formatted XMLs strings for any changes. It is expected that provided + # XML has same structure as Zabbix uses (e.g. it was optimally exported via Zabbix GUI or API) + if template_content is not None and template_type == 'xml': + existing_template = self.dump_template(template_ids, template_type='xml') + + if self.filter_xml_template(template_content) != self.filter_xml_template(existing_template): + changed = True + + return changed + + existing_template = self.dump_template(template_ids, template_type='json') + # Compare JSON objects as deep sorted python dictionaries + if template_content is not None and template_type == 'json': + parsed_template_json = self.load_json_template(template_content) + if self.diff_template(parsed_template_json, existing_template): + changed = True + + return changed + + # If neither template_json or template_xml were used, user provided all parameters via module options + if template_groups is not None: + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.2'): + existing_groups = [g['name'] for g in existing_template['zabbix_export']['template_groups']] + else: + existing_groups = [g['name'] for g in existing_template['zabbix_export']['groups']] + + if set(template_groups) != set(existing_groups): + changed = True + + if 'templates' not in existing_template['zabbix_export']['templates'][0]: + existing_template['zabbix_export']['templates'][0]['templates'] = [] + + # Check if any new templates would be linked or any existing would be unlinked + exist_child_templates = [t['name'] for t in existing_template['zabbix_export']['templates'][0]['templates']] + if link_templates is not None: + if set(link_templates) != set(exist_child_templates): + changed = True + else: + if set([]) != set(exist_child_templates): + changed = True + + # Mark that there will be changes when at least one existing template will be unlinked + if clear_templates is not None: + for t in clear_templates: + if t in exist_child_templates: + changed = True + break + + if 'macros' not in existing_template['zabbix_export']['templates'][0]: + existing_template['zabbix_export']['templates'][0]['macros'] = [] + + if template_macros is not None: + existing_macros = existing_template['zabbix_export']['templates'][0]['macros'] + if template_macros != existing_macros: + changed = True + + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.2'): + if 'tags' not in existing_template['zabbix_export']['templates'][0]: + existing_template['zabbix_export']['templates'][0]['tags'] = [] + if template_tags is not None: + existing_tags = existing_template['zabbix_export']['templates'][0]['tags'] + if template_tags != existing_tags: + changed = True + + return changed + + def update_template(self, template_ids, group_ids, link_template_ids, clear_template_ids, template_macros, template_tags): + template_changes = {} + if group_ids is not None: + template_changes.update({'groups': group_ids}) + + if link_template_ids is not None: + template_changes.update({'templates': link_template_ids}) + else: + template_changes.update({'templates': []}) + + if clear_template_ids is not None: + template_changes.update({'templates_clear': clear_template_ids}) + + if template_macros is not None: + template_changes.update({'macros': template_macros}) + else: + template_changes.update({'macros': []}) + + if template_tags is not None: + template_changes.update({'tags': template_tags}) + else: + template_changes.update({'tags': []}) + + if template_changes: + # If we got here we know that only one template was provided via template_name + template_changes.update(template_ids[0]) + self._zapi.template.update(template_changes) + + def delete_template(self, templateids): + if self._module.check_mode: + self._module.exit_json(changed=True) + + templateids_list = [t.get('templateid') for t in templateids] + self._zapi.template.delete(templateids_list) + + def ordered_json(self, obj): + # Deep sort json dicts for comparison + if isinstance(obj, dict): + return sorted((k, self.ordered_json(v)) for k, v in obj.items()) + if isinstance(obj, list): + return sorted(self.ordered_json(x) for x in obj) + else: + return obj + + def dump_template(self, template_ids, template_type='json', omit_date=False): + template_ids_list = [t.get('templateid') for t in template_ids] + try: + dump = self._zapi.configuration.export({'format': template_type, 'options': {'templates': template_ids_list}}) + if template_type == 'xml': + xmlroot = ET.fromstring(dump.encode('utf-8')) + # remove date field if requested + if omit_date: + date = xmlroot.find(".date") + if date is not None: + xmlroot.remove(date) + if PY2: + return str(ET.tostring(xmlroot, encoding='utf-8')) + else: + return str(ET.tostring(xmlroot, encoding='utf-8').decode('utf-8')) + else: + return self.load_json_template(dump, omit_date=omit_date) + + except Exception as e: + self._module.fail_json(msg='Unable to export template: %s' % e) + + def diff_template(self, template_json_a, template_json_b): + # Compare 2 zabbix templates and return True if they differ. + template_json_a = self.filter_template(template_json_a) + template_json_b = self.filter_template(template_json_b) + if self.ordered_json(template_json_a) == self.ordered_json(template_json_b): + return False + return True + + def filter_template(self, template_json): + # Filter the template json to contain only the keys we will update + keep_keys = set(['graphs', 'templates', 'triggers', 'value_maps']) + unwanted_keys = set(template_json['zabbix_export']) - keep_keys + for unwanted_key in unwanted_keys: + del template_json['zabbix_export'][unwanted_key] + + # Versions older than 2.4 do not support description field within template + desc_not_supported = False + if LooseVersion(self._zbx_api_version) < LooseVersion('2.4'): + desc_not_supported = True + + # Filter empty attributes from template object to allow accurate comparison + for template in template_json['zabbix_export']['templates']: + for key in list(template.keys()): + if not template[key] or (key == 'description' and desc_not_supported): + template.pop(key) + + return template_json + + def filter_xml_template(self, template_xml): + """Filters out keys from XML template that may wary between exports (e.g date or version) and + keys that are not imported via this module. + + It is advised that provided XML template exactly matches XML structure used by Zabbix""" + # Strip last new line and convert string to ElementTree + parsed_xml_root = self.load_xml_template(template_xml.strip()) + keep_keys = ['graphs', 'templates', 'triggers', 'value_maps'] + + # Remove unwanted XML nodes + for node in list(parsed_xml_root): + if node.tag not in keep_keys: + parsed_xml_root.remove(node) + + # Filter empty attributes from template objects to allow accurate comparison + for template in list(parsed_xml_root.find('templates')): + for element in list(template): + if element.text is None and len(list(element)) == 0: + template.remove(element) + + # Filter new lines and indentation + xml_root_text = list(line.strip() for line in ET.tostring(parsed_xml_root, encoding='utf8', method='xml').decode().split('\n')) + return ''.join(xml_root_text) + + def load_json_template(self, template_json, omit_date=False): + try: + jsondoc = json.loads(template_json) + if omit_date and 'date' in jsondoc['zabbix_export']: + del jsondoc['zabbix_export']['date'] + return jsondoc + except ValueError as e: + self._module.fail_json(msg='Invalid JSON provided', details=to_native(e), exception=traceback.format_exc()) + + def load_xml_template(self, template_xml): + try: + return ET.fromstring(template_xml) + except ET.ParseError as e: + self._module.fail_json(msg='Invalid XML provided', details=to_native(e), exception=traceback.format_exc()) + + def import_template(self, template_content, template_type='json'): + if self._module.check_mode: + self._module.exit_json(changed=True) + + # rules schema latest version + update_rules = { + 'applications': { + 'createMissing': True, + 'deleteMissing': True + }, + 'discoveryRules': { + 'createMissing': True, + 'updateExisting': True, + 'deleteMissing': True + }, + 'graphs': { + 'createMissing': True, + 'updateExisting': True, + 'deleteMissing': True + }, + 'host_groups': { + 'createMissing': True + }, + 'httptests': { + 'createMissing': True, + 'updateExisting': True, + 'deleteMissing': True + }, + 'items': { + 'createMissing': True, + 'updateExisting': True, + 'deleteMissing': True + }, + 'templates': { + 'createMissing': True, + 'updateExisting': True + }, + 'template_groups': { + 'createMissing': True + }, + 'templateLinkage': { + 'createMissing': True + }, + 'templateScreens': { + 'createMissing': True, + 'updateExisting': True, + 'deleteMissing': True + }, + 'triggers': { + 'createMissing': True, + 'updateExisting': True, + 'deleteMissing': True + }, + 'valueMaps': { + 'createMissing': True, + 'updateExisting': True + } + } + + try: + # updateExisting for application removed from zabbix api after 3.2 + if LooseVersion(self._zbx_api_version) <= LooseVersion('3.2'): + update_rules['applications']['updateExisting'] = True + + # templateLinkage.deleteMissing only available in 4.0 branch higher .16 and higher 4.4.4 + # it's not available in 4.2 branches or lower 4.0.16 + if LooseVersion(self._zbx_api_version).version[:2] == LooseVersion('4.0').version and \ + LooseVersion(self._zbx_api_version).version[:3] >= LooseVersion('4.0.16').version: + update_rules['templateLinkage']['deleteMissing'] = True + if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4.4'): + update_rules['templateLinkage']['deleteMissing'] = True + + # templateScreens is named templateDashboards in zabbix >= 5.2 + # https://support.zabbix.com/browse/ZBX-18677 + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.2'): + update_rules["templateDashboards"] = update_rules.pop("templateScreens") + + # Zabbix 5.4 no longer supports applications + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4'): + update_rules.pop('applications', None) + + # before Zabbix 6.2 host_groups and template_group are joined into groups parameter + if LooseVersion(self._zbx_api_version) < LooseVersion('6.2'): + update_rules['groups'] = {'createMissing': True} + update_rules.pop('host_groups', None) + update_rules.pop('template_groups', None) + + # The loaded unicode slash of multibyte as a string is escaped when parsing JSON by json.loads in Python2. + # So, it is imported in the unicode string into Zabbix. + # The following processing is removing the unnecessary slash in escaped for decoding correctly to the multibyte string. + # https://github.com/ansible-collections/community.zabbix/issues/314 + if PY2: + template_content = re.sub(r'\\\\u([0-9a-z]{,4})', r'\\u\1', template_content) + + import_data = {'format': template_type, 'source': template_content, 'rules': update_rules} + self._zapi.configuration.import_(import_data) + except Exception as e: + self._module.fail_json(msg='Unable to import template', details=to_native(e), + exception=traceback.format_exc()) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + template_name=dict(type='str', required=False), + template_json=dict(type='json', required=False), + template_xml=dict(type='str', required=False), + template_groups=dict(type='list', required=False), + link_templates=dict(type='list', required=False), + clear_templates=dict(type='list', required=False), + macros=dict( + type='list', + elements='dict', + options=dict( + macro=dict(type='str', required=True), + value=dict(type='str', required=True) + ) + ), + tags=dict( + type='list', + elements='dict', + options=dict( + tag=dict(type='str', required=True), + value=dict(type='str', default='') + ) + ), + omit_date=dict(type='bool', required=False, default=False), + dump_format=dict(type='str', required=False, default='json', choices=['json', 'xml']), + state=dict(type='str', default="present", choices=['present', 'absent', 'dump']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['template_name', 'template_json', 'template_xml'] + ], + mutually_exclusive=[ + ['template_name', 'template_json', 'template_xml'] + ], + required_if=[ + ['state', 'absent', ['template_name']], + ['state', 'dump', ['template_name']] + ], + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + template_name = module.params['template_name'] + template_json = module.params['template_json'] + template_xml = module.params['template_xml'] + template_groups = module.params['template_groups'] + link_templates = module.params['link_templates'] + clear_templates = module.params['clear_templates'] + template_macros = module.params['macros'] + template_tags = module.params['tags'] + omit_date = module.params['omit_date'] + dump_format = module.params['dump_format'] + state = module.params['state'] + + template = Template(module) + + # Identify template names for IDs retrieval + # Template names are expected to reside in ['zabbix_export']['templates'][*]['template'] for both data types + template_content, template_type = None, None + if template_json is not None: + template_type = 'json' + template_content = template_json + json_parsed = template.load_json_template(template_content) + template_names = list(t['template'] for t in json_parsed['zabbix_export']['templates']) + + elif template_xml is not None: + template_type = 'xml' + template_content = template_xml + xml_parsed = template.load_xml_template(template_content) + template_names = list(t.find('template').text for t in list(xml_parsed.find('templates'))) + + else: + template_names = [template_name] + + template_ids = template.get_template_ids(template_names) + + if state == "absent": + if not template_ids: + module.exit_json(changed=False, msg="Template not found. No changed: %s" % template_name) + + template.delete_template(template_ids) + module.exit_json(changed=True, result="Successfully deleted template %s" % template_name) + + elif state == "dump": + module.deprecate("The 'dump' state has been deprecated and will be removed, use 'zabbix_template_info' module instead.", + collection_name="community.zabbix", version='3.0.0') # was 2.14 + if not template_ids: + module.fail_json(msg='Template not found: %s' % template_name) + + if dump_format == 'json': + module.exit_json(changed=False, template_json=template.dump_template(template_ids, template_type='json', omit_date=omit_date)) + elif dump_format == 'xml': + module.exit_json(changed=False, template_xml=template.dump_template(template_ids, template_type='xml', omit_date=omit_date)) + + elif state == "present": + # Load all subelements for template that were provided by user + group_ids = None + if template_groups is not None: + group_ids = template.get_group_ids_by_group_names(template_groups) + + link_template_ids = None + if link_templates is not None: + link_template_ids = template.get_template_ids(link_templates) + + clear_template_ids = None + if clear_templates is not None: + clear_template_ids = template.get_template_ids(clear_templates) + + if template_macros is not None: + # Zabbix configuration.export does not differentiate python types (numbers are returned as strings) + for macroitem in template_macros: + for key in macroitem: + macroitem[key] = str(macroitem[key]) + + if template_tags is not None: + for tagitem in template_tags: + for key in tagitem: + tagitem[key] = str(tagitem[key]) + + if not template_ids: + # Assume new templates are being added when no ID's were found + if template_content is not None: + template.import_template(template_content, template_type) + module.exit_json(changed=True, result="Template import successful") + + else: + if group_ids is None: + module.fail_json(msg='template_groups are required when creating a new Zabbix template') + + template.add_template(template_name, group_ids, link_template_ids, template_macros, template_tags) + module.exit_json(changed=True, result="Successfully added template: %s" % template_name) + + else: + changed = template.check_template_changed(template_ids, template_groups, link_templates, clear_templates, + template_macros, template_tags, template_content, template_type) + + if module.check_mode: + module.exit_json(changed=changed) + + if changed: + if template_type is not None: + template.import_template(template_content, template_type) + else: + template.update_template(template_ids, group_ids, link_template_ids, clear_template_ids, + template_macros, template_tags) + + module.exit_json(changed=changed, result="Template successfully updated") + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py new file mode 100644 index 000000000..acd5b5055 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py @@ -0,0 +1,351 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2019, sky-joker +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +module: zabbix_template_info +short_description: Gather information about Zabbix template +author: + - sky-joker (@sky-joker) +description: + - This module allows you to search for Zabbix template. +requirements: + - "python >= 2.6" +options: + template_name: + description: + - Name of the template in Zabbix. + required: true + type: str + format: + description: + - Format to use when dumping template. + - C(yaml) works only with Zabbix >= 5.2. + choices: ['json', 'xml', 'yaml', 'none'] + default: json + type: str + omit_date: + description: + - Removes the date field for the dumped template + required: false + type: bool + default: false +extends_documentation_fragment: +- community.zabbix.zabbix + +notes: +- there where breaking changes in the Zabbix API with version 5.4 onwards (especially UUIDs) which may + require you to export the templates again (see version tag >= 5.4 in the resulting file/data). +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get Zabbix template as JSON + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template_info: + template_name: Template + format: json + omit_date: yes + register: template_json + +- name: Get Zabbix template as XML + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template_info: + template_name: Template + format: xml + omit_date: no + register: template_json + +- name: Get Zabbix template as YAML + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template_info: + template_name: Template + format: yaml + omit_date: no + register: template_yaml + +- name: Determine if Zabbix template exists + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_template_info: + template_name: Template + format: none + register: template +''' + +RETURN = ''' +--- +template_id: + description: The ID of the template + returned: always + type: str + +template_json: + description: The JSON of the template + returned: when format is json and omit_date is true + type: str + sample: { + "zabbix_export": { + "version": "4.0", + "groups": [ + { + "name": "Templates" + } + ], + "templates": [ + { + "template": "Test Template", + "name": "Template for Testing", + "description": "Testing template import", + "groups": [ + { + "name": "Templates" + } + ], + "applications": [ + { + "name": "Test Application" + } + ], + "items": [], + "discovery_rules": [], + "httptests": [], + "macros": [], + "templates": [], + "screens": [] + } + ] + } + } + +template_xml: + description: The XML of the template + returned: when format is xml and omit_date is false + type: str + sample: >- + <zabbix_export> + <version>4.0</version> + <date>2019-10-27T14:49:57Z</date> + <groups> + <group> + <name>Templates</name> + </group> + </groups> + <templates> + <template> + <template>Test Template</template> + <name>Template for Testing</name> + <description>Testing template import</description> + <groups> + <group> + <name>Templates</name> + </group> + </groups> + <applications> + <application> + <name>Test Application</name> + </application> + </applications> + <items /> + <discovery_rules /> + <httptests /> + <macros /> + <templates /> + <screens /> + </template> + </templates> + </zabbix_export> + +template_yaml: + description: The YAML of the template + returned: when format is yaml and omit_date is false + type: str + sample: >- + zabbix_export: + version: '6.0' + date: '2022-07-09T13:25:18Z' + groups: + - + uuid: 7df96b18c230490a9a0a9e2307226338 + name: Templates + templates: + - + uuid: 88a9ad240f924f669eb7d4eed736320c + template: 'Test Template' + name: 'Template for Testing' + description: 'Testing template import' + groups: + - + name: Templates +''' + + +import traceback +import json +import xml.etree.ElementTree as ET + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_native +from ansible.module_utils.six import PY2 + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class TemplateInfo(ZabbixBase): + def get_template_id(self, template_name): + template_id = [] + try: + template_list = self._zapi.template.get({'output': ['templateid'], + 'filter': {'host': template_name}}) + except Exception as e: + self._module.fail_json(msg='Failed to get template: %s' % e) + + if template_list: + template_id.append(template_list[0]['templateid']) + + return template_id + + def load_json_template(self, template_json, omit_date=False): + try: + jsondoc = json.loads(template_json) + # remove date field if requested + if omit_date and 'date' in jsondoc['zabbix_export']: + del jsondoc['zabbix_export']['date'] + return jsondoc + except ValueError as e: + self._module.fail_json(msg='Invalid JSON provided', details=to_native(e), exception=traceback.format_exc()) + + def load_yaml_template(self, template_yaml, omit_date=False): + if omit_date: + yaml_lines = template_yaml.splitlines(True) + for index, line in enumerate(yaml_lines): + if 'date:' in line: + del yaml_lines[index] + return ''.join(yaml_lines) + else: + return template_yaml + + def dump_template(self, template_id, template_type='json', omit_date=False): + try: + dump = self._zapi.configuration.export({'format': template_type, 'options': {'templates': template_id}}) + if template_type == 'xml': + xmlroot = ET.fromstring(dump.encode('utf-8')) + # remove date field if requested + if omit_date: + date = xmlroot.find(".date") + if date is not None: + xmlroot.remove(date) + if PY2: + return str(ET.tostring(xmlroot, encoding='utf-8')) + else: + return str(ET.tostring(xmlroot, encoding='utf-8').decode('utf-8')) + elif template_type == 'yaml': + return self.load_yaml_template(dump, omit_date) + else: + return self.load_json_template(dump, omit_date) + except Exception as e: + self._module.fail_json(msg='Unable to export template: %s' % e) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + template_name=dict(type='str', required=True), + omit_date=dict(type='bool', required=False, default=False), + format=dict(type='str', choices=['json', 'xml', 'yaml', 'none'], default='json') + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + template_name = module.params['template_name'] + omit_date = module.params['omit_date'] + format = module.params['format'] + + template_info = TemplateInfo(module) + + template_id = template_info.get_template_id(template_name) + + if not template_id: + module.fail_json(msg='Template not found: %s' % template_name) + + if format == 'json': + module.exit_json( + changed=False, + template_id=template_id[0], + template_json=template_info.dump_template(template_id, template_type='json', omit_date=omit_date) + ) + elif format == 'xml': + module.exit_json( + changed=False, + template_id=template_id[0], + template_xml=template_info.dump_template(template_id, template_type='xml', omit_date=omit_date) + ) + elif format == 'yaml': + module.exit_json( + changed=False, + template_id=template_id[0], + template_yaml=template_info.dump_template(template_id, template_type='yaml', omit_date=omit_date) + ) + elif format == 'none': + module.exit_json(changed=False, template_id=template_id[0]) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py new file mode 100644 index 000000000..3c655ffe8 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py @@ -0,0 +1,786 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2019, sky-joker +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r''' +module: zabbix_user +short_description: Create/update/delete Zabbix users +author: + - sky-joker (@sky-joker) +description: + - This module allows you to create, modify and delete Zabbix users. +requirements: + - "python >= 2.6" +options: + username: + description: + - Name of the user alias in Zabbix. + - username is the unique identifier used and cannot be updated using this module. + - alias must be replaced with username since Zabbix 6.4. + aliases: [ alias ] + required: true + type: str + name: + description: + - Name of the user. + type: str + surname: + description: + - Surname of the user. + type: str + usrgrps: + description: + - User groups to add the user to. + - Required when I(state=present). + required: false + type: list + elements: str + passwd: + description: + - User's password. + - Required unless all of the I(usrgrps) are set to use LDAP as frontend access. + - Always required for Zabbix versions lower than 4.0. + required: false + type: str + override_passwd: + description: + - Override password for the user. + - Password will not be updated on subsequent runs without setting this value to yes. + default: no + type: bool + lang: + description: + - Language code of the user's language. + - C(default) can be used with Zabbix version 5.2 or higher. + choices: + - 'en_GB' + - 'en_US' + - 'zh_CN' + - 'cs_CZ' + - 'fr_FR' + - 'he_IL' + - 'it_IT' + - 'ko_KR' + - 'ja_JP' + - 'nb_NO' + - 'pl_PL' + - 'pt_BR' + - 'pt_PT' + - 'ru_RU' + - 'sk_SK' + - 'tr_TR' + - 'uk_UA' + - 'default' + type: str + theme: + description: + - User's theme. + choices: + - 'default' + - 'blue-theme' + - 'dark-theme' + type: str + autologin: + description: + - Whether to enable auto-login. + - If enable autologin, cannot enable autologout. + type: bool + autologout: + description: + - User session life time in seconds. If set to 0, the session will never expire. + - If enable autologout, cannot enable autologin. + type: str + refresh: + description: + - Automatic refresh period in seconds. + type: str + rows_per_page: + description: + - Amount of object rows to show per page. + type: str + after_login_url: + description: + - URL of the page to redirect the user to after logging in. + type: str + user_medias: + description: + - Set the user's media. + - If not set, makes no changes to media. + suboptions: + mediatype: + description: + - Media type name to set. + default: 'Email' + type: str + sendto: + description: + - Address, user name or other identifier of the recipient. + - If C(mediatype) is Email, values are represented as array. For other types of Media types, value is represented as a string. + required: true + type: raw + period: + description: + - Time when the notifications can be sent as a time period or user macros separated by a semicolon. + - Please review the documentation for more information on the supported time period. + - https://www.zabbix.com/documentation/4.0/manual/appendix/time_period + default: '1-7,00:00-24:00' + type: str + severity: + description: + - Trigger severities to send notifications about. + suboptions: + not_classified: + description: + - severity not_classified enable/disable. + default: true + type: bool + information: + description: + - severity information enable/disable. + default: true + type: bool + warning: + description: + - severity warning enable/disable. + default: true + type: bool + average: + description: + - severity average enable/disable. + default: true + type: bool + high: + description: + - severity high enable/disable. + default: true + type: bool + disaster: + description: + - severity disaster enable/disable. + default: true + type: bool + default: + not_classified: true + information: true + warning: true + average: true + high: true + disaster: true + type: dict + active: + description: + - Whether the media is enabled. + default: true + type: bool + type: list + elements: dict + type: + description: + - Type of the user. + - I(type) can be used when Zabbix version is 5.0 or lower. + choices: + - 'Zabbix user' + - 'Zabbix admin' + - 'Zabbix super admin' + type: str + timezone: + description: + - User's time zone. + - I(timezone) can be used with Zabbix version 5.2 or higher. + - For the full list of supported time zones please refer to U(https://www.php.net/manual/en/timezones.php) + type: str + version_added: 1.2.0 + role_name: + description: + - User's role. + - I(role_name) can be used when Zabbix version is 5.2 or higher. + - Default is C(User role) when creating a new user. + - The default value will be removed at the version 2.0.0. + type: str + version_added: 1.2.0 + state: + description: + - State of the user. + - On C(present), it will create if user does not exist or update the user if the associated data is different. + - On C(absent) will remove a user if it exists. + default: 'present' + choices: ['present', 'absent'] + type: str +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: create a new zabbix user. + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user: + username: example + name: user name + surname: user surname + usrgrps: + - Guests + - Disabled + passwd: password + lang: en_GB + theme: blue-theme + autologin: no + autologout: '0' + refresh: '30' + rows_per_page: '200' + after_login_url: '' + user_medias: + - mediatype: Email + sendto: + - example@example.com + - example1@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: no + information: yes + warning: yes + average: yes + high: yes + disaster: yes + active: no + type: Zabbix super admin + state: present + +- name: delete existing zabbix user. + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user: + username: example + state: absent +''' + +RETURN = r''' +user_ids: + description: User id created or changed + returned: success + type: dict + sample: { "userids": [ "5" ] } +''' + + +import copy + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible_collections.community.zabbix.plugins.module_utils.helpers import helper_normalize_data +from ansible.module_utils.compat.version import LooseVersion + +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class User(ZabbixBase): + + def username_key(self): + """ Returns the key name for 'username', which was 'alias' + before Zabbix 5.4. + """ + if LooseVersion(self._zbx_api_version) < LooseVersion('5.4'): + return 'alias' + return 'username' + + def get_default_authentication(self): + auth = self._zapi.authentication.get({'output': 'extend'}) + try: + if auth["authentication_type"] == "0": + return "internal" + elif auth["authentication_type"] == "1": + return "LDAP" + else: + self._module.fail_json(msg="Failed to query authentication type. Unknown authentication type %s" % auth) + except Exception as e: + self._module.fail_json(msg="Unhandled error while querying authentication type. %s" % (e)) + + def get_usergroups_by_name(self, usrgrps): + params = { + 'output': ['usrgrpid', 'name', 'gui_access'], + 'filter': { + 'name': usrgrps + } + } + res = self._zapi.usergroup.get(params) + if res: + ids = [{'usrgrpid': g['usrgrpid']} for g in res] + # User can be created password-less only when all groups are of non-internal + # authentication types + # 0 = use system default authentication method + # 1 = use internal authentication + # 2 = use LDAP authentication + # 3 = disable access to the frontend + + if bool([g for g in res if g['gui_access'] == '1']): + require_password = True + elif bool([g for g in res if g['gui_access'] == '2' or g['gui_access'] == '3']): + require_password = False + elif bool([g for g in res if g['gui_access'] == '0']): + # Zabbix API for versions < 5.2 does not have a way to query the default auth type + # so we must assume its set to internal + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.2'): + default_authentication = self.get_default_authentication() + require_password = True if default_authentication == 'internal' else False + else: + default_authentication = "internal" + require_password = True + + not_found_groups = set(usrgrps) - set([g['name'] for g in res]) + if not_found_groups: + self._module.fail_json(msg='User groups not found: %s' % not_found_groups) + return ids, require_password + else: + self._module.fail_json(msg='No user groups found') + + def check_user_exist(self, username): + zbx_user = self._zapi.user.get({'output': 'extend', 'filter': {self.username_key(): username}, + 'getAccess': True, 'selectMedias': 'extend', + 'selectUsrgrps': 'extend'}) + + return zbx_user + + def convert_user_medias_parameter_types(self, user_medias): + copy_user_medias = copy.deepcopy(user_medias) + for user_media in copy_user_medias: + media_types = self._zapi.mediatype.get({'output': 'extend'}) + for media_type in media_types: + if LooseVersion(self._zbx_api_version) < LooseVersion('4.4'): + if media_type['description'] == user_media['mediatype']: + user_media['mediatypeid'] = media_type['mediatypeid'] + user_media['mediatype'] = media_type['type'] + break + else: + if media_type['name'] == user_media['mediatype']: + user_media['mediatypeid'] = media_type['mediatypeid'] + user_media['mediatype'] = media_type['type'] + break + if 'mediatypeid' not in user_media: + self._module.fail_json(msg="Media type not found: %s" % user_media['mediatype']) + else: + if user_media['mediatype'] == '0': # E-Mail + # Because user media sendto parameter is raw in parameters specs perform explicit check on type + if not (isinstance(user_media['sendto'], list) or isinstance(user_media['sendto'], str)): + self._module.fail_json('For Email media type sendto parameter must be of type list or str.') + if isinstance(user_media['sendto'], str): + # sendto should be a list for Email media type + user_media['sendto'] = [user_media['sendto']] + else: + if not isinstance(user_media['sendto'], str): + self._module.fail_json(user_media) + self._module.fail_json('For any other than Email media type sendto parameter must be of type str.') + del user_media['mediatype'] + + severity_binary_number = '' + for severity_key in 'disaster', 'high', 'average', 'warning', 'information', 'not_classified': + if user_media['severity'][severity_key]: + severity_binary_number = severity_binary_number + '1' + else: + severity_binary_number = severity_binary_number + '0' + user_media['severity'] = str(int(severity_binary_number, 2)) + + if user_media['active']: + user_media['active'] = '0' + else: + user_media['active'] = '1' + + return copy_user_medias + + def get_roleid_by_name(self, role_name): + roles = self._zapi.role.get({'output': 'extend'}) + for role in roles: + if role['name'] == role_name: + return role['roleid'] + + self._module.fail_json(msg="Role not found: %s" % role_name) + + def user_parameter_difference_check(self, zbx_user, username, name, surname, user_group_ids, passwd, lang, theme, + autologin, autologout, refresh, rows_per_page, url, user_medias, user_type, + timezone, role_name, override_passwd): + + # existing data + existing_data = copy.deepcopy(zbx_user[0]) + usrgrpids = [] + for usrgrp in existing_data['usrgrps']: + usrgrpids.append({'usrgrpid': usrgrp['usrgrpid']}) + existing_data['usrgrps'] = sorted(usrgrpids, key=lambda x: x['usrgrpid']) + existing_data['user_medias'] = existing_data['medias'] + for del_key in ['medias', 'attempt_clock', 'attempt_failed', 'attempt_ip', 'debug_mode', 'users_status', + 'gui_access']: + del existing_data[del_key] + + if 'user_medias' in existing_data and existing_data['user_medias']: + for user_media in existing_data['user_medias']: + for del_key in ['mediaid', 'userid']: + del user_media[del_key] + + # request data + request_data = { + 'userid': zbx_user[0]['userid'], + self.username_key(): username, + 'name': name, + 'surname': surname, + 'usrgrps': sorted(user_group_ids, key=lambda x: x['usrgrpid']), + 'lang': lang, + 'theme': theme, + 'autologin': autologin, + 'autologout': autologout, + 'refresh': refresh, + 'rows_per_page': rows_per_page, + 'url': url, + } + + if user_medias: + request_data['user_medias'] = user_medias + else: + if 'user_medias' in existing_data and existing_data['user_medias']: + del existing_data['user_medias'] + + if override_passwd: + request_data['passwd'] = passwd + + # The type key has changed to roleid key since Zabbix 5.2 + if LooseVersion(self._zbx_api_version) < LooseVersion('5.2'): + request_data['type'] = user_type + else: + request_data['roleid'] = self.get_roleid_by_name(role_name) if role_name else None + request_data['timezone'] = timezone + + request_data, del_keys = helper_normalize_data(request_data) + existing_data, _del_keys = helper_normalize_data(existing_data, del_keys) + + user_parameter_difference_check_result = True + diff_dict = {} + if not zabbix_utils.helper_compare_dictionaries(request_data, existing_data, diff_dict): + user_parameter_difference_check_result = False + + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.4'): + if user_medias: + request_data['medias'] = user_medias + del request_data['user_medias'] + + diff_params = { + "before": existing_data, + "after": request_data + } + + return user_parameter_difference_check_result, diff_params + + def add_user(self, username, name, surname, user_group_ids, passwd, lang, theme, autologin, autologout, refresh, + rows_per_page, url, user_medias, user_type, require_password, timezone, role_name): + + if role_name is None and LooseVersion(self._zbx_api_version) >= LooseVersion('5.2'): + # This variable is to set the default value because the module must have a backward-compatible. + # The default value will be removed at the version 2.0.0. + # https://github.com/ansible-collections/community.zabbix/pull/382 + role_name = "User role" + + user_ids = {} + + request_data = { + self.username_key(): username, + 'name': name, + 'surname': surname, + 'usrgrps': user_group_ids, + 'lang': lang, + 'theme': theme, + 'autologin': autologin, + 'autologout': autologout, + 'refresh': refresh, + 'rows_per_page': rows_per_page, + 'url': url, + } + if user_medias: + if LooseVersion(self._zbx_api_version) <= LooseVersion('6.2'): + request_data['user_medias'] = user_medias + else: + request_data['medias'] = user_medias + + if LooseVersion(self._zbx_api_version) < LooseVersion('4.0') or require_password: + request_data['passwd'] = passwd + + # The type key has changed to roleid key since Zabbix 5.2 + if LooseVersion(self._zbx_api_version) < LooseVersion('5.2'): + request_data['type'] = user_type + else: + request_data['roleid'] = self.get_roleid_by_name(role_name) + request_data['timezone'] = timezone + + request_data, _del_keys = helper_normalize_data(request_data) + + diff_params = {} + if not self._module.check_mode: + try: + user_ids = self._zapi.user.create(request_data) + except Exception as e: + self._module.fail_json(msg="Failed to create user %s: %s" % (username, e)) + else: + diff_params = { + "before": "", + "after": request_data + } + + return user_ids, diff_params + + def update_user(self, zbx_user, username, name, surname, user_group_ids, passwd, lang, theme, autologin, autologout, + refresh, rows_per_page, url, user_medias, user_type, timezone, role_name, override_passwd): + + user_ids = {} + + request_data = { + 'userid': zbx_user[0]['userid'], + self.username_key(): username, + 'name': name, + 'surname': surname, + 'usrgrps': user_group_ids, + 'lang': lang, + 'theme': theme, + 'autologin': autologin, + 'autologout': autologout, + 'refresh': refresh, + 'rows_per_page': rows_per_page, + 'url': url, + } + + if override_passwd: + request_data['passwd'] = passwd + + # The type key has changed to roleid key since Zabbix 5.2 + if LooseVersion(self._zbx_api_version) < LooseVersion('5.2'): + request_data['type'] = user_type + else: + request_data['roleid'] = self.get_roleid_by_name(role_name) if role_name else None + request_data['timezone'] = timezone + + request_data, _del_keys = helper_normalize_data(request_data) + + # In the case of zabbix 3.2 or less, it is necessary to use updatemedia method to update media. + if LooseVersion(self._zbx_api_version) <= LooseVersion('3.2'): + try: + user_ids = self._zapi.user.update(request_data) + except Exception as e: + self._module.fail_json(msg="Failed to update user %s: %s" % (username, e)) + + try: + if user_medias: + user_ids = self._zapi.user.updatemedia({ + 'users': [{'userid': zbx_user[0]['userid']}], + 'medias': user_medias + }) + except Exception as e: + self._module.fail_json(msg="Failed to update user medias %s: %s" % (username, e)) + + if (LooseVersion(self._zbx_api_version) >= LooseVersion('3.4') + and LooseVersion(self._zbx_api_version) < LooseVersion('6.4')): + try: + if user_medias: + request_data['user_medias'] = user_medias + user_ids = self._zapi.user.update(request_data) + except Exception as e: + self._module.fail_json(msg="Failed to update user %s: %s" % (username, e)) + + if LooseVersion(self._zbx_api_version) >= LooseVersion('6.4'): + try: + if user_medias: + request_data['medias'] = user_medias + user_ids = self._zapi.user.update(request_data) + except Exception as e: + self._module.fail_json(msg="Failed to update user %s: %s" % (username, e)) + + return user_ids + + def delete_user(self, zbx_user, username): + user_ids = {} + diff_params = {} + + if not self._module.check_mode: + try: + user_ids = self._zapi.user.delete([zbx_user[0]['userid']]) + except Exception as e: + self._module.fail_json(msg="Failed to delete user %s: %s" % (username, e)) + else: + diff_params = { + "before": zbx_user[0], + "after": "" + } + + return user_ids, diff_params + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + username=dict(type='str', required=True, aliases=['alias']), + name=dict(type='str'), + surname=dict(type='str'), + usrgrps=dict(type='list'), + passwd=dict(type='str', required=False, no_log=True), + override_passwd=dict(type='bool', required=False, default=False, no_log=False), + lang=dict(type='str', choices=['en_GB', 'en_US', 'zh_CN', 'cs_CZ', 'fr_FR', + 'he_IL', 'it_IT', 'ko_KR', 'ja_JP', 'nb_NO', + 'pl_PL', 'pt_BR', 'pt_PT', 'ru_RU', 'sk_SK', + 'tr_TR', 'uk_UA', 'default']), + theme=dict(type='str', choices=['default', 'blue-theme', 'dark-theme']), + autologin=dict(type='bool'), + autologout=dict(type='str'), + refresh=dict(type='str'), + rows_per_page=dict(type='str'), + after_login_url=dict(type='str'), + user_medias=dict(type='list', elements='dict', + options=dict(mediatype=dict(type='str', default='Email'), + sendto=dict(type='raw', required=True), + period=dict(type='str', default='1-7,00:00-24:00'), + severity=dict(type='dict', + options=dict( + not_classified=dict(type='bool', default=True), + information=dict(type='bool', default=True), + warning=dict(type='bool', default=True), + average=dict(type='bool', default=True), + high=dict(type='bool', default=True), + disaster=dict(type='bool', default=True)), + default=dict( + not_classified=True, + information=True, + warning=True, + average=True, + high=True, + disaster=True)), + active=dict(type='bool', default=True))), + timezone=dict(type='str'), + role_name=dict(type='str'), + type=dict(type='str', choices=['Zabbix user', 'Zabbix admin', 'Zabbix super admin']), + state=dict(type='str', default="present", choices=['present', 'absent']) + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ['state', 'present', ['usrgrps']] + ], + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + username = module.params['username'] + name = module.params['name'] + surname = module.params['surname'] + usrgrps = module.params['usrgrps'] + passwd = module.params['passwd'] + override_passwd = module.params['override_passwd'] + lang = module.params['lang'] + theme = module.params['theme'] + autologin = module.params['autologin'] + autologout = module.params['autologout'] + refresh = module.params['refresh'] + rows_per_page = module.params['rows_per_page'] + after_login_url = module.params['after_login_url'] + user_medias = module.params['user_medias'] + user_type = module.params['type'] + timezone = module.params['timezone'] + role_name = module.params['role_name'] + state = module.params['state'] + + if autologin is not None: + if autologin: + autologin = '1' + else: + autologin = '0' + + user_type_dict = { + 'Zabbix user': '1', + 'Zabbix admin': '2', + 'Zabbix super admin': '3' + } + user_type = user_type_dict[user_type] if user_type else None + + user = User(module) + + if user_medias: + user_medias = user.convert_user_medias_parameter_types(user_medias) + + user_ids = {} + zbx_user = user.check_user_exist(username) + if state == 'present': + user_group_ids, require_password = user.get_usergroups_by_name(usrgrps) + if LooseVersion(user._zbx_api_version) < LooseVersion('4.0') or require_password: + if passwd is None: + module.fail_json(msg='User password is required. One or more groups are not LDAP based.') + + if zbx_user: + diff_check_result, diff_params = user.user_parameter_difference_check(zbx_user, username, name, surname, + user_group_ids, passwd, lang, theme, + autologin, autologout, refresh, + rows_per_page, after_login_url, + user_medias, user_type, timezone, + role_name, override_passwd) + + if not module.check_mode and diff_check_result: + user_ids = user.update_user(zbx_user, username, name, surname, user_group_ids, passwd, lang, + theme, autologin, autologout, refresh, rows_per_page, after_login_url, + user_medias, user_type, timezone, role_name, override_passwd) + else: + diff_check_result = True + user_ids, diff_params = user.add_user(username, name, surname, user_group_ids, passwd, lang, theme, autologin, + autologout, refresh, rows_per_page, after_login_url, user_medias, + user_type, require_password, timezone, role_name) + + if state == 'absent': + if zbx_user: + diff_check_result = True + user_ids, diff_params = user.delete_user(zbx_user, username) + else: + diff_check_result = False + diff_params = {} + + if not module.check_mode: + if user_ids: + module.exit_json(changed=True, user_ids=user_ids) + else: + module.exit_json(changed=False) + else: + if diff_check_result: + module.exit_json(changed=True, diff=diff_params) + else: + module.exit_json(changed=False, diff=diff_params) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py new file mode 100644 index 000000000..818fe98c0 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py @@ -0,0 +1,645 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_user_directory +short_description: Create/update/delete Zabbix user directories +description: + - This module allows you to create, modify and delete Zabbix user directories. +author: + - Evgeny Yurchenko (@BGmot) +requirements: + - python >= 3.9 +options: + name: + description: + - Unique name of the user directory. + required: true + type: str + idp_type: + description: + - Type of IdP. Only one user directory of type SAML can exist. + - This parameter is available since Zabbix 6.4. + required: false + type: str + choices: ['ldap', 'saml'] + provision_status: + description: + - User directory provisioning status. + - if I(false) Provisioning of users created by this user directory is disabled + - if I(true) Provisioning of users created by this user directory is enabled. + Additionally, the authentication status of C(ldap_jit_status) or C(saml_jit_status) should be enabled. + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + user_username: + description: + - LDAP/SAML attribute name to use for users.name field when user is provisioned + - This parameter is available since Zabbix 6.4. + required: false + type: str + user_lastname: + description: + - LDAP/SAML attribute name to use for users.surname field when user is provisioned + - This parameter is available since Zabbix 6.4. + required: false + type: str + user_ref_attr: + description: + - LDAP user object attribute name. Will be set instead of the placeholder I(%{ref}) in c(group_filter) string. + - This parameter is available since Zabbix 6.4. + required: false + type: str + description: + description: + - User directory description. + required: false + type: str + default: '' + group_membership: + description: + - LDAP property containing groups of user. E.g. I(memberOf) + - This parameter is available since Zabbix 6.4. + required: false + type: str + group_basedn: + description: + - LDAP groups path in LDAP tree to search for groups data. + - Used to configure user membership check in I(openLDAP). + - Required if group_membership is not set. + - This parameter is available since Zabbix 6.4. + type: str + group_name: + description: + - LDAP/SAML attribute name to get group name for group mapping between Zabbix and IdP. + - Used to configure user membership check in LDAP. + - Ignored when provisioning a user if group_membership is set. + - This parameter is available since Zabbix 6.4. + required: false + type: str + group_member: + description: + - LDAP tree attribute name containing group name received with C(group_filter) query. + - Used to configure user membership check in openLDAP. + - Ignored when provisioning a user if group_membership is set. + - This parameter is available since Zabbix 6.4. + type: str + group_filter: + description: + - LDAP search filter to select groups when searching for specific user groups. + - Used to configure user membership check in openLDAP. + - Ignored when provisioning a user if group_membership is set. + - This parameter is available since Zabbix 6.4. + type: str + required: false + bind_password: + description: + - LDAP bind password. Can be empty for anonymous binding. + required: false + type: str + search_filter: + description: + - LDAP custom filter string when authenticating user in LDAP. + - Supported search_filter placeholders + - I(%{attr}) search attribute name (uid, sAMAccountName); + - I(%{user}) username value. + default: (%{attr}=%{user}) + required: false + type: str + start_tls: + description: + - LDAP startTLS option. It cannot be used with ldaps:// protocol hosts. + required: false + type: int + default: 0 + choices: [0, 1] + host: + description: + - LDAP server host name, IP or URI. URI should contain schema, host and port (optional). + - required if C(idp_type) is set to I(ldap). + required: false + type: str + port: + description: + - LDAP server port. + - required if C(idp_type) is set to I(ldap). + required: false + type: int + base_dn: + description: + - LDAP base distinguished name string. + - required if C(idp_type) is set to I(ldap). + required: false + type: str + search_attribute: + description: + - LDAP attribute name to identify user by username in Zabbix database. + - required if C(idp_type) is set to I(ldap). + required: false + type: str + bind_dn: + description: + - LDAP bind distinguished name string. Can be empty for anonymous binding. + required: false + type: str + default: '' + idp_entityid: + description: + - SAML URI that identifies the IdP in SAML messages. + - required if C(idp_type) is set to I(saml). + - This parameter is available since Zabbix 6.4. + required: false + type: str + sp_entityid: + description: + - SAML SP entity ID. + - required if C(idp_type) is set to I(saml). + - This parameter is available since Zabbix 6.4. + required: false + type: str + sso_url: + description: + - SAML URL of the IdP's SAML SSO service, to which Zabbix will send SAML authentication requests. + - required if C(idp_type) is set to I(saml). + - This parameter is available since Zabbix 6.4. + required: false + type: str + slo_url: + description: + - SAML IdP service endpoint URL to which Zabbix will send SAML logout requests. + - This parameter is available since Zabbix 6.4. + required: false + type: str + username_attribute: + description: + - SAML username attribute to be used in comparison with Zabbix user.username value when authenticating. + - required if C(idp_type) is set to I(saml). + - This parameter is available since Zabbix 6.4. + required: false + type: str + nameid_format: + description: + - SAML SP name ID format. + - This parameter is available since Zabbix 6.4. + required: false + type: str + scim_status: + description: + - Whether the SCIM provisioning for SAML is enabled or disabled. + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + encrypt_nameid: + description: + - SAML encrypt name ID. Encrypts if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + encrypt_assertions: + description: + - SAML encrypt assertions. Encrypts if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + sign_messages: + description: + - SAML sign messages. Signs if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + sign_assertions: + description: + - SAML sign assertions. Signs if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + sign_authn_requests: + description: + - SAML sign AuthN requests. Signs if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + sign_logout_requests: + description: + - SAML sign logout requests. Signs if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + sign_logout_responses: + description: + - SAML sign logout responses. Signs if I(true). + - This parameter is available since Zabbix 6.4. + required: false + type: bool + default: false + provision_media: + type: list + elements: dict + description: + - Array of the IdP media type mappings objects. + - This parameter is available since Zabbix 6.4. + suboptions: + name: + description: + - Visible name in the list of media type mappings. + type: str + required: true + mediatype: + description: + - Name of media type to be created. + type: str + required: true + attribute: + description: + - Attribute name. Used as the value for the I(sendto) field. + - If present in data received from IdP and the value is not empty, will trigger media creation for the provisioned user. + type: str + required: true + provision_groups: + type: list + elements: dict + description: + - Array of the IdP media type mappings objects. + - This parameter is available since Zabbix 6.4. + suboptions: + name: + description: + - IdP group full name. + - Supports the wildcard character "*". Unique across all provisioning groups mappings. + type: str + required: true + role: + description: + - User role name to assign to the user. + - Note that if multiple provisioning groups mappings are matched, the role of the highest user type will be assigned to the user. + If there are multiple roles with the same user type, the first role (sorted in alphabetical order) will be assigned to the user. + type: str + required: true + user_groups: + type: list + elements: str + description: + - Array of Zabbix user group names. + - Note that if multiple provisioning groups mappings are matched, Zabbix user groups of all matched mappings will be assigned to the user. + required: true + state: + description: + - State of the user directory. + - On C(present), it will create if user directory does not exist or update it if the associated data is different. + - On C(absent) will remove the user directory if it exists. + choices: ['present', 'absent'] + default: 'present' + type: str + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = r''' +--- +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create new user directory or update existing info (Zabbix <= 6.2) + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user_directory: + state: present + name: TestUserDirectory + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + bind_dn: 'cn=ldap_search,dc=example,dc=org' + description: 'Test user directory' + search_filter: '(%{attr}=test_user)' + start_tls: 0 + +- name: Create new user directory with LDAP IDP or update existing info (Zabbix >= 6.4) + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user_directory: + state: present + name: TestUserDirectory + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + provision_status: true + group_name: cn + group_basedn: ou=Group,dc=example,dc=org + group_member: member + user_ref_attr: uid + group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)' + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + +- name: Create new user directory with SAML IDP or update existing info (Zabbix >= 6.4) + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user_directory: + state: present + name: TestUserDirectory + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + provision_status: true + group_name: cn + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests +''' + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + idp_type=dict(type='str', required=False, choices=['ldap', 'saml']), + host=dict(type='str', required=False), + port=dict(type='int', required=False), + base_dn=dict(type='str', required=False), + search_attribute=dict(type='str', required=False), + bind_dn=dict(type='str', required=False, default=''), + bind_password=dict(type='str', required=False, no_log=True), + description=dict(type='str', required=False, default=''), + search_filter=dict(type='str', default='(%{attr}=%{user})', required=False), + start_tls=dict(type='int', required=False, choices=[0, 1], default=0), + idp_entityid=dict(type='str', required=False), + sp_entityid=dict(type='str', required=False), + sso_url=dict(type='str', required=False), + slo_url=dict(type='str', required=False), + username_attribute=dict(type='str', required=False), + nameid_format=dict(type='str', required=False), + scim_status=dict(type='bool', required=False, default=False), + encrypt_nameid=dict(type='bool', required=False, default=False), + encrypt_assertions=dict(type='bool', required=False, default=False), + sign_messages=dict(type='bool', required=False, default=False), + sign_assertions=dict(type='bool', required=False, default=False), + sign_authn_requests=dict(type='bool', required=False, default=False), + sign_logout_requests=dict(type='bool', required=False, default=False), + sign_logout_responses=dict(type='bool', required=False, default=False), + provision_status=dict(type='bool', required=False, default=False), + group_basedn=dict(type='str', required=False), + group_filter=dict(type='str', required=False), + group_member=dict(type='str', required=False), + group_membership=dict(type='str', required=False), + group_name=dict(type='str', required=False), + user_lastname=dict(type='str', required=False), + user_ref_attr=dict(type='str', required=False), + user_username=dict(type='str', required=False), + provision_media=dict( + type='list', + required=False, + elements='dict', + options=dict( + name=dict(type='str', required=True), + mediatype=dict(type='str', required=True), + attribute=dict(type='str', required=True) + ) + ), + provision_groups=dict( + type='list', + required=False, + elements='dict', + options=dict( + name=dict(type='str', required=True), + role=dict(type='str', required=True), + user_groups=dict(type='list', elements='str', required=True) + ) + ), + state=dict(type='str', default='present', choices=['present', 'absent']) + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + ''' For future when < 6.4 disappears we should use this, now we cannot do this as at this point Zabbix version is unknown + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ('state', 'present', ('idp_type',)), + ('idp_type', 'ldap', ('host', 'port', 'base_dn', 'search_attribute'), False), + ('idp_type', 'saml', ('idp_entityid', 'sp_entityid', 'sso_url', 'username_attribute'), False), + ('provision_status', 'true', ('provision_groups')) + ] + ) + ''' + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + parameters = { + 'name': module.params['name'] + } + for p in ['host', 'port', 'base_dn', 'search_attribute', 'bind_dn', 'bind_password', 'description', 'start_tls']: + if module.params[p]: + if p in ['port', 'start_tls']: + parameters[p] = str(module.params[p]) + else: + parameters[p] = module.params[p] + + state = module.params['state'] + + user_directory = ZabbixBase(module) + + if LooseVersion(user_directory._zbx_api_version) < LooseVersion('6.2'): + module.fail_json(msg='Zabbix < 6.2 does not support user directories.') + + if LooseVersion(user_directory._zbx_api_version) < LooseVersion('6.4'): + parameters['search_filter'] = module.params['search_filter'] + directory = user_directory._zapi.userdirectory.get({'filter': {'name': parameters['name']}}) + else: + # Zabbix >= 6.4 + # Mandatory parameters check + if state == 'present' and not module.params['idp_type']: + module.fail_json('"idp_type" parameter must be provided when state is "present"') + if module.params['idp_type']: + if (module.params['idp_type'] == 'ldap' + and (not module.params['host'] or not module.params['port'] or not module.params['base_dn'] or not module.params['search_attribute'])): + module.fail_json('"host", "port", "base_dn", "search_attribute" must be provided when idp_type is "ldap"') + if (module.params['idp_type'] == 'saml' + and (not module.params['idp_entityid'] or not module.params['sp_entityid'] + or not module.params['sso_url'] or not module.params['username_attribute'])): + module.fail_json('"idp_entityid", "sp_entityid", "sso_url", "username_attribute" must be provided when idp_type is "ldap"') + + directory = user_directory._zapi.userdirectory.get( + { + 'search': {'name': parameters['name']}, + 'selectProvisionMedia': 'extend', + 'selectProvisionGroups': 'extend' + }) + parameters['idp_type'] = str(zabbix_utils.helper_to_numeric_value(['', 'ldap', 'saml'], module.params['idp_type'])) + if parameters['idp_type'] == '1': + # idp_type is ldap + parameters['search_filter'] = module.params['search_filter'] + elif parameters['idp_type'] == '2': + # idp_type is saml + for p in ['idp_entityid', 'sso_url', 'username_attribute', 'sp_entityid', 'slo_url', 'nameid_format']: + # str parameters + if module.params[p]: + parameters[p] = module.params[p] + for p in ['scim_status', 'encrypt_nameid', 'encrypt_assertions', 'sign_messages', 'sign_assertions', + 'sign_authn_requests', 'sign_logout_requests', 'sign_logout_responses']: + # boolean parameters + if module.params[p]: + parameters[p] = str(int(module.params[p])) + + if module.params['provision_status']: + parameters['provision_status'] = int(module.params['provision_status']) + + if module.params['provision_media']: + if 'provision_status' not in parameters or not parameters['provision_status']: + module.fail_json('"provision_status" must be True to define "provision_media"') + parameters['provision_media'] = [] + for media in module.params['provision_media']: + media_type_name = media['mediatype'] + media_type_ids = user_directory._zapi.mediatype.get({'filter': {'name': media_type_name}}) + if not media_type_ids: + module.fail_json('Mediatype "%s" cannot be found' % media_type_name) + parameters['provision_media'].append( + { + 'name': media['name'], + 'mediatypeid': media_type_ids[0]['mediatypeid'], + 'attribute': media['attribute'] + } + ) + + if module.params['provision_groups']: + if 'provision_status' not in parameters or not parameters['provision_status']: + module.fail_json('"provision_status" must be True to define "provision_groups"') + parameters['provision_groups'] = [] + for group in module.params['provision_groups']: + role_name = group['role'] + role_ids = user_directory._zapi.role.get({'filter': {'name': role_name}}) + if not role_ids: + module.fail_json('Role "%s" cannot be found' % role_name) + user_groups = [] + for user_group in group['user_groups']: + ug_ids = user_directory._zapi.usergroup.get({'filter': {'name': user_group}}) + if not ug_ids: + module.fail_json('User group "%s" cannot be found' % user_group) + user_groups.append({'usrgrpid': ug_ids[0]['usrgrpid']}) + parameters['provision_groups'].append( + { + 'name': group['name'], + 'roleid': role_ids[0]['roleid'], + 'user_groups': user_groups + } + ) + for p in ['group_basedn', 'group_filter', 'group_member', 'group_membership', 'group_name', 'group_name', + 'user_lastname', 'user_ref_attr', 'user_username']: + if module.params[p]: + parameters[p] = module.params[p] + + if not directory: + # No User Directory found with given name + if state == 'absent': + module.exit_json(changed=False, msg='User directory not found. Not changed: %s' % parameters['name']) + + elif state == 'present': + if module.check_mode: + module.exit_json(changed=True) + else: + user_directory._zapi.userdirectory.create(parameters) + module.exit_json(changed=True, result='Successfully added user directory %s' % parameters['name']) + else: + # User Directory with given name exists + if state == 'absent': + user_directory._zapi.userdirectory.delete([directory[0]['userdirectoryid']]) + module.exit_json(changed=True, result='Successfully deleted user directory %s' % parameters['name']) + elif state == 'present': + diff_dict = {} + if 'provision_status' in directory[0]: + # Zabbix API returns provision_status as str we need it as int to correctly compare + directory[0]['provision_status'] = int(directory[0]['provision_status']) + if zabbix_utils.helper_compare_dictionaries(parameters, directory[0], diff_dict): + parameters['userdirectoryid'] = directory[0]['userdirectoryid'] + user_directory._zapi.userdirectory.update(parameters) + module.exit_json(changed=True, result='Successfully updated user directory %s' % parameters['name']) + else: + module.exit_json(changed=False, result='User directory %s is up-to date' % parameters['name']) + + module.exit_json(changed=False, result='User directory %s is up-to date' % parameters['name']) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py new file mode 100644 index 000000000..8fd0323c4 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py @@ -0,0 +1,165 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2019, sky-joker +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +module: zabbix_user_info +short_description: Gather information about Zabbix user +author: + - sky-joker (@sky-joker) +description: + - This module allows you to search for Zabbix user entries. +requirements: + - "python >= 2.6" +options: + username: + description: + - Name of the user alias in Zabbix. + - username is the unique identifier used and cannot be updated using this module. + - alias should be replaced with username + aliases: [ alias ] + required: true + type: str +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +EXAMPLES = ''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Get zabbix user info + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user_info: + username: example +''' + +RETURN = ''' +zabbix_user: + description: example + returned: always + type: dict + sample: { + "username": "example", + "attempt_clock": "0", + "attempt_failed": "0", + "attempt_ip": "", + "autologin": "0", + "autologout": "0", + "debug_mode": "0", + "gui_access": "0", + "lang": "en_GB", + "medias": [ + { + "active": "0", + "mediaid": "668", + "mediatypeid": "1", + "period": "1-7,00:00-24:00", + "sendto": "example@example.com", + "severity": "63", + "userid": "660" + } + ], + "name": "user", + "refresh": "30s", + "rows_per_page": "50", + "surname": "example", + "theme": "default", + "type": "1", + "url": "", + "userid": "660", + "users_status": "0", + "usrgrps": [ + { + "debug_mode": "0", + "gui_access": "0", + "name": "Guests", + "users_status": "0", + "usrgrpid": "8" + } + ] + } +''' + + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.compat.version import LooseVersion + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class User(ZabbixBase): + def get_user_by_user_username(self, username): + zabbix_user = "" + try: + data = {'output': 'extend', 'filter': {}, + 'getAccess': True, 'selectMedias': 'extend', + 'selectUsrgrps': 'extend'} + if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4'): + data['filter']['username'] = username + else: + data['filter']['alias'] = username + + zabbix_user = self._zapi.user.get(data) + except Exception as e: + self._zapi.logout() + self._module.fail_json(msg="Failed to get user information: %s" % e) + + if not zabbix_user: + zabbix_user = {} + else: + zabbix_user = zabbix_user[0] + + return zabbix_user + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + username=dict(type='str', required=True, aliases=['alias']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + username = module.params['username'] + + user = User(module) + zabbix_user = user.get_user_by_user_username(username) + module.exit_json(changed=False, zabbix_user=zabbix_user) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py new file mode 100644 index 000000000..596ef5570 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py @@ -0,0 +1,223 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2022, mrvanes +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = r''' +module: zabbix_user_role +short_description: Adds or removes zabbix roles +author: + - Martin van Es (@mrvanes) +description: + - This module adds or removes zabbix roles +requirements: + - "python >= 2.6" +options: + state: + description: + - State of the user_role. + - On C(present), it will create if user_role does not exist or update the user_role if the associated data is different. + - On C(absent) will remove a user_role if it exists. + default: 'present' + choices: ['present', 'absent'] + type: str + required: false + name: + description: + - Name of the role to be processed + type: str + required: true + type: + description: + - User type. + choices: ["User", "Admin", "Super Admin"] + default: "User" + type: str + required: false + rules: + description: + - Rules set as defined in https://www.zabbix.com/documentation/current/en/manual/api/reference/role/object#role-rules + default: {} + type: dict + required: false +extends_documentation_fragment: +- community.zabbix.zabbix +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Create user role Operators with ui elements monitoring.hosts +# disabled and monitoring.maps enabled + +- name: Create Zabbix user role + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_user_role: + state: present + name: Operators + type: User + rules: + ui.default_access: 0 + ui: + - name: "monitoring.hosts" + status: 0 + - name: "monitoring.maps" + status: 1 +''' + +RETURN = r''' +# Return values +msg: + description: The result of the action + type: str + returned: always + sample: 'No action' +changed: + description: The consequence of the action + type: bool + returned: always + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class UserRole(ZabbixBase): + def __find_val(self, outval, inval): + if outval == str(inval): + return True + return False + + def __find_list(self, outval, inval): + if set(outval) == set(inval): + return True + return False + + def __find_dict(self, outval, inval): + for out in outval: + m = True + for k, v in inval.items(): + if out[k] == str(v): + continue + else: + m = False + if m: + break + return m + + def is_part_of(self, inp, out): + verdict = True + for rule, value in inp.items(): + if not isinstance(value, list): + verdict = verdict and self.__find_val(out.get(rule, ''), value) + else: + if len(value): + if not isinstance(value[0], dict): + verdict = verdict and self.__find_list(out.get(rule, []), value) + else: + for v in value: + verdict = verdict and self.__find_dict(out.get(rule, {}), v) + else: + verdict = verdict and self.__find_list(rule, value) + return verdict + + def get_user_role(self, name): + result = self._zapi.role.get({ + "output": "extend", + "selectRules": "extend", + "filter": {"name": name} + }) + return result + + +def main(): + msg = "No action" + changed = False + + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + state=dict(type='str', required=False, default='present', choices=['present', 'absent']), + name=dict(type='str', required=True), + type=dict(type='str', required=False, choices=["User", "Admin", "Super Admin"], default='User'), + rules=dict(type='dict', required=False, default={}), + )) + + # the AnsibleModule object + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=False + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection ' + 'and will be removed in the next release' % p) + + state = module.params['state'] + name = module.params['name'] + type = zabbix_utils.helper_to_numeric_value( + ['', 'user', 'admin', 'super admin'], module.params['type'].lower() + ) + rules = module.params['rules'] + + user_role = UserRole(module) + + result = user_role.get_user_role(name) + if result: + if len(result) == 1: + role = result[0] + if role['readonly'] != 1: + roleid = role['roleid'] + if state == 'absent': + result = user_role._zapi.role.delete([f"{roleid}"]) + changed = True + msg = "Role deleted" + else: + if not user_role.is_part_of(rules, role['rules']): + result = user_role._zapi.role.update({"roleid": roleid, "rules": rules}) + changed = True + msg = "Role updated" + else: + module.fail_json(msg='Too many role matches') + else: + user_role._zapi.role.create({ + "name": name, + "type": type, + "rules": rules + }) + changed = True + msg = "Role created" + + module.exit_json(msg=msg, changed=changed) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py new file mode 100644 index 000000000..b2a341472 --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py @@ -0,0 +1,810 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Tobias Birkefeld (@tcraxs) <t@craxs.de> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: zabbix_usergroup +short_description: Create/delete/update Zabbix user groups +description: + - Create user groups if they do not exist. + - Delete existing user groups if they exist and are empty. + - Update existing user groups. +author: + - "Tobias Birkefeld (@tcraxs)" +requirements: + - "python >= 2.6" +options: + name: + description: + - Name of the user group to create, update or delete. + required: true + type: str + aliases: [ "user_group" ] + gui_access: + description: + - Frontend authentication method of the users in the group. + - "Possible values:" + - default - use the system default authentication method; + - internal - use internal authentication; + - LDAP - use LDAP authentication; + - disable - disable access to the frontend. + required: false + type: str + default: "default" + choices: [ "default", "internal", "LDAP", "disable"] + debug_mode: + description: + - Whether debug mode is enabled or disabled. + required: false + type: str + default: "disabled" + choices: [ "disabled", "enabled" ] + status: + description: + - Whether the user group is enabled or disabled. + required: false + type: str + default: "enabled" + choices: [ "enabled", "disabled" ] + rights: + description: + - Permissions to assign to the group + - For <= Zabbix 6.0 + required: false + type: list + elements: dict + suboptions: + host_group: + description: + - Name of the host group to add permission to. + required: true + type: str + permission: + description: + - Access level to the host group. + required: true + type: str + choices: [ "denied", "read-only", "read-write" ] + hostgroup_rights: + description: + - Host group permissions to assign to the user group + - For => Zabbix 6.2 + required: false + type: list + elements: dict + suboptions: + host_group: + description: + - Name of the host group to add permission to. + required: true + type: str + permission: + description: + - Access level to the host group. + required: true + type: str + choices: [ "denied", "read-only", "read-write" ] + templategroup_rights: + description: + - Template group permissions to assign to the user group + - For => Zabbix 6.2 + required: false + type: list + elements: dict + suboptions: + template_group: + description: + - Name of the template group to add permission to. + required: true + type: str + permission: + description: + - Access level to the templategroup. + required: true + type: str + choices: [ "denied", "read-only", "read-write" ] + tag_filters: + description: + - Tag based permissions to assign to the group + required: false + type: list + elements: dict + suboptions: + host_group: + description: + - Name of the host group to add permission to. + required: true + type: str + tag: + description: + - Tag name. + required: false + type: str + default: '' + value: + description: + - Tag value. + required: false + type: str + default: '' + userdirectory: + description: + - Authentication user directory when gui_access set to LDAP or System default. + - For => Zabbix 6.2 + required: false + type: str + state: + description: + - State of the user group. + - On C(present), it will create if user group does not exist or update the user group if the associated data is different. + - On C(absent) will remove a user group if it exists. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] +notes: + - Only Zabbix >= 4.0 is supported. +extends_documentation_fragment: +- community.zabbix.zabbix +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Base create user group example +- name: Create user group + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + state: present + +# Base create user group with selected user directory for LDAP authentication +- name: Create user group + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + userdirectory: LDAP infra 1 + state: present + +# Base create user group with disabled gui access +- name: Create user group with disabled gui access + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + gui_access: disable + +# Base create user group with permissions for Zabbix <= 6.0 +- name: Create user group with permissions + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + rights: + - host_group: Webserver + permission: read-write + - host_group: Databaseserver + permission: read-only + state: present + +# Base create user group with permissions for Zabbix => 6.2 +- name: Create user group with permissions + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + hostgroup_rights: + - host_group: Webserver + permission: read-write + - host_group: Databaseserver + permission: read-only + templategroup_rights: + - template_group: Linux Templates + permission: read-write + - template_group: Templates + permission: read-only + state: present + +# Base create user group with tag permissions +- name: Create user group with tag permissions + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + tag_filters: + - host_group: Webserver + tag: Application + value: Java + - host_group: Discovered hosts + tag: Service + value: JIRA + state: present + +# Base delete user groups example +- name: Delete user groups + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_usergroup: + name: ACME + state: absent +''' + +RETURN = r''' +state: + description: User group state at the end of execution. + returned: on success + type: str + sample: 'present' +usergroup: + description: User group name. + returned: on success + type: str + sample: 'ACME' +usrgrpid: + description: User group id, if created, changed or deleted. + returned: on success + type: str + sample: '42' +msg: + description: The result of the operation + returned: always + type: str + sample: 'User group created: ACME, ID: 42' +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +from ansible.module_utils.compat.version import LooseVersion +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +class Rights(ZabbixBase): + """ + Restructure the user defined rights to fit the Zabbix API requirements + """ + + def get_hostgroup_by_hostgroup_name(self, name): + """Get host group by host group name. + + Parameters: + name: Name of the host group. + + Returns: + host group matching host group name. + """ + try: + _hostgroup = self._zapi.hostgroup.get({ + 'output': 'extend', + 'filter': {'name': [name]} + }) + if len(_hostgroup) < 1: + self._module.fail_json(msg='Host group not found: %s' % name) + else: + return _hostgroup[0] + except Exception as e: + self._module.fail_json(msg='Failed to get host group "%s": %s' % (name, e)) + + def construct_the_data(self, _rights): + """Construct the user defined rights to fit the Zabbix API requirements + + Parameters: + _rights: rights to construct + + Returns: + dict: user defined rights + """ + if _rights is None: + return [] + constructed_data = [] + for right in _rights: + constructed_right = { + 'id': self.get_hostgroup_by_hostgroup_name(right.get('host_group'))['groupid'], + 'permission': zabbix_utils.helper_to_numeric_value([ + 'denied', + None, + 'read-only', + 'read-write'], right.get('permission') + ) + } + constructed_data.append(constructed_right) + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class HostgroupRights(ZabbixBase): + """ + Restructure the user defined host group rights to fit the Zabbix API requirements + """ + + def get_hostgroup_by_hostgroup_name(self, name): + """Get host group by host group name. + + Parameters: + name: Name of the host group. + + Returns: + host group matching host group name. + """ + try: + _hostgroup = self._zapi.hostgroup.get({ + 'output': 'extend', + 'filter': {'name': [name]} + }) + if len(_hostgroup) < 1: + self._module.fail_json(msg='Host group not found: %s' % name) + else: + return _hostgroup[0] + except Exception as e: + self._module.fail_json(msg='Failed to get host group "%s": %s' % (name, e)) + + def construct_the_data(self, _rights): + """Construct the user defined host group rights to fit the Zabbix API requirements + + Parameters: + _rights: rights to construct + + Returns: + dict: user defined rights + """ + if _rights is None: + return [] + constructed_data = [] + for right in _rights: + constructed_right = { + 'id': self.get_hostgroup_by_hostgroup_name(right.get('host_group'))['groupid'], + 'permission': zabbix_utils.helper_to_numeric_value([ + 'denied', + None, + 'read-only', + 'read-write'], right.get('permission') + ) + } + constructed_data.append(constructed_right) + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class TemplategroupRights(ZabbixBase): + """ + Restructure the user defined template group rights to fit the Zabbix API requirements + """ + + def get_templategroup_by_templategroup_name(self, name): + """Get template group by template group name. + + Parameters: + name: Name of the template group. + + Returns: + template group matching template group name. + """ + try: + _templategroup = self._zapi.templategroup.get({ + 'output': 'extend', + 'filter': {'name': [name]} + }) + if len(_templategroup) < 1: + self._module.fail_json(msg='Template group not found: %s' % name) + else: + return _templategroup[0] + except Exception as e: + self._module.fail_json(msg='Failed to get template group "%s": %s' % (name, e)) + + def construct_the_data(self, _rights): + """Construct the user defined template rights to fit the Zabbix API requirements + + Parameters: + _rights: rights to construct + + Returns: + dict: user defined rights + """ + if _rights is None: + return [] + constructed_data = [] + for right in _rights: + constructed_right = { + 'id': self.get_templategroup_by_templategroup_name(right.get('template_group'))['groupid'], + 'permission': zabbix_utils.helper_to_numeric_value([ + 'denied', + None, + 'read-only', + 'read-write'], right.get('permission') + ) + } + constructed_data.append(constructed_right) + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class TagFilters(Rights): + """ + Restructure the user defined tag_filters to fit the Zabbix API requirements + """ + + def construct_the_data(self, _tag_filters): + """Construct the user defined tag filters to fit the Zabbix API requirements + + Parameters: + _tag_filters: tag filters to construct + + Returns: + dict: user defined tag filters + """ + if _tag_filters is None: + return [] + constructed_data = [] + for tag_filter in _tag_filters: + constructed_tag_filter = { + 'groupid': self.get_hostgroup_by_hostgroup_name(tag_filter.get('host_group'))['groupid'], + 'tag': tag_filter.get('tag'), + 'value': tag_filter.get('value') + } + constructed_data.append(constructed_tag_filter) + return zabbix_utils.helper_cleanup_data(constructed_data) + + +class UserGroup(ZabbixBase): + def _construct_parameters(self, **kwargs): + """Construct parameters of UserGroup object + + Parameters: + **kwargs: Arbitrary keyword parameters. + + Returns: + dict: dictionary of specified parameters + """ + _params = { + 'name': kwargs['name'], + 'gui_access': zabbix_utils.helper_to_numeric_value([ + 'default', + 'internal', + 'LDAP', + 'disable'], kwargs['gui_access'] + ), + 'debug_mode': zabbix_utils.helper_to_numeric_value([ + 'disabled', + 'enabled'], kwargs['debug_mode'] + ), + 'users_status': zabbix_utils.helper_to_numeric_value([ + 'enabled', + 'disabled'], kwargs['status'] + ), + 'tag_filters': kwargs['tag_filters'] + } + if LooseVersion(self._zbx_api_version) < LooseVersion('6.2'): + _params['rights'] = kwargs['rights'] + else: + _params['hostgroup_rights'] = kwargs['hostgroup_rights'] + _params['templategroup_rights'] = kwargs['templategroup_rights'] + + if kwargs['userdirectory']: + try: + if LooseVersion(self._zbx_api_version) <= LooseVersion('6.2'): + _userdir = self._zapi.userdirectory.get({ + 'output': 'extend', + 'filter': {'name': [kwargs['userdirectory']]} + }) + else: + _userdir = self._zapi.userdirectory.get({ + 'output': 'extend', + 'search': {'name': [kwargs['userdirectory']]} + }) + except Exception as e: + self._module.fail_json(msg='Failed to get user directory "%s": %s' % (kwargs['userdirectory'], e)) + if len(_userdir) == 0: + self._module.fail_json(msg='User directory "%s" not found' % kwargs['userdirectory']) + _params['userdirectoryid'] = _userdir[0]['userdirectoryid'] + + return _params + + def check_if_usergroup_exists(self, name): + """Check if user group exists. + + Parameters: + name: Name of the user group. + + Returns: + The return value. True for success, False otherwise. + """ + try: + _usergroup = self._zapi.usergroup.get({ + 'output': 'extend', + 'filter': {'name': [name]} + }) + if len(_usergroup) > 0: + return _usergroup + except Exception as e: + self._module.fail_json(msg='Failed to check if user group "%s" exists: %s' % (name, e)) + + def get_usergroup_by_usergroup_name(self, name): + """Get user group by user group name. + + Parameters: + name: Name of the user group. + + Returns: + User group matching user group name. + """ + try: + if LooseVersion(self._zbx_api_version) < LooseVersion('6.2'): + _usergroup = self._zapi.usergroup.get({ + 'output': 'extend', + 'selectTagFilters': 'extend', + 'selectRights': 'extend', + 'filter': {'name': [name]} + }) + else: + _usergroup = self._zapi.usergroup.get({ + 'output': 'extend', + 'selectTagFilters': 'extend', + 'selectHostGroupRights': 'extend', + 'selectTemplateGroupRights': 'extend', + 'filter': {'name': [name]} + }) + + if len(_usergroup) < 1: + self._module.fail_json(msg='User group not found: %s' % name) + else: + return _usergroup[0] + except Exception as e: + self._module.fail_json(msg='Failed to get user group "%s": %s' % (name, e)) + + def check_difference(self, **kwargs): + """Check difference between user group and user specified parameters. + + Parameters: + **kwargs: Arbitrary keyword parameters. + + Returns: + dict: dictionary of differences + """ + existing_usergroup = zabbix_utils.helper_convert_unicode_to_str(self.get_usergroup_by_usergroup_name(kwargs['name'])) + parameters = zabbix_utils.helper_convert_unicode_to_str(self._construct_parameters(**kwargs)) + change_parameters = {} + _diff = zabbix_utils.helper_compare_dictionaries(parameters, existing_usergroup, change_parameters) + return _diff + + def update(self, **kwargs): + """Update user group. + + Parameters: + **kwargs: Arbitrary keyword parameters. + + Returns: + usergroup: updated user group + """ + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + return self._zapi.usergroup.update(kwargs) + except Exception as e: + self._module.fail_json(msg='Failed to update user group "%s": %s' % (kwargs['usrgrpid'], e)) + + def add(self, **kwargs): + """Add user group. + + Parameters: + **kwargs: Arbitrary keyword parameters. + + Returns: + usergroup: added user group + """ + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + parameters = self._construct_parameters(**kwargs) + usergroup = self._zapi.usergroup.create(parameters) + return usergroup['usrgrpids'][0] + except Exception as e: + self._module.fail_json(msg='Failed to create user group "%s": %s' % (kwargs['name'], e)) + + def delete(self, usrgrpid): + """Delete user group. + + Parameters: + usrgrpid: User group id. + + Returns: + usergroup: deleted user group + """ + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + else: + return self._zapi.usergroup.delete([usrgrpid]) + except Exception as e: + self._module.fail_json(msg='Failed to delete user group "%s": %s' % (usrgrpid, e)) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update( + name=dict(type='str', required=True, aliases=['user_group']), + gui_access=dict(type='str', required=False, default='default', choices=['default', 'internal', 'LDAP', 'disable']), + debug_mode=dict(type='str', required=False, default='disabled', choices=['disabled', 'enabled']), + status=dict(type='str', required=False, default='enabled', choices=['enabled', 'disabled']), + rights=dict(type='list', elements='dict', required=False, options=dict( + host_group=dict(type='str', required=True), + permission=dict(type='str', required=True, choices=['denied', 'read-only', 'read-write']) + )), + hostgroup_rights=dict(type='list', elements='dict', required=False, options=dict( + host_group=dict(type='str', required=True), + permission=dict(type='str', required=True, choices=['denied', 'read-only', 'read-write']) + )), + templategroup_rights=dict(type='list', elements='dict', required=False, options=dict( + template_group=dict(type='str', required=True), + permission=dict(type='str', required=True, choices=['denied', 'read-only', 'read-write']) + )), + tag_filters=dict(type='list', elements='dict', required=False, options=dict( + host_group=dict(type='str', required=True), + tag=dict(type='str', default=''), + value=dict(type='str', default='') + )), + userdirectory=dict(type='str', required=False), + state=dict(type='str', default='present', choices=['present', 'absent']) + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + + name = module.params['name'] + gui_access = module.params['gui_access'] + debug_mode = module.params['debug_mode'] + status = module.params['status'] + rights = module.params['rights'] + hostgroup_rights = module.params['hostgroup_rights'] + templategroup_rights = module.params['templategroup_rights'] + tag_filters = module.params['tag_filters'] + userdirectory = module.params['userdirectory'] + state = module.params['state'] + + userGroup = UserGroup(module) + zbx = userGroup._zapi + if LooseVersion(userGroup._zbx_api_version) < LooseVersion('6.2'): + rgts = Rights(module, zbx) + else: + hostgroup_rgts = HostgroupRights(module, zbx) + templategroup_rgts = TemplategroupRights(module, zbx) + tgflts = TagFilters(module, zbx) + + usergroup_exists = userGroup.check_if_usergroup_exists(name) + + if usergroup_exists: + usrgrpid = userGroup.get_usergroup_by_usergroup_name(name)['usrgrpid'] + if state == 'absent': + userGroup.delete(usrgrpid) + module.exit_json(changed=True, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group deleted: %s, ID: %s' % (name, usrgrpid)) + else: + if LooseVersion(userGroup._zbx_api_version) < LooseVersion('6.2'): + difference = userGroup.check_difference( + usrgrpid=usrgrpid, + name=name, + gui_access=gui_access, + debug_mode=debug_mode, + status=status, + rights=rgts.construct_the_data(rights), + tag_filters=tgflts.construct_the_data(tag_filters) + ) + else: + difference = userGroup.check_difference( + usrgrpid=usrgrpid, + name=name, + gui_access=gui_access, + debug_mode=debug_mode, + status=status, + hostgroup_rights=hostgroup_rgts.construct_the_data(hostgroup_rights), + templategroup_rights=templategroup_rgts.construct_the_data(templategroup_rights), + tag_filters=tgflts.construct_the_data(tag_filters), + userdirectory=userdirectory + ) + if difference == {}: + module.exit_json(changed=False, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group is up to date: %s' % name) + else: + userGroup.update( + usrgrpid=usrgrpid, + **difference + ) + module.exit_json(changed=True, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group updated: %s, ID: %s' % (name, usrgrpid)) + else: + if state == 'absent': + module.exit_json(changed=False, state=state, usergroup=name, msg='User group %s does not exists, nothing to delete' % name) + else: + if LooseVersion(userGroup._zbx_api_version) < LooseVersion('6.2'): + usrgrpid = userGroup.add( + name=name, + gui_access=gui_access, + debug_mode=debug_mode, + status=status, + rights=rgts.construct_the_data(rights), + tag_filters=tgflts.construct_the_data(tag_filters) + ) + else: + usrgrpid = userGroup.add( + name=name, + gui_access=gui_access, + debug_mode=debug_mode, + status=status, + hostgroup_rights=hostgroup_rgts.construct_the_data(hostgroup_rights), + templategroup_rights=templategroup_rgts.construct_the_data(templategroup_rights), + tag_filters=tgflts.construct_the_data(tag_filters), + userdirectory=userdirectory + ) + module.exit_json(changed=True, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group created: %s, ID: %s' % (name, usrgrpid)) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py new file mode 100644 index 000000000..196f8ff7e --- /dev/null +++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py @@ -0,0 +1,317 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2019, Ruben Tsirunyan <rubentsirunyan@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_valuemap +short_description: Create/update/delete Zabbix value maps +description: + - This module allows you to create, modify and delete Zabbix value maps. +author: + - "Ruben Tsirunyan (@rubentsirunyan)" +requirements: + - "python >= 2.6" +options: + name: + type: 'str' + description: + - Name of the value map. + required: true + state: + type: 'str' + description: + - State of the value map. + - On C(present), it will create a value map if it does not exist or update the value map if the associated data is different. + - On C(absent), it will remove the value map if it exists. + choices: ['present', 'absent'] + default: 'present' + mappings: + type: 'list' + elements: dict + description: + - List of value mappings for the value map. + - Required when I(state=present). + suboptions: + value: + type: 'str' + description: Original value. + required: true + map_to: + type: 'str' + description: Value to which the original value is mapped to. + required: true + +extends_documentation_fragment: +- community.zabbix.zabbix + +''' + +RETURN = r''' +''' + +EXAMPLES = r''' +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +- name: Create a value map + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_valuemap: + name: Numbers + mappings: + - value: 1 + map_to: one + - value: 2 + map_to: two + state: present +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + + +def construct_parameters(**kwargs): + """Translates data to a format suitable for Zabbix API + + Args: + **kwargs: Arguments passed to the module. + + Returns: + A dictionary of arguments in a format that is understandable by Zabbix API. + """ + if kwargs['mappings'] is None: + return dict( + name=kwargs['name'] + ) + + return dict( + name=kwargs['name'], + mappings=[ + dict( + value=mapping['value'], + newvalue=mapping['map_to'] + ) for mapping in kwargs['mappings'] + ] + ) + + +def diff(existing, new): + """Constructs the diff for Ansible's --diff option. + + Args: + existing (dict): Existing valuemap data. + new (dict): New valuemap data. + + Returns: + A dictionary like {'before': existing, 'after': new} + with filtered empty values. + """ + before = {} + after = {} + for key in new: + before[key] = existing[key] + if new[key] is None: + after[key] = '' + else: + after[key] = new[key] + + return {'before': before, 'after': after} + + +def get_update_params(existing_valuemap, **kwargs): + """Filters only the parameters that are different and need to be updated. + + Args: + existing_valuemap (dict): Existing valuemap. + **kwargs: Parameters for the new valuemap. + + Returns: + A tuple where the first element is a dictionary of parameters + that need to be updated and the second one is a dictionary + returned by diff() function with + existing valuemap data and new params passed to it. + """ + + params_to_update = {} + if sorted(existing_valuemap['mappings'], key=lambda k: k['value']) != sorted(kwargs['mappings'], key=lambda k: k['value']): + params_to_update['mappings'] = kwargs['mappings'] + return params_to_update, diff(existing_valuemap, kwargs) + + +class ValuemapModule(ZabbixBase): + def check_if_valuemap_exists(self, name): + """Checks if value map exists. + + Args: + name: Zabbix valuemap name + + Returns: + tuple: First element is True if valuemap exists and False otherwise. + Second element is a dictionary of valuemap object if it exists. + """ + try: + valuemap_list = self._zapi.valuemap.get({ + 'output': 'extend', + 'selectMappings': 'extend', + 'filter': {'name': [name]} + }) + if len(valuemap_list) < 1: + return False, None + else: + return True, valuemap_list[0] + except Exception as e: + self._module.fail_json(msg="Failed to get ID of the valuemap '{name}': {e}".format(name=name, e=e)) + + def delete(self, valuemap_id): + try: + return self._zapi.valuemap.delete([valuemap_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete valuemap '{_id}': {e}".format(_id=valuemap_id, e=e)) + + def update(self, **kwargs): + try: + self._zapi.valuemap.update(kwargs) + except Exception as e: + self._module.fail_json(msg="Failed to update valuemap '{_id}': {e}".format(_id=kwargs['valuemapid'], e=e)) + + def create(self, **kwargs): + try: + self._zapi.valuemap.create(kwargs) + except Exception as e: + self._module.fail_json(msg="Failed to create valuemap '{name}': {e}".format(name=kwargs['description'], e=e)) + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + state=dict(type='str', default='present', choices=['present', 'absent']), + mappings=dict( + type='list', + elements='dict', + options=dict( + value=dict(type='str', required=True), + map_to=dict(type='str', required=True) + ) + ) + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['mappings']], + ] + ) + + zabbix_utils.require_creds_params(module) + + for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']: + if p in module.params and not module.params[p] is None: + module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p) + vm = ValuemapModule(module) + + name = module.params['name'] + state = module.params['state'] + mappings = module.params['mappings'] + + valuemap_exists, valuemap_object = vm.check_if_valuemap_exists(name) + + parameters = construct_parameters( + name=name, + mappings=mappings + ) + + if valuemap_exists: + valuemap_id = valuemap_object['valuemapid'] + if state == 'absent': + if module.check_mode: + module.exit_json( + changed=True, + msg="Value map would have been deleted. Name: {name}, ID: {_id}".format( + name=name, + _id=valuemap_id + ) + ) + valuemap_id = vm.delete(valuemap_id) + module.exit_json( + changed=True, + msg="Value map deleted. Name: {name}, ID: {_id}".format( + name=name, + _id=valuemap_id + ) + ) + else: + params_to_update, diff = get_update_params(valuemap_object, **parameters) + if params_to_update == {}: + module.exit_json( + changed=False, + msg="Value map is up to date: {name}".format(name=name) + ) + else: + if module.check_mode: + module.exit_json( + changed=True, + diff=diff, + msg="Value map would have been updated. Name: {name}, ID: {_id}".format( + name=name, + _id=valuemap_id + ) + ) + valuemap_id = vm.update(valuemapid=valuemap_id, **params_to_update) + module.exit_json( + changed=True, + diff=diff, + msg="Value map updated. Name: {name}, ID: {_id}".format( + name=name, + _id=valuemap_id + ) + ) + else: + if state == "absent": + module.exit_json(changed=False) + else: + if module.check_mode: + module.exit_json( + changed=True, + msg="Value map would have been created. Name: {name}, ID: {_id}".format( + name=name, + _id=valuemap_id + ) + ) + valuemap_id = vm.create(**parameters) + module.exit_json( + changed=True, + msg="Value map created: {name}, ID: {_id}".format( + name=name, + _id=valuemap_id + ) + ) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/zabbix/requirements.txt b/ansible_collections/community/zabbix/requirements.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/zabbix/requirements.txt diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/README.md b/ansible_collections/community/zabbix/roles/zabbix_agent/README.md new file mode 100644 index 000000000..f3fe06c9d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/README.md @@ -0,0 +1,556 @@ +# community.zabbix.zabbix_agent role + +![Zabbix Agent](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_agent/badge.svg) + +**Table of Contents** + +- [Requirements](#requirements) + * [Operating systems](#operating-systems) + + [Windows](#windows) + * [Local system access](#local-system-access) + * [Zabbix Versions](#zabbix-versions) +- [Getting started](#getting-started) + * [Minimal Configuration](#minimal-configuration) + * [Issues](#issues) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [SElinux](#selinux) + + [Zabbix Agent](#zabbix-agent) + + [Zabbix Agent vs Zabbix Agent 2 configuration](#zabbix-agent-vs-zabbix-agent-2-configuration) + * [TLS Specific configuration](#tls-specific-configuration) + * [Zabbix API variables](#zabbix-api-variables) + * [Windows Variables](#windows-variables) + * [macOS Variables](#macos-variables) + * [Docker Variables](#docker-variables) + * [FirewallD/Iptables](#firewalld-iptables) + * [IPMI variables](#ipmi-variables) + * [proxy](#proxy) +- [Dependencies](#dependencies) +- [Example Playbook](#example-playbook) + * [zabbix_agent2_plugins](#zabbix-agent2-plugins) + * [agent_interfaces](#agent-interfaces) + * [Other interfaces](#other-interfaces) + * [Vars in role configuration](#vars-in-role-configuration) + * [Combination of group_vars and playbook](#combination-of-group-vars-and-playbook) + * [Example for TLS PSK encrypted agent communication](#example-for-tls-psk-encrypted-agent-communication) +- [Molecule](#molecule) +- [Deploying Userparameters](#deploying-userparameters) +- [License](#license) +- [Author Information](#author-information) + +# Requirements +## Operating systems +This role will work on the following operating systems: + + * Red Hat + * Fedora + * Debian + * Ubuntu + * opensuse + * Windows (Best effort) + * macOS + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`and `community.general`. Installing the collections: + +```sh +ansible-galaxy collection install ansible.posix +ansible-galaxy collection install community.general +``` +If you are willing to create host_groups and hosts in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too: + +``` +ansible-galaxy collection install ansible.netcommon +``` + +### Docker + +When you are a Docker user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.docker`. This collection is needed as the `docker_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.docker +``` + +### Windows + +When you are a Windows user and using Ansible 2.10 or newer, then there are dependencies on collections named `ansible.windows` and `community.windows`. These collections are needed as the `win_` modules are now part of collections and not standard in Ansible anymmore. Installing the collections: + +```sh +ansible-galaxy collection install ansible.windows +ansible-galaxy collection install community.windows +``` + +For more information, see: https://github.com/ansible-collections/community.zabbix/issues/236 + +## Local system access + +To successfully complete the install the role requires `python-netaddr` on the controller to be able to manage IP addresses. This requires that the library is available on your local machine (or that `pip` is installed to be able to run). This will likely mean that running the role will require `sudo` access to your local machine and therefore you may need the `-K` flag to be able to enter your local machine password if you are not running under root. + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases: + +| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----|-----|-----|----------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V | +| Red Hat Fam 6 | V | V | V | V | V | V | | | V | +| Red Hat Fam 5 | | | V | V | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | V | V | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | V | V | V | V | V | V | V | V | | +| Ubuntu 14.04 trusty | V | V | V | V | V | V | V | V | V | +| Debian 10 buster | V | V | V | V | V | V | V | | | +| Debian 9 stretch | V | V | | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +# Getting started + +## Minimal Configuration + +In order to get the Zabbix Agent running, you'll have to define the following properties before executing the role: + +* `zabbix_agent_version` +* `zabbix_agent(2)_server` +* `zabbix_agent(2)_serveractive` (When using active checks) + +The `zabbix_agent_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_agent_version: 4.0`, `zabbix_agent_version: 3.4` or `zabbix_agent_version: 2.2`. + +The `zabbix_agent(2)_server` (and `zabbix_agent(2)_serveractive`) should contain the ip or fqdn of the host running the Zabbix Server. + +## Issues + +Due to issue discussed on [#291](https://github.com/dj-wasabi/ansible-zabbix-agent/issues/291), the Ansible Version 2.9.{0,1,2} isn't working correctly on Windows related targets. + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_agent_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_agent_version_minor`: When you want to specify a minor version to be installed. Is also used for `zabbix_sender` and `zabbix_get`. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. + +### SElinux + +* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the server will run. + +### Zabbix Agent + +* `zabbix_agent_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact. +* `zabbix_agent2`: Default: `False`. When you want to install the `Zabbix Agent2` instead of the "old" `Zabbix Agent`. +* `zabbix_agent_listeninterface`: Interface zabbix-agent listens on. Leave blank for all. +* `zabbix_agent_package_remove`: If `zabbix_agent2: True` and you want to remove the old installation. Default: `False`. +* `zabbix_agent_package`: The name of the zabbix-agent package. Default: `zabbix-agent`. In case for EPEL, it is automatically renamed. +* `zabbix_sender_package`: The name of the zabbix-sender package. Default: `zabbix-sender`. In case for EPEL, it is automatically renamed. +* `zabbix_get_package`: The name of the zabbix-get package. Default: `zabbix-get`. In case for EPEL, it is automatically renamed. +* `zabbix_agent_package_state`: If Zabbix-agent needs to be `present` or `latest`. +* `zabbix_agent_interfaces`: A list that configured the interfaces you can use when configuring via API. +* `zabbix_agent_install_agent_only`: Only install the Zabbix Agent and not the `zabbix-sender` and `zabbix-get` packages. Default: `False` +* `zabbix_agent_userparameters`: Default: `[]]`. List of userparameter names and scripts (if any). Detailed description is given in the [Deploying Userparameters](#deploying-userparameters) section. + * `name`: Userparameter name (should be the same with userparameter template file name) + * `scripts_dir`: Directory name of the custom scripts needed for userparameters +* `zabbix_agent_userparameters_templates_src`: indicates the relative path (from `templates/`) where userparameter templates are searched +* `zabbix_agent_userparameters_scripts_src`: indicates the relative path (from `files/`) where userparameter scripts are searched +* `zabbix_agent_runas_user`: Drop privileges to a specific, existing user on the system. Only has effect if run as 'root' and AllowRoot is disabled. +* `zabbix_agent_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip. +* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely. +* `zabbix_agent_apt_priority`: Add a weight (`Pin-Priority`) for the APT repository. +* `zabbix_agent_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. +* `zabbix_agent_dont_detect_ip`: Default `false`. When set to `true`, it won't detect available ip addresses on the host and no need for the Python module `netaddr` to be installed. +* `zabbix_agent_chassis`: Default: `false`. When set to `true`, it will give Zabbix Agent access to the Linux DMI table allowing system.hw.chassis info to populate. + +### Zabbix Agent vs Zabbix Agent 2 configuration + +The following provides an overview of all the properties that can be set in the Zabbix Agent configuration file. When `(2)` is used in the name of the property, like `zabbix_agent(2)_pidfile`, it will show that you can configure `zabbix_agent_pidfile` for the Zabbix Agent configuration file and `zabbix_agent2_pidfile` for the Zabbix Agent 2 configuration file. + +Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2. + +* `zabbix_agent(2)_server`: The ip address for the zabbix-server or zabbix-proxy. +* `zabbix_agent(2)_serveractive`: The ip address for the zabbix-server or zabbix-proxy for active checks. +* `zabbix_agent(2)_allow_key`: list of AllowKey configurations. +* `zabbix_agent(2)_deny_key`: list of DenyKey configurations. +* `zabbix_agent(2)_pidfile`: name of pid file. +* `zabbix_agent(2)_logfile`: name of log file. +* `zabbix_agent(2)_logfilesize`: maximum size of log file in mb. +* `zabbix_agent(2)_logtype`: Specifies where log messages are written to +* `zabbix_agent(2)_debuglevel`: specifies debug level +* `zabbix_agent(2)_sourceip`: source ip address for outgoing connections. +* `zabbix_agent_enableremotecommands`: whether remote commands from zabbix server are allowed. +* `zabbix_agent_logremotecommands`: enable logging of executed shell commands as warnings. +* `zabbix_agent(2)_listenport`: agent will listen on this port for connections from the server. +* `zabbix_agent2_statusport`: Agent will listen on this port for HTTP status requests. +* `zabbix_agent(2)_listenip`: list of comma delimited ip addresses that the agent should listen on. +* `zabbix_agent_startagents`: number of pre-forked instances of zabbix_agentd that process passive checks. +* `zabbix_agent(2)_hostname`: unique, case sensitive hostname. +* `zabbix_agent(2)_hostnameitem`: item used for generating hostname if it is undefined. +* `zabbix_agent(2)_hostmetadata`: optional parameter that defines host metadata. +* `zabbix_agent(2)_hostmetadataitem`: optional parameter that defines an item used for getting the metadata. +* `zabbix_agent(2)_refreshactivechecks`: how often list of active checks is refreshed, in seconds. +* `zabbix_agent(2)_buffersend`: do not keep data longer than n seconds in buffer. +* `zabbix_agent(2)_buffersize`: maximum number of values in a memory buffer. the agent will send all collected data to zabbix server or proxy if the buffer is full. +* `zabbix_agent2_enablepersistentbuffer`: 0 - disabled, in-memory buffer is used (default); 1 - use persistent buffer +* `zabbix_agent2_persistentbufferperiod`: Zabbix Agent2 will keep data for this time period in case of no connectivity with Zabbix server or proxy. Older data will be lost. Log data will be preserved. +* `zabbix_agent2_persistentbufferfile`: Zabbix Agent2 will keep SQLite database in this file * n is valid if `EnablePersistentBuffer=1` +* `zabbix_agent_maxlinespersecond`: maximum number of new lines the agent will send per second to zabbix server or proxy processing 'log' and 'logrt' active checks. +* `zabbix_agent_allowroot`: allow the agent to run as 'root'. if disabled and the agent is started by 'root', the agent will try to switch to user 'zabbix' instead. has no effect if started under a regular user. +* `zabbix_agent(2)_zabbix_alias`: sets an alias for parameter. it can be useful to substitute long and complex parameter name with a smaller and simpler one. Can be both a string as an list. +* `zabbix_agent(2)_timeout`: spend no more than timeout seconds on processing +* `zabbix_agent(2)_include`: you may include individual files or all files in a directory in the configuration file. +* `zabbix_agent(2)_include_pattern`: Optional file pattern used for included files. +* `zabbix_agent(2)_include_mode`: The mode for the directory mentioned above. +* `zabbix_agent(2)_unsafeuserparameters`: allow all characters to be passed in arguments to user-defined parameters. +* `zabbix_agent_loadmodulepath`: Full path to location of agent modules. +* `zabbix_agent_loadmodule`: Module to load at agent startup. Modules are used to extend functionality of the agent. +* `zabbix_agent2_controlsocket`: The control socket, used to send runtime commands with '-R' option. +* `zabbix_agent_allowroot`: Allow the agent to run as 'root'. 0 - do not allow, 1 - allow +* `zabbix_agent2_plugins`: A list containing plugin configuration. +* `zabbix_agent(2)_listenbacklog`: The maximum number of pending connections in the queue. + +## TLS Specific configuration + +These variables are specific for Zabbix 3.0 and higher. When `(2)` is used in the name of the property, like `zabbix_agent(2)_tlsconnect`, it will show that you can configure `zabbix_agent_tlsconnect` for the Zabbix Agent configuration file and `zabbix_agent2_tlsconnect` for the Zabbix Agent 2 configuration file. + +* `zabbix_agent(2)_tlsconnect`: How the agent should connect to server or proxy. Used for active checks. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_agent(2)_tlsaccept`: What incoming connections to accept. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_agent(2)_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification. +* `zabbix_agent(2)_tlscrlfile`: Full pathname of a file containing revoked certificates. +* `zabbix_agent(2)_tlsservercertissuer`: Allowed server certificate issuer. +* `zabbix_agent(2)_tlsservercertsubject`: Allowed server certificate subject. +* `zabbix_agent(2)_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain. +* `zabbix_agent(2)_tlskeyfile`: Full pathname of a file containing the agent private key. +* `zabbix_agent(2)_tlspskidentity`: Unique, case sensitive string used to identify the pre-shared key. +* `zabbix_agent(2)_tlspskidentity_file`: Full pathname of a file containing the pre-shared key identity. +* `zabbix_agent(2)_tlspskfile`: Full pathname of a file containing the pre-shared key. +* `zabbix_agent(2)_tlspsk_secret`: The pre-shared secret key that should be placed in the file configured with `agent_tlspskfile`. +* `zabbix_agent(2)_tlspsk_auto`: Enables auto generation and storing of individual pre-shared keys and identities on clients. Is false by default. If set to true and if `zabbix_agent_tlspskfile` and `zabbix_agent_tlspsk_secret` are undefined, it generates the files `/etc/zabbix/tls_psk_auto.identity` and `/etc/zabbix/tls_psk_auto.secret`, which are populated by values automatically (identity is set to hostname, underscore and 4 random alphanumeric digits; secret is 64 random alphanumeric digits) in such a way that the values are generated once and are never overwritten. + +The results are stored in the Ansible variables `zabbix_agent_tlspskidentity` and `zabbix_agent_tlspsk_secret`, so that they may be used later in the code, for example with [zabbix_host](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_module.html) to configure the Zabbix server or with `debug: msg:` to display them to the user. + +## Zabbix API variables + +These variables need to be overridden when you want to make use of the Zabbix API for automatically creating and or updating hosts. + +Host encryption configuration will be set to match agent configuration. + +* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth. +* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth. +* `zabbix_api_create_hosts`: Default: `False`. When you want to enable the Zabbix API to create/delete the host. This has to be set to `True` if you want to make use of `zabbix_agent_host_state`. +* `zabbix_api_create_hostgroup`: When you want to enable the Zabbix API to create/delete the hostgroups. This has to be set to `True` if you want to make use of `zabbix_agent_hostgroups_state`.Default: `False` +* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com +* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080 +* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS +* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used +* `zabbix_api_login_user`: Username of user which has API access. +* `zabbix_api_login_pass`: Password for the user which has API access. +* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu` +* `zabbix_agent_hostgroups_state`: present (Default) if the hostgroup needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_hostgroup` is set to `True`. +* `zabbix_host_status`: enabled (Default) when host in monitored, disabled when host is disabled for monitoring. +* `zabbix_agent_host_state`: present (Default) if the host needs to be created or absent is you want to delete it. This only works when `zabbix_api_create_hosts` is set to `True`. +* `zabbix_agent_host_update`: yes (Default) if the host should be updated if already present. This only works when `zabbix_api_create_hosts` is set to `True`. +* `zabbix_useuip`: 1 if connection to zabbix-agent is made via ip, 0 for fqdn. +* `zabbix_host_groups`: A list of hostgroups which this host belongs to. +* `zabbix_agent_link_templates`: A list of templates which needs to be link to this host. The templates should exist. +* `zabbix_agent_macros`: A list with macro_key and macro_value for creating hostmacro's. +* `zabbix_agent_tags`: A list with tag and (optionally) value for creating host tags. +* `zabbix_agent_inventory_mode`: Configure Zabbix inventory mode. Needed for building inventory data, manually when configuring a host or automatically by using some automatic population options. This has to be set to `automatic` if you want to make automatically building inventory data. +* `zabbix_agent_visible_hostname` : Configure Zabbix visible name inside Zabbix web UI for the node. +* `zabbix_agent_description`: Description of the host in Zabbix. +* `zabbix_agent_inventory_zabbix`: Adds Facts for a zabbix inventory + +## Windows Variables + +**NOTE** + +_Supporting Windows is a best effort (I don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._ +When `(2)` is used in the name of the property, like `zabbix_agent(2)_win_logfile`, it will show that you can configure `zabbix_agent_win_logfile` for the Zabbix Agent configuration file and `zabbix_agent2_win_logfile` for the Zabbix Agent 2 configuration file. + +Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2. + +* `zabbix(2)_win_package`: file name pattern (zip only). This will be used to generate the `zabbix(2)_win_download_link` variable. +* `zabbix_version_long`: The long (major.minor.patch) version of the Zabbix Agent. This will be used to generate the `zabbix(2)_win_package` and `zabbix(2)_win_download_link` variables. This takes precedence over `zabbix_agent_version`. +* `zabbix(2)_win_download_link`: The download url to the `win.zip` file. +* `zabbix_win_install_dir`: The directory where Zabbix needs to be installed. +* `zabbix_win_install_dir_conf`: The directory where Zabbix configuration file needs to be installed. +* `zabbix_win_install_dir_bin`: The directory where Zabbix binary file needs to be installed. +* `zabbix_agent(2)_win_logfile`: The full path to the logfile for the Zabbix Agent. +* `zabbix_agent_win_include`: The directory in which the Zabbix Agent specific configuration files are stored. +* `zabbix_agent_win_svc_recovery`: Enable Zabbix Agent service auto-recovery settings. +* `zabbix_win_firewall_management`: Enable Windows firewall management (add service and port to allow rules). Default: `True` + +## macOS Variables + +* `zabbix_version_long`: The long (major.minor.patch) version of the Zabbix Agent. This will be used to generate the `zabbix_mac_download_link` link. +* `zabbix_mac_download_link`: The download url to the `pkg` file. + +## Docker Variables + +When you don't want to install the Zabbix Agent on the host, but would like to run it in a container then these properties are useful. When `zabbix_agent_docker` is set to `True`, then a +Docker image will be downloaded and a Container will be started. No other installations will be done on the host, with the exception of the PSK file and the "Zabbix Include Directory". + +The following directories are mounted in the Container: + +``` + - /etc/zabbix/zabbix_agentd.d:/etc/zabbix/zabbix_agentd.d + - /:/hostfs:ro + - /etc:/hostfs/etc:ro + - /proc:/hostfs/proc:ro + - /sys:/hostfs/sys:ro + - /var/run:/var/run +``` + +Keep in mind that using the Zabbix Agent in a Container requires changes to the Zabbix Template for Linux as `/proc`, `/sys` and `/etc` are mounted in a directory `/hostfs`. + +* `zabbix_agent_docker`: Default: `False`. When set to `True`, it will install a Docker container on the target host instead of installation on the target. +* `zabbix_agent_docker_state`: Default: `started` +* `zabbix_agent_docker_name`: The name of the Container. Default: `zabbix-agent` +* `zabbix_agent_docker_image`: The name of the Docker image. Default: `zabbix/zabbix-agent` +* `zabbix_agent_docker_image_tag`: The tag of the Docker image. +* `zabbix_agent_docker_user_gid`: The group id of the zabbix user in the Container. +* `zabbix_agent_docker_user_uid`: The user id of the zabbix user in the Container. +* `zabbix_agent_docker_network_mode`: The name of the (Docker) network that should be used for the Container. Default `host`. +* `zabbix_agent_docker_restart_policy`: Default: `unless-stopped`. The restart policy of the Container. +* `zabbix_agent_docker_privileged`: When set to `True`, the container is running in privileged mode. +* `zabbix_agent_docker_ports`: A list with `<PORT>:<PORT>` values to open ports to the container. +* `zabbix_agent_docker_security_opts`: A list with available security options. +* `zabbix_agent_docker_volumes`: A list with all directories that needs to be available in the Container. +* `zabbix_agent_docker_env`: A dict with all environment variables that needs to be set for the Container. + +## FirewallD/Iptables + +* `zabbix_agent_firewall_enable`: If IPtables needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport`. +* `zabbix_agent_firewall_source`: When provided, IPtables will be configuring to only allow traffic from this IP address/range. +* `zabbix_agent_firewalld_enable`: If firewalld needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport` and `zabbix_agent_jmx_listenport` if defined. +* `zabbix_agent_firewalld_source`: When provided, firewalld will be configuring to only allow traffic for IP configured in `zabbix_agent_server`. +* `zabbix_agent_firewalld_zone`: When provided, the firewalld rule will be attached to this zone (only if zabbix_agent_firewalld_enable is set to true). The default behavior is to use the default zone define by the remote host firewalld configuration. +* `zabbix_agent_firewall_action`: Default: `insert`. When to `insert` the rule or to `append` to IPTables. +* `zabbix_agent_firewall_chain`: Default `INPUT`. Which `chain` to add the rule to IPTables. + + +## IPMI variables + +* `zabbix_agent_ipmi_authtype`: IPMI authentication algorithm. Possible values are 1 (callback), 2 (user), 3 (operator), 4 (admin), 5 (OEM), with 2 being the API default. +* `zabbix_agent_ipmi_password`: IPMI password. +* `zabbix_agent_ipmi_privilege`: IPMI privilege level. Possible values are 1 (callback), 2 (user), 3 (operator), 4 (admin), 5 (OEM), with 2 being the API default. +* `zabbix_agent_ipmi_username`: IPMI username. + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +# Dependencies + +There are no dependencies on other roles. + +# Example Playbook + +## zabbix_agent2_plugins + +Specifically for the Zabbix Agent 2, a list of extra plugins can be configured. The following provides an overview of configuring the `SystemRun` plugin by setting the `LogRemoteCommands` to `0`: + +```yaml +zabbix_agent2_plugins: + - name: SystemRun + options: + - parameter: LogRemoteCommands + value: 0 +``` + +In the `zabbix_agent2.conf` an entry will be created with the following content: + +``` +Plugins.SystemRun.LogRemoteCommands=0 +``` + +## agent_interfaces + +This will configure the Zabbix Agent interface on the host. +```yaml +zabbix_agent_interfaces: + - type: 1 + main: 1 + useip: "{{ zabbix_useuip }}" + ip: "{{ zabbix_agent_ip }}" + dns: "{{ ansible_fqdn }}" + port: "{{ zabbix_agent_listenport }}" +``` + +## Other interfaces + +You can also configure the `zabbix_agent_interfaces` to add/configure snmp, jmx and ipmi interfaces. + +You'll have to use one of the following type numbers when configuring it: + +| Type Interface | Nr | +|-----------------|-------| +| Zabbix Agent | 1 | +| snmp | 2 | +| ipmi | 3 | +| jmx | 4 | + +Configuring a snmp interface will look like this: + +``` +zabbix_agent_interfaces: + - type: 2 + main: 1 + useip: "{{ zabbix_useuip }}" + ip: "{{ agent_ip }}" + dns: "{{ ansible_fqdn }}" + port: "{{ agent_listenport }}" +``` + +## Vars in role configuration +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: all + roles: + - role: community.zabbix.zabbix_agent + zabbix_agent_server: 192.168.33.30 + zabbix_agent_serveractive: 192.168.33.30 + zabbix_api_server_url: http://zabbix.example.com + zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0 + zabbix_api_login_user: Admin + zabbix_api_login_pass: zabbix + zabbix_agent_host_state: present + zabbix_host_groups: + - Linux Servers + zabbix_agent_link_templates: + - Template OS Linux + - Apache APP Template + zabbix_agent_macros: + - macro_key: apache_type + macro_value: reverse_proxy + macro_type: text + zabbix_agent_tags: + - tag: environment + value: production +``` + +## Combination of group_vars and playbook +You can also use the group_vars or the host_vars files for setting the variables needed for this role. File you should change: `group_vars/all` or `host_vars/<zabbix_server>` (Where <zabbix_server> is the hostname of the machine running Zabbix Server) + +```yaml + zabbix_agent_server: 192.168.33.30 + zabbix_agent_serveractive: 192.168.33.30 + zabbix_api_server_url: http://zabbix.example.com + zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0 + zabbix_api_login_user: Admin + zabbix_api_login_pass: zabbix + zabbix_agent_host_state: present + zabbix_host_groups: + - Linux Servers + zabbix_agent_link_templates: + - Template OS Linux + - Apache APP Template + zabbix_agent_macros: + - macro_key: apache_type + macro_value: reverse_proxy + zabbix_agent_tags: + - tag: environment + value: production +``` + +and in the playbook only specifying: + +```yaml + - hosts: all + roles: + - role: community.zabbix.zabbix_agent +``` + +## Example for TLS PSK encrypted agent communication + +Variables e.g. in the playbook or in `host_vars/myhost`: + +```yaml + zabbix_agent_tlsaccept: psk + zabbix_agent_tlsconnect: psk + zabbix_agent_tlspskidentity: "myhost PSK" + zabbix_agent_tlspsk_secret: b7e3d380b9d400676d47198ecf3592ccd4795a59668aa2ade29f0003abbbd40d + zabbix_agent_tlspskfile: /etc/zabbix/zabbix_agent_pskfile.psk +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# Deploying Userparameters + +The following steps are required to install custom userparameters and/or scripts: + +* Put the desired userparameter file in the `templates/userparameters` directory and name it as `<userparameter_name>.j2`. For example: `templates/userparameters/mysql.j2`. You can change the default directory to a custom one modifying `zabbix_agent_userparameters_templates_src` variable. +* Put the scripts directory (if any) in the `files/scripts` directory. For example: `files/scripts/mysql`. You can change the default directory to a custom one modifying `zabbix_agent_userparameters_scripts_src` variable. +* Add `zabbix_agent_userparameters` variable to the playbook as a list of dictionaries and define userparameter name and scripts directory name (if there are no scripts just no not specify the `scripts_dir` variable). + +Example: + +```yaml +- hosts: mysql_servers + tasks: + - include_role: + name: community.zabbix.zabbix_agent + vars: + zabbix_agent_server: zabbix.mydomain.com + zabbix_agent_userparameters: + - name: mysql + scripts_dir: mysql + - name: galera + +``` + +Example of the "templates/userparameters/mysql.j2" file: + +``` +UserParameter=mysql.ping_to,mysqladmin -uroot ping | grep -c alive +``` + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml new file mode 100644 index 000000000..5fc96071a --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml @@ -0,0 +1,322 @@ +--- +# defaults file for zabbix_agent + +zabbix_agent2: false +# zabbix_agent_version: 6.0 +zabbix_agent_version_minor: "*" +zabbix_version: "{{ zabbix_agent_version }}" +zabbix_version_patch: 0 +zabbix_repo: zabbix +zabbix_agent_package_remove: false +zabbix_agent_package: zabbix-agent +zabbix_sender_package: zabbix-sender +zabbix_get_package: zabbix-get +zabbix_agent_package_state: present +zabbix_agent_server: +zabbix_agent_serveractive: +zabbix_agent2_server: "{{ zabbix_agent_server }}" +zabbix_agent2_serveractive: "{{ zabbix_agent_serveractive }}" +zabbix_selinux: false +zabbix_agent_src_reinstall: false +zabbix_agent_apt_priority: +zabbix_agent_conf_mode: "0644" +zabbix_agent_dont_detect_ip: false +zabbix_agent_allow_key: [] +zabbix_agent_deny_key: [] +zabbix_agent2_allow_key: "{{ zabbix_agent_allow_key }}" +zabbix_agent2_deny_key: "{{ zabbix_agent_deny_key }}" + +# Selinux related vars +selinux_allow_zabbix_run_sudo: false + +zabbix_agent_install_agent_only: false +zabbix_agent_packages: + - "{{ zabbix_agent_package }}" + - "{{ zabbix_sender_package }}" + - "{{ zabbix_get_package }}" + +# Zabbix role related vars +zabbix_install_pip_packages: true +zabbix_apt_force_apt_get: true +zabbix_apt_install_recommends: false + +# Override Ansible specific facts +zabbix_agent_distribution_major_version: "{{ ansible_distribution_major_version }}" +zabbix_agent_distribution_release: "{{ ansible_distribution_release }}" +zabbix_agent_os_family: "{{ ansible_os_family }}" +zabbix_repo_yum_gpgcheck: 0 +zabbix_repo_yum_schema: https +zabbix_repo_yum_disabled: "*" +zabbix_repo_yum_enabled: [] +zabbix_repo_yum: + - name: zabbix + description: Zabbix Official Repository - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version }}/rhel/{{ zabbix_agent_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + - name: zabbix-non-supported + description: Zabbix Official Repository non-supported - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/non-supported/rhel/{{ zabbix_agent_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + - name: zabbix-agent2-plugins + description: Zabbix Official Repository (Agent2 Plugins) - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix-agent2-plugins/1/rhel/{{ zabbix_agent_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + +# Zabbix API stuff +zabbix_validate_certs: true # Will be deprecated in 2.0.0 +zabbix_api_validate_certs: "{{ zabbix_validate_certs }}" +zabbix_agent_server_url: http://localhost # Will be deprecated in 2.0.0 +zabbix_url: "{{ zabbix_agent_server_url }}" # Will be deprecated in 2.0.0 +zabbix_api_server_url: "{{ zabbix_agent_server_url }}" +zabbix_api_server_host: "{{ zabbix_api_server_url | urlsplit('hostname') }}" +zabbix_api_port_from_url: "{{ zabbix_api_server_port | default(zabbix_api_server_url | urlsplit('port')) }}" +zabbix_api_scheme_from_url: "{{ zabbix_api_server_url | urlsplit('scheme') }}" +zabbix_api_port_from_shema: "{{ (zabbix_api_scheme_from_url == 'https') | ternary(443, 80) }}" +# zabbix_http_user: admin # Will be deprecated in 2.0.0 +# zabbix_http_password: admin # Will be deprecated in 2.0.0 +# zabbix_api_http_user: admin +# zabbix_api_http_password: admin +zabbix_api_user: Admin # Will be deprecated in 2.0.0 +zabbix_api_pass: !unsafe zabbix # Will be deprecated in 2.0.0 +zabbix_api_login_user: "{{ zabbix_api_user }}" +zabbix_api_login_pass: "{{ zabbix_api_pass }}" +ansible_httpapi_pass: "{{ zabbix_api_login_pass }}" +ansible_httpapi_port: "{{ (zabbix_api_port_from_url == '') | ternary(zabbix_api_port_from_shema, zabbix_api_port_from_url) }}" +ansible_httpapi_use_ssl: "{{ zabbix_api_use_ssl | default((zabbix_api_scheme_from_url == 'https') | ternary(true, false)) }}" +ansible_httpapi_validate_certs: "{{ zabbix_api_validate_certs }}" +zabbix_api_create_hostgroup: false +zabbix_api_create_hosts: false +zabbix_api_timeout: 30 +zabbix_create_hostgroup: present # or absent # Will be deprecated in 2.0.0 +zabbix_agent_hostgroups_state: "{{ zabbix_create_hostgroup }}" +zabbix_create_host: present # or absent # Will be deprecated in 2.0.0 +zabbix_agent_host_state: "{{ zabbix_create_host }}" +zabbix_update_host: true # Will be deprecated in 2.0.0 +zabbix_agent_host_update: "{{ zabbix_update_host }}" +zabbix_host_status: enabled # or disabled +zabbix_proxy: null # Will be deprecated in 2.0.0 +zabbix_agent_proxy: "{{ zabbix_proxy }}" +zabbix_inventory_mode: disabled # Will be deprecated in 2.0.0 +zabbix_agent_inventory_mode: "{{ zabbix_inventory_mode }}" +zabbix_useuip: 1 +zabbix_host_groups: + - Linux servers +zabbix_link_templates: # Will be deprecated in 2.0.0 + - Template Linux by Zabbix agent +zabbix_agent_link_templates: "{{ zabbix_link_templates }}" + +zabbix_agent_interfaces: + - type: 1 + main: 1 + useip: "{{ zabbix_useuip }}" + ip: "{{ zabbix_agent_ip }}" + dns: "{{ ansible_fqdn }}" + port: "{{ (zabbix_agent2 == True) | ternary(zabbix_agent2_listenport, zabbix_agent_listenport) }}" + +zabbix_agent_firewall_enable: false +zabbix_agent_firewalld_enable: false +zabbix_agent_firewalld_source: "{{ zabbix_agent_server }}" +zabbix_agent_firewall_action: insert +zabbix_agent_firewall_chain: INPUT + +# By default, a null zone will trigger the use of the default zone on the remote host +zabbix_agent_firewalld_zone: +# Zabbix configuration variables +zabbix_agent_pidfile: /var/run/zabbix/zabbix_agentd.pid +zabbix_agent_logtype: file +zabbix_agent_logfile: /var/log/zabbix/zabbix_agentd.log +zabbix_agent_logfilesize: 100 +zabbix_agent_debuglevel: 3 +zabbix_agent_sourceip: +zabbix_agent_enableremotecommands: 0 +zabbix_agent_allowkeys: +zabbix_agent_denykeys: +zabbix_agent_logremotecommands: 0 +zabbix_agent_listenport: 10050 +zabbix_agent_jmx_listenport: +zabbix_agent_listeninterface: +zabbix_agent_listenip: +zabbix_agent_startagents: 3 +zabbix_agent_hostname: "{{ inventory_hostname }}" +zabbix_agent_hostnameitem: +zabbix_agent_hostmetadata: +zabbix_agent_hostmetadataitem: +zabbix_agent_refreshactivechecks: 120 +zabbix_agent_buffersend: 5 +zabbix_agent_buffersize: 100 +zabbix_agent_maxlinespersecond: 100 +zabbix_agent_allowroot: 0 +zabbix_agent_zabbix_alias: +zabbix_agent_timeout: 3 +zabbix_agent_include: /etc/zabbix/zabbix_agentd.d +zabbix_agent_include_pattern: +zabbix_agent_include_mode: "0750" +zabbix_agent_unsafeuserparameters: 0 +zabbix_agent_userparameters: [] +zabbix_agent_userparameters_templates_src: "userparameters" +zabbix_agent_userparameters_scripts_src: "scripts" +zabbix_agent_custom_scripts: false +zabbix_agent_loadmodulepath: ${libdir}/modules +zabbix_agent_loadmodule: +zabbix_agent_become_on_localhost: true +zabbix_agent_description: +zabbix_agent_inventory_zabbix: {} +zabbix_agent_heartbeatfrequency: 60 +zabbix_macros: [] # Will be deprecated in 2.0.0 +zabbix_agent_macros: "{{ zabbix_macros }}" +zabbix_agent_tags: [] +zabbix_agent_chassis: false + +# TLS settings +zabbix_agent_tlsconnect: +zabbix_agent_tlsaccept: +zabbix_agent_tlscafile: +zabbix_agent_tlscrlfile: +zabbix_agent_tlsservercertissuer: +zabbix_agent_tlsservercertsubject: +zabbix_agent_tls_subject: "{{ zabbix_agent_tlsservercertsubject }}" # FIXME this is not correct and should be removed with 2.0.0, here only to prevent regression +zabbix_agent_tlscertfile: +zabbix_agent_tlskeyfile: +zabbix_agent_tlspskidentity: +zabbix_agent_tlspsk_auto: false + +zabbix_agent_tls_config: + unencrypted: "1" + psk: "2" + cert: "4" + +# IPMI settings +zabbix_agent_ipmi_authtype: 2 +zabbix_agent_ipmi_password: +zabbix_agent_ipmi_privilege: 2 +zabbix_agent_ipmi_username: + +# Zabbix Agent2 +zabbix_agent2_pidfile: /var/run/zabbix/zabbix_agent2.pid +zabbix_agent2_logfile: /var/log/zabbix/zabbix_agent2.log +zabbix_agent2_logtype: file +zabbix_agent2_statusport: 9999 +zabbix_agent2_include: /etc/zabbix/zabbix_agent2.d +zabbix_agent2_include_pattern: +zabbix_agent2_logfilesize: 100 +zabbix_agent2_debuglevel: 3 +zabbix_agent2_sourceip: +zabbix_agent2_listenport: 10050 +zabbix_agent2_listenip: +zabbix_agent2_hostname: "{{ inventory_hostname }}" +zabbix_agent2_hostnameitem: +zabbix_agent2_hostmetadata: +zabbix_agent2_hostmetadataitem: +zabbix_agent2_hostinterface: +zabbix_agent2_hostinterfaceitem: +zabbix_agent2_enablepersistentbuffer: 0 +zabbix_agent2_persistentbufferperiod: 1h +zabbix_agent2_persistentbufferfile: +zabbix_agent2_refreshactivechecks: 120 +zabbix_agent2_buffersend: 5 +zabbix_agent2_buffersize: 100 +zabbix_agent2_zabbix_alias: +zabbix_agent2_timeout: 3 +zabbix_agent2_include_mode: "0750" +zabbix_agent2_unsafeuserparameters: 0 +zabbix_agent2_controlsocket: /tmp/agent.sock +zabbix_agent2_plugins: [] + +# Zabbix Agent2 TLS settings +zabbix_agent2_tlsconnect: +zabbix_agent2_tlsaccept: +zabbix_agent2_tlscafile: +zabbix_agent2_tlscrlfile: +zabbix_agent2_tlsservercertissuer: +zabbix_agent2_tlsservercertsubject: +zabbix_agent2_tls_subject: "{{ zabbix_agent2_tlsservercertsubject }}" # FIXME this is not correct and should be removed with 2.0.0, here only to prevent regression +zabbix_agent2_tlscertfile: +zabbix_agent2_tlskeyfile: +zabbix_agent2_tlspskidentity: +zabbix_agent2_tlspsk_auto: false + +# Windows/macOS Related +zabbix_version_long: 5.2.4 + +# Windows Related +zabbix_win_package: zabbix_agent-{{ zabbix_version_long }}-windows-amd64-openssl.zip +zabbix2_win_package: zabbix_agent2-{{ zabbix_version_long }}-windows-amd64-openssl-static.zip +zabbix_win_download_url: https://cdn.zabbix.com/zabbix/binaries/stable +zabbix_win_download_link: "{{ zabbix_win_download_url }}/{{ zabbix_version_long | regex_search('^\\d+\\.\\d+') }}/{{ zabbix_version_long }}/{{ zabbix_win_package }}" +zabbix2_win_download_link: "{{ zabbix_win_download_url }}/{{ zabbix_version_long | regex_search('^\\d+\\.\\d+') }}/{{ zabbix_version_long }}/{{ zabbix2_win_package }}" +zabbix_win_install_dir: 'C:\Zabbix' +zabbix_win_install_dir_conf: '{{ zabbix_win_install_dir }}\\conf' +zabbix_win_install_dir_bin: '{{ zabbix_win_install_dir }}\\bin' +zabbix_agent_win_logfile: "{{ zabbix_win_install_dir }}\\zabbix_agentd.log" +zabbix_agent_win_include: "{{ zabbix_win_install_dir }}\\zabbix_agent.d\\" +zabbix_agent2_win_logfile: "{{ zabbix_win_install_dir }}\\zabbix_agent2.log" +zabbix_agent_win_svc_recovery: true +zabbix_win_firewall_management: true + +# macOS Related +zabbix_mac_package: zabbix_agent-{{ zabbix_version_long }}-macos-amd64-openssl.pkg +zabbix_mac_download_url: https://cdn.zabbix.com/zabbix/binaries/stable +zabbix_mac_download_link: "{{ zabbix_mac_download_url }}/{{ zabbix_agent_version }}/{{ zabbix_version_long }}/{{ zabbix_mac_package }}" + +# Zabbix Agent Docker facts +zabbix_agent_docker: false +zabbix_agent_docker_state: started +zabbix_agent_docker_name: zabbix-agent +zabbix_agent_docker_image: "zabbix/zabbix-agent" +zabbix_agent_docker_image_tag: "ubuntu-{{ zabbix_version }}.{{ zabbix_version_patch }}" +zabbix_agent_docker_user_gid: 101 +zabbix_agent_docker_user_uid: 101 +zabbix_agent_docker_network_mode: host +zabbix_agent_docker_restart_policy: unless-stopped +zabbix_agent_docker_privileged: false +zabbix_agent_docker_ports: + - 10050:10050 +zabbix_agent_docker_security_opts: + - apparmor:unconfined +zabbix_agent_docker_volumes: + - /etc/zabbix/zabbix_agentd.d:{{ zabbix_agent_include }} + - /:/hostfs:ro + - /etc:/hostfs/etc:ro + - /proc:/hostfs/proc:ro + - /sys:/hostfs/sys:ro + - /var/run:/var/run +zabbix_agent_docker_env: + ZBX_HOSTNAME: "{{ zabbix_agent_hostname }}" + ZBX_SERVER_HOST: "{{ zabbix_agent_server }}" + ZBX_PASSIVE_ALLOW: "{{ zabbix_agent_serverpassive_allow | default(omit) }}" + ZBX_PASSIVESERVERS: "{{ zabbix_agent_serverpassive | default(omit) }}" + ZBX_ACTIVE_ALLOW: "{{ zabbix_agent_serveractive_allow | default(omit) }}" + ZBX_LOADMODULE: "{{ zabbix_agent_loadmodule | default(omit) }}" + ZBX_DEBUGLEVEL: "{{ zabbix_agent_debuglevel }}" + ZBX_TIMEOUT: "{{ zabbix_agent_timeout }}" + ZBX_SOURCEIP: "{{ zabbix_agent_sourceip | default(omit) }}" + ZBX_ENABLEREMOTECOMMANDS: "{{ zabbix_agent_enableremotecommands | default(omit) }}" + ZBX_LOGREMOTECOMMANDS: "{{ zabbix_agent_logremotecommands | default(omit) }}" + ZBX_STARTAGENTS: "{{ zabbix_agent_startagents | default(omit) }}" + ZBX_HOSTNAMEITEM: "{{ zabbix_agent_hostnameitem | default(omit) }}" + ZBX_METADATA: "{{ zabbix_agent_hostmetadata | default(omit) }}" + ZBX_METADATAITEM: "{{ zabbix_agent_hostmetadataitem | default(omit) }}" + ZBX_REFRESHACTIVECHECKS: "{{ zabbix_agent_refreshactivechecks | default(omit) }}" + ZBX_BUFFERSEND: "{{ zabbix_agent_buffersend | default(omit) }}" + ZBX_BUFFERSIZE: "{{ zabbix_agent_buffersize | default(omit) }}" + ZBX_MAXLINESPERSECOND: "{{ zabbix_agent_maxlinespersecond | default(omit) }}" + ZBX_LISTENIP: "{{ zabbix_agent_listenip }}" + ZBX_UNSAFEUSERPARAMETERS: "{{ zabbix_agent_unsafeuserparameters | default(omit) }}" + ZBX_TLSCONNECT: "{{ zabbix_agent_tlsconnect | default(omit) }}" + ZBX_TLSACCEPT: "{{ zabbix_agent_tlsaccept | default(omit) }}" + ZBX_TLSCAFILE: "{{ zabbix_agent_tlscafile | default(omit) }}" + ZBX_TLSCRLFILE: "{{ zabbix_agent_tlscrlfile | default(omit) }}" + ZBX_TLSSERVERCERTISSUER: "{{ zabbix_agent_tlsservercertissuer | default(omit) }}" + ZBX_TLSSERVERCERTSUBJECT: "{{ zabbix_agent_tlsservercertsubject | default(omit) }}" + ZBX_TLSCERTFILE: "{{ zabbix_agent_tlscertfile | default(omit) }}" + ZBX_TLSKEYFILE: "{{ zabbix_agent_tlskeyfile | default(omit) }}" + ZBX_TLSPSKIDENTITY: "{{ zabbix_agent_tlspskidentity | default(omit) }}" diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/files/sample.conf b/ansible_collections/community/zabbix/roles/zabbix_agent/files/sample.conf new file mode 100644 index 000000000..64087779f --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/files/sample.conf @@ -0,0 +1,3 @@ +# This is an sample userparameters file. + +UserParameter=mysql.ping_to,mysqladmin -uroot ping | grep -c alive diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/files/win_sample/doSomething.ps1 b/ansible_collections/community/zabbix/roles/zabbix_agent/files/win_sample/doSomething.ps1 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/files/win_sample/doSomething.ps1 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml new file mode 100644 index 000000000..cd0f9d932 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml @@ -0,0 +1,40 @@ +--- +# handlers file for zabbix-agent + +- name: restart zabbix-agent + service: + name: "{{ zabbix_agent_service }}" + state: restarted + enabled: true + become: true + when: + - not zabbix_agent_docker + - zabbix_agent_os_family != "Windows" and zabbix_agent_os_family != "Darwin" + +- name: firewalld-reload + command: "firewall-cmd --reload" + become: true + when: + - ansible_facts.services["firewalld"] is defined + - ansible_facts.services["firewalld"].state == "running" + +- name: restart win zabbix agent + win_service: + name: "{{ zabbix_win_svc_name }}" + state: restarted + when: + - zabbix_agent_os_family == "Windows" + +- name: restart mac zabbix agent + command: "launchctl kickstart -k system/{{ zabbix_agent_service }}" + become: true + when: + - not zabbix_agent_docker + - zabbix_agent_os_family == "Darwin" + +- name: "clean repo files from proxy creds" + shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true + become: true + when: + - ansible_os_family == 'RedHat' + - zabbix_http_proxy is defined or zabbix_https_proxy is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/meta/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/meta/main.yml new file mode 100644 index 000000000..c71c861be --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/meta/main.yml @@ -0,0 +1,42 @@ +--- +galaxy_info: + author: Werner Dijkerman + description: Installing and maintaining zabbix-agent for RedHat/Debian/Ubuntu/Windows/Suse. + company: myCompany.Dotcom + license: MIT + min_ansible_version: 2.7 + platforms: + - name: EL + versions: + - 5 + - 6 + - 7 + - name: Ubuntu + versions: + - lucid + - precise + - trusty + - xenial + - bionic + - name: Debian + versions: + - squeeze + - wheezy + - jessie + - stretch + - buster + - name: opensuse + versions: + - 12.1 + - 12.2 + - 12.3 + - 13.1 + - 13.2 + - name: Windows + versions: + - all + + galaxy_tags: + - zabbix + - monitoring +dependencies: [] diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/Dockerfile.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/Dockerfile.j2 new file mode 100644 index 000000000..e6aa95d30 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/INSTALL.rst b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/INSTALL.rst new file mode 100644 index 000000000..071b99565 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/INSTALL.rst @@ -0,0 +1,26 @@ +******************************** +Docker driver installation guide +******************************** + +Requirements +============ + +* General molecule dependencies (see https://molecule.readthedocs.io/en/latest/installation.html) +* Docker Engine +* docker-py +* docker + +Install +======= + +Ansible < 2.6 + +.. code-block:: bash + + $ sudo pip install docker-py + +Ansible >= 2.6 + +.. code-block:: bash + + $ sudo pip install docker diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml new file mode 100644 index 000000000..e7b8e06ae --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml @@ -0,0 +1,81 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint + +platforms: + - name: zabbix-server-centos + image: milcom/centos7-systemd:latest + groups: + - zabbix_server + - mysql + privileged: true + networks: + - name: zabbix + published_ports: + - "80:80" + - name: zabbix-agent-centos + image: milcom/centos7-systemd:latest + groups: + - zabbix_agent + privileged: true + networks: + - name: zabbix + - name: zabbix-agent-debian + image: minimum2scp/systemd-stretch:latest + command: /sbin/init + groups: + - zabbix_agent + privileged: true + networks: + - name: zabbix + - name: zabbix-agent-ubuntu + image: solita/ubuntu-systemd:bionic + groups: + - zabbix_agent + privileged: true + networks: + - name: zabbix + +provisioner: + name: ansible + playbooks: + docker: + create: ../default/create.yml + destroy: ../default/destroy.yml + lint: + name: ansible-lint + inventory: + group_vars: + all: + zabbix_agent_src_reinstall: false + zabbix_api_create_hosts: true + zabbix_api_create_hostgroup: true + zabbix_api_server_url: http://zabbix-server-centos + zabbix_apache_servername: zabbix-server-centos + mysql: + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + database_type: mysql + database_type_long: mysql + host_vars: + zabbix-agent-fedora: + ansible_python_interpreter: /usr/bin/python3 + zabbix-agent-ubuntu: + zabbix_agent_tlsaccept: psk + zabbix_agent_tlsconnect: psk + zabbix_agent_tlspskidentity: "myhost PSK" + zabbix_agent_tlspsk_secret: b7e3d380b9d400676d47198ecf3592ccd4795a59668aa2ade29f0003abbbd40d + zabbix_agent_tlspskfile: /etc/zabbix/zabbix_agent_pskfile.psk + +scenario: + name: with-server + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml new file mode 100644 index 000000000..e1bb7d8d4 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml @@ -0,0 +1,24 @@ +--- +- name: Converge + hosts: all:!zabbix_server + pre_tasks: + - name: "Get IP Server" + shell: grep $(hostname) /etc/hosts | awk '{ print $1 }' | tail -n 1 + register: ip_address + delegate_to: zabbix-server-centos + changed_when: false + tags: + - skip_ansible_lint + + - name: "Get IP hosts" + shell: grep $(hostname) /etc/hosts | awk '{ print $1 }' | tail -n 1 + register: ip_address_host + changed_when: false + tags: + - skip_ansible_lint + + roles: + - role: zabbix_agent + zabbix_agent_ip: "{{ ip_address_host.stdout }}" + zabbix_agent_server: "{{ ip_address.stdout }}" + zabbix_agent_serveractive: "{{ ip_address.stdout }}" diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml new file mode 100644 index 000000000..6722e5fea --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml @@ -0,0 +1,114 @@ +--- +- name: Prepare + hosts: zabbix_server + pre_tasks: + - name: "Installing EPEL" + yum: + name: + - epel-release + state: present + when: ansible_distribution == 'CentOS' + + - name: "Installing packages" + yum: + name: + - net-tools + - which + - libselinux-python + - python-pip + state: present + register: installation_dependencies + when: ansible_distribution == 'CentOS' + + - name: "Installing which on NON-CentOS" + apt: + name: + - net-tools + - python-pip + - curl + state: present + when: ansible_distribution != 'CentOS' + + - name: "Configure SUDO." + lineinfile: + dest: /etc/sudoers + line: "Defaults !requiretty" + state: present + + - name: "Make sure the docs are installed." + lineinfile: + dest: /etc/yum.conf + line: "tsflags=nodocs" + state: absent + + - name: "Installing some python dependencies" + pip: + name: py-zabbix + state: present + + roles: + - role: geerlingguy.mysql + - role: zabbix_server + - role: zabbix_web + +- name: Prepare + hosts: all:!zabbix_server:!docker + tasks: + - name: "Installing packages on CentOS family" + yum: + name: + - net-tools + - which + state: present + when: + - ansible_os_family == 'RedHat' + + - name: "Installing packages on Debian family" + apt: + name: + - net-tools + state: present + when: + - ansible_os_family == 'Debian' + +- name: Converge + hosts: docker + tasks: + - name: "Download Docker CE repo file" + get_url: + url: https://download.docker.com/linux/centos/docker-ce.repo + dest: /etc/yum.repos.d/docker-ce.repo + mode: 0644 + register: zabbix_agent_prepare_docker_repo + until: zabbix_agent_prepare_docker_repo is succeeded + + - name: "Installing Epel" + package: + pkg: + - epel-release + state: present + register: zabbix_agent_prepare_docker_install + until: zabbix_agent_prepare_docker_install is succeeded + + - name: "Installing Docker" + package: + pkg: + - docker-ce + - python-pip + - python-setuptools + state: present + register: zabbix_agent_prepare_docker_install + until: zabbix_agent_prepare_docker_install is succeeded + + - name: "Installing Docker Python" + pip: + name: + - docker + state: present + register: zabbix_agent_prepare_docker_install + until: zabbix_agent_prepare_docker_install is succeeded + + - name: "Starting Docker service" + service: + name: docker + state: started diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/requirements.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/requirements.yml new file mode 100644 index 000000000..da9d004bc --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/requirements.yml @@ -0,0 +1,5 @@ +--- +- src: geerlingguy.apache +- src: geerlingguy.mysql +- src: dj-wasabi.zabbix-server +- src: dj-wasabi.zabbix-web diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/tests/test_agent.py b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/tests/test_agent.py new file mode 100644 index 000000000..5f373ca89 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/tests/test_agent.py @@ -0,0 +1,44 @@ +import os +from zabbix_api import ZabbixAPI + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('zabbix_agent') + + +def authenticate(): + zapi = ZabbixAPI(server='http://zabbix-server-centos/api_jsonrpc.php') + zapi.login("Admin", "zabbix") + return zapi + + +def test_psk_host(host): + zapi = authenticate() + hostname = host.check_output('hostname -s') + host_name = "zabbix-agent-ubuntu" + + server_data = zapi.host.get({'output': 'extend', 'selectInventory': 'extend', 'filter': {'host': [hostname]}}) + + if hostname == host_name: + assert server_data[0]['tls_psk'] == "b7e3d380b9d400676d47198ecf3592ccd4795a59668aa2ade29f0003abbbd40d" + assert server_data[0]['tls_psk_identity'] == "myhost PSK" + assert server_data[0]['tls_accept'] == "2" + else: + assert server_data[0]['tls_psk'] == "" + assert server_data[0]['tls_psk_identity'] == "" + assert server_data[0]['tls_accept'] == "1" + + +def test_zabbix_agent_psk(host): + hostname = host.check_output('hostname -s') + host_name = "zabbix-agent-ubuntu" + + psk_file = host.file("/etc/zabbix/zabbix_agent_pskfile.psk") + if hostname == host_name: + assert psk_file.user == "zabbix" + assert psk_file.group == "zabbix" + assert psk_file.mode == 0o400 + assert psk_file.contains("b7e3d380b9d400676d47198ecf3592ccd4795a59668aa2ade29f0003abbbd40d") + else: + assert not psk_file.exists diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/tests/test_default.py b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/tests/test_default.py new file mode 100644 index 000000000..cbedaa170 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/tests/test_default.py @@ -0,0 +1,41 @@ +import os +from zabbix_api import ZabbixAPI + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('zabbix_server') + + +def authenticate(): + zapi = ZabbixAPI(server='http://zabbix-server-centos/api_jsonrpc.php') + zapi.login("Admin", "zabbix") + return zapi + + +def get_hosts(): + return [ + "zabbix-agent-debian", + "zabbix-agent-ubuntu", + "zabbix-agent-centos", + "zabbix-agent-docker-centos" + ] + + +def test_hosts(): + zapi = authenticate() + hosts = get_hosts() + servers = zapi.host.get({'output': ["hostid", "name"]}) + + for server in servers: + if server['name'] != 'Zabbix server': + assert server['name'] in hosts + + +def test_hosts_status(): + zapi = authenticate() + servers = zapi.host.get({'output': ["status", "name"]}) + + for server in servers: + if server['name'] != 'Zabbix server': + assert int(server['status']) == 0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml new file mode 100644 index 000000000..e98576f61 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml @@ -0,0 +1,177 @@ +--- + +- name: "Set default ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4'].address }}" + when: + - zabbix_agent_ip is not defined + - "'ansible_default_ipv4' in hostvars[inventory_hostname]" + +- name: "Get Total Private IP Addresses" + set_fact: + total_private_ip_addresses: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('private') | length }}" + when: + - ansible_all_ipv4_addresses is defined + +- name: "Set first public ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('public') | first }}" + zabbix_agent_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent_server) }}" + zabbix_agent_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent_serveractive) }}" + zabbix_agent2_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent2_server) }}" + zabbix_agent2_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent2_serveractive) }}" + when: + - zabbix_agent_ip is not defined + - total_private_ip_addresses is defined + - total_private_ip_addresses == '0' + +- name: "Set first private ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('private') | first }}" + when: + - zabbix_agent_ip is not defined + - total_private_ip_addresses is defined + - total_private_ip_addresses != '0' + +- name: "Fail invalid specified agent_listeninterface" + fail: + msg: "The specified network interface does not exist" + when: + - zabbix_agent_listeninterface + - (zabbix_agent_listeninterface not in ansible_all_ipv4_addresses) + tags: + - zabbix-agent + - config + +- name: "Set network interface" + set_fact: + network_interface: ansible_{{ zabbix_agent_listeninterface }} + when: + - zabbix_agent_listeninterface + - not zabbix_agent_listenip + +- name: "Get IP of agent_listeninterface when no agent_listenip specified" + set_fact: + zabbix_agent_listenip: "{{ hostvars[inventory_hostname][network_interface]['ipv4'].address | default('0.0.0.0') }}" + zabbix_agent_ip: "{{ hostvars[inventory_hostname][network_interface]['ipv4'].address | default('0.0.0.0') }}" + when: + - zabbix_agent_listeninterface + - not zabbix_agent_listenip + tags: + - zabbix-agent + - config + - api + +- name: "Default agent_listenip to all when not specified" + set_fact: + zabbix_agent_listenip: '0.0.0.0' + when: + - not zabbix_agent_listenip + tags: + - zabbix-agent + - config + +- name: "Fail invalid specified agent_listenip" + fail: + msg: "The agent_listenip does not exist" + when: + - zabbix_agent_listenip != '0.0.0.0' + - zabbix_agent_listenip != '127.0.0.1' + - (zabbix_agent_listenip not in ansible_all_ipv4_addresses) + tags: + - zabbix-agent + - config + +- name: "Installing Agent" + include_tasks: macOS.yml + tags: + - always + +- name: "Configure zabbix-agent" + template: + src: zabbix_agentd.conf.j2 + dest: "/usr/local/etc/zabbix/{{ zabbix_agent_conf }}" + owner: zabbix + group: wheel + mode: 0644 + notify: + - restart mac zabbix agent + become: true + when: + - not (zabbix_agent_docker | bool) + tags: + - zabbix-agent + - config + - init + +- name: "Create directory for PSK file if not exist." + file: + path: "{{ zabbix_agent_tlspskfile | dirname }}" + mode: 0755 + state: directory + become: true + when: + - zabbix_agent_tlspskfile is defined + +- name: "Place TLS PSK File" + copy: + dest: "{{ zabbix_agent_tlspskfile }}" + content: "{{ zabbix_agent_tlspsk_secret }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspsk_secret is defined + notify: + - restart mac zabbix agent + +- name: "Create include dir zabbix-agent" + file: + path: "{{ zabbix_agent_include }}" + owner: zabbix + group: zabbix + mode: 0750 + state: directory + become: true + tags: + - config + - include + +- name: "Create pid file directory for zabbix-agent" + file: + path: /var/run/zabbix + state: directory + owner: zabbix + group: zabbix + mode: 0755 + become: true + +- name: "Install the Docker container" + include_tasks: Docker.yml + when: + - zabbix_agent_docker | bool + +- name: "Check if zabbix-agent service is running" + shell: | + set -o pipefail + launchctl list | grep com.zabbix.zabbix_agentd | awk '{print $1}' + register: launchctl_pid + check_mode: false + changed_when: false + failed_when: launchctl_pid.rc == 2 + become: true + tags: + - init + - service + +- name: "Make sure the zabbix-agent service is running" + command: launchctl start com.zabbix.zabbix_agentd + become: true + when: + - not (zabbix_agent_docker | bool) + - launchctl_pid.stdout == "-" + tags: + - init + - service diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml new file mode 100644 index 000000000..ec4a01879 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml @@ -0,0 +1,259 @@ +--- +# Tasks specific for Debian/Ubuntu Systems + +- name: "Include Zabbix gpg ids" + include_vars: zabbix.yml + +- name: "Set short version name" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}" + +- name: "Debian | Installing gnupg" + apt: + pkg: gnupg + update_cache: true + cache_valid_time: 3600 + force: true + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: gnupg_installed + until: gnupg_installed is succeeded + become: true + +- name: "Debian | Install gpg key" + apt_key: + id: "{{ sign_keys[zabbix_short_version][zabbix_agent_distribution_release]['sign_key'] }}" + url: http://repo.zabbix.com/zabbix-official-repo.key + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Check for zabbix repositories" + find: + paths: /etc/apt/sources.list.d + patterns: repo_zabbix_com_zabbix*.list + excludes: "repo_zabbix_com_zabbix_{{ zabbix_underscore_version }}_ubuntu.list" + register: repositories + become: true + when: + - ansible_distribution in ['Ubuntu', 'Debian'] + - zabbix_repo == "zabbix" + tags: + - zabbix-agent + - init + +- name: "Debian | Remove unecessary zabbix repositories" + file: + path: "{{ item.path }}" + state: absent + loop: "{{ repositories.files }}" + when: + - ansible_distribution in ['Ubuntu', 'Debian'] + - zabbix_repo == "zabbix" + - zabbix_agent_src_reinstall + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing deb-src repository Debian" + apt_repository: + repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_version }}/debian/ {{ zabbix_agent_distribution_release }} main" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution == "Debian" + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing deb repository Debian" + apt_repository: + repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/debian/ {{ zabbix_agent_distribution_release }} main" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution == "Debian" + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing deb-src repository Ubuntu Arm64" + apt_repository: + repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu-arm64/ {{ zabbix_agent_distribution_release }} main" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution == "Ubuntu" + - ansible_machine == "aarch64" + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing deb repository Ubuntu Arm64" + apt_repository: + repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu-arm64/ {{ zabbix_agent_distribution_release }} main" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution == "Ubuntu" + - ansible_machine == "aarch64" + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing deb-src repository Ubuntu" + apt_repository: + repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu/ {{ zabbix_agent_distribution_release }} main" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution == "Ubuntu" + - ansible_machine != "aarch64" + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing deb repository Ubuntu" + apt_repository: + repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu/ {{ zabbix_agent_distribution_release }} main" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution == "Ubuntu" + - ansible_machine != "aarch64" + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Create /etc/apt/preferences.d/" + file: + path: /etc/apt/preferences.d/ + state: directory + mode: '0755' + when: + - zabbix_agent_apt_priority | int + become: true + +- name: "Debian | Configuring the weight for APT" + copy: + dest: "/etc/apt/preferences.d/zabbix-agent-{{ zabbix_underscore_version }}" + content: | + Package: {{ zabbix_agent_package }} + Pin: origin repo.zabbix.com + Pin-Priority: {{ zabbix_agent_apt_priority | int }} + owner: root + mode: '0644' + when: + - zabbix_agent_apt_priority | int + become: true + +# Note: set cache_valid_time=0 to ensure that an apt-get update after the added repo-key +# else you often get 'WARNING: The following packages cannot be authenticated! +# See also: +# http://askubuntu.com/questions/75565/why-am-i-getting-authentication-errors-for-packages-from-an-ubuntu-repository +- name: "Debian | Installing zabbix-agent" + apt: + pkg: "{{ zabbix_agent_package }}" + state: "{{ zabbix_agent_package_state }}" + update_cache: true + cache_valid_time: 0 + force_apt_get: "{{ zabbix_apt_force_apt_get }}" + install_recommends: "{{ zabbix_apt_install_recommends }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: ansible_distribution in ['Ubuntu', 'Debian'] + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Installing zabbix-{sender,get}" + apt: + pkg: + - "{{ zabbix_sender_package }}" + - "{{ zabbix_get_package }}" + state: "{{ zabbix_agent_package_state }}" + update_cache: true + cache_valid_time: 0 + force_apt_get: "{{ zabbix_apt_force_apt_get }}" + install_recommends: "{{ zabbix_apt_install_recommends }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - ansible_distribution in ['Ubuntu', 'Debian'] + - not zabbix_agent_install_agent_only + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + become: true + check_mode: false + tags: + - zabbix-agent + - init + +- name: "Mint | Installing zabbix-agent" + apt: + pkg: "zabbix-agent" + state: "{{ zabbix_agent_package_state }}" + update_cache: true + cache_valid_time: 0 + force_apt_get: "{{ zabbix_apt_force_apt_get }}" + install_recommends: "{{ zabbix_apt_install_recommends }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: ansible_distribution not in ['Ubuntu', 'Debian'] + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + become: true + tags: + - zabbix-agent + - init + +- name: "Debian | Enable the service" + service: + name: "{{ zabbix_agent_service }}" + enabled: true + use: service + become: true + tags: + - zabbix-agent + - init + - service diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml new file mode 100644 index 000000000..cbbef204d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml @@ -0,0 +1,33 @@ +--- + +- name: "Create volume mount string" + set_fact: + volume_mount: "{{ zabbix_agent_tlspskfile }}:/var/lib/zabbix/enc/tlspskfile" + tls_key: + ZBX_TLSPSKFILE: tlspskfile + when: + - zabbix_agent_tlspskfile is defined + +- name: "Add zabbix_agent_tlspskfile to volume mount" + set_fact: + zabbix_agent_docker_volumes: "{{ zabbix_agent_docker_volumes + [ volume_mount ] }}" + zabbix_agent_docker_env: "{{ zabbix_agent_docker_env | combine(tls_key) }}" + when: + - zabbix_agent_tlspskfile is defined + +- name: "Ensure Zabbix Docker container is running" + community.docker.docker_container: + name: "{{ zabbix_agent_docker_name }}" + image: "{{ zabbix_agent_docker_image }}:{{ zabbix_agent_docker_image_tag }}" + state: "{{ zabbix_agent_docker_state }}" + restart_policy: "{{ zabbix_agent_docker_restart_policy }}" + network_mode: "{{ zabbix_agent_docker_network_mode }}" + published_ports: "{{ zabbix_agent_docker_ports }}" + privileged: "{{ zabbix_agent_docker_privileged }}" + security_opts: "{{ zabbix_agent_docker_security_opts }}" + volumes: "{{ zabbix_agent_docker_volumes }}" + env: "{{ zabbix_agent_docker_env }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml new file mode 100644 index 000000000..d2c0ba82c --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml @@ -0,0 +1,228 @@ +--- + +- name: "Set default ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4'].address }}" + when: + - zabbix_agent_ip is not defined + - "'ansible_default_ipv4' in hostvars[inventory_hostname]" + +- name: "Get Total Private IP Addresses" + set_fact: + total_private_ip_addresses: "{{ ansible_all_ipv4_addresses | ansible.utils.ipaddr('private') | length }}" + when: + - ansible_all_ipv4_addresses is defined + - not (zabbix_agent_dont_detect_ip) + +- name: "Set first public ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('public') | first }}" + zabbix_agent_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent_server) }}" + zabbix_agent_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent_serveractive) }}" + zabbix_agent2_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent2_server) }}" + zabbix_agent2_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent2_serveractive) }}" + when: + - zabbix_agent_ip is not defined + - total_private_ip_addresses is defined + - total_private_ip_addresses == '0' + +- name: "Set first private ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('private') | first }}" + when: + - zabbix_agent_ip is not defined + - total_private_ip_addresses is defined + - total_private_ip_addresses != '0' + +- name: "Fail invalid specified agent_listeninterface" + fail: + msg: "The specified network interface does not exist" + when: + - (zabbix_agent_listeninterface) + - (zabbix_agent_listeninterface not in ansible_interfaces) + tags: + - zabbix-agent + - config + +- name: "Set network interface" + set_fact: + network_interface: ansible_{{ zabbix_agent_listeninterface }} + when: + - (zabbix_agent_listeninterface) + - not zabbix_agent_listenip + +- name: "Get IP of agent_listeninterface when no agent_listenip specified" + set_fact: + zabbix_agent_listenip: "{{ hostvars[inventory_hostname][network_interface]['ipv4'].address | default('0.0.0.0') }}" + when: + - (zabbix_agent_listeninterface) + - not zabbix_agent_listenip + tags: + - zabbix-agent + - config + - api + +- name: "Default agent_listenip to all when not specified" + set_fact: + zabbix_agent_listenip: '0.0.0.0' + when: + - not (zabbix_agent_listenip) + tags: + - zabbix-agent + - config + +- name: "Fail invalid specified agent_listenip" + fail: + msg: "The agent_listenip does not exist" + when: + - zabbix_agent_listenip != '0.0.0.0' + - zabbix_agent_listenip != '127.0.0.1' + - (zabbix_agent_listenip not in ansible_all_ipv4_addresses) + tags: + - zabbix-agent + - config + +- name: "Configure SELinux when enabled" + include_tasks: selinux.yml + when: + - zabbix_selinux | bool + +- name: "Adding zabbix group" + group: + name: zabbix + state: present + gid: "{{ zabbix_agent_docker_user_gid | default(omit) }}" + become: true + when: + - zabbix_agent_docker | bool + +- name: "Adding zabbix user" + user: + name: zabbix + group: zabbix + state: present + create_home: false + home: /etc/zabbix + uid: "{{ zabbix_agent_docker_user_uid | default(omit) }}" + system: true + become: true + when: + - zabbix_agent_docker | bool + +- name: "Configure zabbix-agent" + template: + src: "{{ 'zabbix_agentd.conf.j2' if not zabbix_agent2 else 'zabbix_agent2.conf.j2' }}" + dest: "/etc/zabbix/{{ zabbix_agent_conf if not zabbix_agent2 else zabbix_agent2_conf }}" + owner: root + group: root + mode: "{{ zabbix_agent_conf_mode }}" + notify: + - restart zabbix-agent + become: true + when: + - not (zabbix_agent_docker | bool) + tags: + - zabbix-agent + - config + - init + +- name: "Create directory for PSK file if not exist." + file: + path: "{{ zabbix_agent_tlspskfile | dirname }}" + mode: 0755 + state: directory + become: true + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680 + - not (zabbix_agent2 | bool) + +- name: "Create directory for PSK file if not exist (zabbix-agent2)" + file: + path: "{{ zabbix_agent2_tlspskfile | dirname }}" + mode: 0755 + state: directory + become: true + when: + - zabbix_agent2_tlspskfile is defined + - zabbix_agent2_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680 + - zabbix_agent2 | bool + +- name: "Place TLS PSK File" + copy: + dest: "{{ zabbix_agent_tlspskfile }}" + content: "{{ zabbix_agent_tlspsk_secret }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680 + - zabbix_agent_tlspsk_secret is defined + - not (zabbix_agent2 | bool) + notify: + - restart zabbix-agent + +- name: "Place TLS PSK File (zabbix-agent2)" + copy: + dest: "{{ zabbix_agent2_tlspskfile }}" + content: "{{ zabbix_agent2_tlspsk_secret }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent2_tlspskfile is defined + - zabbix_agent2_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680 + - zabbix_agent2_tlspsk_secret is defined + - zabbix_agent2 | bool + notify: + - restart zabbix-agent + +- name: "Create include dir zabbix-agent" + file: + path: "{{ zabbix_agent_include if not zabbix_agent2 else zabbix_agent2_include }}" + owner: root + group: zabbix + mode: "{{ zabbix_agent_include_mode if not zabbix_agent2 else zabbix_agent2_include_mode }}" + state: directory + become: true + tags: + - config + - include + +- name: "Install the Docker container" + include_tasks: Docker.yml + when: + - zabbix_agent_docker | bool + +- name: "Configure the firewall(d|iptables)" + include_tasks: firewall.yml + when: + - (zabbix_agent_firewall_enable | bool) or (zabbix_agent_firewalld_enable | bool) + +- name: "Remove zabbix-agent installation when zabbix-agent2 is used." + include_tasks: remove.yml + when: + - zabbix_agent2 | bool + - zabbix_agent_package_remove + +- name: "Make sure the zabbix-agent service is running" + service: + name: "{{ zabbix_agent_service }}" + state: started + enabled: true + become: true + when: + - not (zabbix_agent_docker | bool) + tags: + - init + - service + +- name: "Give zabbix-agent access to system.hw.chassis info" + file: + path: /sys/firmware/dmi/tables/DMI + owner: root + group: zabbix + when: zabbix_agent_chassis | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml new file mode 100644 index 000000000..ef8cfaf09 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml @@ -0,0 +1,170 @@ +--- +# Tasks specific for RedHat systems + +- name: "RedHat | Use EPEL package name" + set_fact: + zabbix_agent_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-agent" + zabbix_sender_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-sender" + zabbix_get_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-get" + when: + - zabbix_repo == "epel" + tags: + - zabbix-agent + - init + +- name: "RedHat | Set zabbix_agent_distribution_major_version to 6 when Amazon" + set_fact: + zabbix_agent_distribution_major_version: 6 + when: + - ansible_distribution == "Amazon" + - ansible_distribution_major_version == "NA" + +- name: "RedHat | Set zabbix_agent_distribution_major_version to 6 when Major Version is 2018.03" + set_fact: + zabbix_agent_distribution_major_version: 6 + when: + - ansible_distribution == "Amazon" + - ansible_distribution_major_version == "2018" + +- name: "RedHat | Set zabbix_agent_distribution_major_version to 7 when Amazon 2" + set_fact: + zabbix_agent_distribution_major_version: 7 + when: + - ansible_distribution == "Amazon" + - ansible_distribution_major_version == "2" + +- name: "Fedora | Override zabbix_agent_distribution_major_version for Fedora <= 27" + set_fact: + zabbix_agent_distribution_major_version: 7 + when: + - ansible_distribution == "Fedora" + - ansible_distribution_major_version <= "27" + +- name: "Fedora | Override zabbix_agent_distribution_major_version for Fedora >= 27" + set_fact: + zabbix_agent_distribution_major_version: 8 + when: + - ansible_distribution == "Fedora" + - ansible_distribution_major_version >= "27" + +- name: "XCP-ng | Override zabbix_agent_distribution_major_version for XCP-ng" + set_fact: + zabbix_agent_distribution_major_version: 7 + when: + - ansible_distribution == "XCP-ng" + +- name: "RedHat | Install basic repo file" + yum_repository: + name: "{{ item.name }}" + description: "{{ item.description }}" + baseurl: "{{ item.baseurl }}" + gpgcheck: "{{ item.gpgcheck }}" + gpgkey: "{{ item.gpgkey }}" + mode: "{{ item.mode | default('0644') }}" + priority: "{{ item.priority | default('98') }}" + state: "{{ item.state | default('present') }}" + proxy: "{{ zabbix_http_proxy | default(omit) }}" + with_items: "{{ zabbix_repo_yum }}" + register: yum_repo_installed + become: true + when: + zabbix_repo == "zabbix" + notify: + - "clean repo files from proxy creds" + tags: + - zabbix-agent + +- name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + +- name: "Do a yum clean" + shell: yum clean all + args: + warn: "{{ produce_warn | default(omit) }}" + when: yum_repo_installed.changed + become: true + tags: + - skip_ansible_lint + +- name: "RedHat | Installing zabbix-agent" + package: + pkg: + - "{{ zabbix_agent_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + state: "{{ zabbix_agent_package_state }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + when: + zabbix_repo != "other" + become: true + tags: + - init + - zabbix-agent + +- name: "RedHat | Installing zabbix-agent (When zabbix_repo == other)" + package: + pkg: + - "{{ zabbix_agent_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}" + state: "{{ zabbix_agent_package_state }}" + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + when: + zabbix_repo == "other" + become: true + tags: + - init + - zabbix-agent + +- name: "RedHat | Installing zabbix-{sender,get}" + package: + pkg: + - "{{ zabbix_sender_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}" + - "{{ zabbix_get_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + state: "{{ zabbix_agent_package_state }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + when: + - zabbix_repo not in ['epel', 'other'] + - not zabbix_agent_install_agent_only + become: true + tags: + - init + - zabbix-agent + +- name: "RedHat | Installing zabbix-{sender,get} (When zabbix_repo == other)" + package: + pkg: + - "{{ zabbix_sender_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}" + - "{{ zabbix_get_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}" + state: "{{ zabbix_agent_package_state }}" + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + when: + - zabbix_repo == "other" + - not zabbix_agent_install_agent_only + become: true + tags: + - init + - zabbix-agent + +- name: "RedHat | Enable the service" + service: + name: "{{ zabbix_agent_service }}" + enabled: true + use: service + become: true + tags: + - zabbix-agent + - init + - service diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml new file mode 100644 index 000000000..82dc3ce7d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml @@ -0,0 +1,55 @@ +--- +# Tasks specific for OpenSuse Systems + +- name: "Include Zabbix gpg ids" + include_vars: zabbix.yml + +- name: "Install zypper repo dependency" + community.general.zypper: + name: + - python-xml + - "{{ suse[ansible_distribution][zabbix_agent_distribution_major_version]['python_libxml2_package'] }}" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true + register: zabbix_agent_package_dependency + until: zabbix_agent_package_dependency is succeeded + +- name: "Suse | Install basic repo file" + community.general.zypper_repository: + repo: "{{ suse[ansible_distribution][zabbix_agent_distribution_major_version]['url'] }}" + name: "{{ suse[ansible_distribution][zabbix_agent_distribution_major_version]['name'] }}" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + when: + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-agent + - init + +- name: "Only install the Zabbix Agent" + set_fact: + zabbix_agent_packages: + - "{{ zabbix_agent_package }}" + when: + - zabbix_agent_install_agent_only + +- name: "Suse | Install zabbix-agent" + community.general.zypper: + name: "{{ zabbix_agent_packages }}" + state: "{{ zabbix_agent_package_state }}" + disable_gpg_check: true + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_agent_package_installed + until: zabbix_agent_package_installed is succeeded + become: true + tags: + - zabbix-agent + - init diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml new file mode 100644 index 000000000..61e12361e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml @@ -0,0 +1,306 @@ +--- +- name: "Windows | Set default architecture" + set_fact: + windows_arch: 32 + +- name: "Windows | Override architecture if 64-bit" + set_fact: + windows_arch: 64 + when: + - ansible_architecture == "64-bit" + +- name: "Windows | Set path to zabbix.exe" + set_fact: + zabbix_win_exe_path: '{{ zabbix_win_install_dir }}\bin\win{{ windows_arch }}\zabbix_agentd.exe' + +- name: "Windows | Set variables specific to Zabbix >= 4" + set_fact: + zabbix_win_svc_name: Zabbix Agent + zabbix_win_exe_path: '{{ zabbix_win_install_dir }}\bin\zabbix_agentd.exe' + zabbix_win_config_name: 'zabbix_agentd.conf' + zabbix2_win_svc_name: Zabbix Agent 2 + zabbix2_win_exe_path: '{{ zabbix_win_install_dir }}\bin\zabbix_agent2.exe' + zabbix2_win_config_name: 'zabbix_agent2.conf' + when: + - zabbix_version_long is version('4.0.0', '>=') + +- name: "Windows | Check if Zabbix agent is present" + ansible.windows.win_stat: + path: '{{ item }}' + with_items: + - "{{ zabbix_win_exe_path }}" + - "{{ zabbix2_win_exe_path }}" + register: agent_file_info + +- name: "Windows | Get Installed Zabbix Agent Version" + community.windows.win_file_version: + path: "{{ item.item }}" + register: zabbix_win_exe_info + when: + - item.stat.exists | bool + with_items: "{{ agent_file_info.results }}" + +- name: "Windows | Set facts current zabbix agent installation" + set_fact: + zabbix_agent_1_binary_exist: true + zabbix_agent_1_version: zabbix_win_exe_info.results[0].win_file_version.product_version + when: + - zabbix_win_exe_info.results[0] is defined + - zabbix_win_exe_info.results[0].item.stat.exists + - zabbix_win_exe_info.results[0].item.stat.path == zabbix_win_exe_path + - zabbix_win_exe_info.results[0].win_file_version.product_version + +- name: "Windows | Set facts current zabbix agent installation (agent 2)" + set_fact: + zabbix_agent_2_binary_exist: true + zabbix_agent_2_version: zabbix_win_exe_info.results[1].win_file_version.product_version + when: + - zabbix_win_exe_info.results[1] is defined + - zabbix_win_exe_info.results[1].item.stat.exists + - zabbix_win_exe_info.results[1].item.stat.path == zabbix2_win_exe_path + - zabbix_win_exe_info.results[1].win_file_version.product_version + +- name: "Windows | Check Zabbix service" + ansible.windows.win_service: + name: "{{ (item.item.stat.path == zabbix_win_exe_path ) | ternary(zabbix_win_svc_name,zabbix2_win_svc_name) }}" + register: zabbix_service_info + when: item.item.stat.exists + with_items: "{{ zabbix_win_exe_info.results }}" + +- name: "Windows | Set facts about current zabbix agent service state" + set_fact: + zabbix_agent_1_service_exist: true + when: + - zabbix_service_info.results[0].exists is defined + - zabbix_service_info.results[0].exists + - zabbix_service_info.results[0].display_name == zabbix_win_svc_name + +- name: "Windows | Set facts about current zabbix agent service state (agent 2)" + set_fact: + zabbix_agent_2_service_exist: true + when: + - zabbix_service_info.results[1].exists is defined + - zabbix_service_info.results[1].exists + - zabbix_service_info.results[1].display_name == zabbix2_win_svc_name + +- name: "Windows | Set fact about version change requirement" + set_fact: + zabbix_agent_version_change: true + when: > + (zabbix_agent_1_binary_exist | default(false) and + zabbix_win_exe_info.results[0].win_file_version.product_version is version(zabbix_version_long, '<>')) + or + (zabbix_agent_2_binary_exist | default(false) and + zabbix_win_exe_info.results[1].win_file_version.product_version is version(zabbix_version_long, '<>')) + or (zabbix_agent_1_binary_exist | default(false) and zabbix_agent2) + or (zabbix_agent_2_binary_exist | default(false) and not zabbix_agent2) + +################## +# delete section # +################## + +- name: "Windows | Stop Zabbix agent v1" + ansible.windows.win_service: + name: "{{ zabbix_win_svc_name }}" + start_mode: auto + state: stopped + when: + - zabbix_agent_version_change | default(false) or zabbix_agent2 + - zabbix_agent_1_service_exist | default(false) + +- name: "Windows | Stop Zabbix agent v2" + ansible.windows.win_service: + name: "{{ zabbix2_win_svc_name }}" + start_mode: auto + state: stopped + when: + - zabbix_agent_version_change | default(false) or not zabbix_agent2 + - zabbix_agent_2_service_exist | default(false) + +- name: "Windows | Uninstall Zabbix v1" + ansible.windows.win_command: '"{{ zabbix_win_exe_path }}" --config "{{ zabbix_win_install_dir_conf }}\{{ zabbix_win_config_name }}" --uninstall' + when: + - zabbix_agent_version_change | default(false) or zabbix_agent2 + - zabbix_agent_1_service_exist | default(false) + +- name: "Windows | Uninstall Zabbix v2" + ansible.windows.win_command: '"{{ zabbix2_win_exe_path }}" --config "{{ zabbix_win_install_dir_conf }}\{{ zabbix2_win_config_name }}" --uninstall' + when: + - zabbix_agent_version_change | default(false) or not zabbix_agent2 + - zabbix_agent_2_service_exist | default(false) + +- name: "Windows | Removing Zabbix Directory" + ansible.windows.win_file: + path: '{{ zabbix_win_install_dir }}' + state: absent + when: ((zabbix_agent_version_change | default(false) or zabbix_agent2) and zabbix_agent_1_binary_exist | default(false)) or + ((zabbix_agent_version_change | default(false) or not zabbix_agent2) and zabbix_agent_2_binary_exist | default(false)) + +################### +# install section # +################### + +- name: "Windows | Create directory structure" + ansible.windows.win_file: + path: "{{ item }}" + state: directory + with_items: + - "{{ zabbix_win_install_dir }}" + +- name: "Windows | Create directory structure, includes" + ansible.windows.win_file: + path: "{{ item }}" + state: directory + with_items: + - "{{ zabbix_agent_win_include }}" + when: + - ('.conf' not in zabbix_agent_win_include) + +- name: "Windows | Set installation settings (agent 2)" + set_fact: + zabbix_win_package: "{{ zabbix2_win_package }}" + zabbix_win_download_link: "{{ zabbix2_win_download_link }}" + zabbix_win_exe_path: "{{ zabbix2_win_exe_path }}" + zabbix_win_config_name: "{{ zabbix2_win_config_name }}" + zabbix_win_svc_name: "{{ zabbix2_win_svc_name }}" + when: zabbix_agent2 | bool + +- name: "Windows | Check if agent file is already downloaded" + ansible.windows.win_stat: + path: '{{ zabbix_win_install_dir }}\{{ zabbix_win_package }}' + register: file_info + +- name: "Windows | Check if agent binaries in place" + ansible.windows.win_stat: + path: "{{ zabbix_win_exe_path }}" + register: zabbix_windows_binaries + +- name: "Windows | Download Zabbix Agent Zip file" + ansible.windows.win_get_url: + url: "{{ zabbix_win_download_link }}" + dest: '{{ zabbix_win_install_dir }}\{{ zabbix_win_package }}' + url_username: "{{ zabbix_download_user | default(omit) }}" + url_password: "{{ zabbix_download_pass | default(omit) }}" + force: false + follow_redirects: all + proxy_url: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + validate_certs: "{{ zabbix_download_validate_certs | default(False) | bool }}" + timeout: "{{ zabbix_download_timeout | default(120) | int }}" + when: + - not file_info.stat.exists + - not zabbix_windows_binaries.stat.exists + register: zabbix_agent_win_download_zip + until: zabbix_agent_win_download_zip is succeeded + throttle: "{{ zabbix_download_throttle | default(5) | int }}" + +- name: "Windows | Unzip file" + community.windows.win_unzip: + src: '{{ zabbix_win_install_dir }}\{{ zabbix_win_package }}' + dest: "{{ zabbix_win_install_dir }}" + creates: "{{ zabbix_win_exe_path }}" + +- name: "Windows | Cleanup downloaded Zabbix Agent Zip file" + ansible.windows.win_file: + path: '{{ zabbix_win_install_dir }}\{{ zabbix_win_package }}' + state: absent + when: + - zabbix_agent_win_download_zip.changed + +- name: "Windows | Copy binary files to expected location" + ansible.windows.win_copy: + src: "{{ zabbix_win_install_dir }}\\bin\\{{ item }}" + dest: "{{ zabbix_win_install_dir_bin }}\\{{ item }}" + remote_src: yes + loop: + - zabbix_agentd.exe + - zabbix_sender.exe + when: + - zabbix_win_install_dir_bin is defined + - not (zabbix_agent2 | bool) + +- name: "Windows | Copy binary files to expected location (zabbix-agent2)" + ansible.windows.win_copy: + src: "{{ zabbix_win_install_dir }}\\bin\\{{ item }}" + dest: "{{ zabbix_win_install_dir_bin }}\\{{ item }}" + remote_src: yes + loop: + - zabbix_agent2.exe + when: + - zabbix_win_install_dir_bin is defined + - zabbix_agent2 | bool + +- set_fact: + zabbix_win_exe_path: "{{ zabbix_win_install_dir_bin }}\\zabbix_agentd.exe" + when: + - zabbix_win_install_dir_bin is defined + - not (zabbix_agent2 | bool) + +- set_fact: + zabbix_win_exe_path: "{{ zabbix_win_install_dir_bin }}\\zabbix_agent2.exe" + when: + - zabbix_win_install_dir_bin is defined + - zabbix_agent2 | bool + +- name: "Create directory for PSK file if not exist." + win_file: + path: "{{ zabbix_agent_tlspskfile | win_dirname }}" + state: directory + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspskfile + - not (zabbix_agent2 | bool) + +- name: "Create directory for PSK file if not exist (zabbix-agent2)" + win_file: + path: "{{ zabbix_agent2_tlspskfile | win_dirname }}" + state: directory + when: + - zabbix_agent2_tlspskfile is defined + - zabbix_agent2_tlspskfile + - zabbix_agent2 | bool + +- name: "Place TLS PSK File" + win_copy: + dest: "{{ zabbix_agent_tlspskfile }}" + content: "{{ zabbix_agent_tlspsk_secret }}" + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspskfile + - zabbix_agent_tlspsk_secret is defined + - not (zabbix_agent2 | bool) + notify: + - restart win zabbix agent + +- name: "Place TLS PSK File (zabbix-agent2)" + win_copy: + dest: "{{ zabbix_agent2_tlspskfile }}" + content: "{{ zabbix_agent2_tlspsk_secret }}" + when: + - zabbix_agent2_tlspskfile is defined + - zabbix_agent2_tlspskfile + - zabbix_agent2_tlspsk_secret is defined + - zabbix_agent2 | bool + notify: + - restart win zabbix agent + +- name: "Windows | Check if windows service exist" + ansible.windows.win_service: + name: "{{ zabbix_win_svc_name }}" + register: zabbix_windows_service + +- name: "Windows | Register Service" + ansible.windows.win_command: '"{{ zabbix_win_exe_path }}" --config "{{ zabbix_win_install_dir_conf }}\{{ zabbix_win_config_name }}" --install' + when: not zabbix_windows_service.exists + +- name: "Windows | Set service startup mode to auto, ensure it is started and set auto-recovery" + ansible.windows.win_service: + name: "{{ zabbix_win_svc_name }}" + start_mode: auto + failure_actions: + - type: restart + delay_ms: 5000 + - type: restart + delay_ms: 10000 + - type: restart + delay_ms: 20000 + failure_reset_period_sec: 86400 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml new file mode 100644 index 000000000..f6c5c331e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml @@ -0,0 +1,47 @@ +--- + +- name: "Set default ip address for zabbix_agent_ip" + set_fact: + zabbix_agent_ip: "{{ hostvars[inventory_hostname]['ansible_ip_addresses'] | ansible.utils.ipv4 | first }}" + when: + - zabbix_agent_ip is not defined + - "'ansible_ip_addresses' in hostvars[inventory_hostname]" + +- name: "Windows | Configure zabbix-agent" + ansible.windows.win_template: + src: "{{ zabbix_win_config_name }}.j2" + dest: "{{ zabbix_win_install_dir_conf }}\\{{ zabbix_win_config_name }}" + notify: restart win zabbix agent + +- name: "Windows | Set service startup mode to auto, ensure it is started and set auto-recovery" + ansible.windows.win_service: + name: "{{ zabbix_win_svc_name }}" + start_mode: auto + state: started + failure_actions: + - type: restart + delay_ms: 5000 + - type: restart + delay_ms: 10000 + - type: restart + delay_ms: 20000 + failure_reset_period_sec: 86400 + +- name: "Windows | Check firewall service" + ansible.windows.win_service_info: + name: MpsSvc + register: firewall_info + when: zabbix_win_firewall_management + +- name: "Windows | Firewall rule" + community.windows.win_firewall_rule: + name: "{{ zabbix_win_svc_name }}" + localport: "{{ zabbix_agent_listenport }}" + action: allow + direction: in + protocol: tcp + state: present + enabled: true + when: + - zabbix_win_firewall_management + - firewall_info.services[0].state == 'started' or firewall_info.services[0].start_mode == 'auto' diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml new file mode 100644 index 000000000..13f734edc --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml @@ -0,0 +1,108 @@ +--- +- name: "API | Create host groups" + community.zabbix.zabbix_group: + host_group: "{{ zabbix_host_groups }}" + state: "{{ zabbix_agent_hostgroups_state }}" + validate_certs: "{{ zabbix_api_validate_certs|default(omit) }}" + timeout: "{{ zabbix_api_timeout }}" + when: + - zabbix_api_create_hostgroup | bool + register: zabbix_api_hostgroup_created + until: zabbix_api_hostgroup_created is succeeded + delegate_to: "{{ zabbix_api_server_host }}" + become: false + tags: + - api + +- name: "API | Create a new host or update an existing host's info" + community.zabbix.zabbix_host: + host_name: "{{ zabbix_agent_hostname }}" + host_groups: "{{ zabbix_host_groups }}" + link_templates: "{{ zabbix_agent_link_templates }}" + status: "{{ zabbix_host_status }}" + state: "{{ zabbix_agent_host_state }}" + force: "{{ zabbix_agent_host_update }}" + proxy: "{{ zabbix_agent_proxy }}" + inventory_mode: "{{ zabbix_agent_inventory_mode }}" + interfaces: "{{ zabbix_agent_interfaces }}" + visible_name: "{{ zabbix_agent_visible_hostname | default(zabbix_agent_hostname) }}" + tls_psk: "{{ zabbix_agent_tlspsk_secret | default(omit) }}" + tls_psk_identity: "{{ zabbix_agent_tlspskidentity | default(omit) }}" + tls_issuer: "{{ zabbix_agent_tlsservercertissuer | default(omit) }}" + tls_subject: "{{ zabbix_agent_tls_subject | default(omit) }}" + tls_accept: "{{ zabbix_agent_tls_config[zabbix_agent_tlsaccept if zabbix_agent_tlsaccept else 'unencrypted'] }}" + tls_connect: "{{ zabbix_agent_tls_config[zabbix_agent_tlsconnect if zabbix_agent_tlsconnect else 'unencrypted'] }}" + validate_certs: "{{ zabbix_api_validate_certs | default(omit) }}" + timeout: "{{ zabbix_api_timeout }}" + description: "{{ zabbix_agent_description | default(omit) }}" + inventory_zabbix: "{{ zabbix_agent_inventory_zabbix | default({}) }}" + ipmi_authtype: "{{ zabbix_agent_ipmi_authtype | default(omit) }}" + ipmi_password: "{{ zabbix_agent_ipmi_password| default(omit) }}" + ipmi_privilege: "{{ zabbix_agent_ipmi_privilege | default(omit) }}" + ipmi_username: "{{ zabbix_agent_ipmi_username | default(omit) }}" + tags: "{{ zabbix_agent_tags }}" + when: + - not zabbix_agent2 + register: zabbix_api_host_created + until: zabbix_api_host_created is succeeded + delegate_to: "{{ zabbix_api_server_host }}" + become: false + changed_when: false + tags: + - api + +- name: "API | Create a new host using agent2 or update an existing host's info" + community.zabbix.zabbix_host: + host_name: "{{ zabbix_agent2_hostname }}" + host_groups: "{{ zabbix_host_groups }}" + link_templates: "{{ zabbix_agent_link_templates }}" + status: "{{ zabbix_host_status }}" + state: "{{ zabbix_agent_host_state }}" + force: "{{ zabbix_agent_host_update }}" + proxy: "{{ zabbix_agent_proxy }}" + inventory_mode: "{{ zabbix_agent_inventory_mode }}" + interfaces: "{{ zabbix_agent_interfaces }}" + visible_name: "{{ zabbix_agent_visible_hostname | default(zabbix_agent2_hostname) }}" + tls_psk: "{{ zabbix_agent2_tlspsk_secret | default(omit) }}" + tls_psk_identity: "{{ zabbix_agent2_tlspskidentity | default(omit) }}" + tls_issuer: "{{ zabbix_agent2_tlsservercertissuer | default(omit) }}" + tls_subject: "{{ zabbix_agent2_tls_subject | default(omit) }}" + tls_accept: "{{ zabbix_agent_tls_config[zabbix_agent2_tlsaccept if zabbix_agent2_tlsaccept else 'unencrypted'] }}" + tls_connect: "{{ zabbix_agent_tls_config[zabbix_agent2_tlsconnect if zabbix_agent2_tlsconnect else 'unencrypted'] }}" + validate_certs: "{{ zabbix_api_validate_certs | default(omit) }}" + timeout: "{{ zabbix_api_timeout }}" + description: "{{ zabbix_agent_description | default(omit) }}" + inventory_zabbix: "{{ zabbix_agent_inventory_zabbix | default({}) }}" + ipmi_authtype: "{{ zabbix_agent_ipmi_authtype | default(omit) }}" + ipmi_password: "{{ zabbix_agent_ipmi_password| default(omit) }}" + ipmi_privilege: "{{ zabbix_agent_ipmi_privilege | default(omit) }}" + ipmi_username: "{{ zabbix_agent_ipmi_username | default(omit) }}" + tags: "{{ zabbix_agent_tags }}" + when: + - zabbix_agent2 | bool + register: zabbix_api_host_created + until: zabbix_api_host_created is succeeded + delegate_to: "{{ zabbix_api_server_host }}" + become: false + changed_when: false + tags: + - api + +- name: "API | Updating host configuration with macros" + community.zabbix.zabbix_hostmacro: + host_name: "{{ (zabbix_agent2 | bool) | ternary(zabbix_agent2_hostname, zabbix_agent_hostname) }}" + macro_name: "{{ item.macro_key }}" + macro_value: "{{ item.macro_value }}" + macro_type: "{{ item.macro_type|default('text') }}" + validate_certs: "{{ zabbix_api_validate_certs | default(omit) }}" + timeout: "{{ zabbix_api_timeout }}" + with_items: "{{ zabbix_agent_macros | default([]) }}" + when: + - zabbix_agent_macros is defined + - item.macro_key is defined + register: zabbix_api_hostmarcro_created + until: zabbix_api_hostmarcro_created is succeeded + delegate_to: "{{ zabbix_api_server_host }}" + become: false + tags: + - api diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml new file mode 100644 index 000000000..24ba96cb0 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml @@ -0,0 +1,55 @@ +--- + +- name: "Firewall | Configure IPTables (zabbix_agent_listenport)" + iptables: + action: "{{ zabbix_agent_firewall_action }}" + destination_port: "{{ zabbix_agent_listenport | string }}" + source: "{{ zabbix_agent_firewall_source | default(omit) }}" + protocol: tcp + chain: "{{ zabbix_agent_firewall_chain }}" + jump: ACCEPT + become: true + when: + - zabbix_agent_firewall_enable | bool + +- name: "Firewall | Configure IPTables (zabbix_agent_jmx_listenport)" + iptables: + action: "{{ zabbix_agent_firewall_action }}" + destination_port: "{{ zabbix_agent_listenport | string }}" + source: "{{ zabbix_agent_firewall_source | default(omit) }}" + protocol: tcp + chain: "{{ zabbix_agent_firewall_chain }}" + jump: ACCEPT + become: true + when: + - zabbix_agent_firewall_enable | bool + - zabbix_agent_jmx_listenport | bool + +- name: "Firewall | Configure firewalld (zabbix_agent_listenport)" + ansible.posix.firewalld: + rich_rule: 'rule family="ipv4" source address="{{ zabbix_agent_firewalld_source }}" port protocol="tcp" port="{{ zabbix_agent_listenport }}" accept' + zone: "{{ zabbix_agent_firewalld_zone }}" + permanent: true + immediate: true + state: enabled + become: true + when: + - zabbix_agent_firewalld_enable | bool + notify: + - firewalld-reload + tags: zabbix_agent_firewalld_enable + +- name: "Firewall | Configure firewalld (zabbix_agent_jmx_listenport)" + ansible.posix.firewalld: + rich_rule: 'rule family="ipv4" source address="{{ zabbix_agent_firewalld_source }}" port protocol="tcp" port="{{ zabbix_agent_jmx_listenport }}" accept' + zone: "{{ zabbix_agent_firewalld_zone }}" + permanent: true + immediate: true + state: enabled + become: true + when: + - zabbix_agent_firewalld_enable | bool + - zabbix_agent_jmx_listenport | bool + notify: + - firewalld-reload + tags: zabbix_agent_firewalld_enable diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml new file mode 100644 index 000000000..0904c39f1 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml @@ -0,0 +1,24 @@ +--- +# Tasks specific for macOS +- name: "macOS | Check installed package version" + shell: | + set -o pipefail + pkgutil --pkg-info 'com.zabbix.pkg.ZabbixAgent' | grep 'version:' | cut -d ' ' -f 2 + register: pkgutil_version + check_mode: false + changed_when: false + failed_when: pkgutil_version.rc == 2 + +- name: "macOS | Download the Zabbix package" + get_url: + url: "{{ zabbix_mac_download_link }}" + dest: "/tmp/{{ zabbix_mac_package }}" + mode: 0644 + when: pkgutil_version.stdout != zabbix_version_long + +- name: "macOS | Install the Zabbix package" + command: installer -pkg "/tmp/{{ zabbix_mac_package }}" -target / + become: true + when: pkgutil_version.stdout != zabbix_version_long + tags: + - zabbix-agent diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml new file mode 100644 index 000000000..5ce427ce4 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml @@ -0,0 +1,143 @@ +--- +# tasks file for zabbix_agent + +- name: "Set variables specific for Zabbix Agent 2" + set_fact: + zabbix_agent_service: zabbix-agent2 + zabbix_agent_package: zabbix-agent2 + when: + - zabbix_agent2 is defined + - zabbix_agent2 + tags: + - always + +- name: "Fix facts for linuxmint - distribution release" + set_fact: + zabbix_agent_distribution_release: xenial + when: + - ansible_os_family == "Linuxmint" + - ansible_distribution_release == "sonya" or ansible_distribution_release == "serena" + tags: + - always + +- name: "Fix facts for linuxmint - family" + set_fact: + zabbix_agent_os_family: Debian + when: + - ansible_os_family == "Linuxmint" + tags: + - always + +- name: "Fix facts for XCP-ng - family" + set_fact: + zabbix_agent_os_family: RedHat + when: + - ansible_os_family == "XCP-ng" + +- name: "Include OS-specific variables" + include_vars: "{{ zabbix_agent_os_family }}.yml" + tags: + - always + +- name: Determine Latest Supported Zabbix Version + set_fact: + zabbix_agent_version: "{{ zabbix_valid_agent_versions[ansible_distribution_major_version][0] | default(6.0) }}" + when: zabbix_agent_version is not defined + +- name: "Reset zabbix_agent_version for Ubuntu 22.04 to 6.0" + # README https://support.zabbix.com/browse/ZBXNEXT-7624 + set_fact: + zabbix_version: 6.0 + zabbix_agent_version: 6.0 + when: + - ansible_distribution_release is defined + - ansible_distribution_release == "jammy" + - ( zabbix_agent_version is version ('6.0','lt') or + zabbix_version is version ('6.0','lt') ) + +- name: "Install the correct repository" + include_tasks: "{{ zabbix_agent_os_family if (zabbix_agent_os_family not in ['Sangoma']) else 'RedHat' }}.yml" + when: + - not (zabbix_agent_docker | bool) + tags: + - always + +- name: "Set the 'ansible_python_interpreter' to the one we use for running this playbook." + set_fact: + ansible_python_interpreter: "{{ ansible_playbook_python }}" + delegate_to: localhost + delegate_facts: true + when: + - (zabbix_install_pip_packages | bool) or (zabbix_api_create_hostgroup | bool) or (zabbix_api_create_hosts | bool) + +- name: "Install local python-netaddr package" + pip: + name: netaddr + state: present + register: zabbix_python_netaddr_package_installed + until: zabbix_python_netaddr_package_installed is succeeded + delegate_to: localhost + run_once: true + become: "{{ zabbix_agent_become_on_localhost }}" + when: + - zabbix_install_pip_packages | bool + - ansible_all_ipv4_addresses is defined or (zabbix_agent_ip is not defined and total_private_ip_addresses is defined) + +- name: "Encrypt with TLS PSK auto management" + include_tasks: tlspsk_auto.yml + when: + - not zabbix_agent2 + - zabbix_agent_tlspsk_auto | bool + - (zabbix_agent_tlspskfile is undefined) or (zabbix_agent_tlspskfile | length == '0') + - (zabbix_agent_tlspsk_secret is undefined) or (zabbix_agent_tlspsk_secret | length == '0') + +- name: "Encrypt with TLS PSK auto management" + include_tasks: tlspsk_auto_agent2.yml + when: + - zabbix_agent2 | bool + - zabbix_agent2_tlspsk_auto | bool + - (zabbix_agent2_tlspskfile is undefined) or (zabbix_agent2_tlspskfile | length == '0') + - (zabbix_agent2_tlspsk_secret is undefined) or (zabbix_agent2_tlspsk_secret | length == '0') + +- name: "Configure Agent" + include_tasks: Windows_conf.yml + when: + - zabbix_agent_os_family == "Windows" + tags: + - always + +- name: "Configure Agent" + include_tasks: Darwin.yml + when: + - zabbix_agent_os_family == "Darwin" + tags: + - always + +- name: "Configure Agent" + include_tasks: Linux.yml + when: + - (zabbix_agent_os_family != "Windows" and zabbix_agent_os_family != "Darwin") or (zabbix_agent_docker | bool) + tags: + - always + +- name: "Run the API calls to Zabbix Server" + vars: + gather_facts: false + ansible_user: "{{ zabbix_api_login_user }}" + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + # Can't think of a way to make http_login_* vars be undefined -( + http_login_user: "{{ zabbix_api_http_user | default(zabbix_http_user | default(-42)) }}" + http_login_password: "{{ zabbix_api_http_password | default(zabbix_http_password | default(-42)) }}" + include_tasks: api.yml + when: + - (zabbix_api_create_hostgroup | bool) or (zabbix_api_create_hosts | bool) + tags: + - api + +- name: "Including userparameters" + include_tasks: "userparameter.yml" + when: zabbix_agent_userparameters|length > 0 + tags: + - zabbix-agent + - userparameter diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml new file mode 100644 index 000000000..57968146c --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml @@ -0,0 +1,25 @@ +--- +- name: Pull service facts + service_facts: + +- name: "Remove | Make sure the \"old\" zabbix-agent service stopped" + service: + name: "zabbix-agent" + state: stopped + enabled: false + become: true + when: | + ansible_facts.services["zabbix-agent.service"] is defined or + ansible_facts.services["zabbix-agent"] is defined + +- name: "Remove | Package removal" + package: + name: "zabbix-agent" + state: absent + become: true + +- name: "Remove | Remove the agent-include-dir" + file: + path: "{{ zabbix_agent_include }}" + state: absent + become: true diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml new file mode 100644 index 000000000..b7ec69e7b --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml @@ -0,0 +1,102 @@ +--- + +- name: "SELinux | Debian | Install policycoreutils-python" + apt: + pkg: policycoreutils-python-utils + state: present + update_cache: true + cache_valid_time: 0 + force_apt_get: "{{ zabbix_apt_force_apt_get }}" + install_recommends: "{{ zabbix_apt_install_recommends }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_agent_policycoreutils_installed + until: zabbix_agent_package_installed is succeeded + become: true + when: + - zabbix_agent_os_family == "Debian" + +- name: "SELinux | RedHat | Install policycoreutils-python" + package: + name: policycoreutils-python + state: installed + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_agent_policycoreutils_installed + until: zabbix_agent_policycoreutils_installed is succeeded + when: + - zabbix_agent_os_family == "RedHat" + - (zabbix_agent_distribution_major_version == "6" or zabbix_agent_distribution_major_version == "7") + become: true + tags: + - init + - zabbix-agent + +- name: "SELinux | RedHat | Install python3-policycoreutils on RHEL8" + package: + name: python3-policycoreutils + state: installed + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_agent_policycoreutils_installed + until: zabbix_agent_policycoreutils_installed is succeeded + when: + - zabbix_agent_os_family == "RedHat" + - ansible_distribution_major_version == "8" + become: true + tags: + - init + - zabbix-agent + +- name: "SELinux | RedHat | Install selinux-policy-targeted" + package: + name: selinux-policy-targeted + state: installed + register: zabbix_agent_selinuxpolicytargeted_installed + until: zabbix_agent_selinuxpolicytargeted_installed is succeeded + when: + - zabbix_agent_os_family == "RedHat" + become: true + tags: + - init + - zabbix-agent + +# straight to getenforce binary , workaround for missing python_selinux library +- name: "SELinux | Get getenforce binary" + stat: + path: /usr/sbin/getenforce + register: getenforce_bin + become: true + +- name: "SELinux | Collect getenforce output" + command: /usr/sbin/getenforce + register: sestatus + when: 'getenforce_bin.stat.exists' + changed_when: false + become: true + check_mode: false + +- name: "SELinux | Set zabbix_selinux to true if getenforce returns Enforcing or Permissive" + set_fact: + zabbix_selinux: "{{ true }}" + when: + - 'getenforce_bin.stat.exists and ("Enforcing" in sestatus.stdout or "Permissive" in sestatus.stdout)' + +- name: "SELinux | Allow zabbix_agent to start (SELinux)" + community.general.selinux_permissive: + name: zabbix_agent_t + permissive: true + become: true + +- name: "SELinux | Allow zabbix to run sudo commands (SELinux)" + ansible.posix.seboolean: + name: zabbix_run_sudo + persistent: true + state: true + when: + - ansible_selinux.status == "enabled" + - selinux_allow_zabbix_run_sudo|bool + tags: selinux diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml new file mode 100644 index 000000000..aaa733872 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml @@ -0,0 +1,12 @@ +--- +- include_tasks: tlspsk_auto_linux.yml + when: (zabbix_agent_os_family != "Windows") or (zabbix_agent_docker | bool) + +- include_tasks: tlspsk_auto_windows.yml + when: zabbix_agent_os_family == "Windows" + +- name: AutoPSK | Default tlsaccept and tlsconnect to enforce PSK + set_fact: + zabbix_agent_tlsaccept: psk + zabbix_agent_tlsconnect: psk + when: zabbix_api_create_hosts diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml new file mode 100644 index 000000000..77eafc878 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml @@ -0,0 +1,12 @@ +--- +- include_tasks: tlspsk_auto_agent2_linux.yml + when: (zabbix_agent_os_family != "Windows") or (zabbix_agent_docker | bool) + +- include_tasks: tlspsk_auto_agent2_windows.yml + when: zabbix_agent_os_family == "Windows" + +- name: AutoPSK | Default tlsaccept and tlsconnect to enforce PSK + set_fact: + zabbix_agent2_tlsaccept: psk + zabbix_agent2_tlsconnect: psk + when: zabbix_api_create_hosts diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml new file mode 100644 index 000000000..4a7b897ae --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml @@ -0,0 +1,44 @@ +--- +# Process PSK Secret +- name: AutoPSK | Save existing TLS PSK secret + set_fact: + zabbix_agent2_tlspsk_read: "{{ zabbix_agent2_tlspsk_base64['content'] | b64decode | trim }}" + when: zabbix_agent2_tlspskcheck.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Use existing TLS PSK secret + set_fact: + zabbix_agent2_tlspsk_secret: "{{ zabbix_agent2_tlspsk_read }}" + when: + - zabbix_agent2_tlspskcheck.stat.exists + - zabbix_agent2_tlspsk_read|length >= 32 + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Generate new TLS PSK secret + set_fact: + zabbix_agent2_tlspsk_secret: "{{ lookup('password', '/dev/null chars=hexdigits length=64') }}" + when: + - not zabbix_agent2_tlspskcheck.stat.exists + - (zabbix_agent2_tlspsk_read is not defined) or (zabbix_agent2_tlspsk_read|length < 32) + no_log: "{{ ansible_verbosity < 3 }}" + + +# Process PSK Identity +- name: AutoPSK | Use existing TLS PSK identity + set_fact: + zabbix_agent2_tlspskidentity: "{{ zabbix_agent2_tlspskidentity_base64['content'] | b64decode | trim }}" + when: + - zabbix_agent2_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Generate new TLS PSK identity + set_fact: + zabbix_agent2_tlspskidentity: >- + {{ + zabbix_agent_visible_hostname + | default(((zabbix_agent2 == True) | ternary(zabbix_agent2_hostname, zabbix_agent_hostname))) + + '_' + + lookup('password', '/dev/null chars=hexdigits length=4') + }} + when: not zabbix_agent2_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml new file mode 100644 index 000000000..721f1cb86 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml @@ -0,0 +1,66 @@ +--- +- name: AutoPSK | Set default path variables (Linux) + set_fact: + zabbix_agent2_tlspskfile: "/etc/zabbix/tls_psk_auto.secret" + zabbix_agent2_tlspskidentity_file: "/etc/zabbix/tls_psk_auto.identity" + +- name: AutoPSK | Check for existing TLS PSK file (Linux) + stat: + path: "{{ zabbix_agent2_tlspskfile }}" + register: zabbix_agent2_tlspskcheck + become: true + +- name: AutoPSK | Check for existing TLS PSK identity (Linux) + stat: + path: "{{ zabbix_agent2_tlspskidentity_file }}" + register: zabbix_agent2_tlspskidentity_check + become: true + +- name: AutoPSK | read existing TLS PSK file (Linux) + slurp: + src: "{{ zabbix_agent2_tlspskfile }}" + register: zabbix_agent2_tlspsk_base64 + become: true + when: + - zabbix_agent2_tlspskcheck.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Read existing TLS PSK identity file (Linux) + slurp: + src: "{{ zabbix_agent2_tlspskidentity_file }}" + register: zabbix_agent2_tlspskidentity_base64 + become: true + when: zabbix_agent2_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- include_tasks: tlspsk_auto_agent2_common.yml + +- name: AutoPSK | Template TLS PSK identity in file (Linux) + copy: + dest: "{{ zabbix_agent2_tlspskidentity_file }}" + content: "{{ zabbix_agent2_tlspskidentity }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent2_tlspskidentity_file is defined + - zabbix_agent2_tlspskidentity is defined + notify: + - restart zabbix-agent + - restart mac zabbix agent + +- name: AutoPSK | Template TLS PSK secret in file (Linux) + copy: + dest: "{{ zabbix_agent2_tlspskfile }}" + content: "{{ zabbix_agent2_tlspsk_secret }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent2_tlspskfile is defined + - zabbix_agent2_tlspsk_secret is defined + notify: + - restart zabbix-agent + - restart mac zabbix agent diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml new file mode 100644 index 000000000..770d60776 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml @@ -0,0 +1,52 @@ +--- +- name: AutoPSK | Set default path variables for Windows + set_fact: + zabbix_agent2_tlspskfile: "{{ zabbix_win_install_dir }}\\tls_psk_auto.secret.txt" + zabbix_agent2_tlspskidentity_file: "{{ zabbix_win_install_dir }}\\tls_psk_auto.identity.txt" + +- name: AutoPSK | Check for existing TLS PSK file (Windows) + ansible.windows.win_stat: + path: "{{ zabbix_agent2_tlspskfile }}" + register: zabbix_agent2_tlspskcheck + +- name: AutoPSK | Check for existing TLS PSK identity (Windows) + ansible.windows.win_stat: + path: "{{ zabbix_agent2_tlspskidentity_file }}" + register: zabbix_agent2_tlspskidentity_check + +- name: AutoPSK | read existing TLS PSK file (Windows) + slurp: + src: "{{ zabbix_agent2_tlspskfile }}" + register: zabbix_agent2_tlspsk_base64 + when: + - zabbix_agent2_tlspskcheck.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Read existing TLS PSK identity file (Windows) + slurp: + src: "{{ zabbix_agent2_tlspskidentity_file }}" + register: zabbix_agent2_tlspskidentity_base64 + when: zabbix_agent2_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- include_tasks: tlspsk_auto_agent2_common.yml + +- name: Windows | AutoPSK | Template TLS PSK identity in file (Windows) + win_copy: + dest: "{{ zabbix_agent2_tlspskidentity_file }}" + content: "{{ zabbix_agent2_tlspskidentity }}" + when: + - zabbix_agent2_tlspskidentity_file is defined + - zabbix_agent2_tlspskidentity is defined + notify: + - restart win zabbix agent + +- name: AutoPSK | Template TLS PSK secret in file (Windows) + win_copy: + dest: "{{ zabbix_agent2_tlspskfile }}" + content: "{{ zabbix_agent2_tlspsk_secret }}" + when: + - zabbix_agent2_tlspskfile is defined + - zabbix_agent2_tlspsk_secret is defined + notify: + - restart win zabbix agent diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml new file mode 100644 index 000000000..4b02fafb6 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml @@ -0,0 +1,43 @@ +--- +# Process PSK Secret +- name: AutoPSK | Save existing TLS PSK secret + set_fact: + zabbix_agent_tlspsk_read: "{{ zabbix_agent_tlspsk_base64['content'] | b64decode | trim }}" + when: zabbix_agent_tlspskcheck.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Use existing TLS PSK secret + set_fact: + zabbix_agent_tlspsk_secret: "{{ zabbix_agent_tlspsk_read }}" + when: + - zabbix_agent_tlspskcheck.stat.exists + - zabbix_agent_tlspsk_read|length >= 32 + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Generate new TLS PSK secret + set_fact: + zabbix_agent_tlspsk_secret: "{{ lookup('password', '/dev/null chars=hexdigits length=64') }}" + when: + - (not zabbix_agent_tlspskcheck.stat.exists) or (zabbix_agent_tlspsk_read|length < 32) + no_log: "{{ ansible_verbosity < 3 }}" + + +# Process PSK Identity +- name: AutoPSK | Use existing TLS PSK identity + set_fact: + zabbix_agent_tlspskidentity: "{{ zabbix_agent_tlspskidentity_base64['content'] | b64decode | trim }}" + when: + - zabbix_agent_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Generate new TLS PSK identity + set_fact: + zabbix_agent_tlspskidentity: >- + {{ + zabbix_agent_visible_hostname + | default(((zabbix_agent2 != True) | ternary(zabbix_agent_hostname, zabbix_agent_hostname))) + + '_' + + lookup('password', '/dev/null chars=hexdigits length=4') + }} + when: not zabbix_agent_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml new file mode 100644 index 000000000..1dbea4082 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml @@ -0,0 +1,66 @@ +--- +- name: AutoPSK | Set default path variables (Linux) + set_fact: + zabbix_agent_tlspskfile: "/etc/zabbix/tls_psk_auto.secret" + zabbix_agent_tlspskidentity_file: "/etc/zabbix/tls_psk_auto.identity" + +- name: AutoPSK | Check for existing TLS PSK file (Linux) + stat: + path: "{{ zabbix_agent_tlspskfile }}" + register: zabbix_agent_tlspskcheck + become: true + +- name: AutoPSK | Check for existing TLS PSK identity (Linux) + stat: + path: "{{ zabbix_agent_tlspskidentity_file }}" + register: zabbix_agent_tlspskidentity_check + become: true + +- name: AutoPSK | read existing TLS PSK file (Linux) + slurp: + src: "{{ zabbix_agent_tlspskfile }}" + register: zabbix_agent_tlspsk_base64 + become: true + when: + - zabbix_agent_tlspskcheck.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Read existing TLS PSK identity file (Linux) + slurp: + src: "{{ zabbix_agent_tlspskidentity_file }}" + register: zabbix_agent_tlspskidentity_base64 + become: true + when: zabbix_agent_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- include_tasks: tlspsk_auto_common.yml + +- name: AutoPSK | Template TLS PSK identity in file (Linux) + copy: + dest: "{{ zabbix_agent_tlspskidentity_file }}" + content: "{{ zabbix_agent_tlspskidentity }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent_tlspskidentity_file is defined + - zabbix_agent_tlspskidentity is defined + notify: + - restart zabbix-agent + - restart mac zabbix agent + +- name: AutoPSK | Template TLS PSK secret in file (Linux) + copy: + dest: "{{ zabbix_agent_tlspskfile }}" + content: "{{ zabbix_agent_tlspsk_secret }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspsk_secret is defined + notify: + - restart zabbix-agent + - restart mac zabbix agent diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml new file mode 100644 index 000000000..146cfd457 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml @@ -0,0 +1,53 @@ +--- +- name: AutoPSK | Set default path variables for Windows + set_fact: + zabbix_agent_tlspskfile: "{{ zabbix_win_install_dir }}\\tls_psk_auto.secret.txt" + zabbix_agent_tlspskidentity_file: "{{ zabbix_win_install_dir }}\\tls_psk_auto.identity.txt" + +- name: AutoPSK | Check for existing TLS PSK file (Windows) + ansible.windows.win_stat: + path: "{{ zabbix_agent_tlspskfile }}" + register: zabbix_agent_tlspskcheck + +- name: AutoPSK | Check for existing TLS PSK identity (Windows) + ansible.windows.win_stat: + path: "{{ zabbix_agent_tlspskidentity_file }}" + register: zabbix_agent_tlspskidentity_check + +- name: AutoPSK | read existing TLS PSK file (Windows) + slurp: + src: "{{ zabbix_agent_tlspskfile }}" + register: zabbix_agent_tlspsk_base64 + when: + - zabbix_agent_tlspskcheck.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- name: AutoPSK | Read existing TLS PSK identity file (Windows) + slurp: + src: "{{ zabbix_agent_tlspskidentity_file }}" + register: zabbix_agent_tlspskidentity_base64 + when: zabbix_agent_tlspskidentity_check.stat.exists + no_log: "{{ ansible_verbosity < 3 }}" + +- include_tasks: tlspsk_auto_common.yml + +- name: AutoPSK | Template TLS PSK identity in file (Windows) + win_copy: + dest: "{{ zabbix_agent_tlspskidentity_file }}" + content: "{{ zabbix_agent_tlspskidentity }}" + when: + - zabbix_agent_tlspskidentity_file is defined + - zabbix_agent_tlspskidentity is defined + notify: + - restart win zabbix agent + +- name: AutoPSK | Template TLS PSK secret in file (Windows) + win_copy: + dest: "{{ zabbix_agent_tlspskfile }}" + content: "{{ zabbix_agent_tlspsk_secret }}" + when: + - zabbix_agent_tlspskfile is defined + - zabbix_agent_tlspsk_secret is defined + - zabbix_agent_os_family == "Windows" + notify: + - restart win zabbix agent diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml new file mode 100644 index 000000000..9a86b536a --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml @@ -0,0 +1,85 @@ +--- +- block: + - name: "Windows | Installing user-defined userparameters" + ansible.windows.win_template: + src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2" + dest: '{{ zabbix_agent_win_include }}\{{ item.name }}.conf' + notify: + - restart win zabbix agent + with_items: "{{ zabbix_agent_userparameters }}" + + - name: "Windows | Installing user-defined scripts" + ansible.windows.win_copy: + src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}" + dest: '{{ zabbix_win_install_dir }}\scripts\' + notify: + - restart win zabbix agent + with_items: "{{ zabbix_agent_userparameters }}" + when: item.scripts_dir is defined + + when: zabbix_agent_os_family == "Windows" + + +- block: + - name: "Installing user-defined userparameters" + template: + src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2" + dest: "{{ zabbix_agent_include }}/userparameter_{{ item.name }}.conf" + owner: zabbix + group: zabbix + mode: 0644 + notify: + - restart zabbix-agent + - restart mac zabbix agent + become: true + with_items: "{{ zabbix_agent_userparameters }}" + + - name: "Installing user-defined scripts" + copy: + src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}" + dest: "/etc/zabbix/scripts/" + owner: zabbix + group: zabbix + mode: 0755 + notify: + - restart zabbix-agent + - restart mac zabbix agent + become: true + with_items: "{{ zabbix_agent_userparameters }}" + when: item.scripts_dir is defined + + when: + - zabbix_agent_os_family != "Windows" + - not zabbix_agent2 + +- block: + - name: "Installing user-defined userparameters" + template: + src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2" + dest: "{{ zabbix_agent2_include }}/userparameter_{{ item.name }}.conf" + owner: zabbix + group: zabbix + mode: 0644 + notify: + - restart zabbix-agent + - restart mac zabbix agent + become: true + with_items: "{{ zabbix_agent_userparameters }}" + + - name: "Installing user-defined scripts" + copy: + src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}" + dest: "/etc/zabbix/scripts/" + owner: zabbix + group: zabbix + mode: 0755 + notify: + - restart zabbix-agent + - restart mac zabbix agent + become: true + with_items: "{{ zabbix_agent_userparameters }}" + when: item.scripts_dir is defined + + when: + - zabbix_agent_os_family != "Windows" + - zabbix_agent2 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/userparameters/mysql.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/userparameters/mysql.j2 new file mode 100644 index 000000000..64087779f --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/userparameters/mysql.j2 @@ -0,0 +1,3 @@ +# This is an sample userparameters file. + +UserParameter=mysql.ping_to,mysqladmin -uroot ping | grep -c alive diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/userparameters/win_sample.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/userparameters/win_sample.j2 new file mode 100644 index 000000000..2a27b634d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/userparameters/win_sample.j2 @@ -0,0 +1 @@ +UserParameter=do.something, powershell -NoProfile -ExecutionPolicy Bypass -File {{ zabbix_win_install_dir }}\scripts\{{ item.name }}\doSomething.ps1 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2 new file mode 100644 index 000000000..39829abc3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2 @@ -0,0 +1,135 @@ +{{ ansible_managed | comment }} +# This is a configuration file for Zabbix Agent 2 +# To get more information about Zabbix, visit http://www.zabbix.com + +# This configuration file is "minimalized", which means all the original comments +# are removed. The full documentation for your Zabbix Agent 2 can be found here: +# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_agent2{{ "_win" if zabbix_agent_os_family == "Windows" else "" }} + +{% if zabbix_agent_os_family != "Windows" %} +PidFile={{ zabbix_agent2_pidfile }} +{% endif %} +LogType={{ zabbix_agent2_logtype }} +{% if zabbix_agent_os_family == "Windows" %} +LogFile={{ zabbix_agent2_win_logfile }} +{% else %} +LogFile={{ zabbix_agent2_logfile }} +{% endif %} +LogFileSize={{ zabbix_agent2_logfilesize }} +DebugLevel={{ zabbix_agent2_debuglevel }} +{% if zabbix_agent2_sourceip is defined and zabbix_agent2_sourceip %} +SourceIP={{ zabbix_agent2_sourceip }} +{% endif %} +Server={{ zabbix_agent2_server }} +ListenPort={{ zabbix_agent2_listenport }} +{% if zabbix_agent2_listenip is defined and zabbix_agent2_listenip !='0.0.0.0' and zabbix_agent2_listenip %} +ListenIP={{ zabbix_agent2_listenip }} +{% endif %} +{% if zabbix_agent2_statusport is defined and zabbix_agent2_statusport %} +StatusPort={{ zabbix_agent2_statusport }} +{% endif %} +ServerActive={{ zabbix_agent2_serveractive }} +{% if zabbix_agent2_hostname is defined and zabbix_agent2_hostname %} +Hostname={{ zabbix_agent2_hostname }} +{% endif %} +{% if zabbix_agent2_hostnameitem is defined and zabbix_agent2_hostnameitem %} +HostnameItem={{ zabbix_agent2_hostnameitem }} +{% endif %} +{% if zabbix_agent2_hostmetadata is defined and zabbix_agent2_hostmetadata %} +HostMetadata={{ zabbix_agent2_hostmetadata }} +{% endif %} +{% if zabbix_agent2_hostmetadataitem is defined and zabbix_agent2_hostmetadataitem %} +HostMetadataItem={{ zabbix_agent2_hostmetadataitem }} +{% endif %} +{% if zabbix_agent2_hostinterface is defined and zabbix_agent2_hostinterface %} +HostInterface={{ zabbix_agent2_hostinterface }} +{% endif %} +{% if zabbix_agent2_hostinterfaceitem is defined and zabbix_agent2_hostinterfaceitem %} +HostInterfaceItem={{ zabbix_agent2_hostinterfaceitem }} +{% endif %} +{% if zabbix_agent2_allow_key is defined and zabbix_agent2_allow_key %} +{% for item in zabbix_agent2_allow_key %} +AllowKey={{ item }} +{% endfor %} +{% endif %} +{% if zabbix_agent2_deny_key is defined and zabbix_agent2_deny_key %} +{% for item in zabbix_agent2_deny_key %} +DenyKey={{ item }} +{% endfor %} +{% endif %} +RefreshActiveChecks={{ zabbix_agent2_refreshactivechecks }} +BufferSend={{ zabbix_agent2_buffersend }} +BufferSize={{ zabbix_agent2_buffersize }} +{% if zabbix_agent2_enablepersistentbuffer is defined and zabbix_agent2_enablepersistentbuffer %} +EnablePersistentBuffer={{ zabbix_agent2_enablepersistentbuffer }} +{% endif %} +{% if zabbix_agent2_persistentbufferperiod is defined and zabbix_agent2_persistentbufferperiod %} +PersistentBufferPeriod={{ zabbix_agent2_persistentbufferperiod }} +{% endif %} +{% if zabbix_agent2_persistentbufferfile is defined and zabbix_agent2_persistentbufferfile %} +PersistentBufferFile={{ zabbix_agent2_persistentbufferfile }} +{% endif %} +{% if zabbix_agent2_zabbix_alias is defined and zabbix_agent2_zabbix_alias %} +{% if zabbix_agent2_zabbix_alias is string %} +Alias={{ zabbix_agent2_zabbix_alias }} +{% else %} +{% for item in zabbix_agent2_zabbix_alias %} +Alias={{ item }} +{% endfor %} +{% endif %} +{% endif %} +Timeout={{ zabbix_agent2_timeout }} +{% if zabbix_agent_os_family == "Windows" %} +Include={{ zabbix_agent_win_include }} +{% else %} +Include={{ zabbix_agent2_include }}/{{ zabbix_agent2_include_pattern }} +{% endif %} +UnsafeUserParameters={{ zabbix_agent2_unsafeuserparameters }} +{% if zabbix_agent_os_family != "Windows" %} +ControlSocket={{ zabbix_agent2_controlsocket }} +{% endif %} +{% if zabbix_agent2_tlsconnect is defined and zabbix_agent2_tlsconnect %} +TLSConnect={{ zabbix_agent2_tlsconnect }} +{% endif %} +{% if zabbix_agent2_tlsaccept is defined and zabbix_agent2_tlsaccept %} +TLSAccept={{ zabbix_agent2_tlsaccept }} +{% endif %} +{% if zabbix_agent2_tlscafile is defined and zabbix_agent2_tlscafile %} +TLSCAFile={{ zabbix_agent2_tlscafile }} +{% endif %} +{% if zabbix_agent2_tlscrlfile is defined and zabbix_agent2_tlscrlfile %} +TLSCRLFile={{ zabbix_agent2_tlscrlfile }} +{% endif %} +{% if zabbix_agent2_tlsservercertissuer is defined and zabbix_agent2_tlsservercertissuer %} +TLSServerCertIssuer={{ zabbix_agent2_tlsservercertissuer }} +{% endif %} +{% if zabbix_agent2_tlsservercertsubject is defined and zabbix_agent2_tlsservercertsubject %} +TLSServerCertSubject={{ zabbix_agent2_tlsservercertsubject }} +{% endif %} +{% if zabbix_agent2_tlscertfile is defined and zabbix_agent2_tlscertfile %} +TLSCertFile={{ zabbix_agent2_tlscertfile }} +{% endif %} +{% if zabbix_agent2_tlskeyfile is defined and zabbix_agent2_tlskeyfile %} +TLSKeyFile={{ zabbix_agent2_tlskeyfile }} +{% endif %} +{% if zabbix_agent2_tlspskidentity is defined and zabbix_agent2_tlspskidentity %} +TLSPSKIdentity={{ zabbix_agent2_tlspskidentity }} +{% endif %} +{% if zabbix_agent2_tlspskfile is defined and zabbix_agent2_tlspskfile %} +TLSPSKFile={{ zabbix_agent2_tlspskfile }} +{% endif %} +{% if zabbix_agent2_plugins is defined and zabbix_agent2_plugins is iterable %} +{% for entry in zabbix_agent2_plugins %} +{% set my_name = entry['name'] %} +{% for property in entry['options'] %} +{% set param = property['parameter'] %} +{% set value = property['value'] %} +Plugins.{{ my_name }}.{{ param }}={{ value }} +{% endfor %} +{% endfor %} +{% endif %} +{% if zabbix_version is version('6.0', '>=') %} +{% if zabbix_agent2_listenbacklog is defined and zabbix_agent2_listenbacklog %} +ListenBacklog={{ zabbix_agent2_listenbacklog }} +{% endif %} +{% endif %} diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2 new file mode 100644 index 000000000..5e5d31d9b --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2 @@ -0,0 +1,144 @@ +{{ ansible_managed | comment }} +# This is a configuration file for Zabbix Agent +# To get more information about Zabbix, visit http://www.zabbix.com + +# This configuration file is "minimalized", which means all the original comments +# are removed. The full documentation for your Zabbix Agent can be found here: +# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_agentd{{ "_win" if zabbix_agent_os_family == "Windows" else "" }} + +{% if zabbix_agent_os_family != "Windows" %} +PidFile={{ zabbix_agent_pidfile }} +{% endif %} +{% if zabbix_agent_version is version('3.0', '>=') %} +LogType={{ zabbix_agent_logtype }} +{% endif %} +{% if zabbix_agent_os_family == "Windows" %} +LogFile={{ zabbix_agent_win_logfile }} +{% else %} +LogFile={{ zabbix_agent_logfile }} +{% endif %} +LogFileSize={{ zabbix_agent_logfilesize }} +DebugLevel={{ zabbix_agent_debuglevel }} +{% if zabbix_agent_sourceip is defined and zabbix_agent_sourceip %} +SourceIP={{ zabbix_agent_sourceip }} +{% endif %} +{% if zabbix_agent_version is version('6.0', '<=') %} +EnableRemoteCommands={{ zabbix_agent_enableremotecommands }} +{% else %} +{% if zabbix_agent_allowkeys is defined and zabbix_agent_allowkeys %} +AllowKey={{ zabbix_agent_allowkeys }} +{% endif %} +{% if zabbix_agent_denykeys is defined and zabbix_agent_denykeys %} +DenyKey={{ zabbix_agent_denykeys }} +{% endif %} +{% endif %} +LogRemoteCommands={{ zabbix_agent_logremotecommands }} +Server={{ zabbix_agent_server }} +ListenPort={{ zabbix_agent_listenport }} +{% if zabbix_agent_listenip is defined and zabbix_agent_listenip !='0.0.0.0' and zabbix_agent_listenip %} +ListenIP={{ zabbix_agent_listenip }} +{% endif %} +StartAgents={{ zabbix_agent_startagents }} +ServerActive={{ zabbix_agent_serveractive }} +{% if zabbix_agent_hostname is defined and zabbix_agent_hostname %} +Hostname={{ zabbix_agent_hostname }} +{% endif %} +{% if zabbix_agent_hostnameitem is defined and zabbix_agent_hostnameitem %} +HostnameItem={{ zabbix_agent_hostnameitem }} +{% endif %} +{% if zabbix_agent_hostmetadata is defined and zabbix_agent_hostmetadata %} +HostMetadata={{ zabbix_agent_hostmetadata }} +{% endif %} +{% if zabbix_agent_hostmetadataitem is defined and zabbix_agent_hostmetadataitem %} +HostMetadataItem={{ zabbix_agent_hostmetadataitem }} +{% endif %} +{% if zabbix_agent_allow_key is defined and zabbix_agent_allow_key %} +{% for item in zabbix_agent_allow_key %} +AllowKey={{ item }} +{% endfor %} +{% endif %} +{% if zabbix_agent_deny_key is defined and zabbix_agent_deny_key %} +{% for item in zabbix_agent_deny_key %} +DenyKey={{ item }} +{% endfor %} +{% endif %} +RefreshActiveChecks={{ zabbix_agent_refreshactivechecks }} +BufferSend={{ zabbix_agent_buffersend }} +BufferSize={{ zabbix_agent_buffersize }} +MaxLinesPerSecond={{ zabbix_agent_maxlinespersecond }} +{% if zabbix_version is version_compare('6.2', '>=') %} +HeartbeatFrequency={{ zabbix_agent_heartbeatfrequency }} +{% endif %} +{% if zabbix_agent_zabbix_alias is defined and zabbix_agent_zabbix_alias %} +{% if zabbix_agent_zabbix_alias is string %} +Alias={{ zabbix_agent_zabbix_alias }} +{% else %} +{% for item in zabbix_agent_zabbix_alias %} +Alias={{ item }} +{% endfor %} +{% endif %} +{% endif %} +Timeout={{ zabbix_agent_timeout }} +{% if zabbix_agent_os_family != "Windows" %} +AllowRoot={{ zabbix_agent_allowroot }} +{% endif %} +{% if zabbix_agent_runas_user is defined and zabbix_agent_runas_user %} +User={{ zabbix_agent_runas_user }} +{% endif %} +{% if zabbix_agent_os_family == "Windows" %} +Include={{ zabbix_agent_win_include }} +{% else %} +Include={{ zabbix_agent_include }}/{{ zabbix_agent_include_pattern }} +{% endif %} +UnsafeUserParameters={{ zabbix_agent_unsafeuserparameters }} +{% if zabbix_version is version_compare('2.2', '>=') %} +{% if zabbix_agent_os_family != "Windows" %} +LoadModulePath={{ zabbix_agent_loadmodulepath }} +{% endif %} +{% endif %} +{% if zabbix_agent_loadmodule is defined and zabbix_agent_loadmodule %} +{% if zabbix_agent_loadmodule is string %} +LoadModule={{ zabbix_agent_loadmodule }} +{% else %} +{% for module in zabbix_agent_loadmodule %} +LoadModule={{ module }} +{% endfor %} +{% endif %} +{% endif %} +{% if zabbix_version is version_compare('3.0', '>=') %} +{% if zabbix_agent_tlsconnect is defined and zabbix_agent_tlsconnect %} +TLSConnect={{ zabbix_agent_tlsconnect }} +{% endif %} +{% if zabbix_agent_tlsaccept is defined and zabbix_agent_tlsaccept %} +TLSAccept={{ zabbix_agent_tlsaccept }} +{% endif %} +{% if zabbix_agent_tlscafile is defined and zabbix_agent_tlscafile %} +TLSCAFile={{ zabbix_agent_tlscafile }} +{% endif %} +{% if zabbix_agent_tlscrlfile is defined and zabbix_agent_tlscrlfile %} +TLSCRLFile={{ zabbix_agent_tlscrlfile }} +{% endif %} +{% if zabbix_agent_tlsservercertissuer is defined and zabbix_agent_tlsservercertissuer %} +TLSServerCertIssuer={{ zabbix_agent_tlsservercertissuer }} +{% endif %} +{% if zabbix_agent_tlsservercertsubject is defined and zabbix_agent_tlsservercertsubject %} +TLSServerCertSubject={{ zabbix_agent_tlsservercertsubject }} +{% endif %} +{% if zabbix_agent_tlscertfile is defined and zabbix_agent_tlscertfile %} +TLSCertFile={{ zabbix_agent_tlscertfile }} +{% endif %} +{% if zabbix_agent_tlskeyfile is defined and zabbix_agent_tlskeyfile %} +TLSKeyFile={{ zabbix_agent_tlskeyfile }} +{% endif %} +{% if zabbix_agent_tlspskidentity is defined and zabbix_agent_tlspskidentity %} +TLSPSKIdentity={{ zabbix_agent_tlspskidentity }} +{% endif %} +{% if zabbix_agent_tlspskfile is defined and zabbix_agent_tlspskfile %} +TLSPSKFile={{ zabbix_agent_tlspskfile }} +{% endif %} +{% endif %} +{% if zabbix_version is version('6.0', '>=') %} +{% if zabbix_agent_listenbacklog is defined and zabbix_agent_listenbacklog %} +ListenBacklog={{ zabbix_agent_listenbacklog }} +{% endif %} +{% endif %} diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml new file mode 100644 index 000000000..164b02460 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml @@ -0,0 +1,6 @@ +--- +# vars file for zabbix_agent (Debian) + +zabbix_agent: zabbix-agent +zabbix_agent_service: com.zabbix.zabbix_agentd +zabbix_agent_conf: zabbix_agentd.conf diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml new file mode 100644 index 000000000..3100ca957 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml @@ -0,0 +1,38 @@ +--- +# vars file for zabbix_agent (Debian) + +zabbix_agent: zabbix-agent +zabbix_agent_service: zabbix-agent +zabbix_agent_conf: zabbix_agentd.conf +zabbix_agent2_conf: zabbix_agent2.conf + +zabbix_valid_agent_versions: + # Debian + "11": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "10": + - 6.0 + - 5.0 + - 4.0 + "9": + - 6.0 + - 5.0 + - 4.0 + # Ubuntu + "22": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "20": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "18": + - 6.0 + - 5.0 + - 4.0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml new file mode 100644 index 000000000..b9f2378dd --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml @@ -0,0 +1,24 @@ +--- +# vars file for zabbix_agent (RedHat) + +zabbix_agent: zabbix-agent +zabbix_agent_service: zabbix-agent +zabbix_agent_conf: zabbix_agentd.conf +zabbix_agent2_conf: zabbix_agent2.conf + +zabbix_valid_agent_versions: + "9": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "8": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "7": + - 6.4 + - 6.0 + - 5.0 + - 4.0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml new file mode 100644 index 000000000..5bcc846ab --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml @@ -0,0 +1,7 @@ +--- +# vars file for zabbix_agent (Sangola) + +zabbix_agent: zabbix-agent +zabbix_agent_service: zabbix-agent +zabbix_agent_conf: zabbix_agentd.conf +zabbix_agent2_conf: zabbix_agent2.conf diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml new file mode 100644 index 000000000..abecd9c23 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml @@ -0,0 +1,7 @@ +--- +# vars file for zabbix_agent (Suse) + +zabbix_agent: zabbix-agentd +zabbix_agent_service: zabbix_agentd +zabbix_agent_conf: zabbix_agentd.conf +zabbix_agent2_conf: zabbix-agent2.conf diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml new file mode 100644 index 000000000..8add26238 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml @@ -0,0 +1,2 @@ +--- +# vars file for zabbix_agent (Windows) diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/main.yml new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/main.yml diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml new file mode 100644 index 000000000..c78d3a76e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml @@ -0,0 +1,285 @@ +--- +sign_keys: + "64": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "62": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "60": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + jammy: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + "54": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + jammy: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "52": + # bullseye: not available upstream + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + jammy: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "50": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + jammy: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "44": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "42": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "40": + bullseye: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "34": + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "32": + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + sonya: + sign_key: 79EA5ED4 + serena: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "30": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "24": + jessie: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + "22": + squeeze: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + lucid: + sign_key: 79EA5ED4 + +suse: + "openSUSE Leap": + "42": + name: server:monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/ + python_libxml2_package: python-libxml2 + "openSUSE": + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }} + python_libxml2_package: python-libxml2 + "SLES": + "11": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/ + python_libxml2_package: python-libxml2 + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP5/ + python_libxml2_package: python-libxml2 + "15": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_15_SP3/ + python_libxml2_package: python3-libxml2-python + "SLES_SAP": # SAP specific version of SLES + "11": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/ + python_libxml2_package: python-libxml2 + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP5/ + python_libxml2_package: python-libxml2 + "15": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_15_SP3/ + python_libxml2_package: python3-libxml2-python diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md b/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md new file mode 100644 index 000000000..70427d97c --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md @@ -0,0 +1,142 @@ +# community.zabbix.zabbix_javagateway role + +![Zabbix Javagateway](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_javagateway/badge.svg) + +**Table of Contents** + +- [Overview](#overview) + * [Operating systems](#operating-systems) + * [Zabbix Versions](#zabbix-versions) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [Java Gatewaty](#java-gatewaty) + + [proxy](#proxy) +- [Dependencies](#dependencies) +- [Example Playbook](#example-playbook) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +## Operating systems + +This role will work on the following operating systems: + + * Red Hat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases. + +| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.2 | 5.0 | 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----------|-----|-----|-----|-----------|-----------| +| Red Hat Fam 8 | V | V | V | V | V | V | | | +| Red Hat Fam 7 | | | | V | V | V | V | V | +| Red Hat Fam 6 | | | | V | V | | | V | +| Red Hat Fam 5 | | | | V | V | | | V | +| Fedora | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | | | | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | V | V | V | V | V | +| Debian 10 buster | V | V | V | V | V | V | | | +| Debian 9 stretch | | | | V | V | V | V | | +| Debian 8 jessie | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | V | V | +| macOS 10.15 | | | | | | V | V | | +| macOS 10.14 | | | | | | V | V | | + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_javagateway_version`: This is the version of zabbix. Default: 5.2. Can be overridden to 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. +* `zabbix_javagateway_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed. +* `zabbix_javagateway_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. + +### Java Gatewaty + +* `zabbix_javagateway_pidfile`: Default: `/run/zabbix/zabbix_java_gateway.pid`. The location for the pid file. +* `zabbix_javagateway_listenip`: Default: `0.0.0.0`. The IP address to listen on. +* `zabbix_javagateway_listenport`: Default: `10052`. The port on which Java Gateway is listening on. +* `zabbix_javagateway_startpollers`: Default: `5`. The amount of pollers to start. + +### proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +# Dependencies + +The java gateway can be installed on either the zabbix-server or the zabbix-proxy machine. So one of these should be installed. You'll need to provide an parameter in your playbook for using the javagateway. + +When using the zabbix-server: +```yaml + roles: + - role: community.zabbix.zabbix_server + zabbix_server_javagateway: 192.168.1.2 +``` + +or when using the zabbix-proxy: +```yaml + roles: + - role: community.zabbix.zabbix_proxy + zabbix_proxy_server: 192.168.1.1 + zabbix_proxy_javagateway: 192.168.1.2 +``` + +# Example Playbook + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: zabbix-server + sudo: yes + roles: + - role: community.zabbix.zabbix_server + zabbix_server_javagateway: 192.168.1.2 + - role: community.zabbix.zabbix_javagateway +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml new file mode 100644 index 000000000..a34046616 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml @@ -0,0 +1,34 @@ +--- +# defaults file for zabbix_javagateway + +zabbix_javagateway_version: 6.4 +zabbix_version: "{{ zabbix_javagateway_version }}" +zabbix_javagateway_package_state: present +zabbix_selinux: false +zabbix_repo: zabbix +zabbix_repo_yum_schema: https +zabbix_java_gateway_conf_mode: "0644" + +zabbix_repo_yum_gpgcheck: 0 +zabbix_repo_yum_disabled: "*" +zabbix_repo_yum_enabled: [] +zabbix_repo_yum: + - name: zabbix + description: Zabbix Official Repository - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + mode: "0644" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + - name: zabbix-non-supported + description: Zabbix Official Repository non-supported - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/non-supported/rhel/{{ ansible_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + +zabbix_javagateway_pidfile: /run/zabbix/zabbix_java_gateway.pid +zabbix_javagateway_listenip: 0.0.0.0 +zabbix_javagateway_listenport: 10052 +zabbix_javagateway_startpollers: 5 diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/files/systemd.service b/ansible_collections/community/zabbix/roles/zabbix_javagateway/files/systemd.service new file mode 100644 index 000000000..b4a78650e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/files/systemd.service @@ -0,0 +1,15 @@ +[Unit] +Description=Zabbix Java Gateway +After=syslog.target +After=network.target + +[Service] +Type=forking +KillMode=process +ExecStart=/usr/sbin/zabbix_java_gateway +SuccessExitStatus=143 +User=zabbix +Group=zabbix + +[Install] +WantedBy=multi-user.target diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml new file mode 100644 index 000000000..c7034aa7d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml @@ -0,0 +1,16 @@ +--- +# handlers file for zabbix-javagateway + +- name: zabbix-java-gateway restarted + service: + name: zabbix-java-gateway + state: restarted + enabled: true + become: true + +- name: "clean repo files from proxy creds" + shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true + become: true + when: + - ansible_os_family == 'RedHat' + - zabbix_http_proxy is defined or zabbix_https_proxy is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/meta/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/meta/main.yml new file mode 100644 index 000000000..b484db2a4 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/meta/main.yml @@ -0,0 +1,23 @@ +--- +galaxy_info: + author: Werner Dijkerman + description: Installing and maintaining zabbix-javagateway for RedHat/Debian/Ubuntu. + company: myCompany.Dotcom + license: license (GPLv3) + min_ansible_version: 2.4 + platforms: + - name: EL + versions: + - 6 + - 7 + - name: Ubuntu + versions: + - lucid + - precise + - trusty + - name: Debian + versions: + - squeeze + - wheezy + galaxy_tags: + - monitoring diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml new file mode 100644 index 000000000..d025e6ca8 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml @@ -0,0 +1,97 @@ +--- + +- name: "Include Zabbix gpg ids" + include_vars: zabbix.yml + +- name: "Set some variables" + set_fact: + zabbix_short_version: "{{ zabbix_javagateway_version | regex_replace('\\.', '') }}" + +- name: "Debian | Install gpg key" + apt_key: + id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}" + url: http://repo.zabbix.com/zabbix-official-repo.key + become: true + +- name: "Debian | Installing repository Debian" + apt_repository: + repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/debian/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - ansible_distribution == "Debian" + - zabbix_repo == "zabbix" + +- name: "Debian | Installing repository Debian" + apt_repository: + repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/debian/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - ansible_distribution == "Debian" + - ansible_machine == "aarch64" + - zabbix_repo == "zabbix" + +- name: "Debian | Installing repository Ubuntu" + apt_repository: + repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu-arm64/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - ansible_distribution == "Ubuntu" + - ansible_machine == "aarch64" + - zabbix_repo == "zabbix" + + +- name: "Debian | Installing repository Ubuntu" + apt_repository: + repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - ansible_distribution == "Ubuntu" + - ansible_machine != "aarch64" + - zabbix_repo == "zabbix" + +- name: "Debian | Installing repository Ubuntu" + apt_repository: + repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu-arm64/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - ansible_distribution == "Ubuntu" + - ansible_machine == "aarch64" + - zabbix_repo == "zabbix" + + +- name: "Debian | Installing repository Ubuntu" + apt_repository: + repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - ansible_distribution == "Ubuntu" + - zabbix_repo == "zabbix" + +- name: "Debian | Installing zabbix-java-gateway" + apt: + pkg: zabbix-java-gateway + state: "{{ zabbix_javagateway_package_state }}" + update_cache: true + force: true + cache_valid_time: 3600 + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_java_gateway_install + until: zabbix_java_gateway_install is succeeded + become: true + +- name: "Make sure Zabbix Java Gateway is not yet running" + systemd: + name: zabbix-java-gateway + state: stopped + enabled: true + daemon_reload: true + when: + - zabbix_java_gateway_install.changed diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml new file mode 100644 index 000000000..877628381 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml @@ -0,0 +1,34 @@ +--- +# Tasks specific for RedHat systems + +- name: "RedHat | Install basic repo file" + yum_repository: + name: "{{ item.name }}" + description: "{{ item.description }}" + baseurl: "{{ item.baseurl }}" + gpgcheck: "{{ item.gpgcheck }}" + gpgkey: "{{ item.gpgkey }}" + mode: "{{ item.mode | default('0644') }}" + priority: "{{ item.priority | default('98') }}" + state: "{{ item.state | default('present') }}" + proxy: "{{ zabbix_http_proxy | default(omit) }}" + with_items: "{{ zabbix_repo_yum }}" + register: yum_repo_installed + become: true + when: + zabbix_repo == "zabbix" + notify: + - "clean repo files from proxy creds" + +- name: "RedHat | Installing zabbix-java-gateway" + package: + pkg: zabbix-java-gateway + state: "{{ zabbix_javagateway_package_state }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_java_gateway_install + until: zabbix_java_gateway_install is succeeded + become: true diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml new file mode 100644 index 000000000..b95322426 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml @@ -0,0 +1,46 @@ +--- +# tasks file for zabbix_proxy + +- name: "Install the correct repository" + include_tasks: "RedHat.yml" + when: + - ansible_os_family == "RedHat" + +- name: "Install the correct repository" + include_tasks: "Debian.yml" + when: + - ansible_os_family == "Debian" + +- name: "Place systemd unit file" + copy: + src: systemd.service + dest: /etc/systemd/system/zabbix-java-gateway.service + mode: '0644' + register: systemd_state + when: + - zabbix_version is version('5.4', '<') + +- name: "Reload systemd" + shell: systemctl daemon-reload + when: + - zabbix_version is version('5.4', '<') + - systemd_state.changed + tags: + - skip_ansible_lint + +- name: "Configure zabbix-proxy" + template: + src: zabbix_java_gateway.conf.j2 + dest: /etc/zabbix/zabbix_java_gateway.conf + owner: zabbix + group: zabbix + mode: "{{ zabbix_java_gateway_conf_mode }}" + notify: + - zabbix-java-gateway restarted + +- name: "Make sure Zabbix Java Gateway is running" + systemd: + name: zabbix-java-gateway + state: started + enabled: true + daemon_reload: true diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2 new file mode 100644 index 000000000..9b197600d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2 @@ -0,0 +1,12 @@ +{{ ansible_managed | comment }} +# This is a configuration file for Zabbix Java Gateway +# To get more information about Zabbix, visit http://www.zabbix.com + +# This configuration file is "minimalized", which means all the original comments +# are removed. The full documentation for your Zabbix Java Gateway can be found here: +# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/concepts/java + +LISTEN_IP={{ zabbix_javagateway_listenip }} +LISTEN_PORT={{ zabbix_javagateway_listenport }} +PID_FILE={{ zabbix_javagateway_pidfile }} +START_POLLERS={{ zabbix_javagateway_startpollers }} diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml new file mode 100644 index 000000000..1eecc3170 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml @@ -0,0 +1,6 @@ +--- +apache_user: www-data +apache_group: www-data +apache_log: apache2 + +mysql_create_dir: '' diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml new file mode 100644 index 000000000..8c1997706 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml @@ -0,0 +1,6 @@ +--- +apache_user: apache +apache_group: apache +apache_log: httpd + +mysql_create_dir: create/ diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/main.yml new file mode 100644 index 000000000..dee610c60 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for zabbix_javagateway diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml new file mode 100644 index 000000000..bd960deba --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml @@ -0,0 +1,258 @@ +--- +sign_keys: + "64": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + jammy: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + "62": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + jammy: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + "60": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + jammy: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + "54": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "52": + # bullseye: not available upstream + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "50": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "44": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "42": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "40": + bullseye: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "34": + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "32": + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + sonya: + sign_key: 79EA5ED4 + serena: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "30": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "24": + jessie: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + "22": + squeeze: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + lucid: + sign_key: 79EA5ED4 + +suse: + "openSUSE Leap": + "42": + name: server:monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/ + "openSUSE": + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }} + "SLES": + "11": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/ + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP3/ diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md b/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md new file mode 100644 index 000000000..6682f6c18 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md @@ -0,0 +1,387 @@ +# community.zabbix.zabbix_proxy role + +![Zabbix Proxy](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_proxy/badge.svg) + +**Table of Contents** + +- [Overview](#overview) + * [Operating systems](#operating-systems) + * [Zabbix Versions](#zabbix-versions) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [SElinux](#selinux) + + [Zabbix Proxy](#zabbix-proxy) + + [Database specific](#database-specific) + + [TLS Specific configuration](#tls-specific-configuration) + * [proxy](#proxy) + * [Database](#database) + + [MySQL](#mysql) + - [Local Setup](#local-setup) + - [Separate Setup](#separate-setup) + + [PostgreSQL](#postgresql) + - [Local Setup](#local-setup-1) + - [Separate Setup](#separate-setup-1) + + [SQLite3](#sqlite3) + * [Zabbix API variables](#zabbix-api-variables) +- [Example Playbook](#example-playbook) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +## Operating systems + +This role will work on the following operating systems: + + * Red Hat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +# Requirements +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collection is now required: `ansible.posix`. Installing the collection: + +```sh +ansible-galaxy collection install ansible.posix +``` + +If you are willing to create proxy in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too: + +``` +ansible-galaxy collection install ansible.netcommon +``` + +### MySQL + +When you are a MySQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.mysql`. This collections are needed as the `mysql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.mysql +``` + +### PostgreSQL + +When you are a PostgreSQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.postgresql`. This collections are needed as the `postgresql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.postgresql +``` + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases. + +| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V | +| Red Hat Fam 6 | | | | | V | V | | | V | +| Red Hat Fam 5 | | | | | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | | V | V | V | V | V | +| Debian 10 buster | V | | V | V | V | V | V | | | +| Debian 9 stretch | V | | V | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_proxy_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_proxy_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. + +### SElinux + +* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the Proxy will run. + +### Zabbix Proxy + +* `zabbix_proxy_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact. +* `zabbix_proxy_server`: The ip or dns name for the zabbix-server machine. +* `zabbix_proxy_serverport`: The port on which the zabbix-server is running. Default: 10051 +* `*zabbix_proxy_package_state`: Default: `present`. Can be overridden to `latest` to update packages +* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client. +* `zabbix_proxy_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip. +* `zabbix_proxy_manage_service`: Default: `True`. When you run multiple Zabbix proxies in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-proxy service, because Pacemaker is in control of zabbix-proxy service. +* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely. +* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started.This parameter is supported since Zabbix 4.2.0. +* `zabbix_proxy_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_logtype`: Specifies where log messages are written to: system, file, console. +* `zabbix_proxy_logfile`: Name of log file. +* `zabbix_proxy_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_proxy_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_proxy_include`. +* `zabbix_proxy_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. +* `zabbix_proxy_statsallowedip`: Default: `127.0.0.1`. Allowed IP foe remote gathering of the ZabbixPorixy internal metrics. +* `zabbix_proxy_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission +* `zabbix_proxy_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified. +* `zabbix_proxy_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'. +* `zabbix_proxy_listenbacklog`: The maximum number of pending connections in the queue. + +### Database specific + +* `zabbix_proxy_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database. +* `zabbix_proxy_database`: Default: `mysql`. The type of database used. Can be: `mysql`, `pgsql` or `sqlite3` +* `zabbix_proxy_database_long`: Default: `mysql`. The type of database used, but long name. Can be: `mysql`, `postgresql` or `sqlite3` +* `zabbix_proxy_dbhost`: The hostname on which the database is running. Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections) Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_dbname`: The database name which is used by the Zabbix Proxy. +* `zabbix_proxy_dbuser`: The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_dbpassword`: The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `zabbix_proxy_dbport`: The database port which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False. +* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client. Default true +* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False. +* `zabbix_proxy_dbencoding`: Default: `utf8`. The encoding for the MySQL database. +* `zabbix_proxy_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database.zabbix_proxy_ +* `zabbix_server_allowunsupporteddbversions`: Allow proxy to work with unsupported database versions. +* `zabbix_proxy_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`. + +### TLS Specific configuration + +These variables are specific for Zabbix 3.0 and higher: + +* `zabbix_proxy_tlsconnect`: How the agent should connect to server or proxy. Used for active checks. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_proxy_tlsaccept`: What incoming connections to accept. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_proxy_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification. +* `zabbix_proxy_tlscrlfile`: Full pathname of a file containing revoked certificates. +* `zabbix_proxy_tlsservercertissuer`: Allowed server certificate issuer. +* `zabbix_proxy_tlsservercertsubject`: Allowed server certificate subject. +* `zabbix_proxy_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain. +* `zabbix_proxy_tlskeyfile`: Full pathname of a file containing the agent private key. +* `zabbix_proxy_dbtlsconnect`: Setting this option enforces to use TLS connection to database: + +`required` - connect using TLS +`verify_ca` - connect using TLS and verify certificate +`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate + +On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported. +By default not set to any option and the behaviour depends on database configuration. +This parameter is supported since Zabbix 5.0.0. + +* `zabbix_proxy_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlscertfile`: Full pathname of file containing Zabbix Proxy certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlscipher`: The list of encryption ciphers that Zabbix Proxy permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0. +* `zabbix_proxy_dbtlscipher13`: The list of encryption ciphersuites that Zabbix Proxy permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0. + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +## Database + +With Zabbix Proxy you can make use of 2 different databases: + +* `mysql` +* `postgresql` +* `SQLite3` + +In the following paragraphs we dive into both setups. + +### MySQL + +To make the Zabbix Proxy work with a `MySQL` database, there are 2 types on setup: + +1. Local setup, `MySQL` running on same host as the Zabbix Proxy; +2. Separate setup, `MySQL` running on a different host than the Zabbix Proxy. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `MySQL` instance on the host. Example: `geerlingguy.mysql` can be used, but also others can be used. Please make sure that before installing the Zabbix Proxy, you have a fully functional `MySQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: mysql +zabbix_proxy_database_long: mysql +zabbix_proxy_dbport: 3306 +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `MySQL`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `MySQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `MySQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: mysql +zabbix_proxy_database_long: mysql +zabbix_proxy_dbport: 3306 +zabbix_proxy_dbhost: mysql-host +zabbix_proxy_dbhost_run_install: false +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +zabbix_proxy_privileged_host: '%' +zabbix_proxy_mysql_login_host: mysql-host +zabbix_proxy_mysql_login_user: root +zabbix_proxy_mysql_login_password: changeme +zabbix_proxy_mysql_login_port: 3306 +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `MySQL`. + +The `zabbix_proxy_privileged_host` can be set to the hostname/ip of the host running Zabbix Proxy for security related purposes. Also make sure that `zabbix_proxy_mysql_login_password` is set to the correct password for the user provided with `zabbix_proxy_mysql_login_host` to create a database and user in the `MySQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `MySQL` on a different host will be running. + +### PostgreSQL + +To make the Zabbix Proxy work with a `PgSQL` database, there are 2 types on setup: + +1. Local setup, `PgSQL` running on same host as the Zabbix Proxy; +2. Separate setup, `PgSQL` running on a different host than the Zabbix Proxy. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `PgSQL` instance on the host. Example: `geerlingguy.postgresql` can be used, but also others can be used. Please make sure that before installing the Zabbix Proxy, you have a fully functional `PgSQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: pgsql +zabbix_proxy_database_long: postgresql +zabbix_proxy_dbport: 5432 +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `PgSQL`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `PgSQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `PgSQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_proxy_database: pgsql +zabbix_proxy_database_long: postgresql +zabbix_proxy_dbport: 5432 +zabbix_proxy_dbhost: pgsql-host +zabbix_proxy_dbhost_run_install: false +zabbix_proxy_dbpassword: <SOME_SECRET_STRING> +zabbix_proxy_privileged_host: '%' +zabbix_proxy_pgsql_login_host: pgsql-host +zabbix_proxy_pgsql_login_user: postgres +zabbix_proxy_pgsql_login_password: changeme +zabbix_proxy_pgsql_login_port: 5432 +``` + +Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `PgSQL`. + +The `zabbix_proxy_privileged_host` can be set to the hostname/ip of the host running Zabbix Proxy for security related purposes. Also make sure that `zabbix_proxy_mysql_login_password` is set to the correct password for the user provided with `zabbix_proxy_mysql_login_host` to create a database and user in the `PgSQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `PgSQL` on a different host will be running.zabbix_proxy_ + +### SQLite3 + +The SQLite3 can only be used on the same host as on which the Zabbix Proxy is running. If you want to use a seperate host for running the database for the proxy, please consider going for MySQL or PostGreSQL. + +The following properties needs to be set when using `SQLite3` as the database: + +```yaml +zabbix_proxy_database: sqlite3 +zabbix_proxy_database_long: sqlite3 +zabbix_proxy_dbname: /path/to/sqlite3.db +``` + +NOTE: When using `zabbix_proxy_dbname: zabbix_proxy` (Which is default with this role), it will automatically be stored on `/var/lib/zabbix/zabbix_proxy.db` + +## Zabbix API variables + +These variables need to be overridden when you want to make use of the Zabbix API for automatically creating and or updating proxies, i.e. when `zabbix_api_create_proxy` is set to `True`. + +* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth. +* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth. +* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com +* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080 +* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS +* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used +* `zabbix_api_login_user`: Username of user which has API access. +* `zabbix_api_login_pass`: Password for the user which has API access. +* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu` +* `zabbix_api_create_proxy`: When you want to enable the Zabbix API to create/delete the proxy. This has to be set to `True` if you want to make use of `zabbix_proxy_state`. Default: `False` +* `zabbix_proxy_name`: name of the Zabbix proxy as it is seen by Zabbix server +* `zabbix_proxy_state`: present (Default) if the proxy needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_proxy` is set to `True`. +* `zabbix_proxy_status`: active (Default) if the proxy needs to be active or passive. +* `zabbix_api_timeout`: timeout for API calls (default to 30 seconds) + +# Example Playbook + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: zabbix-proxy + roles: + - role: community.zabbix.zabbix_proxy + zabbix_proxy_server: 192.168.1.1 + zabbix_proxy_database: mysql + zabbix_proxy_database_long: mysql +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml new file mode 100644 index 000000000..82a70cb09 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml @@ -0,0 +1,196 @@ +--- +# defaults file for zabbix_proxy + +# zabbix_proxy_version: 6.0 +zabbix_proxy_version_minor: "*" +zabbix_version: "{{ zabbix_proxy_version }}" +zabbix_selinux: false + +# These variables are optional. They specify the version of Zabbix proxy package. + +# zabbix_proxy_rhel_version: 4.4.4 +# zabbix_proxy_debian_version: 1:4.4.4-1+stretch +# zabbix_proxy_ubuntu_version: 1:4.4.4-1+xenial + +zabbix_repo: zabbix +zabbix_proxy_apt_priority: +zabbix_proxy_package_state: present +zabbix_proxy_install_recommends: true +zabbix_proxy_install_database_client: true +zabbix_install_pip_packages: true +zabbix_repo_yum_schema: https +zabbix_proxy_conf_mode: "0644" +zabbix_repo_yum_gpgcheck: 0 +zabbix_repo_yum_disabled: "*" +zabbix_repo_yum_enabled: [] +zabbix_repo_yum: + - name: zabbix + description: Zabbix Official Repository - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + mode: "0644" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + - name: zabbix-non-supported + description: Zabbix Official Repository non-supported - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/non-supported/rhel/{{ ansible_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + +# User (EPEL specific) +zabbix_proxy_username: zabbix +zabbix_proxy_groupname: zabbix + +zabbix_server_host: 192.168.1.1 # Will be deprecated in 2.0.0 +zabbix_proxy_server: "{{ zabbix_server_host }}" +zabbix_server_port: 10051 # Will be deprecated in 2.0.0 +zabbix_proxy_serverport: "{{ zabbix_server_port }}" +zabbix_database_creation: true +zabbix_database_sqlload: true +zabbix_proxy_dbtlsconnect: +zabbix_proxy_dbtlscafile: +zabbix_proxy_dbtlscertfile: +zabbix_proxy_dbtlskeyfile: +zabbix_proxy_dbtlscipher: +zabbix_proxy_dbtlscipher13: +zabbix_proxy_allowunsupporteddbversions: 0 + +# Some role specific vars +zabbix_proxy_database: mysql +zabbix_proxy_database_long: mysql +# zabbix_proxy_database: pgsql +# zabbix_proxy_database_long: postgresql +# zabbix_proxy_database: sqlite3 +# zabbix_proxy_database_long: sqlite3 + +# zabbix-proxy specific vars +zabbix_proxy_mode: 0 +zabbix_proxy_hostname: "{{ inventory_hostname }}" +zabbix_proxy_listenport: 10051 +zabbix_proxy_sourceip: +zabbix_proxy_logtype: file +zabbix_proxy_logfile: /var/log/zabbix/zabbix_proxy.log +zabbix_proxy_logfilesize: 10 +zabbix_proxy_enableremotecommands: 0 +zabbix_proxy_debuglevel: 3 +zabbix_proxy_pidfile: /var/run/zabbix/zabbix_proxy.pid +zabbix_proxy_socketdir: /var/run/zabbix +zabbix_proxy_dbencoding: utf8 +zabbix_proxy_dbcollation: utf8_bin +zabbix_proxy_dbhost: localhost +zabbix_proxy_dbname: zabbix_proxy +zabbix_proxy_dbschema: +zabbix_proxy_dbuser: zabbix_proxy +zabbix_proxy_dbpassword: zabbix_proxy +zabbix_proxy_dbsocket: +zabbix_proxy_dbport: 5432 +zabbix_proxy_dbpassword_hash_method: md5 +zabbix_proxy_startodbcpollers: 1 +zabbix_proxy_dbhost_run_install: true +zabbix_proxy_privileged_host: localhost +zabbix_proxy_localbuffer: 0 # Will be deprecated in 2.0.0 +zabbix_proxy_proxylocalbuffer: "{{ zabbix_proxy_localbuffer }}" +zabbix_proxy_offlinebuffer: 1 # Will be deprecated in 2.0.0 +zabbix_proxy_proxyofflinebuffer: "{{ zabbix_proxy_offlinebuffer }}" +zabbix_proxy_heartbeatfrequency: 60 +zabbix_proxy_configfrequency: 3600 +zabbix_proxy_datasenderfrequency: 1 +zabbix_proxy_startpollers: 5 +zabbix_proxy_startipmipollers: 0 +zabbix_proxy_startpollersunreachable: 1 +zabbix_proxy_starttrappers: 5 +zabbix_proxy_startpingers: 1 +zabbix_proxy_startdiscoverers: 1 +zabbix_proxy_starthttppollers: 1 +zabbix_proxy_startpreprocessors: 3 +zabbix_proxy_javagateway: +zabbix_proxy_javagatewayport: 10052 +zabbix_proxy_startjavapollers: 5 +zabbix_proxy_startvmwarecollector: 0 +zabbix_proxy_vmwarefrequency: 60 +zabbix_proxy_vmwarecachesize: 8 +zabbix_proxy_snmptrapperfile: /tmp/zabbix_traps.tmp +zabbix_proxy_snmptrapper: 0 +zabbix_proxy_listenip: +zabbix_proxy_housekeepingfrequency: 1 +zabbix_proxy_cachesize: 8 +zabbix_proxy_startdbsyncers: 4 +zabbix_proxy_historycachesize: 8 +zabbix_proxy_historyindexcachesize: 4 +zabbix_proxy_historytextcachesize: 16 +zabbix_proxy_timeout: 3 +zabbix_proxy_trappertimeout: 300 +zabbix_proxy_unreachableperiod: 45 +zabbix_proxy_unavaliabledelay: 60 +zabbix_proxy_unreachabedelay: 15 +zabbix_proxy_externalscripts: /usr/lib/zabbix/externalscripts +zabbix_proxy_fpinglocation: /usr/sbin/fping +zabbix_proxy_fping6location: /usr/sbin/fping6 +zabbix_proxy_sshkeylocation: +zabbix_proxy_loglowqueries: 0 +zabbix_proxy_tmpdir: /tmp +zabbix_proxy_allowroot: 0 +zabbix_proxy_include: /etc/zabbix/zabbix_proxy.conf.d +zabbix_proxy_include_mode: "0755" +zabbix_proxy_libdir: /usr/lib/zabbix +zabbix_proxy_loadmodulepath: "{{ zabbix_proxy_libdir }}/modules" +zabbix_proxy_manage_service: true +zabbix_proxy_statsallowedip: "127.0.0.1" +zabbix_proxy_vaulttoken: +zabbix_proxy_vaulturl: https://127.0.0.1:8200 +zabbix_proxy_vaultdbpath: +zabbix_proxy_listenbacklog: + +# TLS settings +zabbix_proxy_tlsconnect: +zabbix_proxy_tlsaccept: +zabbix_proxy_tlscafile: +zabbix_proxy_tlscrlfile: +zabbix_proxy_tlsservercertissuer: +zabbix_proxy_tlsservercertsubject: +zabbix_proxy_tls_subject: "{{ zabbix_proxy_tlsservercertsubject }}" # FIXME this is not correct and should be removed with 2.0.0, here only to prevent regression +zabbix_proxy_tlscertfile: +zabbix_proxy_tlskeyfile: +zabbix_proxy_tlspskidentity: + +zabbix_proxy_tls_config: + no_encryption: "no_encryption" + psk: "PSK" + cert: "certificate" + +# Zabbix API stuff +zabbix_validate_certs: true # Will be deprecated in 2.0.0 +zabbix_api_validate_certs: "{{ zabbix_validate_certs }}" +zabbix_url: http://localhost # Will be deprecated in 2.0.0 +zabbix_api_server_url: "{{ zabbix_url }}" +zabbix_api_server_host: "{{ zabbix_api_server_url | urlsplit('hostname') }}" +zabbix_api_port_from_url: "{{ zabbix_api_server_port | default(zabbix_api_server_url | urlsplit('port')) }}" +zabbix_api_scheme_from_url: "{{ zabbix_api_server_url | urlsplit('scheme') }}" +zabbix_api_port_from_shema: "{{ (zabbix_api_scheme_from_url == 'https') | ternary(443, 80) }}" +# zabbix_http_user: admin # Will be deprecated in 2.0.0 +# zabbix_http_password: admin # Will be deprecated in 2.0.0 +# zabbix_api_http_user: admin +# zabbix_api_http_password: admin +zabbix_api_user: Admin # Will be deprecated in 2.0.0 +zabbix_api_pass: !unsafe zabbix # Will be deprecated in 2.0.0 +zabbix_api_login_user: "{{ zabbix_api_user }}" +zabbix_api_login_pass: "{{ zabbix_api_pass }}" +ansible_httpapi_pass: "{{ zabbix_api_login_pass }}" +ansible_httpapi_port: "{{ (zabbix_api_port_from_url == '') | ternary(zabbix_api_port_from_shema, zabbix_api_port_from_url) }}" +ansible_httpapi_use_ssl: "{{ zabbix_api_use_ssl | default((zabbix_api_scheme_from_url == 'https') | ternary(true, false)) }}" +ansible_httpapi_validate_certs: "{{ zabbix_api_validate_certs }}" +zabbix_api_create_proxy: false +zabbix_api_timeout: 30 +zabbix_create_proxy: present # or absent # Will be deprecated in 2.0.0 +zabbix_proxy_state: "{{ zabbix_create_proxy }}" +zabbix_proxy_status: active # or passive + +zabbix_useuip: 1 +zabbix_proxy_become_on_localhost: true +zabbix_proxy_interface: + useip: "{{ zabbix_useuip }}" + ip: "{{ zabbix_proxy_ip }}" + dns: "{{ ansible_fqdn }}" + port: "{{ zabbix_proxy_listenport }}" diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/files/install_semodule.bsx b/ansible_collections/community/zabbix/roles/zabbix_proxy/files/install_semodule.bsx Binary files differnew file mode 100755 index 000000000..d37320c9f --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/files/install_semodule.bsx diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml new file mode 100644 index 000000000..8f42133be --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml @@ -0,0 +1,29 @@ +--- +# handlers file for zabbix-proxy + +- name: restart zabbix-proxy + service: + name: zabbix-proxy + state: restarted + enabled: true + become: true + when: + - zabbix_proxy_manage_service | bool + - zabbix_repo != 'epel' + +- name: restart zabbix-proxy + service: + name: zabbix-proxy-mysql{{ zabbix_proxy_database_long }} + state: restarted + enabled: true + become: true + when: + - zabbix_proxy_manage_service | bool + - zabbix_repo == 'epel' + +- name: "clean repo files from proxy creds" + shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true + become: true + when: + - ansible_os_family == 'RedHat' + - zabbix_http_proxy is defined or zabbix_https_proxy is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/meta/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/meta/main.yml new file mode 100644 index 000000000..6f2052a5d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/meta/main.yml @@ -0,0 +1,27 @@ +--- +galaxy_info: + author: Werner Dijkerman + description: Installing and maintaining zabbix-proxy for RedHat/Debian/Ubuntu. + company: myCompany.Dotcom + license: MIT + min_ansible_version: 2.4 + platforms: + - name: EL + versions: + - 6 + - 7 + - name: Ubuntu + versions: + - lucid + - precise + - trusty + - name: Debian + versions: + - squeeze + - wheezy + - stretch + galaxy_tags: + - zabbix + - monitoring + +dependencies: [] diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/requirements.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/requirements.yml new file mode 100644 index 000000000..37db26ffa --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/requirements.yml @@ -0,0 +1,3 @@ +--- +- src: geerlingguy.mysql +- src: geerlingguy.postgresql diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml new file mode 100644 index 000000000..fae6b5b96 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml @@ -0,0 +1,294 @@ +--- +- name: "Include Zabbix gpg ids" + include_vars: zabbix.yml + +- name: "Set some variables" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + zabbix_proxy_apt_repository: + - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/" + - "{{ ansible_distribution_release }}" + - "main" + zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}" + zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}" + when: + - ansible_machine != "aarch64" + +- name: "Set some variables" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + zabbix_proxy_apt_repository: + - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}-arm64/" + - "{{ ansible_distribution_release }}" + - "main" + zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}" + zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}" + when: + - ansible_machine == "aarch64" + +- name: "Debian | Set some facts" + set_fact: + apache_log: apache2 + datafiles_path: "/usr/share/zabbix-proxy-{{ zabbix_proxy_database }}" + when: + - zabbix_version is version_compare('3.0', '<') + tags: + - zabbix-proxy + - init + - config + +- name: "Debian | Set some facts for Zabbix >= 3.0 && < 5.4" + set_fact: + apache_log: apache2 + datafiles_path: /usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }} + when: + - zabbix_version is version('3.0', '>=') + - zabbix_version is version('5.4', '<') + tags: + - zabbix-proxy + - init + - config + +- name: "Debian | Set some facts for Zabbix == 5.4" + set_fact: + datafiles_path: /usr/share/doc/zabbix-sql-scripts/{{ zabbix_proxy_database_long }} + when: + - zabbix_version is version('5.4', '==') + tags: + - zabbix-proxy + - init + - config + +- name: "Debian | Set some facts for Zabbix >= 6.0" + set_fact: + datafiles_path: /usr/share/zabbix-sql-scripts/{{ zabbix_proxy_database_long }} + when: + - zabbix_version is version('6.0', '>=') + tags: + - zabbix-proxy + - init + - config + +- name: "Debian | Installing gnupg" + apt: + pkg: gnupg + update_cache: true + cache_valid_time: 3600 + force: true + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: gnupg_installed + until: gnupg_installed is succeeded + become: true + +- name: "Debian | Install gpg key" + apt_key: + id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}" + url: http://repo.zabbix.com/zabbix-official-repo.key + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + when: + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-proxy + - init + +- name: "Debian | Installing repository {{ ansible_distribution }}" + apt_repository: + repo: "{{ item }} {{ zabbix_proxy_apt_repository | join(' ') }}" + state: present + when: zabbix_repo == "zabbix" + become: true + with_items: + - deb-src + - deb + tags: + - zabbix-proxy + - init + +- name: "Debian | Create /etc/apt/preferences.d/" + file: + path: /etc/apt/preferences.d/ + state: directory + mode: '0755' + when: + - zabbix_proxy_apt_priority | int + become: true + +- name: "Debian | Configuring the weight for APT" + copy: + dest: "/etc/apt/preferences.d/zabbix-proxy-{{ zabbix_proxy_database }}" + content: | + Package: zabbix-proxy-{{ zabbix_proxy_database }} + Pin: origin repo.zabbix.com + Pin-Priority: {{ zabbix_proxy_apt_priority }} + owner: root + mode: '0644' + when: + - zabbix_proxy_apt_priority | int + become: true + +- name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + +- name: apt-get clean + shell: apt-get clean; apt-get update + args: + warn: "{{ produce_warn | default(omit) }}" + changed_when: false + become: true + tags: + - skip_ansible_lint + +# On certain 18.04 images, such as docker or lxc, dpkg is configured not to +# install files into paths /usr/share/doc/* +# Since this is where Zabbix installs its database schemas, we need to allow +# files to be installed to /usr/share/doc/zabbix* +- name: Check for the dpkg exclude line + command: grep -F 'path-exclude=/usr/share/doc/*' /etc/dpkg/dpkg.cfg.d/excludes + register: dpkg_exclude_line + failed_when: false + changed_when: false + check_mode: false + +- name: Allow Zabbix dpkg installs to /usr/share/doc/zabbix* + lineinfile: + path: /etc/dpkg/dpkg.cfg.d/excludes + line: 'path-include=/usr/share/doc/zabbix*' + become: true + when: + - dpkg_exclude_line.rc == 0 + +- name: "Debian | Installing zabbix-proxy-{{ zabbix_proxy_database }}" + apt: + pkg: zabbix-proxy-{{ zabbix_proxy_database }} + state: "{{ zabbix_proxy_package_state }}" + update_cache: true + cache_valid_time: 0 + install_recommends: "{{ zabbix_proxy_install_recommends }}" + default_release: "{{ ansible_distribution_release }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_package_installed + until: zabbix_proxy_package_installed is succeeded + become: true + tags: + - zabbix-proxy + - init + +- name: "Debian | Installing zabbix-sql-scripts" + apt: + pkg: zabbix-sql-scripts + state: "{{ zabbix_proxy_package_state }}" + update_cache: true + cache_valid_time: 0 + default_release: "{{ ansible_distribution_release }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_package_sql_installed + until: zabbix_proxy_package_sql_installed is succeeded + when: + - zabbix_version is version('5.4', '>=') + become: true + tags: + - zabbix-proxy + - init + +- name: "Debian | Install Ansible module dependencies" + apt: + name: "{{ zabbix_python_prefix }}-psycopg2" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - zabbix_database_creation + tags: + - zabbix-proxy + - init + +- name: "Debian | Install Mysql Client package" + apt: + name: + - default-mysql-client + - "{{ zabbix_python_prefix }}-mysqldb" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - zabbix_proxy_database == 'mysql' + - zabbix_proxy_install_database_client + - ansible_distribution_release != "buster" + tags: + - zabbix-proxy + - init + - database + +- name: "Debian 10 | Install Mysql Client package" + apt: + name: + - mariadb-client + - "{{ zabbix_python_prefix }}-mysqldb" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - zabbix_proxy_database == 'mysql' + - zabbix_proxy_install_database_client + - ansible_distribution_release == "buster" + tags: + - zabbix-proxy + - init + - database + +- name: "Debian | Install PostgreSQL Client package" + apt: + name: postgresql-client + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + become: true + when: + - zabbix_database_creation or zabbix_database_sqlload + - zabbix_proxy_database == 'pgsql' + - zabbix_proxy_install_database_client + tags: + - zabbix-proxy + - init + - database + +- name: "Debian | Install sqlite3" + apt: + name: sqlite3 + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + become: true + when: + - zabbix_proxy_database == 'sqlite3' + tags: + - zabbix-proxy diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml new file mode 100644 index 000000000..34a40396e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml @@ -0,0 +1,323 @@ +--- +# Tasks specific for RedHat systems + +- name: "Set short version name" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + +- name: "RedHat | Use EPEL package name" + set_fact: + zabbix_proxy_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-proxy" + when: + - zabbix_repo == "epel" + tags: + - zabbix-proxy + - init + +- name: "RedHat | Define package with version" + set_fact: + zabbix_proxy_package: "zabbix{{ zabbix_short_version }}-proxy-{{ zabbix_proxy_database }}" + cacheable: true + when: + - zabbix_proxy_rhel_version is defined + - zabbix_repo != "epel" + +- name: "RedHat | Define package without version" + set_fact: + zabbix_proxy_package: "zabbix-proxy-{{ zabbix_proxy_database }}" + cacheable: true + when: + - zabbix_proxy_rhel_version is not defined + - zabbix_repo != "epel" + +- name: "RedHat | Set some facts Zabbix < 3.0" + set_fact: + apache_log: httpd + datafiles_path: "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}-{{ zabbix_version }}*/create" + when: + - zabbix_version is version('3.0', '<') + tags: + - zabbix-proxy + +- name: "RedHat | Set facts for Zabbix >= 3.0 && < 5.4" + set_fact: + apache_log: httpd + datafiles_path: "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}-{{ zabbix_version }}*" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_version is version('5.4', '<') + tags: + - zabbix-proxy + +- name: "RedHat | Set facts for Zabbix == 5.4" + set_fact: + datafiles_path: "/usr/share/doc/zabbix-sql-scripts/{{ zabbix_proxy_database_long }}" + when: + - zabbix_version is version('5.4', '==') + tags: + - zabbix-server + +- name: "RedHat | Set facts for Zabbix >= 6.0" + set_fact: + datafiles_path: "/usr/share/zabbix-sql-scripts/{{ zabbix_proxy_database_long }}" + when: + - zabbix_version is version('6.0', '>=') + tags: + - zabbix-server + +- name: "RedHat | Set facts for Zabbix >= 3.0 and RedHat 8" + set_fact: + apache_log: httpd + datafiles_path: "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_version is version('5.4', '<') + - ansible_distribution_major_version == '8' + tags: + - zabbix-proxy + +- name: "RedHat | Set some facts EPEL" + set_fact: + datafiles_path: "/usr/share/zabbix-{{ zabbix_proxy_database_long }}" + when: + - zabbix_repo == "epel" + tags: + - zabbix-server + +- name: "RedHat | Create 'zabbix' group (EPEL)" + group: + name: "{{ zabbix_proxy_groupname | default('zabbix') }}" + gid: "{{ zabbix_proxy_groupid | default(omit) }}" + state: present + become: true + when: + - zabbix_repo == "epel" + +- name: "RedHat | Create 'zabbix' user (EPEL)" + user: + name: "{{ zabbix_proxy_username | default('zabbix') }}" + comment: Zabbix Monitoring System + uid: "{{ zabbix_proxy_userid | default(omit) }}" + group: zabbix + become: true + when: + - zabbix_repo == "epel" + +- name: "Make sure old file is absent" + file: + path: /etc/yum.repos.d/zabbix-supported.repo + state: absent + become: true + +- name: "RedHat | Install basic repo file" + yum_repository: + name: "{{ item.name }}" + description: "{{ item.description }}" + baseurl: "{{ item.baseurl }}" + gpgcheck: "{{ item.gpgcheck }}" + gpgkey: "{{ item.gpgkey }}" + mode: "{{ item.mode | default('0644') }}" + priority: "{{ item.priority | default('98') }}" + state: "{{ item.state | default('present') }}" + proxy: "{{ zabbix_http_proxy | default(omit) }}" + with_items: "{{ zabbix_repo_yum }}" + register: yum_repo_installed + become: true + when: + - zabbix_repo == "zabbix" + notify: + - "clean repo files from proxy creds" + tags: + - zabbix-agent + +- name: "RedHat | Installing zabbix-proxy-{{ zabbix_proxy_database }}" + package: + pkg: "{{ zabbix_proxy_package }}-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}" + state: "{{ zabbix_proxy_package_state }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true + when: + zabbix_repo != "other" + register: is_zabbix_proxy_package_installed + until: is_zabbix_proxy_package_installed is succeeded + +- name: "RedHat | Installing zabbix-proxy-{{ zabbix_proxy_database }} (When zabbix_repo == other)" + package: + pkg: "{{ zabbix_proxy_package }}-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}" + state: "{{ zabbix_proxy_package_state }}" + become: true + when: + zabbix_repo == "other" + register: is_zabbix_proxy_package_installed + until: is_zabbix_proxy_package_installed is succeeded + +- name: "RedHat | Installing zabbix-sql-scripts" + package: + pkg: "zabbix-sql-scripts-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}" + state: "{{ zabbix_proxy_package_state }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_sql_package_installed + until: zabbix_proxy_sql_package_installed is succeeded + when: + - zabbix_version is version('5.4', '>=') + - zabbix_repo != "other" + become: true + tags: + - zabbix-server + +- name: "RedHat | Installing zabbix-sql-scripts (When zabbix_repo == other)" + package: + pkg: "zabbix-sql-scripts-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}" + state: "{{ zabbix_proxy_package_state }}" + register: zabbix_proxy_sql_package_installed + until: zabbix_proxy_sql_package_installed is succeeded + when: + - zabbix_version is version('5.4', '>=') + - zabbix_repo == "other" + become: true + tags: + - zabbix-server + +- name: "RedHat | Install Ansible PostgreSQL module dependencies" + yum: + name: python-psycopg2 + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + when: + - zabbix_database_creation or zabbix_database_sqlload + - zabbix_proxy_database == 'pgsql' + - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6" + tags: + - zabbix-proxy + - init + +- name: "RedHat | Install Ansible module dependencies on RHEL9 or RHEL8" + yum: + name: python3-psycopg2 + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - zabbix_database_creation + - zabbix_proxy_database == 'pgsql' + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-server + +- name: "RedHat | Install Mysql Client package RHEL7" + yum: + name: + - mariadb + - MySQL-python + state: installed + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + when: + - zabbix_database_creation or zabbix_database_sqlload + - zabbix_proxy_database == 'mysql' + - ansible_distribution_major_version == '7' + tags: + - zabbix-proxy + - init + +- name: "RedHat | Install Mysql Client packages RHEL9 or RHEL8" + yum: + name: + - mysql + - python3-PyMySQL + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - zabbix_proxy_database == 'mysql' + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-proxy + - init + +- name: "RedHat | Install Mysql Client package RHEL5 - 6" + yum: + name: + - mysql + - MySQL-python + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + when: + - zabbix_database_creation or zabbix_database_sqlload + - zabbix_proxy_database == 'mysql' + - ansible_distribution_major_version == "6" or ansible_distribution_major_version == "5" + - zabbix_proxy_install_database_client + tags: + - zabbix-proxy + - init + - database + +- name: "RedHat | Install PostgreSQL client package" + yum: + name: postgresql + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + become: true + register: are_zabbix_proxy_dependency_packages_installed + until: are_zabbix_proxy_dependency_packages_installed is succeeded + when: + - zabbix_database_creation or zabbix_database_sqlload + - zabbix_proxy_database == 'pgsql' + - zabbix_proxy_install_database_client + tags: + - zabbix-proxy + - init + - database + +- name: "RedHat | Install sqlite3" + yum: + name: + - sqlite + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - zabbix_proxy_database == 'sqlite3' + tags: + - zabbix-proxy + +- name: "Configure SELinux when enabled" + include_tasks: selinux.yml + when: + - zabbix_selinux | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml new file mode 100644 index 000000000..bd39b5b8a --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml @@ -0,0 +1,138 @@ +--- +# tasks file for zabbix_proxy +- name: "Include OS-specific variables" + include_vars: "{{ ansible_os_family }}.yml" + +- name: Determine Latest Supported Zabbix Version + set_fact: + zabbix_proxy_version: "{{ zabbix_valid_proxy_versions[ansible_distribution_major_version][0] | default(6.0) }}" + when: zabbix_proxy_version is not defined + +- name: "Replace Sangoma with RedHat task" + set_fact: + ansible_os_family: "RedHat" + when: + - ansible_os_family == 'Sangoma' + +- name: "Set default ip address for zabbix_proxy_ip" + set_fact: + zabbix_proxy_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4'].address }}" + when: + - zabbix_proxy_ip is not defined + - "'ansible_default_ipv4' in hostvars[inventory_hostname]" + +- name: "Set OS dependent variables" + include_vars: "{{ item }}" + with_first_found: + - "../vars/{{ ansible_distribution }}.yml" + - "../vars/main.yml" + +- name: "Install the correct repository" + include_tasks: "{{ ansible_os_family }}.yml" + +- name: "Installing the {{ zabbix_proxy_database_long }} database" + include_tasks: "{{ zabbix_proxy_database_long }}.yml" + +- name: "Create include dir zabbix-proxy" + file: + path: "{{ zabbix_proxy_include }}" + owner: zabbix + group: zabbix + mode: "{{ zabbix_proxy_include_mode }}" + state: directory + become: true + +- name: "Create module dir zabbix-proxy" + file: + path: "{{ zabbix_proxy_loadmodulepath }}" + owner: zabbix + group: zabbix + state: directory + mode: "0755" + become: true + +- name: "Create directory for PSK file if not exist." + file: + path: "{{ zabbix_proxy_tlspskfile | dirname }}" + mode: 0755 + state: directory + become: true + when: + - zabbix_proxy_tlspskfile is defined + +- name: "Place TLS PSK File" + copy: + dest: "{{ zabbix_proxy_tlspskfile }}" + content: "{{ zabbix_proxy_tlspsk_secret }}" + owner: zabbix + group: zabbix + mode: 0400 + become: true + when: + - zabbix_proxy_tlspskfile is defined + - zabbix_proxy_tlspsk_secret is defined + notify: + - restart zabbix-proxy + +- name: "Allow zabbix-proxy to open connections (SELinux)" + ansible.posix.seboolean: + name: zabbix_can_network + persistent: true + state: true + become: true + when: ansible_selinux.status == "enabled" + tags: selinux + +- name: "Allow zabbix-proxy to connect to zabbix_proxy_preprocessing.sock (SELinux)" + ansible.posix.seboolean: + name: daemons_enable_cluster_mode + persistent: true + state: true + become: true + when: ansible_selinux.status == "enabled" + tags: selinux + +- name: "Configure zabbix-proxy" + template: + src: zabbix_proxy.conf.j2 + dest: /etc/zabbix/zabbix_proxy.conf + owner: zabbix + group: zabbix + mode: "{{ zabbix_proxy_conf_mode }}" + notify: restart zabbix-proxy + become: true + +- name: Ensure proxy definition is up-to-date (added/updated/removed) + vars: + gather_facts: false + ansible_user: "{{ zabbix_api_login_user }}" + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + # Can't think of a way to make http_login_* vars be undefined -( + http_login_user: "{{ zabbix_api_http_user | default(zabbix_http_user | default(-42)) }}" + http_login_password: "{{ zabbix_api_http_password | default(zabbix_http_password | default(-42)) }}" + community.zabbix.zabbix_proxy: + state: "{{ zabbix_proxy_state }}" + status: "{{ zabbix_proxy_status }}" + proxy_name: "{{ zabbix_proxy_name }}" + description: "{{ zabbix_proxy_description | default(omit) }}" + interface: "{{ zabbix_proxy_interface }}" + tls_psk: "{{ zabbix_proxy_tlspsk_secret | default(omit) }}" + tls_psk_identity: "{{ zabbix_proxy_tlspskidentity | default(omit) }}" + tls_subject: "{{ zabbix_proxy_tls_subject | default(omit) }}" + tls_connect: "{{ zabbix_proxy_tls_config[zabbix_proxy_tlsaccept if zabbix_proxy_tlsaccept else 'no_encryption'] }}" + tls_accept: "{{ zabbix_proxy_tls_config[zabbix_proxy_tlsconnect if zabbix_proxy_tlsconnect else 'no_encryption'] }}" + when: + - zabbix_api_create_proxy | bool + delegate_to: "{{ zabbix_api_server_host }}" + become: false + tags: + - api + +- name: "zabbix-proxy started" + service: + name: zabbix-proxy + state: started + enabled: true + become: true + when: zabbix_proxy_manage_service | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml new file mode 100644 index 000000000..6d699ea83 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml @@ -0,0 +1,176 @@ +--- +# task file for mysql +- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ zabbix_proxy_dbhost if (zabbix_proxy_dbhost != 'localhost') else inventory_hostname }}" + when: + - zabbix_proxy_dbhost_run_install + +- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ inventory_hostname }}" + when: + - not zabbix_proxy_dbhost_run_install + +- name: "Override delegated_dbhost with real dbhost when dbhost is behind loadbalancer" + set_fact: + delegated_dbhost: "{{ zabbix_proxy_real_dbhost }}" + when: zabbix_proxy_real_dbhost | default(false) + +- name: "MySQL | Create database" + community.mysql.mysql_db: + name: "{{ zabbix_proxy_dbname }}" + encoding: "{{ zabbix_proxy_dbencoding }}" + collation: "{{ zabbix_proxy_dbcollation }}" + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + state: present + when: zabbix_database_creation + register: zabbix_database_created + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-proxy + - database + - skip_ansible_lint + +- name: "MySQL | Create database user" + community.mysql.mysql_user: + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + name: "{{ zabbix_proxy_dbuser }}" + password: "{{ zabbix_proxy_dbpassword }}" + priv: "{{ zabbix_proxy_dbname }}.*:ALL" + host: "{{ zabbix_proxy_privileged_host }}" + state: present + when: zabbix_database_creation + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-proxy + - database + +- name: "Get the file for schema.sql" + shell: ls -1 {{ datafiles_path }}/{{ 'schema' if zabbix_version is version('6.0', '<') else 'proxy' }}.sq* + changed_when: false + when: + - zabbix_database_sqlload + - zabbix_repo != "epel" + register: ls_output_create + tags: + - zabbix-proxy + - database + +- name: "Check if we have done files" + stat: + path: /etc/zabbix/schema.done + register: done_file + when: + - zabbix_database_sqlload + - zabbix_repo != "epel" + +- name: "MySQL | Get version_comment" + community.mysql.mysql_variables: + variable: version + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + delegate_to: "{{ delegated_dbhost }}" + register: install_mysql_version + tags: + - zabbix-proxy + - database + +- name: "MySQL | Get current value for innodb_default_row_format" + community.mysql.mysql_variables: + variable: innodb_default_row_format + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + delegate_to: "{{ delegated_dbhost }}" + register: mysql_innodb_default_row_format + when: + - install_mysql_version.msg is version('5.6', '>=') + tags: + - zabbix-proxy + - database + +- name: "MySQL | Set innodb_default_row_format to dynamic" + community.mysql.mysql_variables: + variable: innodb_default_row_format + value: dynamic + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - not done_file.stat.exists + - install_mysql_version.msg is version('5.6', '>=') + - mysql_innodb_default_row_format.msg != 'dynamic' + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-proxy + - database + +- name: "MySQL | Create database and import file" + community.mysql.mysql_db: + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + name: "{{ zabbix_proxy_dbname }}" + encoding: "{{ zabbix_proxy_dbencoding }}" + collation: "{{ zabbix_proxy_dbcollation }}" + state: import + target: "{{ ls_output_create.stdout }}" + when: + - zabbix_database_sqlload + - zabbix_repo != "epel" + - not done_file.stat.exists + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-proxy + - database + +- name: "MySQL | Revert innodb_default_row_format to previous value" + community.mysql.mysql_variables: + variable: innodb_default_row_format + value: '{{ mysql_innodb_default_row_format.msg }}' + login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - not done_file.stat.exists + - mysql_innodb_default_row_format.msg != 'dynamic' + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-proxy + - database + +- name: "Create done file" + file: + path: /etc/zabbix/schema.done + state: touch + mode: '0644' + when: + - zabbix_database_sqlload + - zabbix_repo != "epel" + - not done_file.stat.exists diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml new file mode 100644 index 000000000..f32618d94 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml @@ -0,0 +1,92 @@ +--- +# task file for postgresql + +- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ zabbix_proxy_dbhost if (zabbix_proxy_dbhost != 'localhost') else inventory_hostname }}" + when: + - zabbix_proxy_dbhost_run_install + +- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ inventory_hostname }}" + when: + - not zabbix_proxy_dbhost_run_install + +- name: "PostgreSQL | Delegated" + block: + - name: "PostgreSQL | Delegated | Create database" + community.postgresql.postgresql_db: + name: "{{ zabbix_proxy_dbname }}" + port: "{{ zabbix_proxy_dbport }}" + state: present + - name: "PostgreSQL | Delegated | Create database user" + postgresql_user: + db: "{{ zabbix_proxy_dbname }}" + name: "{{ zabbix_proxy_dbuser }}" + password: "{{ ('md5' + (zabbix_proxy_dbpassword + zabbix_proxy_dbuser)|hash('md5')) if zabbix_proxy_dbpassword_hash_method == 'md5' else zabbix_proxy_dbpassword }}" + port: "{{ zabbix_proxy_dbport }}" + priv: ALL + state: present + encrypted: true + become: true + become_user: postgres + delegate_to: "{{ delegated_dbhost }}" + when: + - zabbix_database_creation + - zabbix_proxy_pgsql_login_host is not defined + tags: + - zabbix-proxy + - database + +- name: "PostgreSQL | Remote" + block: + - name: "PostgreSQL | Remote | Create database" + community.postgresql.postgresql_db: + login_host: "{{ zabbix_proxy_pgsql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_pgsql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_pgsql_login_password | default(omit) }}" + login_unix_socket: "{{ zabbix_proxy_pgsql_login_unix_socket | default(omit) }}" + name: "{{ zabbix_proxy_dbname }}" + port: "{{ zabbix_proxy_dbport }}" + state: present + - name: "PostgreSQL | Remote | Create database user" + postgresql_user: + login_host: "{{ zabbix_proxy_pgsql_login_host | default(omit) }}" + login_user: "{{ zabbix_proxy_pgsql_login_user | default(omit) }}" + login_password: "{{ zabbix_proxy_pgsql_login_password | default(omit) }}" + db: "{{ zabbix_proxy_dbname }}" + name: "{{ zabbix_proxy_dbuser }}" + password: "{{ ('md5' + (zabbix_proxy_dbpassword + zabbix_proxy_dbuser)|hash('md5')) if zabbix_proxy_dbpassword_hash_method == 'md5' else zabbix_proxy_dbpassword }}" + port: "{{ zabbix_proxy_dbport }}" + priv: ALL + state: present + encrypted: true + when: + - zabbix_database_creation + - zabbix_proxy_pgsql_login_host is defined + tags: + - zabbix-proxy + - database + +- name: "PostgreSQL | Importing schema file" + shell: | + set -euxo pipefail + FILE={{ 'schema.sql' if zabbix_version is version('6.0', '<') else 'proxy.sql' }} + cd {{ datafiles_path }} + if [ -f ${FILE}.gz ] + then zcat ${FILE}.gz > /tmp/schema.sql + else + cp ${FILE} /tmp/schema.sql + fi + cat /tmp/schema.sql | psql -h '{{ zabbix_proxy_dbhost }}' -U '{{ zabbix_proxy_dbuser }}' \ + -d '{{ zabbix_proxy_dbname }}' + touch /etc/zabbix/schema.done + rm -f /tmp/schema.sql + args: + creates: /etc/zabbix/schema.done + executable: /bin/bash + environment: + PGPASSWORD: '{{ zabbix_proxy_dbpassword }}' + when: + - zabbix_database_creation diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml new file mode 100644 index 000000000..02fb4ebaf --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml @@ -0,0 +1,50 @@ +--- + +- name: "SELinux | RedHat | Install related SELinux package to fix issues" + yum: + name: + - policycoreutils-python + - libsemanage-python + - checkpolicy + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6" + tags: + - zabbix-proxy + +- name: "SELinux | RedHat | Install related SELinux package to fix issues on RHEL8" + yum: + name: + - policycoreutils + - checkpolicy + - python3-libsemanage + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_proxy_dependencies_installed + until: zabbix_proxy_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-proxy + +- name: "SELinux | RedHat | Add SEmodule to fix SELinux issue: zabbix_proxy_alerter.sock" + script: + cmd: files/install_semodule.bsx + args: + creates: /etc/selinux/targeted/active/modules/400/zabbix_proxy_add/cil + become: true + when: + - ansible_os_family == "RedHat" + tags: + - zabbix-proxy diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml new file mode 100644 index 000000000..03fbf6fb3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml @@ -0,0 +1,57 @@ +--- +# task file for sqlite3 + +- name: "Sqlite3 | Default Database Path" + set_fact: + zabbix_proxy_dbname: /var/lib/zabbix/zabbix_proxy.db + when: + - zabbix_proxy_dbname == "zabbix_proxy" + +- name: "Sqlite3 | Create database" + file: + name: "{{ zabbix_proxy_dbname | dirname }}" + mode: 0744 + owner: zabbix + group: zabbix + seuser: system_u + serole: object_r + setype: zabbix_var_lib_t + state: directory + become: true + when: + - zabbix_database_creation + +- name: "Sqlite3 | Importing schema file" + become: true + become_user: zabbix + shell: | + set -o pipefail + FILE={{ 'schema.sql' if zabbix_version is version('6.0', '<') else 'proxy.sql' }} + cd {{ datafiles_path }} + if [ -f ${FILE}.gz ] + then zcat ${FILE}.gz > /tmp/schema.sql + else + cp ${FILE} /tmp/schema.sql + fi + cat /tmp/schema.sql | sqlite3 {{ zabbix_proxy_dbname }} + rm -f /tmp/schema.sql + args: + creates: "{{ zabbix_proxy_dbname }}" + executable: /bin/bash + environment: + PGPASSWORD: '{{ zabbix_proxy_dbpassword }}' + when: + - zabbix_database_creation + +- name: "Fix zabbix db file permission (SELinux)" + file: + path: "{{ zabbix_proxy_dbname }}" + state: file + seuser: system_u + serole: object_r + setype: zabbix_var_lib_t + become: true + when: + - ansible_selinux.status == "enabled" + - zabbix_database_creation + tags: selinux diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2 new file mode 100644 index 000000000..b61842d12 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2 @@ -0,0 +1,200 @@ +{{ ansible_managed | comment }} +# This is a configuration file for Zabbix Proxy process +# To get more information about Zabbix, visit http://www.zabbix.com + +# This configuration file is "minimalized", which means all the original comments +# are removed. The full documentation for your Zabbix Proxy can be found here: +# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_proxy + +ProxyMode={{ zabbix_proxy_mode }} +Server={{ zabbix_proxy_server }} +{% if zabbix_version is version('6.0', '<') %} +ServerPort={{ zabbix_proxy_serverport }} +{% endif %} +{% if zabbix_proxy_hostname is defined and zabbix_proxy_hostname %} +Hostname={{ zabbix_proxy_hostname }} +{% endif %} +{% if zabbix_proxy_hostnameitem is defined and zabbix_proxy_hostnameitem %} +HostnameItem={{ zabbix_proxy_hostnameitem }} +{% endif %} +ListenPort={{ zabbix_proxy_listenport }} +{% if zabbix_proxy_sourceip is defined and zabbix_proxy_sourceip %} +SourceIP={{ zabbix_proxy_sourceip }} +{% endif %} +{% if zabbix_version is version('6.0', '>=') %} +LogType={{ zabbix_proxy_logtype }} +{% endif %} +LogFile={{ zabbix_proxy_logfile }} +LogFileSize={{ zabbix_proxy_logfilesize }} +EnableRemoteCommands={{ zabbix_proxy_enableremotecommands }} +DebugLevel={{ zabbix_proxy_debuglevel }} +PidFile={{ zabbix_proxy_pidfile }} +{% if zabbix_version is version('3.2', '>') %} +SocketDir={{ zabbix_proxy_socketdir }} +{% endif %} +DBHost={{ zabbix_proxy_dbhost }} +DBName={{ zabbix_proxy_dbname }} +{% if zabbix_proxy_dbschema is defined and zabbix_proxy_dbschema %} +DBSchema={{ zabbix_proxy_dbschema }} +{% endif %} +DBUser={{ zabbix_proxy_dbuser }} +DBPassword={{ zabbix_proxy_dbpassword }} +DBPort={{ zabbix_proxy_dbport }} +{% if zabbix_version is version('6.0', '>=') %} +AllowUnsupportedDBVersions={{ zabbix_proxy_allowunsupporteddbversions }} +{% endif %} +ProxyLocalBuffer={{ zabbix_proxy_proxylocalbuffer }} +ProxyOfflineBuffer={{ zabbix_proxy_proxyofflinebuffer }} +{% if zabbix_version is version('6.4', '<') %} +HeartbeatFrequency={{ zabbix_proxy_heartbeatfrequency }} +{% endif %} +{% if zabbix_proxy_configfrequency is defined and zabbix_proxy_configfrequency is not none %} +{% if zabbix_version is version('6.4', '<') %} +ConfigFrequency={{ zabbix_proxy_configfrequency }} +{% else %} +ProxyConfigFrequency={{ zabbix_proxy_configfrequency }} +{% endif %} +{% else %} +{% if zabbix_version is version('6.2', '<') %} +ConfigFrequency=3600 +{% elif zabbix_version is version('6.4', '<') %} +ConfigFrequency=300 +{% else %} +ProxyConfigFrequency=10 +{% endif %} +{% endif %} +DataSenderFrequency={{ zabbix_proxy_datasenderfrequency }} +StartPollers={{ zabbix_proxy_startpollers }} +StartIPMIPollers={{ zabbix_proxy_startipmipollers }} +{% if zabbix_version is version('4.2', '>=') %} +StartPreprocessors={{ zabbix_proxy_startpreprocessors }} +{% endif %} +StartPollersUnreachable={{ zabbix_proxy_startpollersunreachable }} +StartTrappers={{ zabbix_proxy_starttrappers }} +StartPingers={{ zabbix_proxy_startpingers }} +StartDiscoverers={{ zabbix_proxy_startdiscoverers }} +StartHTTPPollers={{ zabbix_proxy_starthttppollers }} +{% if zabbix_proxy_javagateway is defined and zabbix_proxy_javagateway %} +JavaGateway={{ zabbix_proxy_javagateway }} +JavaGatewayPort={{ zabbix_proxy_javagatewayport }} +StartJavaPollers={{ zabbix_proxy_startjavapollers }} +{% endif %} +{% if zabbix_version is version_compare('2.4', '>=') %} +StartVMwareCollectors={{ zabbix_proxy_startvmwarecollector }} +VMwareFrequency={{ zabbix_proxy_vmwarefrequency }} +VMwareCacheSize={{ zabbix_proxy_vmwarecachesize -}}M +{% endif %} +SNMPTrapperFile={{ zabbix_proxy_snmptrapperfile }} +StartSNMPTrapper={{ zabbix_proxy_snmptrapper }} +{% if zabbix_proxy_listenip is defined and zabbix_proxy_listenip %} +ListenIP={{ zabbix_proxy_listenip }} +{% endif %} +HousekeepingFrequency={{ zabbix_proxy_housekeepingfrequency }} +CacheSize={{ zabbix_proxy_cachesize -}}M +StartDBSyncers={{ zabbix_proxy_startdbsyncers }} +HistoryCacheSize={{ zabbix_proxy_historycachesize -}}M +{% if zabbix_version is version_compare('3.2', '>=') %} +HistoryIndexCacheSize={{ zabbix_proxy_historyindexcachesize -}}M +{% endif %} +{% if zabbix_version is version_compare('2.4', '<') %} +HistoryTextCacheSize={{ zabbix_proxy_historytextcachesize -}}M +{% endif %} +Timeout={{ zabbix_proxy_timeout }} +TrapperTimeout={{ zabbix_proxy_trappertimeout }} +UnreachablePeriod={{ zabbix_proxy_unreachableperiod }} +UnavailableDelay={{ zabbix_proxy_unavaliabledelay }} +UnreachableDelay={{ zabbix_proxy_unreachabedelay }} +{% if zabbix_version is version_compare('6.2', '>=') %} +StartODBCPollers={{ zabbix_proxy_startodbcpollers }} +{% endif %} +ExternalScripts={{ zabbix_proxy_externalscripts }} +FpingLocation={{ zabbix_proxy_fpinglocation }} +Fping6Location={{ zabbix_proxy_fping6location }} +{% if zabbix_proxy_sshkeylocation is defined and zabbix_proxy_sshkeylocation %} +SSHKeyLocation={{ zabbix_proxy_sshkeylocation }} +{% endif %} +LogSlowQueries={{ zabbix_proxy_loglowqueries }} +TmpDir={{ zabbix_proxy_tmpdir }} +{% if zabbix_version is version_compare('2.4', '<') %} +AllowRoot={{ zabbix_proxy_allowroot }} +{% endif %} +Include={{ zabbix_proxy_include }} +{% if zabbix_version is version_compare('3.0', '<') %} +LoadModulePath={{ zabbix_proxy_loadmodulepath }} +{% endif %} +{% if zabbix_proxy_loadmodule is defined and zabbix_proxy_loadmodule %} +LoadModule={{ zabbix_proxy_loadmodule }} +{% endif %} +{% if zabbix_version is version_compare('4.0', '>=') %} +StatsAllowedIP={{ zabbix_proxy_statsallowedip }} +{% endif %} +{% if zabbix_version is version_compare('3.0', '>=') %} +{% if zabbix_proxy_tlsconnect is defined and zabbix_proxy_tlsconnect %} +TLSConnect={{ zabbix_proxy_tlsconnect }} +{% endif %} +{% if zabbix_proxy_tlsaccept is defined and zabbix_proxy_tlsaccept %} +TLSAccept={{ zabbix_proxy_tlsaccept }} +{% endif %} +{% if zabbix_proxy_tlscafile is defined and zabbix_proxy_tlscafile %} +TLSCAFile={{ zabbix_proxy_tlscafile }} +{% endif %} +{% if zabbix_proxy_tlscrlfile is defined and zabbix_proxy_tlscrlfile %} +TLSCRLFile={{ zabbix_proxy_tlscrlfile }} +{% endif %} +{% if zabbix_proxy_tlsservercertissuer is defined and zabbix_proxy_tlsservercertissuer %} +TLSServerCertIssuer={{ zabbix_proxy_tlsservercertissuer }} +{% endif %} +{% if zabbix_proxy_tlsservercertsubject is defined and zabbix_proxy_tlsservercertsubject %} +TLSServerCertSubject={{ zabbix_proxy_tlsservercertsubject }} +{% endif %} +{% if zabbix_proxy_tlscertfile is defined and zabbix_proxy_tlscertfile %} +TLSCertFile={{ zabbix_proxy_tlscertfile }} +{% endif %} +{% if zabbix_proxy_tlskeyfile is defined and zabbix_proxy_tlskeyfile %} +TLSKeyFile={{ zabbix_proxy_tlskeyfile }} +{% endif %} +{% if zabbix_proxy_tlspskidentity is defined and zabbix_proxy_tlspskidentity %} +TLSPSKIdentity={{ zabbix_proxy_tlspskidentity }} +{% endif %} +{% if zabbix_proxy_tlspskfile is defined and zabbix_proxy_tlspskfile %} +TLSPSKFile={{ zabbix_proxy_tlspskfile }} +{% endif %} +{% endif %} +{% if zabbix_proxy_dbtlsconnect is defined and zabbix_proxy_dbtlsconnect is not none %} +DBTLSConnect={{ zabbix_proxy_dbtlsconnect }} +{% endif %} +{% if zabbix_proxy_dbtlscafile is defined and zabbix_proxy_dbtlscafile is not none %} +DBTLSCAFile={{ zabbix_proxy_dbtlscafile }} +{% endif %} +{% if zabbix_proxy_dbtlscertfile is defined and zabbix_proxy_dbtlscertfile is not none %} +DBTLSCertFile={{ zabbix_proxy_dbtlscertfile }} +{% endif %} +{% if zabbix_proxy_dbtlskeyfile is defined and zabbix_proxy_dbtlskeyfile is not none %} +DBTLSKeyFile={{ zabbix_proxy_dbtlskeyfile }} +{% endif %} +{% if zabbix_proxy_dbtlscipher is defined and zabbix_proxy_dbtlscipher is not none %} +DBTLSCipher={{ zabbix_proxy_dbtlscipher }} +{% endif %} +{% if zabbix_proxy_dbtlscipher13 is defined and zabbix_proxy_dbtlscipher13 is not none %} +DBTLSCipher13={{ zabbix_proxy_dbtlscipher13 }} +{% endif %} +{% if zabbix_version is version('6.0', '>=') %} +{% if zabbix_proxy_vaulttoken is defined and zabbix_proxy_vaulttoken is not none %} +VaultToken={{ zabbix_proxy_vaulttoken }} +{% endif %} +{% if zabbix_proxy_vaulturl is defined and zabbix_proxy_vaulturl is not none %} +VaultURL={{ zabbix_proxy_vaulturl }} +{% endif %} +{% if zabbix_proxy_vaultdbpath is defined and zabbix_proxy_vaultdbpath is not none %} +VaultDBPath={{ zabbix_proxy_vaultdbpath }} +{% endif %} +{% if zabbix_proxy_vaulttlscertfile is defined and zabbix_proxy_vaulttlscertfile is not none %} +VaultTLSKeyFile={{ zabbix_proxy_vaulttlscertfile }} +{% endif %} +{% if zabbix_proxy_vaulttlskeyfile is defined and zabbix_proxy_vaulttlskeyfile is not none %} +VaultTLSCertFile={{ zabbix_proxy_vaulttlskeyfile }} +{% endif %} +{% if zabbix_proxy_listenbacklog is defined and zabbix_proxy_listenbacklog is not none %} +ListenBacklog={{ zabbix_proxy_listenbacklog }} +{% endif %} +{% endif %} diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml new file mode 100644 index 000000000..605be3896 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml @@ -0,0 +1,2 @@ +--- +ansible_distribution_major_version: "6" diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml new file mode 100644 index 000000000..2c87e2d61 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml @@ -0,0 +1,26 @@ +zabbix_valid_proxy_versions: + # Debian + "11": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "10": + - 6.0 + - 5.0 + - 4.0 + "9": + - 4.0 + # Ubuntu + "22": + - 6.4 + - 6.0 + "20": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "18": + - 6.0 + - 5.0 + - 4.0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml new file mode 100644 index 000000000..31da6800f --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml @@ -0,0 +1,12 @@ +zabbix_valid_proxy_versions: + "9": + - 6.4 + - 6.0 + "8": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "7": + - 5.0 + - 4.0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml new file mode 100644 index 000000000..ea434bdc4 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for zabbix_proxy diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml new file mode 100644 index 000000000..7ac7dc354 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml @@ -0,0 +1,255 @@ +--- +sign_keys: + "64": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "62": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "60": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "54": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "52": + # bullseye: not available upstream + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "50": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "44": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "42": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "40": + bullseye: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "34": + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "32": + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + sonya: + sign_key: 79EA5ED4 + serena: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "30": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "24": + jessie: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + "22": + squeeze: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + lucid: + sign_key: 79EA5ED4 + +suse: + "openSUSE Leap": + "42": + name: server:monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/ + "openSUSE": + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }} + "SLES": + "11": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/ diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/README.md b/ansible_collections/community/zabbix/roles/zabbix_server/README.md new file mode 100644 index 000000000..4643fbc3f --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/README.md @@ -0,0 +1,385 @@ +# community.zabbix.zabbix_server role + +![Zabbix Server](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_server/badge.svg) + +**Table of Contents** + +- [Overview](#overview) +- [Requirements](#requirements) + * [Operating systems](#operating-systems) + * [Zabbix Versions](#zabbix-versions) +- [Installation](#installation) +- [Role Variables](#role-variables) + * [Main variables](#main-variables) + + [Overall Zabbix](#overall-zabbix) + + [SElinux](#selinux) + + [Zabbix Server](#zabbix-server) + + [Database specific](#database-specific) + + [TLS Specific configuration](#tls-specific-configuration) + + [Custom Zabbix Scripts](#custom-zabbix-scripts) + * [proxy](#proxy) + * [Database](#database) + + [MySQL](#mysql) + - [Local Setup](#local-setup) + - [Separate Setup](#separate-setup) + + [PostgreSQL](#postgresql) + - [Local Setup](#local-setup-1) + - [Separate Setup](#separate-setup-1) +- [Example Playbook](#example-playbook) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +This is a Ansible role for installing and maintaining the zabbix-server. This will only install the Zabbix Server component and not the Zabbix Web. + +# Requirements + +## Operating systems + +This role will work on the following operating systems: + + * Red Hat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collection is now required: `ansible.posix`. Installing the collection: + +```sh +ansible-galaxy collection install ansible.posix +``` + +### MySQL + +When you are a MySQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.mysql`. This collections are needed as the `mysql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.mysql +``` + +### PostgreSQL + +When you are a PostgreSQL user and using Ansible 2.10 or newer, then there is a dependency on the collection named `community.postgresql`. This collections are needed as the `postgresql_` modules are now part of collections and not standard in Ansible anymmore. Installing the collection: + +```sh +ansible-galaxy collection install community.postgresql +``` + +## Zabbix Versions + +See the following list of supported Operating systems with the Zabbix releases: + +| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | | | | | | V | V | V | V | +| Red Hat Fam 6 | | | | | V | V | | | V | +| Red Hat Fam 5 | | | | | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | | +| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | | V | V | V | V | V | +| Debian 10 buster | | | V | V | V | V | V | | | +| Debian 9 stretch | | | V | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +See https://support.zabbix.com/browse/ZBX-18790 why RHEL7 is not supported anymore. + +# Installation + +Installing this role is very simple: `ansible-galaxy install community.zabbix.zabbix_server` + +Please be aware that this role only installs the Zabbix Server and not the Zabbix Web. If you do want to have a Zabbix Web, please execute the following command: `ansible-galaxy install community.zabbix.zabbix_web` + +# Role Variables + +## Main variables + +The following is an overview of all available configuration default for this role. + +### Overall Zabbix + +* `zabbix_server_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_server_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. +* `zabbix_service_state`: Default: `started`. Can be overridden to stopped if needed +* `zabbix_service_enabled`: Default: `True` Can be overridden to `False` if needed + +### SElinux + +* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the server will run. +* `selinux_allow_zabbix_can_network`: Default: `False`. +* `selinux_allow_zabbix_can_http`: Default: `False`. + +### Zabbix Server + +* `zabbix_server_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed. +* `zabbix_server_listenport`: Default: `10051`. On which port the Zabbix Server is available. +* `zabbix_server_install_recommends`: Default: `True`. `False` does not install the recommended packages that come with the zabbix-server install. +* `zabbix_server_manage_service`: Default: `True`. When you run multiple Zabbix servers in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-server service, because Pacemaker is in control of zabbix-server service and in this case, it needs to be set to `False`. +* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started. This parameter is supported since Zabbix 4.2.0. +* `zabbix_server_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used. +* `zabbix_server_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_server_include`. +* `zabbix_server_conf_mode`: Default: `0640`. The "mode" for the Zabbix configuration file. +* `zabbix_server_listenbacklog`: The maximum number of pending connections in the queue. +* `zabbix_server_trendcachesize`: Size of trend cache, in bytes. +* `zabbix_server_trendfunctioncachesize`: Size of trend function cache, in bytes. +* `zabbix_server_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission +* `zabbix_server_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified. +* `zabbix_server_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'. +* `zabbix_server_startreportwriters`: Number of pre-forked report writer instances. +* `zabbix_server_webserviceurl`: URL to Zabbix web service, used to perform web related tasks. +* `zabbix_server_servicemanagersyncfrequency`: How often Zabbix will synchronize configuration of a service manager (in seconds). +* `zabbix_server_problemhousekeepingfrequency`: How often Zabbix will delete problems for deleted triggers (in seconds). +* `zabbix_server_connectors`: Number of pre-forked instances of preprocessing workers. + +### High Availability + +These variables are specific for Zabbix 6.0 and higher: + +* `zabbix_server_hanodename`: The high availability cluster node name. When empty, server is working in standalone mode; a node with empty name is registered with address for the frontend to connect to. (Default: empty) +* `zabbix_server_nodeaddress`: IP or hostname with optional port to specify how frontend should connect to the server. + +### Database specific + +* `zabbix_server_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database. +* `zabbix_server_database`: Default: `pgsql`. The type of database used. Can be: `mysql` or `pgsql` +* `zabbix_server_database_long`: Default: `postgresql`. The type of database used, but long name. Can be: `mysql` or `postgresql` +* `zabbix_server_dbhost`: The hostname on which the database is running. +* `zabbix_server_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections) +* `zabbix_server_dbname`: The database name which is used by the Zabbix Server. +* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server. +* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server. +* `zabbix_server_dbport`: The database port which is used by the Zabbix Server. +* `zabbix_server_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`. +* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False. +* `zabbix_server_install_database_client`: Default: `True`. False does not install database client. Default true +* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False. +* `zabbix_database_timescaledb`:False / True. When you want to use timescaledb extension into the database, you can set it to True (this option only works for postgreSQL database). +* `zabbix_server_dbencoding`: Default: `utf8`. The encoding for the MySQL database. +* `zabbix_server_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database. +* `zabbix_server_allowunsupporteddbversions`: Allow server to work with unsupported database versions. + +### TLS Specific configuration + +These variables are specific for Zabbix 3.0 and higher: + +* `zabbix_server_tlsconnect`: How the agent should connect to server or proxy. Used for active checks. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_server_tlsaccept`: What incoming connections to accept. + Possible values: + * unencrypted + * psk + * cert +* `zabbix_server_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification. +* `zabbix_server_tlscrlfile`: Full pathname of a file containing revoked certificates. +* `zabbix_server_tlsservercertissuer`: Allowed server certificate issuer. +* `zabbix_server_tlsservercertsubject`: Allowed server certificate subject. +* `zabbix_server_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain. +* `zabbix_server_tlskeyfile`: Full pathname of a file containing the agent private key. +* `zabbix_server_dbtlsconnect`: Setting this option enforces to use TLS connection to database: + +`required` - connect using TLS +`verify_ca` - connect using TLS and verify certificate +`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate + +On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported. +By default not set to any option and the behaviour depends on database configuration. +This parameter is supported since Zabbix 5.0.0. + +* `zabbix_server_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlscertfile`: Full pathname of file containing Zabbix server certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlscipher`: The list of encryption ciphers that Zabbix server permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0. +* `zabbix_server_dbtlscipher13`: The list of encryption ciphersuites that Zabbix server permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0. + +### Custom Zabbix Scripts + +Define these variables to copy scripts to your respective scripts path. + +* `zabbix_server_alertscripts`: List of alertscripts to be added to `zabbix_server_alertscriptspath` +* `zabbix_server_externalscripts`: List of alertscripts to be added to `zabbix_server_externalscriptspath` + +Example: + +```yaml + zabbix_server_alertscripts: + - path: "{{ lookup('first_found', 'zabbix-scripts/somescript.php') }}" + name: "somescript.php" +``` + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +## Database + +With Zabbix Server you can make use of 2 different databases: + +* `mysql` +* `postgresql` + +In the following paragraphs we dive into both setups. + +### MySQL + +To make the Zabbix Server work with a `MySQL` database, there are 2 types on setup: + +1. Local setup, `MySQL` running on same host as the Zabbix Server; +2. Separate setup, `MySQL` running on a different host than the Zabbix Server. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `MySQL` instance on the host. Example: `geerlingguy.mysql` can be used, but also others can be used. Please make sure that before installing the Zabbix Server, you have a fully functional `MySQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: mysql +zabbix_server_database_long: mysql +zabbix_server_dbport: 3306 +zabbix_server_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `MySQL`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `MySQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `MySQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: mysql +zabbix_server_database_long: mysql +zabbix_server_dbport: 3306 +zabbix_server_dbhost: mysql-host +zabbix_server_dbhost_run_install: false +zabbix_server_dbpassword: <SOME_SECRET_STRING> +zabbix_server_privileged_host: '%' +zabbix_server_mysql_login_host: mysql-host +zabbix_server_mysql_login_user: root +zabbix_server_mysql_login_password: changeme +zabbix_server_mysql_login_port: 3306 +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `MySQL`. + +The `zabbix_server_privileged_host` can be set to the hostname/ip of the host running Zabbix Server for security related purposes. Also make sure that `zabbix_server_mysql_login_password` is set to the correct password for the user provided with `zabbix_server_mysql_login_host` to create a database and user in the `MySQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `MySQL` on a different host will be running. + +### PostgreSQL + +To make the Zabbix Server work with a `PgSQL` database, there are 2 types on setup: + +1. Local setup, `PgSQL` running on same host as the Zabbix Server; +2. Separate setup, `PgSQL` running on a different host than the Zabbix Server. + +#### Local Setup + +We need to have the following dependencies met: + +1. Find an (Ansible) role that will install a `PgSQL` instance on the host. Example: `geerlingguy.postgresql` can be used, but also others can be used. Please make sure that before installing the Zabbix Server, you have a fully functional `PgSQL` instance running. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: pgsql +zabbix_server_database_long: postgresql +zabbix_server_dbport: 5432 +zabbix_server_dbpassword: <SOME_SECRET_STRING> +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `PgSQL`. Set `zabbix_server_dbpassword_hash_method` for PostgreSQL 10 and newer if they default to `scram-sha-256`. +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `PgSQL` will be running. + +#### Separate Setup + +We need to have the following dependencies met: + +1. We need to either have a `PgSQL` instance running somewhere in the environment. If this is the case, we need to have a username/password combination that is allowed to create a database and an user account. If there isn't one, please make sure there is one. +2. We need to set some variables, either as input for the playbook or set them into the `group_vars` or `host_vars` (Your preference choice). We need to set the following properties: + +```yaml +zabbix_server_database: pgsql; +zabbix_server_database_long: postgresql +zabbix_server_dbport: 5432 +zabbix_server_dbhost: pgsql-host +zabbix_server_dbhost_run_install: false +zabbix_server_dbpassword: <SOME_SECRET_STRING> +zabbix_server_privileged_host: '%' +zabbix_server_pgsql_login_host: pgsql-host +zabbix_server_pgsql_login_user: postgres +zabbix_server_pgsql_login_password: changeme +zabbix_server_pgsql_login_port: 5432 +``` + +Please generate a value for the `zabbix_server_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-server role will create an database and username (With the provided value for the password) in `PgSQL`. Set `zabbix_server_dbpassword_hash_methodh` for PostgreSQL 10 and newer if they default to `scram-sha-256`. + +The `zabbix_server_privileged_host` can be set to the hostname/ip of the host running Zabbix Server for security related purposes. Also make sure that `zabbix_server_mysql_login_password` is set to the correct password for the user provided with `zabbix_server_mysql_login_host` to create a database and user in the `PgSQL` instance. + +3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `PgSQL` on a different host will be running. + +# Example Playbook + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + +```yaml + - hosts: zabbix-server + roles: + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via Github Actions to validate the change on a new installation. Each PR should result into a correct working Zabbix Server installation and PR's will not be merged once this process fails. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml new file mode 100644 index 000000000..e9b837c99 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml @@ -0,0 +1,161 @@ +--- +# defaults file for zabbix_server + +# zabbix_server_version: 6.0 +zabbix_server_version_minor: "*" +zabbix_version: "{{ zabbix_server_version }}" +zabbix_repo: zabbix + +zabbix_server_apt_priority: +zabbix_server_package_state: present +zabbix_server_install_recommends: true +zabbix_server_install_database_client: true +zabbix_server_conf_mode: 0640 + +zabbix_service_state: started +zabbix_service_enabled: true + +zabbix_repo_yum_gpgcheck: 0 +zabbix_repo_yum_schema: https +zabbix_repo_yum_disabled: "*" +zabbix_repo_yum_enabled: [] +zabbix_repo_yum: + - name: zabbix + description: Zabbix Official Repository - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + mode: "0644" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + - name: zabbix-non-supported + description: Zabbix Official Repository non-supported - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/non-supported/rhel/{{ ansible_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + +# User (EPEL specific) +zabbix_server_username: zabbix +zabbix_server_groupname: zabbix + +# Database +zabbix_server_database: pgsql +zabbix_server_database_long: postgresql +zabbix_database_creation: true +zabbix_database_sqlload: true +zabbix_database_timescaledb: false +zabbix_server_dbtlsconnect: +zabbix_server_dbtlscafile: +zabbix_server_dbtlscertfile: +zabbix_server_dbtlskeyfile: +zabbix_server_dbtlscipher: +zabbix_server_dbtlscipher13: + +# zabbix-server specific vars +zabbix_server_listenport: 10051 +zabbix_server_sourceip: +zabbix_server_logtype: file +zabbix_server_logfile: /var/log/zabbix/zabbix_server.log +zabbix_server_logfilesize: 10 +zabbix_server_debuglevel: 3 +zabbix_server_pidfile: /var/run/zabbix/zabbix_server.pid +zabbix_server_socketdir: /var/run/zabbix +zabbix_server_real_dbhost: +zabbix_server_dbhost: localhost +zabbix_server_dbname: zabbix-server +zabbix_server_dbencoding: utf8 +zabbix_server_dbcollation: utf8_bin +zabbix_server_dbschema: +zabbix_server_dbuser: zabbix-server +zabbix_server_dbpassword: zabbix-server +zabbix_server_dbsocket: +zabbix_server_dbport: 5432 +zabbix_server_dbhost_run_install: true +zabbix_server_dbpassword_hash_method: md5 +zabbix_server_allowunsupporteddbversions: 0 +zabbix_server_privileged_host: localhost +zabbix_server_historystorageurl: +zabbix_server_historystoragetypes: uint,dbl,str,log,text +zabbix_server_historystoragedateindex: 0 +zabbix_server_exportdir: +zabbix_server_exportfilesize: 1G +zabbix_server_startpollers: 5 +zabbix_server_startlldprocessors: 2 +zabbix_server_startipmipollers: 0 +zabbix_server_startpollersunreachable: 1 +zabbix_server_starttrappers: 5 +zabbix_server_startpingers: 1 +zabbix_server_startdiscoverers: 1 +zabbix_server_starthttppollers: 1 +zabbix_server_startpreprocessors: 3 +zabbix_server_connectors: 0 +zabbix_server_startodbcpollers: 1 +zabbix_server_starttimers: 1 +zabbix_server_starthistorypollers: 5 +zabbix_server_javagateway: +zabbix_server_javagatewayport: 10052 +zabbix_server_startjavapollers: 5 +zabbix_server_startvmwarecollectors: 0 +zabbix_server_vmwarefrequency: 60 +zabbix_server_vmwarecachesize: 8M +zabbix_server_snmptrapperfile: /tmp/zabbix_traps.tmp +zabbix_server_startsnmptrapper: 0 +zabbix_server_listenip: +zabbix_server_housekeepingfrequency: 1 +zabbix_server_maxhousekeeperdelete: 500 +zabbix_server_senderfrequency: 30 +zabbix_server_cachesize: 32M +zabbix_server_startdbsyncers: 4 +zabbix_server_historycachesize: 16M +zabbix_server_historyindexcachesize: 4M +zabbix_server_trendcachesize: 4M +zabbix_server_trendfunctioncachesize: 4M +zabbix_server_historytextcachesize: 16M +zabbix_server_valuecachesize: 8M +zabbix_server_nodenoevents: 0 +zabbix_server_nodenohistory: 0 +zabbix_server_timeout: 3 +zabbix_server_trappertimeout: 300 +zabbix_server_unreachableperiod: 45 +zabbix_server_unavailabledelay: 60 +zabbix_server_unreachabledelay: 15 +zabbix_server_alertscriptspath: /usr/lib/zabbix/alertscripts +zabbix_server_externalscriptspath: /usr/lib/zabbix/externalscripts +zabbix_server_sshkeylocation: +zabbix_server_logslowqueries: 0 +zabbix_server_tmpdir: /tmp +zabbix_server_startproxypollers: 1 +zabbix_server_proxydatafrequency: 1 +zabbix_server_allowroot: 0 +zabbix_server_user: zabbix +zabbix_server_include: /etc/zabbix/zabbix_server.conf.d +zabbix_server_include_mode: "0755" +zabbix_server_sslcertlocation: ${datadir}/zabbix/ssl/certs +zabbix_server_sslkeylocation: ${datadir}/zabbix/ssl/keys +zabbix_server_sslcalocation: +zabbix_server_loadmodulepath: ${libdir}/modules +zabbix_server_loadmodule: +zabbix_server_tlscafile: +zabbix_server_tlscrlfile: +zabbix_server_tlscertfile: +zabbix_server_tlskeyfile: +zabbix_server_startescalators: 1 +zabbix_server_vmwareperffrequency: 60 +zabbix_server_vmwaretimeout: 10 +zabbix_server_manage_service: true +zabbix_server_vaulttoken: +zabbix_server_vaulturl: https://127.0.0.1:8200 +zabbix_server_vaultdbpath: +zabbix_server_startreportwriters: 0 +zabbix_server_webserviceurl: +zabbix_server_servicemanagersyncfrequency: 60 +zabbix_server_problemhousekeepingfrequency: 60 +zabbix_server_listenbacklog: +zabbix_server_hanodename: +zabbix_server_nodeaddress: + +# SELinux specific +zabbix_selinux: false +selinux_allow_zabbix_can_network: false +selinux_allow_zabbix_can_http: false diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/files/install_semodule.bsx b/ansible_collections/community/zabbix/roles/zabbix_server/files/install_semodule.bsx Binary files differnew file mode 100755 index 000000000..d37320c9f --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/files/install_semodule.bsx diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml new file mode 100644 index 000000000..74b15bdc5 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml @@ -0,0 +1,30 @@ +--- +# handlers file for wdijkerman.zabbix + +- name: zabbix-server restarted + service: + name: zabbix-server + state: restarted + enabled: true + tags: zabbix-server + become: true + when: + - zabbix_server_manage_service | bool + - zabbix_repo != 'epel' + +- name: zabbix-server restarted + service: + name: zabbix-proxy-mysql{{ zabbix_proxy_database_long }} + state: restarted + enabled: true + become: true + when: + - zabbix_proxy_manage_service | bool + - zabbix_repo == 'epel' + +- name: "clean repo files from proxy creds" + shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true + become: true + when: + - ansible_os_family == 'RedHat' + - zabbix_http_proxy is defined or zabbix_https_proxy is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/meta/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/meta/main.yml new file mode 100644 index 000000000..8f01938a6 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/meta/main.yml @@ -0,0 +1,26 @@ +--- +galaxy_info: + author: Werner Dijkerman + description: Installing and maintaining zabbix-server for RedHat/Debian/Ubuntu. + company: myCompany.Dotcom + license: MIT + min_ansible_version: 2.4 + platforms: + - name: EL + versions: + - 6 + - 7 + - name: Ubuntu + versions: + - lucid + - precise + - trusty + - name: Debian + versions: + - squeeze + - wheezy + galaxy_tags: + - zabbix + - monitoring + +dependencies: [] diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/requirements.yml b/ansible_collections/community/zabbix/roles/zabbix_server/requirements.yml new file mode 100644 index 000000000..217a431bc --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/requirements.yml @@ -0,0 +1,5 @@ +--- +- src: geerlingguy.apache +- src: geerlingguy.mysql +- src: geerlingguy.postgresql +- src: community.postgresql diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml new file mode 100644 index 000000000..d7d9a08e3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml @@ -0,0 +1,279 @@ +--- + +- name: "Include Zabbix gpg ids" + include_vars: zabbix.yml + +- name: "Set some variables" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + zabbix_server_apt_repository: + - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/" + - "{{ ansible_distribution_release }}" + - "main" + zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}" + zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}" + when: + - ansible_machine != "aarch64" + +- name: "Set some variables" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + zabbix_server_apt_repository: + - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}-arm64/" + - "{{ ansible_distribution_release }}" + - "main" + zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}" + zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}" + when: + - ansible_machine == "aarch64" + + +- name: "Debian | Set some facts" + set_fact: + datafiles_path: /usr/share/zabbix-server-{{ zabbix_server_database }} + when: + - zabbix_version is version('3.0', '<') + tags: + - zabbix-server + - init + - config + +- name: "Debian | Set some facts for Zabbix >= 3.0 && < 5.4" + set_fact: + datafiles_path: /usr/share/doc/zabbix-server-{{ zabbix_server_database }} + when: + - zabbix_version is version('3.0', '>=') + - zabbix_version is version('5.4', '<') + tags: + - zabbix-server + - init + - config + +- name: "Debian | Set some facts for Zabbix == 5.4" + set_fact: + datafiles_path: /usr/share/doc/zabbix-sql-scripts/{{ zabbix_server_database_long }} + when: + - zabbix_version is version('5.4', '==') + tags: + - zabbix-server + - init + - config + +- name: "Debian | Set some facts for Zabbix >= 6.0" + set_fact: + datafiles_path: /usr/share/zabbix-sql-scripts/{{ zabbix_server_database_long }} + when: + - zabbix_version is version('6.0', '>=') + tags: + - zabbix-server + - init + - config + +- name: "Debian | Installing gnupg" + apt: + pkg: gnupg + update_cache: true + cache_valid_time: 3600 + force: true + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: gnupg_installed + until: gnupg_installed is succeeded + become: true + +- name: "Debian | Install gpg key" + apt_key: + id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}" + url: http://repo.zabbix.com/zabbix-official-repo.key + register: zabbix_server_repo_files_installed + until: zabbix_server_repo_files_installed is succeeded + when: + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-server + - init + +- name: "Debian | Installing repository {{ ansible_distribution }}" + apt_repository: + repo: "{{ item }} {{ zabbix_server_apt_repository | join(' ') }}" + state: present + when: zabbix_repo == "zabbix" + become: true + with_items: + - deb-src + - deb + tags: + - zabbix-server + - init + +- name: "Debian | Create /etc/apt/preferences.d/" + file: + path: /etc/apt/preferences.d/ + state: directory + mode: '0755' + when: + - zabbix_server_apt_priority | int + become: true + +- name: "Debian | Configuring the weight for APT" + copy: + dest: "/etc/apt/preferences.d/zabbix_server-{{ zabbix_proxy_database }}" + content: | + Package: zabbix_server-{{ zabbix_proxy_database }} + Pin: origin repo.zabbix.com + Pin-Priority: {{ zabbix_server_apt_priority }} + owner: root + mode: '0644' + when: + - zabbix_server_apt_priority | int + become: true + +- name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + +- name: apt-get clean + shell: apt-get clean; apt-get update + args: + warn: "{{ produce_warn | default(omit) }}" + changed_when: false + become: true + tags: + - skip_ansible_lint + +# On certain 18.04 images, such as docker or lxc, dpkg is configured not to +# install files into paths /usr/share/doc/* +# Since this is where Zabbix installs its database schemas, we need to allow +# files to be installed to /usr/share/doc/zabbix* +- name: Check for the dpkg exclude line + command: grep -F 'path-exclude=/usr/share/doc/*' /etc/dpkg/dpkg.cfg.d/excludes + register: dpkg_exclude_line + failed_when: false + changed_when: false + check_mode: false + +- name: Allow Zabbix dpkg installs to /usr/share/doc/zabbix* + lineinfile: + path: /etc/dpkg/dpkg.cfg.d/excludes + line: 'path-include=/usr/share/doc/zabbix*' + become: true + when: + - dpkg_exclude_line.rc == 0 + +- name: "Debian | Installing zabbix-server-{{ zabbix_server_database }}" + apt: + pkg: zabbix-server-{{ zabbix_server_database }} + state: "{{ zabbix_server_package_state }}" + update_cache: true + cache_valid_time: 0 + install_recommends: "{{ zabbix_server_install_recommends }}" + default_release: "{{ ansible_distribution_release }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_package_installed + until: zabbix_server_package_installed is succeeded + become: true + tags: + - zabbix-server + - init + +- name: "Debian | Installing zabbix-sql-scripts" + apt: + pkg: zabbix-sql-scripts + state: "{{ zabbix_server_package_state }}" + update_cache: true + cache_valid_time: 0 + install_recommends: "{{ zabbix_server_install_recommends }}" + default_release: "{{ ansible_distribution_release }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_package_sql_installed + until: zabbix_server_package_sql_installed is succeeded + when: + - zabbix_version is version('5.4', '>=') + become: true + tags: + - zabbix-server + - init + +- name: "Debian | Install Ansible module dependencies" + apt: + name: "{{ zabbix_python_prefix }}-psycopg2" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_database_creation + tags: + - zabbix-server + - init + +- name: "Debian | Install Mysql Client package" + apt: + name: + - default-mysql-client + - "{{ zabbix_python_prefix }}-mysqldb" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'mysql' + - zabbix_server_install_database_client + - ansible_distribution_release != "buster" + tags: + - zabbix-server + - init + - database + +- name: "Debian 10 | Install Mysql Client package" + apt: + name: + - mariadb-client + - "{{ zabbix_python_prefix }}-mysqldb" + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'mysql' + - zabbix_server_install_database_client + - ansible_distribution_release == "buster" + tags: + - zabbix-server + - init + - database + +- name: "Debian | Install PostgreSQL Client package" + apt: + name: postgresql-client + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'pgsql' + - zabbix_server_install_database_client + tags: + - zabbix-server + - init + - database diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml new file mode 100644 index 000000000..5d6c33b31 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml @@ -0,0 +1,296 @@ +--- +# Tasks specific for RedHat systems + +- name: "Set short version name" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + +- name: "RedHat | Use Zabbix package name" + set_fact: + zabbix_server_package: "zabbix-server-{{ zabbix_server_database }}" + when: + - zabbix_repo == "zabbix" or zabbix_repo == "other" + tags: + - zabbix-server + +- name: "RedHat | Use EPEL package name" + set_fact: + zabbix_server_package: "zabbix{{ zabbix_short_version }}-server-{{ zabbix_server_database }}" + when: + - zabbix_repo == "epel" + tags: + - zabbix-server + +- name: "RedHat | Set some facts Zabbix <= 3.2" + set_fact: + datafiles_path: "/usr/share/doc/zabbix-server-{{ zabbix_server_database }}-{{ zabbix_version }}*" + when: + - zabbix_version is version('3.2', '<=') + tags: + - zabbix-server + +- name: "RedHat | Set facts for Zabbix > 3.2 && < 5.4" + set_fact: + datafiles_path: "/usr/share/doc/zabbix-server-{{ zabbix_server_database }}*" + when: + - zabbix_version is version('3.2', '>') + - zabbix_version is version('5.4', '<') + tags: + - zabbix-server + +- name: "RedHat | Set facts for Zabbix == 5.4" + set_fact: + datafiles_path: "/usr/share/doc/zabbix-sql-scripts/{{ zabbix_server_database_long }}" + when: + - zabbix_version is version('5.4', '==') + tags: + - zabbix-server + +- name: "RedHat | Set facts for Zabbix >= 6.0" + set_fact: + datafiles_path: "/usr/share/zabbix-sql-scripts/{{ zabbix_server_database_long }}" + when: + - zabbix_version is version('6.0', '>=') + tags: + - zabbix-server + +- name: "RedHat | Set facts for RHEL8" + set_fact: + datafiles_path: "/usr/share/doc/zabbix-server-{{ zabbix_server_database }}" + when: + - ansible_distribution_major_version == "8" + - zabbix_version is version('5.4', '<') + tags: + - zabbix-server + +- name: "RedHat | Set some facts EPEL" + set_fact: + datafiles_path: "/usr/share/zabbix-{{ zabbix_server_database_long }}" + when: + - zabbix_repo == "epel" + tags: + - zabbix-server + +- name: "RedHat | Create 'zabbix' group (EPEL)" + group: + name: "{{ zabbix_server_groupname | default('zabbix') }}" + gid: "{{ zabbix_server_groupid | default(omit) }}" + state: present + become: true + when: + - zabbix_repo == "epel" + +- name: "RedHat | Create 'zabbix' user (EPEL)" + user: + name: "{{ zabbix_server_username | default('zabbix') }}" + comment: Zabbix Monitoring System + uid: "{{ zabbix_server_userid | default(omit) }}" + group: zabbix + become: true + when: + - zabbix_repo == "epel" + +- name: "Make sure old file is absent" + file: + path: /etc/yum.repos.d/zabbix-supported.repo + state: absent + become: true + +- name: "RedHat | Install basic repo file" + yum_repository: + name: "{{ item.name }}" + description: "{{ item.description }}" + baseurl: "{{ item.baseurl }}" + gpgcheck: "{{ item.gpgcheck }}" + gpgkey: "{{ item.gpgkey }}" + mode: "{{ item.mode | default('0644') }}" + priority: "{{ item.priority | default('98') }}" + state: "{{ item.state | default('present') }}" + proxy: "{{ zabbix_http_proxy | default(omit) }}" + with_items: "{{ zabbix_repo_yum }}" + register: yum_repo_installed + become: true + when: + zabbix_repo == "zabbix" + notify: + - "clean repo files from proxy creds" + tags: + - zabbix-server + +- name: "RedHat | Installing zabbix-server-{{ zabbix_server_database }}" + package: + pkg: "{{ zabbix_server_package }}-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}" + state: "{{ zabbix_server_package_state }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_package_installed + until: zabbix_server_package_installed is succeeded + when: + zabbix_repo != "other" + become: true + tags: + - zabbix-server + +- name: "RedHat | Installing zabbix-server-{{ zabbix_server_database }} (When zabbix_repo == other)" + package: + pkg: "{{ zabbix_server_package }}-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}" + state: "{{ zabbix_server_package_state }}" + register: zabbix_server_package_installed + until: zabbix_server_package_installed is succeeded + when: + zabbix_repo == "other" + become: true + tags: + - zabbix-server + +- name: "RedHat | Installing zabbix-sql-scripts" + package: + pkg: "zabbix-sql-scripts-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}" + state: "{{ zabbix_server_package_state }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_sql_package_installed + until: zabbix_server_sql_package_installed is succeeded + when: + - zabbix_version is version('5.4', '>=') + - zabbix_repo != "other" + become: true + tags: + - zabbix-server + + +- name: "RedHat | Installing zabbix-sql-scripts (When zabbix_repo == other)" + package: + pkg: "zabbix-sql-scripts-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}" + state: "{{ zabbix_server_package_state }}" + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_sql_package_installed + until: zabbix_server_sql_package_installed is succeeded + when: + - zabbix_version is version('5.4', '>=') + - zabbix_repo == "other" + become: true + tags: + - zabbix-server + +- name: "RedHat | Install Ansible module dependencies" + yum: + name: python-psycopg2 + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_database_creation + - zabbix_server_database == 'pgsql' + - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6" + tags: + - zabbix-server + +- name: "RedHat | Install Ansible module dependencies on RHEL9 or RHEL8" + yum: + name: python3-psycopg2 + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_database_creation + - zabbix_server_database == 'pgsql' + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-server + +- name: "RedHat | Install Mysql Client packages RHEL9 or RHEL8" + yum: + name: + - mysql + - python3-PyMySQL + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'mysql' + - zabbix_server_install_database_client + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-server + +- name: "RedHat | Install Mysql Client package RHEL7" + yum: + name: + - mariadb + - MySQL-python + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'mysql' + - zabbix_server_install_database_client + - ansible_distribution_major_version == "7" + tags: + - zabbix-server + +- name: "RedHat | Install Mysql Client package RHEL5 - 6" + yum: + name: + - mysql + - MySQL-python + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'mysql' + - zabbix_server_install_database_client + - ansible_distribution_major_version == "6" or ansible_distribution_major_version == "5" + tags: + - zabbix-server + +- name: "RedHat | Install PostgreSQL client package" + yum: + name: postgresql + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - zabbix_server_database == 'pgsql' + - zabbix_server_install_database_client + tags: + - zabbix-server + +- name: "Configure SELinux when enabled" + include_tasks: selinux.yml + when: + - zabbix_selinux | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml new file mode 100644 index 000000000..d3264883d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml @@ -0,0 +1,56 @@ +--- +# tasks file for wdijkerman.zabbix + +- name: "Include OS-specific variables" + include_vars: "{{ ansible_os_family }}.yml" + +- name: Determine Latest Supported Zabbix Version + set_fact: + zabbix_server_version: "{{ zabbix_valid_server_versions[ansible_distribution_major_version][0] | default(6.0) }}" + when: zabbix_server_version is not defined + +- name: "Install the correct repository" + include_tasks: "{{ ansible_os_family }}.yml" + +- name: "Installing the {{ zabbix_server_database_long }} database" + include_tasks: "{{ zabbix_server_database_long }}.yml" + +- name: "Configure zabbix-server" + template: + src: zabbix_server.conf.j2 + dest: /etc/zabbix/zabbix_server.conf + owner: zabbix + group: zabbix + mode: "{{ zabbix_server_conf_mode }}" + notify: + - zabbix-server restarted + tags: + - zabbix-server + - init + - config + +- name: "Create include dir zabbix-server" + file: + path: "{{ zabbix_server_include }}" + owner: zabbix + group: zabbix + state: directory + mode: "{{ zabbix_server_include_mode }}" + tags: + - zabbix-server + - init + - config + +- name: "Add zabbix-server scripts" + include_tasks: "scripts.yml" + when: ( zabbix_server_alertscripts is defined ) or + ( zabbix_server_externalscripts is defined ) + +- name: "Zabbix-server started" + service: + name: zabbix-server + state: "{{ zabbix_service_state }}" + enabled: "{{ zabbix_service_enabled }}" + tags: + - zabbix-server + when: zabbix_server_manage_service | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml new file mode 100644 index 000000000..9e419b125 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml @@ -0,0 +1,307 @@ +--- +# task file for mysql +- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ zabbix_server_dbhost if (zabbix_server_dbhost != 'localhost') else inventory_hostname }}" + when: + - zabbix_server_dbhost_run_install + +- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ inventory_hostname }}" + when: + - not zabbix_server_dbhost_run_install + +- name: "Override delegated_dbhost with real dbhost when dbhost is behind loadbalancer" + set_fact: + delegated_dbhost: "{{ zabbix_server_real_dbhost }}" + when: zabbix_server_real_dbhost | default(false) + +- name: "MySQL | Create database" + community.mysql.mysql_db: + name: "{{ zabbix_server_dbname }}" + encoding: "{{ zabbix_server_dbencoding }}" + collation: "{{ zabbix_server_dbcollation }}" + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + state: present + when: zabbix_database_creation + register: zabbix_database_created + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + - skip_ansible_lint + +- name: "MySQL | Create database user" + community.mysql.mysql_user: + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + name: "{{ zabbix_server_dbuser }}" + password: "{{ zabbix_server_dbpassword }}" + priv: "{{ zabbix_server_dbname }}.*:ALL" + host: "{{ zabbix_server_privileged_host }}" + state: present + when: zabbix_database_creation + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + +- name: "Get the file for create.sql >= 3.0" + shell: ls -1 {{ datafiles_path }}/{{ 'create' if zabbix_version is version('6.0', '<') else 'server' }}.sq* + changed_when: false + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + register: ls_output_create + tags: + - zabbix-server + - database + +- name: MySQL | Get current database version + shell: | + mysql -h {{ zabbix_server_dbhost }} -u{{ zabbix_server_dbuser }} \ + -p'{{ zabbix_server_dbpassword }}' -D '{{ zabbix_server_dbname }}' \ + -e 'SELECT mandatory FROM dbversion;' + register: mysql_db_version + changed_when: false + ignore_errors: true + +# If the above check failed, then there was no dbversion table in the database. +# We'll create it, below. Otherwise, we can access the database version in +# `mysql_db_version["stdout_lines"][1]`, for example 5000000 for Zabbix 5.0. +- name: MySQL | Check if database needs to be populated + set_fact: + mysql_schema_empty: "{{ mysql_db_version is failed }}" + +- name: "MySQL | Get version_comment" + community.mysql.mysql_variables: + variable: version + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + delegate_to: "{{ delegated_dbhost }}" + register: install_mysql_version + tags: + - zabbix-server + - database + +- name: "MySQL | Get current value for innodb_default_row_format" + community.mysql.mysql_variables: + variable: innodb_default_row_format + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + delegate_to: "{{ delegated_dbhost }}" + register: mysql_innodb_default_row_format + when: + - not ansible_check_mode + - install_mysql_version.msg is version('5.6', '>=') + tags: + - zabbix-server + - database + +- name: "MySQL | Set innodb_default_row_format to dynamic" + community.mysql.mysql_variables: + variable: innodb_default_row_format + value: dynamic + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + - install_mysql_version.msg is version('5.6', '>=') + - mysql_innodb_default_row_format.msg != 'dynamic' + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + +- name: "MySQL | Disable InnoDB Strict Mode" + community.mysql.mysql_variables: + variable: innodb_strict_mode + value: 0 + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + - install_mysql_version.msg is version('5.6', '>=') + - ansible_distribution_release == "buster" + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + +- name: "Fetch sql create file" + fetch: + src: "{{ ls_output_create.stdout }}" + dest: /tmp/{{ role_name }}/ + flat: true + when: + - delegated_dbhost != inventory_hostname + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + +- name: "Copy sql create file" + copy: + src: /tmp/{{ role_name }}/ + dest: "{{ ls_output_create.stdout | dirname }}" + mode: '0640' + delegate_to: "{{ delegated_dbhost }}" + when: + - delegated_dbhost != inventory_hostname + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + +- name: "MySQL | Create database and import file >= 3.0" + community.mysql.mysql_db: + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + name: "{{ zabbix_server_dbname }}" + encoding: "{{ zabbix_server_dbencoding }}" + collation: "{{ zabbix_server_dbcollation }}" + state: import + target: "{{ ls_output_create.stdout }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + +- name: "MySQL | Revert innodb_default_row_format to previous value" + community.mysql.mysql_variables: + variable: innodb_default_row_format + value: '{{ mysql_innodb_default_row_format.msg }}' + login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}" + login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}" + login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + - mysql_innodb_default_row_format.msg != 'dynamic' + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + +- name: "Check if we have sql_done files >= 3.0" + file: + path: /etc/zabbix/create.done + state: touch + mode: '0644' + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload | bool + - zabbix_repo != "epel" + - mysql_schema_empty + +- name: "Get the correct path for the SQL files < 3.0" + shell: ls -1 {{ datafiles_path }}/{{ mysql_create_dir }}{{ item }}.sql* + changed_when: false + register: ls_output_schema + with_items: + - schema + - images + - data + when: + - zabbix_version is version('3.0', '<') + - zabbix_database_sqlload | bool + tags: + - zabbix-server + - database + +- name: "Check if we have done files < 3.0" + stat: + path: /etc/zabbix/{{ item }}.done + register: done_files + with_items: + - schema + - images + - data + when: + - zabbix_version is version('3.0', '<') + - zabbix_database_sqlload | bool + tags: + - zabbix-server + - database + +- name: "Create fact if sql_done files exists" + set_fact: + sql_files_executed: "{{ sql_files_executed | default({}) | combine({item.item: item.stat}) }}" + with_items: "{{ done_files.results }}" + when: + - zabbix_version is version('3.0', '<') + - zabbix_database_sqlload | bool + tags: + - zabbix-server + - database + +- name: "MySQL | Create database and import files < 3.0" + community.mysql.mysql_db: + name: "{{ zabbix_server_dbname }}" + encoding: "{{ zabbix_server_dbencoding }}" + collation: "{{ zabbix_server_dbcollation }}" + state: import + target: "{{ item.stdout }}" + with_items: "{{ ls_output_schema.results }}" + when: + - zabbix_version is version('3.0', '<') + - zabbix_database_sqlload | bool + - not sql_files_executed[item.item].exists + delegate_to: "{{ delegated_dbhost }}" + tags: + - zabbix-server + - database + +- name: "Check if we have sql_done files < 3.0" + file: + path: /etc/zabbix/{{ item }}.done + state: touch + mode: '0644' + with_items: + - schema + - images + - data + when: + - zabbix_version is version('3.0', '<') + - zabbix_database_sqlload | bool + - not sql_files_executed[item].exists + tags: + - zabbix-server + - database diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml new file mode 100644 index 000000000..77e300c01 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml @@ -0,0 +1,225 @@ +--- +# task file for postgresql + +- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ zabbix_server_dbhost if (zabbix_server_dbhost != 'localhost') else inventory_hostname }}" + when: + - zabbix_server_dbhost_run_install + +- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)" + set_fact: + delegated_dbhost: "{{ inventory_hostname }}" + when: + - not zabbix_server_dbhost_run_install + +- name: "PostgreSQL | Delegated" + block: + - name: "PostgreSQL | Delegated | Create database" + community.postgresql.postgresql_db: + name: "{{ zabbix_server_dbname }}" + port: "{{ zabbix_server_dbport }}" + state: present + - name: "PostgreSQL | Delegated | Create database user" + community.postgresql.postgresql_user: + db: "{{ zabbix_server_dbname }}" + name: "{{ zabbix_server_dbuser }}" + password: "{{ ('md5' + (zabbix_server_dbpassword + zabbix_server_dbuser)|hash('md5')) if zabbix_server_dbpassword_hash_method == 'md5' else zabbix_server_dbpassword }}" + port: "{{ zabbix_server_dbport }}" + priv: ALL + state: present + encrypted: true + - name: "PostgreSQL | Delegated | Create timescaledb extension" + community.postgresql.postgresql_ext: + db: "{{ zabbix_server_dbname }}" + name: timescaledb + when: zabbix_database_timescaledb + become: true + become_user: postgres + delegate_to: "{{ delegated_dbhost }}" + when: + - zabbix_database_creation + - zabbix_server_pgsql_login_host is not defined + tags: + - zabbix-server + - database + +- name: "PostgreSQL | Remote" + block: + - name: "PostgreSQL | Remote | Create database" + community.postgresql.postgresql_db: + login_host: "{{ zabbix_server_pgsql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_pgsql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_pgsql_login_password | default(omit) }}" + login_unix_socket: "{{ zabbix_server_pgsql_login_unix_socket | default(omit) }}" + name: "{{ zabbix_server_dbname }}" + port: "{{ zabbix_server_dbport }}" + state: present + - name: "PostgreSQL | Remote | Create database user" + community.postgresql.postgresql_user: + login_host: "{{ zabbix_server_pgsql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_pgsql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_pgsql_login_password | default(omit) }}" + db: "{{ zabbix_server_dbname }}" + name: "{{ zabbix_server_dbuser }}" + password: "{{ ('md5' + (zabbix_server_dbpassword + zabbix_server_dbuser)|hash('md5')) if zabbix_server_dbpassword_hash_method == 'md5' else zabbix_server_dbpassword }}" + port: "{{ zabbix_server_dbport }}" + priv: ALL + state: present + encrypted: true + - name: "PostgreSQL | Remote | Create timescaledb extension" + community.postgresql.postgresql_ext: + login_host: "{{ zabbix_server_pgsql_login_host | default(omit) }}" + login_user: "{{ zabbix_server_pgsql_login_user | default(omit) }}" + login_password: "{{ zabbix_server_pgsql_login_password | default(omit) }}" + login_unix_socket: "{{ zabbix_server_pgsql_login_unix_socket | default(omit) }}" + db: "{{ zabbix_server_dbname }}" + name: timescaledb + when: zabbix_database_timescaledb + when: + - zabbix_database_creation + - zabbix_server_pgsql_login_host is defined + tags: + - zabbix-server + - database + +- name: Check if warn parameter can be used for shell module + set_fact: + produce_warn: False + when: ansible_version.full is version("2.14", "<") + +- name: "PostgreSQL | Create schema" + shell: | + set -euxo pipefail + FILE={{ 'create.sql' if zabbix_version is version('6.0', '<') else 'server.sql' }} + cd {{ datafiles_path }} + if [ -f ${FILE}.gz ] + then zcat ${FILE}.gz > /tmp/create.sql + else + cp ${FILE} /tmp/create.sql + fi + cat /tmp/create.sql | psql -h '{{ zabbix_server_dbhost }}' \ + -U '{{ zabbix_server_dbuser }}' \ + -d '{{ zabbix_server_dbname }}' \ + -p '{{ zabbix_server_dbport }}' + touch /etc/zabbix/schema.done + rm -f /tmp/create.sql + args: + creates: /etc/zabbix/schema.done + executable: /bin/bash + warn: "{{ produce_warn | default(omit) }}" + environment: + PGPASSWORD: "{{ zabbix_server_dbpassword }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_sqlload + tags: + - zabbix-server + - database + +- name: "PostgreSQL | Create TimescaleDB hypertables" + shell: | + set -euxo pipefail + cd {{ datafiles_path }} && + if [ -f timescaledb.sql.gz ]; then zcat timescaledb.sql.gz > /etc/timescaledb.sql ; else cp -p timescaledb.sql /etc/timescaledb.sql ; fi + cat /etc/timescaledb.sql | psql -h '{{ zabbix_server_dbhost }}' \ + -U '{{ zabbix_server_dbuser }}' \ + -d '{{ zabbix_server_dbname }}' \ + -p '{{ zabbix_server_dbport }}' + touch /etc/zabbix/timescaledb.done + rm -f /tmp/timescaledb.sql + args: + creates: /etc/zabbix/timescaledb.done + executable: /bin/bash + warn: "{{ produce_warn | default(omit) }}" + environment: + PGPASSWORD: "{{ zabbix_server_dbpassword }}" + when: + - zabbix_version is version('3.0', '>=') + - zabbix_database_timescaledb + tags: + - zabbix-server + - database + +- name: "Get complete path" + shell: ls -d {{ datafiles_path }} + register: datafiles_path_full + changed_when: false + when: + - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload) + tags: + - skip_ansible_lint + +- name: "Check if we have a create dir" + stat: + path: "{{ datafiles_path_full.stdout }}/create" + register: create_dir_or_not + when: + - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload) + +- name: "Set fact" + set_fact: + datafiles_path: "{{ datafiles_path }}/create" + when: + - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload) + - create_dir_or_not.stat.isdir is defined and create_dir_or_not.stat.isdir + - create_dir_or_not.stat.exists + +- name: "PostgreSQL | Importing schema file" + shell: | + set -euxo pipefail + cd {{ datafiles_path }} + if [ -f schema.sql.gz ]; then zcat schema.sql.gz > /tmp/schema.sql ; else cp -p schema.sql /tmp/schema.sql ;fi + cat /tmp/schema.sql | psql -h '{{ zabbix_server_dbhost }}' \ + -U '{{ zabbix_server_dbuser }}' \ + -d '{{ zabbix_server_dbname }}' \ + -p '{{ zabbix_server_dbport }}' + touch /etc/zabbix/schema.done + rm -f /etc/schema.sql + args: + creates: /etc/zabbix/schema.done + executable: /bin/bash + warn: "{{ produce_warn | default(omit) }}" + environment: + PGPASSWORD: "{{ zabbix_server_dbpassword }}" + when: + - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload) + tags: + - zabbix-server + - database + +- name: "PostgreSQL | Importing images file" + shell: > + cd {{ datafiles_path }} && + psql -h '{{ zabbix_server_dbhost }}' + -U '{{ zabbix_server_dbuser }}' + -d '{{ zabbix_server_dbname }}' + -p '{{ zabbix_server_dbport }}' + -f images.sql && touch /etc/zabbix/images.done + args: + creates: /etc/zabbix/images.done + warn: "{{ produce_warn | default(omit) }}" + environment: + PGPASSWORD: "{{ zabbix_server_dbpassword }}" + when: (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload) + tags: + - zabbix-server + - database + +- name: "PostgreSQL | Importing data file" + shell: > + cd {{ datafiles_path }} && + psql -h '{{ zabbix_server_dbhost }}' + -U '{{ zabbix_server_dbuser }}' + -d '{{ zabbix_server_dbname }}' + -p '{{ zabbix_server_dbport }}' + -f data.sql && touch /etc/zabbix/data.done + args: + creates: /etc/zabbix/data.done + warn: "{{ produce_warn | default(omit) }}" + environment: + PGPASSWORD: "{{ zabbix_server_dbpassword }}" + when: (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload) + tags: + - zabbix-server + - database diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml new file mode 100644 index 000000000..418436128 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml @@ -0,0 +1,20 @@ +--- +- name: "Configure zabbix-server alertscripts" + template: + src: "{{ item.path }}" + dest: "{{ zabbix_server_alertscriptspath }}/{{ item.name }}" + owner: zabbix + group: zabbix + mode: 0755 + with_items: "{{ zabbix_server_alertscripts }}" + when: zabbix_server_alertscripts is defined + +- name: "Configure zabbix-server externalscripts" + template: + src: "{{ item.path }}" + dest: "{{ zabbix_server_externalscriptspath }}/{{ item.name }}" + owner: zabbix + group: zabbix + mode: 0755 + with_items: "{{ zabbix_server_externalscripts }}" + when: zabbix_server_externalscripts is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml new file mode 100644 index 000000000..38a8d85fe --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml @@ -0,0 +1,124 @@ +--- + +# straight to getenforce binary , workaround for missing python_selinux library +- name: "Get getenforce binary" + stat: + path: /usr/sbin/getenforce + register: getenforce_bin + become: true + +- name: "Collect getenforce output" + command: getenforce + register: sestatus + when: 'getenforce_bin.stat.exists' + changed_when: false + become: true + check_mode: false + +- name: "Set zabbix_selinux to true if getenforce returns Enforcing or Permissive" + set_fact: + zabbix_selinux: "{{ true }}" + when: 'getenforce_bin.stat.exists and ("Enforcing" in sestatus.stdout or "Permissive" in sestatus.stdout)' + +- name: "SELinux | RedHat | Install related SELinux package" + yum: + name: + - libsemanage-python + - policycoreutils + - checkpolicy + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - selinux_allow_zabbix_can_network + - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6" + tags: + - zabbix-server + +- name: "SELinux | RedHat | Install related SELinux package on RHEL9 and RHEL8" + yum: + name: + - python3-libsemanage + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - selinux_allow_zabbix_can_network + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-server + +- name: "SELinux | RedHat | Enable httpd_can_connect_zabbix SELinux boolean" + ansible.posix.seboolean: + name: httpd_can_connect_zabbix + state: true + persistent: true + become: true + when: + - selinux_allow_zabbix_can_http + tags: + - zabbix-server + +- name: "SELinux | RedHat | Enable zabbix_can_network SELinux boolean" + ansible.posix.seboolean: + name: zabbix_can_network + state: true + persistent: true + become: true + when: + - selinux_allow_zabbix_can_network + tags: + - zabbix-server + +- name: "SELinux | RedHat | Install related SELinux package to fix issues" + yum: + name: + - policycoreutils-python + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6" + tags: + - zabbix-server + +- name: "SELinux | RedHat | Install related SELinux package on RHEL9 and RHEL8" + yum: + name: + - policycoreutils + - checkpolicy + - python3-libsemanage + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_server_dependencies_installed + until: zabbix_server_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-server + +- name: "SELinux | RedHat | Add SEmodule to fix SELinux issue: zabbix_server_alerter.sock" + script: + cmd: files/install_semodule.bsx + args: + creates: /etc/selinux/targeted/active/modules/400/zabbix_server_add/cil + become: true diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2 new file mode 100644 index 000000000..19c99aa33 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2 @@ -0,0 +1,264 @@ +{{ ansible_managed | comment }} +# This is a configuration file for Zabbix Server process +# To get more information about Zabbix, visit http://www.zabbix.com + +# This configuration file is "minimalized", which means all the original comments +# are removed. The full documentation for your Zabbix Server can be found here: +# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_server + +ListenPort={{ zabbix_server_listenport }} +{% if zabbix_server_sourceip is defined and zabbix_server_sourceip %} +SourceIP={{ zabbix_server_sourceip }} +{% endif %} +{% if zabbix_version is version('3.0', '>=') %} +LogType={{ zabbix_server_logtype }} +{% endif %} +LogFile={{ zabbix_server_logfile }} +LogFileSize={{ zabbix_server_logfilesize }} +DebugLevel={{ zabbix_server_debuglevel }} +{% if zabbix_version is version('3.4', '>=') %} +SocketDir={{ zabbix_server_socketdir }} +{% endif %} +PidFile={{ zabbix_server_pidfile }} +DBHost={{ zabbix_server_dbhost }} +DBName={{ zabbix_server_dbname }} +{% if zabbix_server_dbschema is defined and zabbix_server_dbschema %} +DBSchema={{ zabbix_server_dbschema }} +{% endif %} +DBUser={{ zabbix_server_dbuser }} +DBPassword={{ zabbix_server_dbpassword }} +{% if zabbix_server_dbsocket is defined and zabbix_server_dbsocket %} +DBSocket={{ zabbix_server_dbsocket }} +{% endif %} +{% if zabbix_server_dbport is defined and zabbix_server_dbport %} +DBPort={{ zabbix_server_dbport }} +{% endif %} +{% if zabbix_version is version('6.0', '>=') %} +AllowUnsupportedDBVersions={{ zabbix_server_allowunsupporteddbversions }} +{% endif %} +{% if zabbix_server_historystorageurl is defined and zabbix_server_historystorageurl %} +HistoryStorageURL={{ zabbix_server_historystorageurl }} +{% endif %} +{% if zabbix_version is version('3.4', '>=') %} +HistoryStorageTypes={{ zabbix_server_historystoragetypes }} +{% endif %} +{% if zabbix_version is version('4.0', '>=') %} +HistoryStorageDateIndex={{ zabbix_server_historystoragedateindex }} +{% endif %} +{% if zabbix_version is version('4.0', '>=') %} +{% if zabbix_server_exportdir is defined and zabbix_server_exportdir %} +ExportDir={{ zabbix_server_exportdir }} +{% endif %} +{% endif %} +{% if zabbix_version is version('4.0', '>=') %} +ExportFileSize={{ zabbix_server_exportfilesize }} +{% endif %} +StartPollers={{ zabbix_server_startpollers }} +StartIPMIPollers={{ zabbix_server_startipmipollers }} +{% if zabbix_version is version('4.2', '>=') %} +StartLLDProcessors={{ zabbix_server_startlldprocessors }} +{% endif %} +{% if zabbix_version is version('4.2', '>=') %} +StartPreprocessors={{ zabbix_server_startpreprocessors }} +{% endif %} +StartPollersUnreachable={{ zabbix_server_startpollersunreachable }} +{% if zabbix_version is version('6.4', '>=') %} +StartConnectors={{ zabbix_server_connectors }} +{% endif %} +{% if zabbix_version is version('6.2', '>=') %} +StartHistoryPollers={{ zabbix_server_starthistorypollers }} +{% endif %} +StartTrappers={{ zabbix_server_starttrappers }} +StartPingers={{ zabbix_server_startpingers }} +StartDiscoverers={{ zabbix_server_startdiscoverers }} +StartHTTPPollers={{ zabbix_server_starthttppollers }} +{% if zabbix_version is version('2.0', '>=') %} +StartTimers={{ zabbix_server_starttimers }} +{% endif %} +{% if zabbix_version is version('3.0', '>=') %} +StartEscalators={{ zabbix_server_startescalators }} +{% endif %} +{% if zabbix_server_javagateway is defined and zabbix_server_javagateway %} +JavaGateway={{ zabbix_server_javagateway }} +JavaGatewayPort={{ zabbix_server_javagatewayport }} +StartJavaPollers={{ zabbix_server_startjavapollers }} +{% endif %} +{% if zabbix_version is version('2.2', '>=') %} +StartVMwareCollectors={{ zabbix_server_startvmwarecollectors }} +VMwareFrequency={{ zabbix_server_vmwarefrequency }} +{% if zabbix_version is version('3.0', '>=') %} +VMwarePerfFrequency={{ zabbix_server_vmwareperffrequency }} +{% endif %} +VMwareCacheSize={{ zabbix_server_vmwarecachesize }} +{% endif %} +{% if zabbix_version is version('3.0', '>=') %} +VMwareTimeout={{ zabbix_server_vmwaretimeout }} +{% endif %} +SNMPTrapperFile={{ zabbix_server_snmptrapperfile }} +StartSNMPTrapper={{ zabbix_server_startsnmptrapper }} +{% if zabbix_server_listenip is defined and zabbix_server_listenip %} +ListenIP={{ zabbix_server_listenip }} +{% endif %} +HousekeepingFrequency={{ zabbix_server_housekeepingfrequency }} +MaxHousekeeperDelete={{ zabbix_server_maxhousekeeperdelete }} +{% if zabbix_version is version('3.2', '<=') %} +SenderFrequency={{ zabbix_server_senderfrequency }} +{% endif %} +{% if zabbix_server_cachesize is defined and zabbix_server_cachesize is not none %} +CacheSize={{ zabbix_server_cachesize }} +{% else %} +{% if zabbix_version is version('6.2', '<') %} +CacheSize=8M +{% else %} +CacheSize=32M +{% endif %} +{% endif %} +{% if zabbix_server_cacheupdatefrequency is defined and zabbix_server_cacheupdatefrequency is not none %} +CacheUpdateFrequency={{ zabbix_server_cacheupdatefrequency }} +{% else %} +{% if zabbix_version is version('6.4', '<') %} +CacheUpdateFrequency=60 +{% else %} +CacheUpdateFrequency=10 +{%endif %} +{%endif %} +StartDBSyncers={{ zabbix_server_startdbsyncers }} +HistoryCacheSize={{ zabbix_server_historycachesize }} +{% if zabbix_version is version('3.0', '>=') %} +HistoryIndexCacheSize={{ zabbix_server_historyindexcachesize }} +{% endif %} +TrendCacheSize={{ zabbix_server_trendcachesize }} +{% if zabbix_version is version('6.0', '>=') %} +TrendFunctionCacheSize={{ zabbix_server_trendfunctioncachesize }} +{% endif %} +{% if zabbix_version is version('3.0', '<') %} + ### option: historytextcachesize +HistoryTextCacheSize={{ zabbix_server_historytextcachesize }} +{% endif %} +{% if zabbix_version is version('2.2', '>=') %} +ValueCacheSize={{ zabbix_server_valuecachesize }} +{% endif %} +{% if zabbix_version is version('2.4', '<') %} +NodeNoEvents={{ zabbix_server_nodenoevents }} +NodeNoHistory={{ zabbix_server_nodenohistory }} +{% endif %} +Timeout={{ zabbix_server_timeout }} +TrapperTimeout={{ zabbix_server_trappertimeout }} +UnreachablePeriod={{ zabbix_server_unreachableperiod }} +UnavailableDelay={{ zabbix_server_unavailabledelay }} +UnreachableDelay={{ zabbix_server_unreachabledelay }} +AlertScriptsPath={{ zabbix_server_alertscriptspath }} +ExternalScripts={{ zabbix_server_externalscriptspath }} +FpingLocation={{ zabbix_server_fpinglocation }} +Fping6Location={{ zabbix_server_fping6location }} +{% if zabbix_server_sshkeylocation is defined and zabbix_server_sshkeylocation %} +SSHKeyLocation={{ zabbix_server_sshkeylocation }} +{% endif %} +LogSlowQueries={{ zabbix_server_logslowqueries }} +TmpDir={{ zabbix_server_tmpdir }} +StartProxyPollers={{ zabbix_server_startproxypollers }} +{% if zabbix_server_proxyconfigfrequency is defined and zabbix_server_proxyconfigfrequency is not none %} +ProxyConfigFrequency={{ zabbix_server_proxyconfigfrequency }} +{% else %} +{% if zabbix_version is version('6.2', '<') %} +ProxyConfigFrequency=3600 +{% elif zabbix_version is version('6.4', '<') %} +ProxyConfigFrequency=300 +{% else %} +ProxyConfigFrequency=10 +{% endif %} +{% endif %} +ProxyDataFrequency={{ zabbix_server_proxydatafrequency }} +{% if zabbix_version is version('2.2', '>=') %} +AllowRoot={{ zabbix_server_allowroot }} +{% endif %} +{% if zabbix_version is version('3.0', '>=') %} +User={{ zabbix_server_user }} +{% endif %} +Include={{ zabbix_server_include }} +{% if zabbix_version is version('3.0', '>=') %} +SSLCertLocation={{ zabbix_server_sslcertlocation }} +SSLKeyLocation={{ zabbix_server_sslkeylocation }} +{% if zabbix_server_sslcalocation is defined and zabbix_server_sslcalocation is not none %} +SSLCALocation={{ zabbix_server_sslcalocation }} +{% endif %} +{% endif %} +{% if zabbix_version is version('2.2', '>=') %} +LoadModulePath={{ zabbix_server_loadmodulepath }} +{% endif %} +{% if zabbix_server_loadmodule is defined and zabbix_server_loadmodule %} +LoadModule = {{ zabbix_server_loadmodule }} +{% endif %} +{% if zabbix_version is version('3.0', '>=') %} +{% if zabbix_server_tlscafile is defined and zabbix_server_tlscafile is not none %} +TLSCAFile={{ zabbix_server_tlscafile }} +{% endif %} +{% if zabbix_server_tlscrlfile is defined and zabbix_server_tlscrlfile is not none %} +TLSCRLFile={{ zabbix_server_tlscrlfile }} +{% endif %} +{% if zabbix_server_tlscertfile is defined and zabbix_server_tlscertfile is not none %} +TLSCertFile={{ zabbix_server_tlscertfile }} +{% endif %} +{% if zabbix_server_tlskeyfile is defined and zabbix_server_tlskeyfile is not none %} +TLSKeyFile={{ zabbix_server_tlskeyfile }} +{% endif %} +{% endif %} +{% if zabbix_server_dbtlsconnect is defined and zabbix_server_dbtlsconnect is not none %} +DBTLSConnect={{ zabbix_server_dbtlsconnect }} +{% endif %} +{% if zabbix_server_dbtlscafile is defined and zabbix_server_dbtlscafile is not none %} +DBTLSCAFile={{ zabbix_server_dbtlscafile }} +{% endif %} +{% if zabbix_server_dbtlscertfile is defined and zabbix_server_dbtlscertfile is not none %} +DBTLSCertFile={{ zabbix_server_dbtlscertfile }} +{% endif %} +{% if zabbix_server_dbtlskeyfile is defined and zabbix_server_dbtlskeyfile is not none %} +DBTLSKeyFile={{ zabbix_server_dbtlskeyfile }} +{% endif %} +{% if zabbix_server_dbtlscipher is defined and zabbix_server_dbtlscipher is not none %} +DBTLSCipher={{ zabbix_server_dbtlscipher }} +{% endif %} +{% if zabbix_server_dbtlscipher13 is defined and zabbix_server_dbtlscipher13 is not none %} +DBTLSCipher13={{ zabbix_server_dbtlscipher13 }} +{% endif %} +{% if zabbix_version is version('6.0', '>=') %} +{% if zabbix_server_vaulttoken is defined and zabbix_server_vaulttoken is not none %} +VaultToken={{ zabbix_server_vaulttoken }} +{% endif %} +{% if zabbix_server_vaulturl is defined and zabbix_server_vaulturl is not none %} +VaultURL={{ zabbix_server_vaulturl }} +{% endif %} +{% if zabbix_server_vaultdbpath is defined and zabbix_server_vaultdbpath is not none %} +VaultDBPath={{ zabbix_server_vaultdbpath }} +{% endif %} +{% if zabbix_server_vaulttlscertfile is defined and zabbix_server_vaulttlscertfile is not none %} +VaultTLSKeyFile={{ zabbix_server_vaulttlscertfile }} +{% endif %} +{% if zabbix_server_vaulttlskeyfile is defined and zabbix_server_vaulttlskeyfile is not none %} +VaultTLSCertFile={{ zabbix_server_vaulttlskeyfile }} +{% endif %} +{% if zabbix_server_startreportwriters is defined and zabbix_server_startreportwriters is not none %} +StartReportWriters={{ zabbix_server_startreportwriters }} +{% endif %} +{% if zabbix_server_webserviceurl is defined and zabbix_server_webserviceurl is not none %} +WebServiceURL={{ zabbix_server_webserviceurl }} +{% endif %} +{% if zabbix_server_servicemanagersyncfrequency is defined and zabbix_server_servicemanagersyncfrequency is not none %} +ServiceManagerSyncFrequency={{ zabbix_server_servicemanagersyncfrequency }} +{% endif %} +{% if zabbix_server_problemhousekeepingfrequency is defined and zabbix_server_problemhousekeepingfrequency is not none %} +ProblemHousekeepingFrequency={{ zabbix_server_problemhousekeepingfrequency }} +{% endif %} +{% if zabbix_version is version('6.2', '>=') %} +StartODBCPollers={{ zabbix_server_startodbcpollers }} +{% endif %} +{% if zabbix_server_listenbacklog is defined and zabbix_server_listenbacklog is not none %} +ListenBacklog={{ zabbix_server_listenbacklog }} +{% endif %} +{% if zabbix_server_hanodename is defined and zabbix_server_hanodename is not none %} +HANodeName={{ zabbix_server_hanodename }} +{% endif %} +{% if zabbix_server_nodeaddress is defined and zabbix_server_nodeaddress is not none %} +NodeAddress={{ zabbix_server_nodeaddress }} +{% endif %} +{% endif %} diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml new file mode 100644 index 000000000..1639e94b3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml @@ -0,0 +1,36 @@ +--- +apache_user: www-data +apache_group: www-data +apache_log: apache2 + +mysql_create_dir: "" + +zabbix_valid_server_versions: + # Debian + "11": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "10": + - 6.0 + - 5.0 + - 4.0 + "9": + - 4.0 + # Ubuntu + "22": + - 6.4 + - 6.0 + "20": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "18": + - 6.0 + - 5.0 + - 4.0 + +zabbix_server_fpinglocation: /usr/bin/fping +zabbix_server_fping6location: /usr/bin/fping6 diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml new file mode 100644 index 000000000..016eae514 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml @@ -0,0 +1,22 @@ +--- +apache_user: apache +apache_group: apache +apache_log: httpd + +mysql_create_dir: create/ + +zabbix_valid_server_versions: + "9": + - 6.4 + - 6.0 + "8": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "7": + - 5.0 + - 4.0 + +zabbix_server_fpinglocation: /usr/sbin/fping +zabbix_server_fping6location: /usr/sbin/fping6 diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/main.yml new file mode 100644 index 000000000..3f674d7c1 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for zabbix_server diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml new file mode 100644 index 000000000..7a642c9d6 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml @@ -0,0 +1,261 @@ +--- +sign_keys: + "64": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "62": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "60": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "54": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + jessie: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "52": + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + jessie: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "50": + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + jessie: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "44": + focal: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "42": + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "40": + focal: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "34": + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "32": + bionic: + sign_key: A14FE591 + sonya: + sign_key: 79EA5ED4 + serena: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + jessie: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "30": + bionic: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "24": + wheezy: + sign_key: 79EA5ED4 + jessie: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + "22": + squeeze: + sign_key: 79EA5ED4 + jessie: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + lucid: + sign_key: 79EA5ED4 + +suse: + "openSUSE Leap": + "42": + name: server:monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/ + "openSUSE": + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }} + "SLES": + "11": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/ + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP3/ diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/README.md b/ansible_collections/community/zabbix/roles/zabbix_web/README.md new file mode 100644 index 000000000..cef5d62e7 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/README.md @@ -0,0 +1,349 @@ +# community.zabbix.zabbix_web role + +![Zabbix Web](https://github.com/ansible-collections/community.zabbix/workflows/community.zabbix.zabbix_web/badge.svg) + +**Table of Contents** + +- [Overview](#overview) +- [Requirements](#requirements) + - [Operating Systems](#operating-systems) + - [Zabbix Versions](#zabbix-versions) +- [Installation](#installation) +- [Role Variables](#role-variables) + - [Main variables](#main-variables) + - [Overall Zabbix](#overall-zabbix) + - [Zabbix Web specific](#zabbix-web-specific) + - [Apache configuration](#apache-configuration) + - [Nginx configuration](#nginx-configuration) + - [PHP-FPM](#php-fpm) + - [Zabbix Server](#zabbix-server) + * [proxy](#proxy) +- [Example Playbook](#example-playbook) + - [Single instance](#single-instance) + - [Multi host setup](#multi-host-setup) + - [Adding Environment Variables for zabbix_web](#adding-environment-variables-for-zabbixweb) + - [Using Elasticsearch for history storage](#using-elasticsearch-for-history-storage) +- [Molecule](#molecule) +- [License](#license) +- [Author Information](#author-information) + +# Overview + +# Requirements +## Operating Systems + +This role will work on the following operating systems: + + * RedHat + * Debian + * Ubuntu + +So, you'll need one of those operating systems.. :-) +Please send Pull Requests or suggestions when you want to use this role for other Operating systems. + +## Ansible 2.10 and higher + +With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`. The `community.general` collection is required when defining the `zabbix_web_htpasswd` variable (see variable section below). Installing the collections: + +```sh +ansible-galaxy collection install ansible.posix +ansible-galaxy collection install community.general +``` + +## Zabbix Versions + +See the following list of supported Operating Systems with the Zabbix releases. + +| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) | +|---------------------|-----|-----|-----------|-----|-----|------------|-----|-----------|-----------| +| Red Hat Fam 9 | V | V | V | | | | | | | +| Red Hat Fam 8 | V | V | V | V | V | V | V | | | +| Red Hat Fam 7 | | V | V | V | V | V | V | V | V | +| Red Hat Fam 6 | | | | | V | V | | | V | +| Red Hat Fam 5 | | | | | V | V | | | V | +| Fedora | | | | | | | V | V | | +| Ubuntu 22.04 jammy | V | V | V | | | | | | | +| Ubuntu 20.04 focal | V | V | V | V | V | V | V | | | +| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | | +| Ubuntu 16.04 xenial | | | | | V | V | V | V | | +| Ubuntu 14.04 trusty | | | | | V | V | V | V | V | +| Debian 10 buster | V | V | V | V | V | V | V | | | +| Debian 9 stretch | | | V | V | V | V | V | V | | +| Debian 8 jessie | | | | | V | V | V | V | V | +| Debian 7 wheezy | | | | | | | | V | V | +| macOS 10.15 | | | | | | | V | V | | +| macOS 10.14 | | | | | | | V | V | | + +# Installation + +Installing this role is very simple: `ansible-galaxy install community.zabbix.zabbix_web` + +When the Zabbix Web needs to be running on the same host as the Zabbix Server, please also install the Zabbix Server by executing the following command: `ansible-galaxy install community.zabbix.zabbix_server` + +Default username/password for the Zabbix Web interface is the default. + +Username: Admin +Password: zabbix + +# Role Variables + +## Main variables + +The following is an overview of all available configuration defaults for this role. + +### Overall Zabbix + +* `zabbix_web_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility. +* `zabbix_web_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available) +* `zabbix_repo`: Default: `zabbix` + * `epel`: install agent from EPEL repo + * `zabbix`: (default) install agent from Zabbix repo + * `other`: install agent from pre-existing or other repo +* `zabbix_repo_yum`: A list with Yum repository configuration. +* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https) +* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`. +* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages. + +* `zabbix_web_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed. +* `zabbix_web_centos_release`: Default: True. When the `centos-release-scl` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`. +* `zabbix_web_rhel_release`: Default: True. When the `scl-utils` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`. +* `zabbix_web_doubleprecision`: Default: `False`. For upgraded installations, please read database [upgrade notes](https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500) (Paragraph "Enabling extended range of numeric (float) values") before enabling this option. +* `zabbix_web_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file. + +### Zabbix Web specific + +* `zabbix_api_server_url`: This is the url on which the zabbix web interface is available. Default is zabbix.example.com, you should override it. For example, see "Example Playbook" +* `zabbix_url_aliases`: A list with Aliases for the Apache Virtual Host configuration. +* `zabbix_timezone`: Default: `Europe/Amsterdam`. This is the timezone. The Apache Virtual Host needs this parameter. +* `zabbix_vhost`: Default: `true`. When you don't want to create an Apache Virtual Host configuration, you can set it to False. +* `zabbix_web_env`: (Optional) A Dictionary of PHP Environments settings. +* `zabbix_web_conf_web_user`: When provided, the user (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`). +* `zabbix_web_conf_web_group`: When provided, the group (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`). +* `zabbix_web_htpasswd`: (Optional) Allow HTTP authentication at the webserver level via a htpasswd file. +* `zabbix_web_htpasswd_file`: Default: `/etc/zabbix/web/htpasswd`. Allows the change the default path to the htpasswd file. +* `zabbix_web_htpasswd_users`: (Optional) Dictionary for creating users via `htpasswd_user` and passphrases via `htpasswd_pass` in htpasswd file. +* `zabbix_web_allowlist_ips`: (Optional) Allow web access at webserver level to a list of defined IPs or CIDR. +* `zabbix_web_connect_ha_backend`: (Optional) Default: `false`. When set to `true` values for Zabbix server will not be written and frontend gets values from database to connect to active cluster node. Set `true` when operating Zabbix servers in a cluste (only >=6.0). +* `zabbix_saml_idp_crt`: (Optional) The path to the certificate of the Identity Provider used for SAML authentication +* `zabbix_saml_sp_crt`: (Optional) The path to the public certificate of Zabbix as Service Provider +* `zabbix_saml_sp_key`: (Optional) The path to the private certificate of Zabbix as Service Provider + +#### Apache configuration + +* `zabbix_apache_vhost_port`: The port on which Zabbix HTTP vhost is running. +* `zabbix_apache_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running. +* `zabbix_apache_vhost_listen_ip`: On which interface the Apache Virtual Host is available. +* `zabbix_apache_can_connect_ldap`: Default: `false`. Set SELinux boolean to allow httpd to connect to LDAP. +* `zabbix_php_install`: Default: `true`. True / False. Switch for extra install of packages for PHP, currently on for Debian/Ubuntu. +* `zabbix_web_max_execution_time`: +* `zabbix_web_memory_limit`: +* `zabbix_web_post_max_size`: +* `zabbix_web_upload_max_filesize`: +* `zabbix_web_max_input_time`: +* `zabbix_apache_include_custom_fragment`: Default: `true`. Includes php_value vars max_execution_time, memory_limit, post_max_size, upload_max_filesize, max_input_time and date.timezone in vhost file.. place those in php-fpm configuration. +* `zabbix_apache_tls`: If the Apache vhost should be configured with TLS encryption or not. +* `zabbix_apache_redirect`: If a redirect should take place from HTTP to HTTPS +* `zabbix_apache_tls_crt`: The path to the TLS certificate file. +* `zabbix_apache_tls_key`: The path to the TLS key file. +* `zabbix_apache_tls_chain`: The path to the TLS certificate chain file. +* `zabbix_apache_SSLPassPhraseDialog`: Type of pass phrase dialog for encrypted private keys. +* `zabbix_apache_SSLSessionCache`: Type of the global/inter-process SSL Session Cache +* `zabbix_apache_SSLSessionCacheTimeout`: Number of seconds before an SSL session expires in the Session Cache +* `zabbix_apache_SSLCryptoDevice`: Enable use of a cryptographic hardware accelerator +* `zabbix_apache_custom_includes`: Configure custom includes. Default: `[]` + +When `zabbix_apache_tls_crt`, `zabbix_apache_tls_key` and/or `zabbix_apache_tls_chain` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files. + +See https://httpd.apache.org/docs/current/mod/mod_ssl.html for SSL* configuration options for Apache HTTPD. + +#### Nginx configuration + +* `zabbix_nginx_vhost_port`: The port on which Zabbix HTTP vhost is running. +* `zabbix_nginx_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running. +* `zabbix_nginx_tls`: If the Nginx vhost should be configured with TLS encryption or not. +* `zabbix_nginx_tls_crt`: The path to the TLS certificate file. +* `zabbix_nginx_tls_key`: The path to the TLS key file. +* `zabbix_nginx_tls_dhparam`: The path to the TLS DHParam file. +* `zabbix_nginx_tls_session_cache`: Type of the global/inter-process SSL Session Cache +* `zabbix_nginx_tls_session_timeout`: +* `zabbix_nginx_tls_session_tickets`: +* `zabbix_nginx_tls_protocols`: The TLS Protocols to accept. +* `zabbix_nginx_tls_ciphers`: The TLS Ciphers to be allowed. + +When `zabbix_nginx_tls_crt` and `zabbix_nginx_tls_key` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files. + +#### PHP-FPM + +The following properties are specific to Zabbix 5.0 and for the PHP(-FPM) configuration: + +* `zabbix_php_version`: Either `7.3` or `7.4` (Based on the OS Family). When you want to override the PHP Version. +* `zabbix_php_fpm_session`: The directory where sessions will be stored. If none are provided, defaults are used. +* `zabbix_php_fpm_listen`: The path to a socket file or ipaddress:port combination on which PHP-FPM needs to listen. If none are provided, defaults are used. +* `zabbix_php_fpm_conf_listen`: Default: `true`. If we want to configure the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_conf_user`: The owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file). +* `zabbix_php_fpm_conf_enable_user`: Default: `true`. If we want to configure the owner of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_conf_group`: The group of the owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file). +* `zabbix_php_fpm_conf_enable_group`: Default: `true`. If we want to configure the group of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_conf_mode`: The mode for the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file). +* `zabbix_php_fpm_conf_enable_mode`: Default: `true`. If we want to configure the mode of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file. +* `zabbix_php_fpm_dir_etc`: etc HOME root directory of PHP-FPM setup. +* `zabbix_php_fpm_dir_var`: Var HOME root directory of PHP-FPM setup. + +### Zabbix Server + +* `zabbix_server_name`: The name of the Zabbix Server. +* `zabbix_server_database`: The type of database used. Can be: mysql or pgsql +* `zabbix_server_database_long`: The type of database used, but long name. Can be: mysql or postgresql +* `zabbix_server_hostname`: The hostname on which the zabbix-server is running. Default set to: {{ inventory_hostname }} +* `zabbix_server_listenport`: On which port the Zabbix Server is available. Default: 10051 +* `zabbix_server_dbhost`: The hostname on which the database is running. +* `zabbix_server_dbname`: The database name which is used by the Zabbix Server. +* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server. +* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server. +* `zabbix_server_dbport`: The database port which is used by the Zabbix Server. + +The following properties are related when using Elasticsearch for history storage: + +* `zabbix_server_history_url`: String with url to the Elasticsearch server or a list if the types are stored on different Elasticsearch URLs. +* `zabbix_server_history_types`: List of history types to store in Elasticsearch. + +See the following links for more information regarding Zabbix and Elasticsearch +https://www.zabbix.com/documentation/3.4/manual/appendix/install/elastic_search_setup +https://www.zabbix.com/documentation/4.0/manual/appendix/install/elastic_search_setup + +## proxy + +When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy: + +* `zabbix_http_proxy` +* `zabbix_https_proxy` + +# Example Playbook + +There are two ways of using the zabbix-web: + +* Single instance +* Multi host setup + +## Single instance + +When there is one host running both Zabbix Server and the Zabbix Web (Running MySQL as database): + +```yaml +- hosts: zabbix-server + become: yes + roles: + - role: geerlingguy.apache + - role: geerlingguy.php + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + - role: community.zabbix.zabbix_web + zabbix_api_server_url: zabbix.mydomain.com + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +## Multi host setup + +This is a two host setup. On one host (Named: "zabbix-server") the Zabbix Server is running, and the other host (Named: zabbix-web) runs Zabbix Web (with MySQL as database): + +```yaml +- hosts: zabbix-server + become: yes + roles: + - role: community.zabbix.zabbix_server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + +- hosts: zabbix-web + become: yes + roles: + - role: geerlingguy.apache + - role: geerlingguy.php + - role: community.zabbix.zabbix_web + zabbix_api_server_url: zabbix.mydomain.com + zabbix_server_hostname: zabbix-server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 +``` + +## Adding Environment Variables for zabbix_web + +Sometimes you need to add environment variables to your +zabbix.conf.php, for example to add LDAP CA certificates. To do this add a `zabbix_web_env` dictionary: + +```yaml +- hosts: zabbix-web + become: yes + roles: + - role: geerlingguy.apache + - role: geerlingguy.php + php_memory_limit: "128M" + php_max_execution_time: "300" + php_upload_max_filesize: "256M" + php_packages: + - php + - php-fpm + - php-acpu + - role: geerlingguy.apache-php-fpm + - role: community.zabbix.zabbix_web + zabbix_api_server_url: zabbix.mydomain.com + zabbix_server_hostname: zabbix-server + zabbix_server_database: mysql + zabbix_server_database_long: mysql + zabbix_server_dbport: 3306 + zabbix_web_env: + LDAPTLS_CACERT: /etc/ssl/certs/ourcert.pem +``` + +## Using Elasticsearch for history storage + +To use Elasticsearch for history storage you need to configure the `zabbix_server_history_url` and `zabbix_server_history_types`. You will also need to configure Elasticsearch +in the zabbix_server role. + +Zabbix can store the following history types +in Elasticsearch: +* Numeric (unsigned) - `uint` +* Numeric (float) - `dbl` +* Character - `str` +* Log - `log` +* Text - `text` + +To store all history types in the same history URL the following variables should be set (make sure history url points to your Elasticsearch cluster): + +``` +zabbix_server_history_url: "http://localhost:9200" +zabbix_server_history_types: + - 'str' + - 'text' + - 'log' + - 'uint' + - 'dbl' +``` + +# Molecule + +This role is configured to be tested with Molecule. You can find on this page some more information regarding Molecule: + +* http://werner-dijkerman.nl/2016/07/10/testing-ansible-roles-with-molecule-testinfra-and-docker/ +* http://werner-dijkerman.nl/2016/07/27/extending-ansible-role-testing-with-molecule-by-adding-group_vars-dependencies-and-using-travis-ci/ +* http://werner-dijkerman.nl/2016/07/31/testing-ansible-roles-in-a-cluster-setup-with-docker-and-molecule/ + +With each Pull Request, Molecule will be executed via travis.ci. Pull Requests will only be merged once these tests run successfully. + +# License + +GNU General Public License v3.0 or later + +See LICENCE to see the full text. + +# Author Information + +Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role. + +Github: https://github.com/ansible-collections/community.zabbix diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml new file mode 100644 index 000000000..6e326461e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml @@ -0,0 +1,144 @@ +--- +# defaults file for zabbix-web + +# zabbix_web_version: 6.0 +zabbix_web_version_minor: "*" +zabbix_version: "{{ zabbix_web_version }}" +zabbix_repo: zabbix +zabbix_web_package_state: present +zabbix_web_centos_release: true +zabbix_web_rhel_release: true +zabbix_selinux: false +zabbix_web_doubleprecision: false +zabbix_web_conf_mode: "0640" +zabbix_web_connect_ha_backend: false + +zabbix_url: zabbix.example.com # Will be deprecated in 2.0.0 +zabbix_api_server_url: "{{ zabbix_url }}" +zabbix_websrv: apache +zabbix_websrv_servername: "{{ zabbix_api_server_url | regex_findall('(?:https?\\://)?([\\w\\-\\.]+)') | first }}" +zabbix_url_aliases: [] +zabbix_web_htpasswd: false +zabbix_web_htpasswd_file: /etc/zabbix/web/htpasswd +zabbix_timezone: Europe/Amsterdam +zabbix_vhost: true + +zabbix_php_install: true +zabbix_php_frontend_deprecated: false +zabbix_php_fpm: false +zabbix_php_fpm_dir_etc: /etc/opt/rh/rh-php72/ +zabbix_php_fpm_dir_var: /var/opt/rh/rh-php72/ +zabbix_php_fpm_conf_listen: true +zabbix_php_fpm_conf_enable_user: true +zabbix_php_fpm_conf_enable_group: true +zabbix_php_fpm_conf_mode: "0664" +zabbix_php_fpm_conf_enable_mode: true +zabbix_php_install_state: present + +zabbix_apache_vhost_port: 80 +zabbix_apache_vhost_tls_port: 443 +zabbix_apache_vhost_listen_ip: "*" +zabbix_apache_tls: false +zabbix_apache_redirect: false +zabbix_apache_tls_crt: /etc/pki/server.crt +zabbix_apache_tls_key: /etc/pki/server.key +zabbix_apache_tls_chain: +zabbix_apache_can_connect_ldap: false +zabbix_apache_include_custom_fragment: true +zabbix_apache_SSLPassPhraseDialog: exec:/usr/libexec/httpd-ssl-pass-dialog +zabbix_apache_SSLSessionCache: shmcb:/run/httpd/sslcache(512000) +zabbix_apache_SSLSessionCacheTimeout: 300 +zabbix_apache_SSLCryptoDevice: builtin +zabbix_apache_custom_includes: [] + +zabbix_nginx_vhost_port: 80 +zabbix_nginx_vhost_tls_port: 443 +zabbix_nginx_tls: false +zabbix_nginx_redirect: false +zabbix_nginx_tls_session_timeout: 1d +zabbix_nginx_tls_session_cache: shared:MySSL:10m +zabbix_nginx_tls_session_tickets: !!str off +zabbix_nginx_tls_protocols: TLSv1.2 +zabbix_nginx_tls_ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + +zabbix_letsencrypt: false +zabbix_letsencrypt_webroot_path: /var/www/letsencrypt +zabbix_letsencrypt_webroot_mode: 0755 + +zabbix_repo_yum_gpgcheck: 0 +zabbix_repo_yum_schema: https +zabbix_repo_yum_disabled: "*" +zabbix_repo_yum_enabled: [] +zabbix_repo_yum: + - name: zabbix + description: Zabbix Official Repository - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + mode: "0644" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + - name: zabbix-non-supported + description: Zabbix Official Repository non-supported - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/non-supported/rhel/{{ ansible_distribution_major_version }}/$basearch/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + +zabbix_5_repo_yum: + - name: zabbix-frontend + description: Zabbix Official Repository - $basearch + baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/frontend/" + mode: "0644" + gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}" + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX + state: present + +zabbix_web_max_execution_time: 300 +zabbix_web_memory_limit: 128M +zabbix_web_post_max_size: 16M +zabbix_web_upload_max_filesize: 2M +zabbix_web_max_input_time: 300 +zabbix_web_max_input_vars: 10000 + +# Database +zabbix_server_database: pgsql +zabbix_server_database_long: postgresql +zabbix_server_name: "{{ inventory_hostname }}" +zabbix_server_hostname: "{{ inventory_hostname }}" +zabbix_server_listenport: 10051 +zabbix_server_dbhost: localhost +zabbix_server_dbname: zabbix-server +zabbix_server_dbuser: zabbix-server +zabbix_server_dbpassword: zabbix-server +zabbix_server_dbport: 5432 +zabbix_server_dbencryption: false +zabbix_server_dbverifyhost: false +zabbix_server_dbschema: + +# Elasticsearch +# zabbix_server_history_url: +# - "'uint' => 'http://localhost:9200'" +# - "'text' => 'http://localhost:9200'" +# - "'log' => 'http://localhost:9200'" +# - "'dbl' => 'http://localhost:9200'" +# - "'str' => 'http://localhost:9200'" +zabbix_server_history_types: + - "str" + - "text" + - "log" + - "uint" + - "dbl" + +selinux_allow_zabbix_can_network: false +_zabbix_web_apache_php_addition: false + +# SAML certificates +# zabbix_saml_idp_crt: +# zabbix_saml_sp_crt: +# zabbix_saml_sp_key: + +# When the `geerlingguys apache role` is not provided, we have some defaults. +apache_ssl_cipher_suite: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 +apache_ssl_protocol: all -SSLv3 -TLSv1 -TLSv1.1 +apache_vhosts_version: "2.4" diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml new file mode 100644 index 000000000..0d0974632 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml @@ -0,0 +1,54 @@ +--- + +- name: restart apache + service: + name: "{{ _apache_service }}" + state: restarted + enabled: true + become: true + when: + - zabbix_websrv == 'apache' + +- name: test nginx config + listen: restart nginx + command: nginx -t + register: zabbix_nginx_cfg_check + notify: restart nginx tested + become: true + when: + - zabbix_websrv == 'nginx' + +- name: restart nginx tested + service: + name: nginx + state: restarted + enabled: true + become: true + when: + - zabbix_websrv == 'nginx' + - zabbix_nginx_cfg_check.rc == 0 + +- name: restart redhat-php-fpm + service: + name: "{{ 'rh-php72-php-fpm' if zabbix_php_fpm else 'php-fpm' }}" + state: restarted + enabled: true + become: true + when: + - zabbix_version is version('5.0', '>=') + +- name: restart php-fpm-version + service: + name: php{{ zabbix_php_version }}-fpm + state: restarted + enabled: true + become: true + when: + - zabbix_version is version('5.0', '>=') + +- name: "clean repo files from proxy creds" + shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true + become: true + when: + - ansible_os_family == 'RedHat' + - zabbix_http_proxy is defined or zabbix_https_proxy is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/meta/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/meta/main.yml new file mode 100644 index 000000000..907a3c86a --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/meta/main.yml @@ -0,0 +1,28 @@ +--- +galaxy_info: + author: Werner Dijkerman + description: Installing and maintaining zabbix-web for RedHat/Debian/Ubuntu. + company: myCompany.Dotcom + license: license (GPLv3) + min_ansible_version: 2.4 + platforms: + - name: EL + versions: + - 6 + - 7 + - name: Ubuntu + versions: + - lucid + - precise + - trusty + - name: Debian + versions: + - squeeze + - wheezy + - jessie + - stretch + galaxy_tags: + - monitoring + - zabbix + +dependencies: [] diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml new file mode 100644 index 000000000..8a27b841c --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml @@ -0,0 +1,108 @@ +--- + +- name: "Include Zabbix gpg ids" + include_vars: zabbix.yml + +- name: "Set short version name" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + +- name: "Debian | Install gpg key" + apt_key: + id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}" + url: http://repo.zabbix.com/zabbix-official-repo.key + when: + - zabbix_repo == "zabbix" + become: true + tags: + - zabbix-web + - init + - config + +- name: "Debian | Installing repository {{ ansible_distribution }}" + apt_repository: + repo: "{{ item }} http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - zabbix_repo == "zabbix" + - ansible_machine != "aarch64" + with_items: + - deb-src + - deb + tags: + - zabbix-web + - init + - config + +- name: "Debian | Installing repository {{ ansible_distribution }}" + apt_repository: + repo: "{{ item }} http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}-arm64/ {{ ansible_distribution_release }} main" + state: present + become: true + when: + - zabbix_repo == "zabbix" + - ansible_machine == "aarch64" + with_items: + - deb-src + - deb + tags: + - zabbix-web + - init + - config + +- name: "Debian | Install PHP apart from zabbix-frontend-php deps" + include_tasks: "php_Debian.yml" + when: zabbix_php_install + +- name: "Debian | Install zabbix-web" + apt: + pkg: "zabbix-frontend-php{{ '-deprecated' if zabbix_php_frontend_deprecated else '' }}" + state: "{{ zabbix_web_package_state }}" + update_cache: true + cache_valid_time: 0 + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_package_install + until: zabbix_web_package_install is succeeded + become: true + tags: + - zabbix-web + - init + - config + +- name: "Debian | Link graphfont.ttf (workaround ZBX-10467)" + file: + src: '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf' + path: '/usr/share/zabbix/fonts/graphfont.ttf' + state: link + tags: + - zabbix-web + - init + - config + +- name: "Debian | Install PHP" + template: + src: php-fpm.conf.j2 + dest: "{{ zabbix_php_fpm_dir }}/zabbix.conf" + owner: "{{ _apache_user }}" + group: "{{ _apache_group }}" + mode: 0644 + become: true + when: + - zabbix_vhost + notify: + - restart php-fpm-version + +- name: "Including Apache Configuration" + include_tasks: apache_Debian.yml + vars: + zabbix_apache_servername: "{{ zabbix_websrv_servername }}" + when: + - zabbix_websrv == 'apache' + +- name: "Configure SELinux when enabled" + include_tasks: selinux.yml + when: + - zabbix_selinux | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml new file mode 100644 index 000000000..bcd4dd666 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml @@ -0,0 +1,183 @@ +--- +# Tasks specific for RedHat systems + +- name: "RedHat | Install basic repo file" + yum_repository: + name: "{{ item.name }}" + description: "{{ item.description }}" + baseurl: "{{ item.baseurl }}" + gpgcheck: "{{ item.gpgcheck }}" + gpgkey: "{{ item.gpgkey }}" + mode: "{{ item.mode | default('0644') }}" + priority: "{{ item.priority | default('98') }}" + state: "{{ item.state | default('present') }}" + proxy: "{{ zabbix_http_proxy | default(omit) }}" + with_items: "{{ zabbix_repo_yum }}" + register: yum_repo_installed + become: true + when: + zabbix_repo == "zabbix" + notify: + - "clean repo files from proxy creds" + tags: + - zabbix-web + +- name: "RedHat | Install basic repo file (Zabbix 5.x)" + yum_repository: + name: "{{ item.name }}" + description: "{{ item.description }}" + baseurl: "{{ item.baseurl }}" + gpgcheck: "{{ item.gpgcheck }}" + gpgkey: "{{ item.gpgkey }}" + mode: "{{ item.mode | default('0644') }}" + priority: "{{ item.priority | default('98') }}" + state: "{{ item.state | default('present') }}" + proxy: "{{ zabbix_http_proxy | default(omit) }}" + with_items: "{{ zabbix_5_repo_yum }}" + become: true + when: + - zabbix_repo == "zabbix" + - zabbix_version is version('5.0', '>=') + - ansible_distribution_major_version != '8' + - ansible_distribution_major_version != '9' + notify: + - "clean repo files from proxy creds" + tags: + - zabbix-web + +- name: "RedHat | Install zabbix-web dependency (Zabbix 5.x) (CentOS)" + yum: + pkg: + - centos-release-scl + state: "{{ zabbix_web_package_state }}" + update_cache: true + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_dependency_package_install + until: zabbix_web_dependency_package_install is succeeded + become: true + when: + - zabbix_version is version('5.0', '>=') + - zabbix_web_centos_release + - ansible_distribution_major_version != '9' + - ansible_distribution_major_version != '8' + - ansible_distribution == "CentOS" + tags: + - zabbix-web + +- name: "RedHat | Install zabbix-web dependency (Zabbix 5.x) (RHEL)" + yum: + pkg: + - scl-utils + - scl-utils-build + state: "{{ zabbix_web_package_state }}" + update_cache: true + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_dependency_package_install + until: zabbix_web_dependency_package_install is succeeded + become: true + when: + - zabbix_version is version('5.0', '>=') + - zabbix_web_centos_release + - ansible_distribution_major_version != '9' + - ansible_distribution_major_version != '8' + - ansible_distribution == "RedHat" + tags: + - zabbix-web + +- name: "RedHat | Install zabbix-web (Zabbix 5.x)" + yum: + pkg: + - zabbix-apache-conf-scl-{{ zabbix_web_version }}.{{ zabbix_web_version_minor }} + state: "{{ zabbix_web_package_state }}" + update_cache: true + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_package_install + until: zabbix_web_package_install is succeeded + become: true + when: + - zabbix_version is version('5.0', '>=') + - ansible_distribution_major_version != '9' + - ansible_distribution_major_version != '8' + - zabbix_websrv == 'apache' + tags: + - zabbix-web + +- name: "RedHat | Install zabbix-web-{{ zabbix_server_database }}" + yum: + pkg: zabbix-web-{{ zabbix_server_database }}{{ '-scl' if zabbix_version is version('5.0', '>=') and ansible_distribution_major_version|int < 8 else '' }}-{{ zabbix_web_version }}.{{ zabbix_web_version_minor }} + state: "{{ zabbix_web_package_state }}" + update_cache: true + disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}" + enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}" + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_package_install + until: zabbix_web_package_install is succeeded + become: true + tags: + - zabbix-web + +- name: RedHat 9 | Install PHP" + package: + name: php + state: "{{ zabbix_php_install_state }}" + when: + - zabbix_version is version('6.0', '>=') + - ansible_distribution_major_version == '9' + - zabbix_vhost + +- name: "RedHat | Install PHP" + template: + src: php-fpm.conf.j2 + dest: "{{ zabbix_php_fpm_dir }}/zabbix.conf" + owner: "{{ zabbix_web_conf_web_user }}" + group: "{{ zabbix_web_conf_web_group }}" + mode: 0644 + become: true + when: + - zabbix_vhost + notify: + - restart redhat-php-fpm + +- include_tasks: apache_RedHat.yml + vars: + zabbix_apache_servername: "{{ zabbix_websrv_servername }}" + when: + - zabbix_websrv == 'apache' + +- name: "RedHat | Install Nginx vhost" + template: + src: nginx_vhost.conf.j2 + dest: /etc/nginx/conf.d/zabbix.conf + owner: root + group: root + mode: 0644 + when: + - zabbix_vhost + - zabbix_websrv == 'nginx' + become: true + notify: + - restart nginx + tags: + - zabbix-web + - init + - config + - nginx + +- name: "Configure SELinux when enabled" + include_tasks: selinux.yml + when: + - zabbix_selinux | bool diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml new file mode 100644 index 000000000..f02a6ebe4 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml @@ -0,0 +1,32 @@ +--- +- name: "htpasswd | check Python version to set prefix variable" + set_fact: + zabbix_python_prefix: "python{% if ansible_python_version is version_compare('3', '>=') %}3{% endif %}" + when: + - zabbix_web_htpasswd is defined + - zabbix_web_htpasswd + - zabbix_web_htpasswd_users is defined + +- name: "htpasswd | install passlib for Python interpreter" + package: + name: "{{ zabbix_python_prefix }}-passlib" + state: present + when: + - zabbix_web_htpasswd is defined + - zabbix_web_htpasswd + - zabbix_web_htpasswd_users is defined + +- name: "htpasswd | manage HTTP authentication controls" + community.general.htpasswd: + path: "{{ zabbix_web_htpasswd_file }}" + name: "{{ item.value.htpasswd_user }}" + password: "{{ item.value.htpasswd_pass }}" + group: www-data + state: present + loop_control: + label: "{{ item.value.htpasswd_user }}" + with_dict: "{{ zabbix_web_htpasswd_users }}" + when: + - zabbix_web_htpasswd is defined + - zabbix_web_htpasswd + - zabbix_web_htpasswd_users is defined diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml new file mode 100644 index 000000000..f33b9b765 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml @@ -0,0 +1,35 @@ +--- +- name: "Apache | Get Apache version" + shell: | + PATH=/usr/sbin:$PATH + set -o pipefail + apachectl -v | grep 'version' | awk -F '/' '{ print $2 }'| awk '{ print $1 }' | cut -c 1-3 + changed_when: false + register: apachectl_version + check_mode: false + args: + executable: /bin/bash + tags: + - zabbix-web + +- name: "Apache | Set correct apache_version" + set_fact: + apache_version: "{{ apachectl_version.stdout }}" + tags: + - zabbix-web + +- name: "Set some" + set_fact: + _zabbix_web_apache_php_addition: true + when: + - zabbix_version is version('4.4', '<=') + tags: + - zabbix-web + +- name: "Set some" + set_fact: + _zabbix_web_apache_php_addition: true + when: + - ansible_os_family == "Debian" + tags: + - zabbix-web diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml new file mode 100644 index 000000000..732feaea9 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml @@ -0,0 +1,54 @@ +--- + +- name: "Debian | Install legacy PHP integration for Apache" + apt: + state: present + update_cache: true + cache_valid_time: 3600 + name: + - libapache2-mod-php + become: true + +- name: "Debian | install apache vhost" + template: + src: apache_vhost.conf.j2 + dest: /etc/apache2/sites-available/zabbix.conf + owner: "{{ zabbix_web_conf_web_user }}" + group: "{{ zabbix_web_conf_web_group }}" + mode: 0644 + when: zabbix_vhost + become: true + notify: + - restart apache + tags: + - zabbix-web + - init + - config + - apache + +- name: "Debian | Remove provided zabbix.conf files" + file: + path: "{{ item }}" + state: absent + when: zabbix_vhost + become: true + with_items: + - /etc/apache2/conf-available/zabbix.conf + - /etc/apache2/conf-enabled/zabbix.conf + +- name: "Debian | enable apache vhost" + file: + src: /etc/apache2/sites-available/zabbix.conf + dest: /etc/apache2/sites-enabled/zabbix.conf + owner: "{{ zabbix_web_conf_web_user }}" + group: "{{ zabbix_web_conf_web_group }}" + state: link + when: zabbix_vhost + become: true + notify: + - restart apache + tags: + - zabbix-server + - init + - config + - apache diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml new file mode 100644 index 000000000..3a271331d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml @@ -0,0 +1,17 @@ +--- + +- include_tasks: apache.yml + +- name: "RedHat | Install apache vhost" + template: + src: apache_vhost.conf.j2 + dest: /etc/httpd/conf.d/zabbix.conf + owner: "{{ zabbix_web_conf_web_user }}" + group: "{{ zabbix_web_conf_web_group }}" + mode: 0644 + when: zabbix_vhost + become: true + notify: + - restart apache + tags: + - zabbix-server diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml new file mode 100644 index 000000000..fad607b1d --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml @@ -0,0 +1,103 @@ +--- +# tasks file for wdijkerman.zabbix-web + +- name: "Include OS-specific variables" + include_vars: "{{ ansible_os_family }}.yml" + tags: + - always + +- name: Determine Latest Supported Zabbix Version + set_fact: + zabbix_web_version: "{{ zabbix_valid_web_versions[ansible_distribution_major_version][0] | default(6.0) }}" + when: zabbix_web_version is not defined + +- name: "Include distribution and version-specific vars" + include_vars: "{{ item }}" + with_first_found: + - files: + - "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml" + - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml" + tags: + - always + +- name: "Set some versions" + set_fact: + zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}" + zabbix_php_version: "{{ zabbix_php_version if zabbix_php_version is defined else _zabbix_php_version }}" + _zabbix_php_package_prefix: "" + tags: + - always + +- name: "Set default PHP-FPM variables" + set_fact: + zabbix_php_fpm_dir: "{{ zabbix_php_fpm_dir if zabbix_php_fpm_dir is defined else _php_fpm_dir }}" + zabbix_php_fpm_session: "{{ zabbix_php_fpm_session if zabbix_php_fpm_session is defined else _php_fpm_session }}" + zabbix_php_fpm_listen: "{{ zabbix_php_fpm_listen if zabbix_php_fpm_listen is defined else _php_fpm_listen }}" + when: + - not zabbix_php_fpm + +- name: "Set default PHP-FPM variables specific RH provided" + set_fact: + zabbix_php_fpm_dir: "{{ zabbix_php_fpm_dir if zabbix_php_fpm_dir is defined else _php_fpm_dir }}" + zabbix_php_fpm_session: "{{ zabbix_php_fpm_session if zabbix_php_fpm_session is defined else _zabbix_php_fpm_session }}" + zabbix_php_fpm_listen: "{{ zabbix_php_fpm_listen if zabbix_php_fpm_listen is defined else _zabbix_php_fpm_listen }}" + when: + - zabbix_php_fpm + - ansible_os_family == "RedHat" + +- name: "Set websrv specific variables (Apache)" + set_fact: + zabbix_web_conf_web_user: "{{ zabbix_web_conf_web_user if zabbix_web_conf_web_user is defined else _apache_user }}" + zabbix_web_conf_web_group: "{{ zabbix_web_conf_web_group if zabbix_web_conf_web_group is defined else _apache_group }}" + when: + - zabbix_websrv == 'apache' + +- include_tasks: nginx.yml + when: + - zabbix_websrv == 'nginx' + +- name: "Install the correct repository" + include_tasks: "RedHat.yml" + when: ansible_os_family == "RedHat" + tags: + - zabbix-web + +- name: "Install the correct repository" + include_tasks: "Debian.yml" + when: ansible_os_family == "Debian" + tags: + - zabbix-web + +- name: "Create zabbix-web directory" + file: + path: /etc/zabbix/web + owner: "{{ zabbix_web_conf_web_user }}" + group: "{{ zabbix_web_conf_web_group }}" + state: directory + mode: 0755 + tags: + - zabbix-web + - init + - config + +- name: "Configure zabbix-web" + template: + src: zabbix.conf.php.j2 + dest: /etc/zabbix/web/zabbix.conf.php + owner: "{{ zabbix_web_conf_web_user }}" + group: "{{ zabbix_web_conf_web_group }}" + mode: "{{ zabbix_web_conf_mode }}" + notify: + - restart apache + tags: + - zabbix-web + - init + - config + +- include_tasks: access.yml + when: + - zabbix_web_htpasswd + tags: + - zabbix-web + - init + - config diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml new file mode 100644 index 000000000..9e4ec41f1 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml @@ -0,0 +1,153 @@ +--- +- name: "Nginx | Set websrv specific variables" + set_fact: + zabbix_web_conf_web_user: "{{ zabbix_web_conf_web_user if zabbix_web_conf_web_user is defined else _nginx_user }}" + zabbix_web_conf_web_group: "{{ zabbix_web_conf_web_group if zabbix_web_conf_web_group is defined else _nginx_group }}" + zabbix_nginx_config_path: "{{ zabbix_nginx_config_path if zabbix_nginx_config_path is defined else _nginx_config_path }}" + zabbix_nginx_log_path: "{{ zabbix_nginx_log_path if zabbix_nginx_log_path is defined else _nginx_log_path }}" + zabbix_nginx_service: "{{ zabbix_nginx_service if zabbix_nginx_service is defined else _nginx_service }}" + zabbix_nginx_tls_crt: "{{ zabbix_nginx_tls_crt if zabbix_nginx_tls_crt is defined else _nginx_tls_crt }}" + zabbix_nginx_tls_key: "{{ zabbix_nginx_tls_key if zabbix_nginx_tls_key is defined else _nginx_tls_key }}" + zabbix_nginx_tls_dhparam: "{{ zabbix_nginx_tls_dhparam if zabbix_nginx_tls_dhparam is defined else _nginx_tls_dhparam }}" + zabbix_apache_service: "{{ zabbix_apache_service if zabbix_apache_service is defined else _apache_service }}" + +- name: "Nginx | Check Apache service if same ports" + command: systemctl status "{{ zabbix_apache_service }}" + failed_when: false + register: zabbix_apache_service_check + changed_when: zabbix_apache_service_check.rc == 0 + check_mode: false + when: + - zabbix_apache_vhost_port == zabbix_nginx_vhost_port + - zabbix_apache_vhost_tls_port == zabbix_nginx_vhost_tls_port + +- name: "Nginx | Stop Apache running on same ports" + service: + name: "{{ zabbix_apache_service }}" + state: stopped + enabled: false + tags: + - zabbix-web + when: + - zabbix_apache_vhost_port == zabbix_nginx_vhost_port + - zabbix_apache_vhost_tls_port == zabbix_nginx_vhost_tls_port + - zabbix_apache_service_check.rc == 0 + +- name: "Nginx | Debian | Install Nginx and ssl-cert packages" + # README don't go for HTTP2 with nginx-full yet due to: + # https://support.zabbix.com/browse/ZBXNEXT-4670 + apt: + state: present + name: + - nginx-light + - ssl-cert + when: ansible_os_family == "Debian" + +- name: "Nginx | RedHat | Install Nginx packages" + yum: + state: present + name: + - nginx + when: ansible_os_family == "RedHat" + +- name: "Nginx | Start and enable service" + service: + name: "{{ zabbix_nginx_service }}" + state: started + enabled: true + +- name: "Nginx | Install OpenSSL package for DH parameters" + package: + name: openssl + state: present + +- name: "Nginx | Generate SSL DH parameters" + command: "openssl dhparam -out {{ zabbix_nginx_tls_dhparam }} {{ zabbix_nginx_tls_dhparam_bits | default('2048') }}" + args: + creates: "{{ zabbix_nginx_tls_dhparam }}" + +- name: "Let's Encrypt | check for certificate created by certbot" + stat: + path: "/etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem" + register: zabbix_letsencrypt_cert + failed_when: false + when: zabbix_letsencrypt + +- name: "Let's Encrypt | Create directory for certbot webroot if not exist" + file: + path: "{{ zabbix_letsencrypt_webroot_path }}" + mode: "{{ zabbix_letsencrypt_webroot_mode }}" + state: directory + when: + - zabbix_letsencrypt + become: true + +- name: "Nginx | Install vhost in conf.d" + template: + src: nginx_vhost.conf.j2 + dest: "{{ zabbix_nginx_config_path }}/zabbix.conf" + owner: root + group: root + mode: 0644 + when: + - zabbix_vhost + become: true + notify: + - restart nginx + +- name: "Let's Encrypt | Check if zabbix_websrv_servername is resolvable" + set_fact: + zabbix_websrv_servername_ip: "{{ lookup('dig', 'qtype=A', zabbix_websrv_servername) }}" + changed_when: zabbix_websrv_servername_ip != ansible_default_ipv4.address + register: zabbix_letsencrypt_resolve + when: zabbix_letsencrypt + +- name: "Let's Encrypt | check if certbot CLI is present" + shell: "certbot --version" + register: zabbix_cerbot_check + changed_when: zabbix_cerbot_check.rc != 0 + check_mode: false + when: zabbix_letsencrypt + +- name: "Let's Encrypt | flash all handlers before certbot" + meta: flush_handlers + when: + - zabbix_letsencrypt + - zabbix_letsencrypt_resolve is not changed + - zabbix_cerbot_check.rc == 0 + +- name: "Let's Encrypt | generate certs with certbot CLI" + command: > + certbot --non-interactive certonly --expand + -a webroot --webroot-path={{ zabbix_letsencrypt_webroot_path }} + --email {{ zabbix_letsencrypt_account_email }} --agree-tos + --cert-name {{ zabbix_websrv_servername }} + -d {{ zabbix_websrv_servername }} + args: + creates: "/etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem" + when: + - zabbix_letsencrypt + - zabbix_letsencrypt_resolve is not changed + - zabbix_cerbot_check.rc == 0 + +- name: "Let's Encrypt | Check for certificate created by certbot" + stat: + path: "/etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem" + register: zabbix_letsencrypt_cert + failed_when: false + when: zabbix_letsencrypt + +- name: "Let's Encrypt | Reinstall Nginx vhost" + template: + src: nginx_vhost.conf.j2 + dest: /etc/nginx/conf.d/zabbix.conf + owner: root + group: root + mode: 0644 + when: + - zabbix_letsencrypt + - zabbix_letsencrypt_resolve is not changed + - zabbix_cerbot_check.rc == 0 + become: true + notify: + - restart nginx diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml new file mode 100644 index 000000000..6a2f329b6 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml @@ -0,0 +1,43 @@ +--- + +- include_tasks: apache.yml + when: + - zabbix_websrv == 'apache' + +# This obviously needs to have some improvements.. :) + +- name: "Debian | Determine php prefix for packages installations (legacy php5)" + set_fact: + _zabbix_php_package_prefix: 5 + when: + - ansible_distribution == 'Ubuntu' and ansible_distribution_version is version_compare('16.04', '<') + or ansible_distribution == 'Debian' and ansible_distribution_version is version_compare('9', '<') + +- name: "Debian | Determine php prefix for packages installations (Current distros)" + set_fact: + _zabbix_php_package_prefix: "{{ zabbix_php_version }}" + when: + - ansible_distribution == 'Ubuntu' and ansible_distribution_version is version_compare('16.04', '>=') or + ansible_distribution == 'Debian' and ansible_distribution_version is version_compare('9', '>=') + - zabbix_version is version_compare('5.0', '>=') + - not _zabbix_web_apache_php_addition + +- name: "Debian | Install php packages" + apt: + state: present + update_cache: true + cache_valid_time: 3600 + name: + - php{{ _zabbix_php_package_prefix }}-{{ zabbix_server_database }} + - php{{ _zabbix_php_package_prefix }}-bcmath + - php{{ _zabbix_php_package_prefix }}-mbstring + - php{{ _zabbix_php_package_prefix }}-ldap + - php{{ _zabbix_php_package_prefix }}-xml + - php{{ _zabbix_php_package_prefix }}-gd + - php{{ _zabbix_php_package_prefix }}-fpm + register: zabbix_web_php_dependency_install + until: zabbix_web_php_dependency_install is succeeded + become: true + tags: + - zabbix-web + - init diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml new file mode 100644 index 000000000..df8936eb1 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml @@ -0,0 +1,82 @@ +--- + +- name: "SELinux | RedHat | Install related SELinux package" + yum: + name: + - libsemanage-python + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_dependencies_installed + until: zabbix_web_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - selinux_allow_zabbix_can_network + - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6" + tags: + - zabbix-web + +- name: "SELinux | RedHat | Install related SELinux package on RHEL9 and RHEL8" + yum: + name: + - python3-libsemanage + state: present + environment: + http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}" + https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}" + register: zabbix_web_dependencies_installed + until: zabbix_web_dependencies_installed is succeeded + become: true + when: + - ansible_os_family == "RedHat" + - selinux_allow_zabbix_can_network + - ansible_distribution_major_version|int >= 8 + tags: + - zabbix-web + +- name: "SELinux | RedHat | Enable zabbix_can_network SELinux boolean" + ansible.posix.seboolean: + name: zabbix_can_network + state: true + persistent: true + become: true + when: + - ansible_os_family == "RedHat" + - selinux_allow_zabbix_can_network + tags: + - zabbix-web + +- name: "SELinux | Allow httpd to connect to db (SELinux)" + ansible.posix.seboolean: + name: httpd_can_network_connect_db + persistent: true + state: true + become: true + when: + - ansible_selinux.status == "enabled" + - selinux_allow_zabbix_can_network + tags: selinux + +- name: "SELinux | Allow httpd to connect to zabbix (SELinux)" + ansible.posix.seboolean: + name: httpd_can_connect_zabbix + persistent: true + state: true + become: true + when: + - ansible_selinux.status == "enabled" + - selinux_allow_zabbix_can_network + tags: selinux + +- name: "SELinux | Allow httpd to connect to ldap (SELinux)" + ansible.posix.seboolean: + name: httpd_can_connect_ldap + persistent: true + state: true + become: true + when: + - ansible_selinux.status == "enabled" + - zabbix_apache_can_connect_ldap | bool + tags: selinux diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2 new file mode 100644 index 000000000..4149c43fa --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2 @@ -0,0 +1,199 @@ +<VirtualHost {{ zabbix_apache_vhost_listen_ip }}:{{ zabbix_apache_vhost_port }}> + ServerName {{ zabbix_apache_servername }} + {% for alias in zabbix_url_aliases %} + ServerAlias {{ alias }} + {% endfor %} + + ## Vhost docroot + DocumentRoot "/usr/share/zabbix" + +{% if zabbix_apache_custom_includes is iterable and (zabbix_apache_custom_includes | length>0) %} + {% for include in zabbix_apache_custom_includes %} + {{ include }} + {% endfor %} +{% endif %} + +{% if zabbix_apache_redirect and zabbix_apache_tls %} + RewriteEngine On + RewriteCond %{HTTPS} !=on + RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] +{% endif %} + +{% set directory_paths = ['/usr/share/zabbix/conf', '/usr/share/zabbix/app', '/usr/share/zabbix/include', '/usr/share/zabbix/include/classes'] %} + + <Directory "/usr/share/zabbix"> + {% if apache_version|string() == '2.4' %} + Options FollowSymLinks + AllowOverride None + Require all granted + {% else %} + AllowOverride None + Order Allow,Deny + Allow from all + {% endif %} + + <IfModule dir_module> + DirectoryIndex index.php + </IfModule> + +{% if ansible_os_family == "RedHat" %} + <FilesMatch \.(php|phar)$> + SetHandler "proxy:unix:{{ zabbix_php_fpm_listen }}|fcgi://localhost" + </FilesMatch> +{% endif %} + + </Directory> + +{% for my_path in directory_paths %} + <Directory "{{ my_path }}"> + {% if apache_version|string() == '2.4' %} + Require all denied + {% else %} + AllowOverride None + Order Deny,Allow + Deny from all + {% endif %} + </Directory> + +{% endfor %} + ## Logging + ErrorLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_error.log" + ServerSignature Off + CustomLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_access.log" combined + + ## Rewrite rules + RewriteEngine On + RewriteRule ^$ /index.php [L] + +{% if _zabbix_web_apache_php_addition | default(false) %} +{% if zabbix_apache_include_custom_fragment | default(true) %} + ## Custom fragment + {% if zabbix_php_fpm %} + ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/usr/share/zabbix/$1 + ProxyTimeout 1800 + {% else %} + php_value max_execution_time {{ zabbix_web_max_execution_time | default('300') }} + php_value memory_limit {{ zabbix_web_memory_limit | default('128M') }} + php_value post_max_size {{ zabbix_web_post_max_size | default('16M') }} + php_value upload_max_filesize {{ zabbix_web_upload_max_filesize | default('2M') }} + php_value max_input_time {{ zabbix_web_max_input_time | default('300') }} + + {% if zabbix_version is version('5.0', '>=') %} + php_value max_input_vars {{ zabbix_web_max_input_vars | default('10000') }} + {% endif %} + + # Set correct timezone. + php_value date.timezone {{ zabbix_timezone }} + {% endif %} +{% endif %} +{% endif %} +</VirtualHost> + +{# Set up TLS vhosts #} +{% if zabbix_apache_tls and zabbix_apache_vhost_tls_port %} + +SSLPassPhraseDialog {{ zabbix_apache_SSLPassPhraseDialog }} +SSLSessionCache {{ zabbix_apache_SSLSessionCache }} +SSLSessionCacheTimeout {{ zabbix_apache_SSLSessionCacheTimeout }} +SSLRandomSeed startup file:/dev/urandom 256 +SSLRandomSeed connect builtin +SSLCryptoDevice {{ zabbix_apache_SSLCryptoDevice }} + +<VirtualHost _default_:{{ zabbix_apache_vhost_tls_port }}> + ServerName {{ zabbix_apache_servername }} + {% for alias in zabbix_url_aliases %} + ServerAlias {{ alias }} + {% endfor %} + + ## Vhost docroot + DocumentRoot "/usr/share/zabbix" + +{% if zabbix_apache_custom_includes is iterable and (zabbix_apache_custom_includes | length>0) %} + {% for include in zabbix_apache_custom_includes %} + {{ include }} + {% endfor %} +{% endif %} + + SSLEngine on + SSLCipherSuite {{ apache_ssl_cipher_suite }} + SSLProtocol {{ apache_ssl_protocol }} + SSLHonorCipherOrder On +{% if apache_vhosts_version == "2.4" %} + SSLCompression off +{% endif %} + SSLCertificateFile {{ zabbix_apache_tls_crt }} + SSLCertificateKeyFile {{ zabbix_apache_tls_key }} +{% if zabbix_apache_tls_chain %} + SSLCertificateChainFile {{ zabbix_apache_tls_chain }} +{% endif %} + +{% set directory_paths = ['/usr/share/zabbix/conf', '/usr/share/zabbix/app', '/usr/share/zabbix/include', '/usr/share/zabbix/include/classes'] %} + + <Directory "/usr/share/zabbix"> + {% if apache_version|string() == '2.4' %} + Options FollowSymLinks + AllowOverride None + Require all granted + {% else %} + AllowOverride None + Order Allow,Deny + Allow from all + {% endif %} + + <IfModule dir_module> + DirectoryIndex index.php + </IfModule> + +{% if ansible_os_family == "RedHat" %} + <FilesMatch \.(php|phar)$> + SetHandler "proxy:unix:{{ zabbix_php_fpm_listen }}|fcgi://localhost" + </FilesMatch> +{% endif %} + + </Directory> + +{% for my_path in directory_paths %} + <Directory "{{ my_path }}"> + {% if apache_version|string() == '2.4' %} + Require all granted + {% else %} + AllowOverride None + Order Deny,Allow + Deny from all + {% endif %} + </Directory> + +{% endfor %} + ## Logging + ErrorLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_tls_error.log" + ServerSignature Off + CustomLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_tls_access.log" combined + + ## Rewrite rules + RewriteEngine On + RewriteRule ^$ /index.php [L] + +{% if _zabbix_web_apache_php_addition | default(false) %} +{% if zabbix_apache_include_custom_fragment | default(true) %} + ## Custom fragment + {% if zabbix_php_fpm %} + ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/usr/share/zabbix/$1 + ProxyTimeout 1800 + {% else %} + php_value max_execution_time {{ zabbix_web_max_execution_time | default('300') }} + php_value memory_limit {{ zabbix_web_memory_limit | default('128M') }} + php_value post_max_size {{ zabbix_web_post_max_size | default('16M') }} + php_value upload_max_filesize {{ zabbix_web_upload_max_filesize | default('2M') }} + php_value max_input_time {{ zabbix_web_max_input_time | default('300') }} + + {% if zabbix_version is version('5.0', '>=') %} + php_value max_input_vars {{ zabbix_web_max_input_vars | default('10000') }} + {% endif %} + + # Set correct timezone. + php_value date.timezone {{ zabbix_timezone }} + {% endif %} +{% endif %} +{% endif %} +</VirtualHost> +{% endif %} diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2 new file mode 100644 index 000000000..49671984c --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2 @@ -0,0 +1,110 @@ +# Nginx configuration for Zabbix Web + +server { +{% if not zabbix_nginx_tls %} + listen {{ zabbix_nginx_vhost_port }}; +{% else %} +{% if zabbix_letsencrypt %} + listen 80; + server_tokens off; + server_name {{ zabbix_websrv_servername }} {% for alias in zabbix_url_aliases -%}{{ alias -}} {% endfor %}; + location ^~ /.well-known/acme-challenge { + root {{ zabbix_letsencrypt_webroot_path | default('/var/www/letsencrypt') }}; + # disables IP restrictions and HTTP auth + allow all; + default_type text/plain; + try_files $uri =404; + } + location / { return 301 https://$host:{{ zabbix_nginx_vhost_tls_port }}$request_uri; } +} + +server { +{% endif %} + listen {{ zabbix_nginx_vhost_tls_port }} ssl; +{% if zabbix_letsencrypt and zabbix_letsencrypt_cert.stat.exists %} + ssl_certificate /etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ zabbix_websrv_servername }}/privkey.pem; +{% else %} + ssl_certificate {{ zabbix_nginx_tls_crt }}; + ssl_certificate_key {{ zabbix_nginx_tls_key }}; +{% endif %} + ssl_session_timeout {{ zabbix_nginx_tls_session_timeout }}; + ssl_session_cache {{ zabbix_nginx_tls_session_cache }}; + ssl_session_tickets {{ zabbix_nginx_tls_session_tickets }}; + ssl_dhparam {{ zabbix_nginx_tls_dhparam }}; + + ssl_protocols {{ zabbix_nginx_tls_protocols }}; + ssl_ciphers {{ zabbix_nginx_tls_ciphers }}; + ssl_prefer_server_ciphers off; + +{% endif %} + server_tokens off; + server_name {{ zabbix_websrv_servername }} {% for alias in zabbix_url_aliases -%}{{ alias -}} {% endfor %}; + +{% if zabbix_web_allowlist_ips is defined and zabbix_web_allowlist_ips %} + # Allow list IPs via zabbix_web_allowlist_ips + satisfy any; +{% for ip in zabbix_web_allowlist_ips | ansible.netcommon.ipaddr %} + allow {{ ip }}; +{% endfor %} + deny all; + +{% endif %} +{% if zabbix_web_htpasswd is defined and zabbix_web_htpasswd %} + # HTTP authentication via zabbix_web_htpasswd + auth_basic "Restricted"; + auth_basic_user_file {{ zabbix_web_htpasswd_file }}; + +{% endif %} + root /usr/share/zabbix; + + index index.php; + + location = /favicon.ico { + log_not_found off; + } + + location / { + try_files $uri $uri/ =404; + } + + location /assets { + access_log off; + expires 10d; + } + + location ~ /\.ht { + deny all; + } + + location ~ /(api\/|conf[^\.]|include|locale) { + deny all; + return 404; + } + + location ~ [^/]\.php(/|$) { + fastcgi_pass unix:{{ zabbix_php_fpm_listen }}; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_index index.php; + + fastcgi_param DOCUMENT_ROOT /usr/share/zabbix; + fastcgi_param SCRIPT_FILENAME /usr/share/zabbix$fastcgi_script_name; + fastcgi_param PATH_TRANSLATED /usr/share/zabbix$fastcgi_script_name; + + include fastcgi_params; + fastcgi_param QUERY_STRING $query_string; + fastcgi_param REQUEST_METHOD $request_method; + fastcgi_param CONTENT_TYPE $content_type; + fastcgi_param CONTENT_LENGTH $content_length; + + fastcgi_intercept_errors on; + fastcgi_ignore_client_abort off; + fastcgi_connect_timeout 60; + fastcgi_send_timeout 180; + fastcgi_read_timeout 180; + fastcgi_buffer_size 128k; + fastcgi_buffers 4 256k; + fastcgi_busy_buffers_size 256k; + fastcgi_temp_file_write_size 256k; + } +} diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2 new file mode 100644 index 000000000..bf2faef7a --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2 @@ -0,0 +1,35 @@ +[zabbix] +user = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_conf_web_user }} +group = {{ zabbix_php_fpm_conf_group if zabbix_php_fpm_conf_group is defined else zabbix_web_conf_web_group }} + +listen = {{ zabbix_php_fpm_listen }} +{% if zabbix_php_fpm_conf_listen and ansible_os_family != 'Debian' %} +listen.acl_users = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_conf_web_user }} +{% endif %} +{% if zabbix_php_fpm_conf_enable_user is defined %} +listen.owner = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_conf_web_user }} +{% endif %} +{% if zabbix_php_fpm_conf_enable_group %} +listen.group = {{ _nginx_group if zabbix_websrv=='nginx' else _apache_group }} +{% endif %} +{% if zabbix_php_fpm_conf_enable_mode %} +listen.mode = {{ zabbix_php_fpm_conf_mode }} +{% endif %} +listen.allowed_clients = 127.0.0.1 + +pm = dynamic +pm.max_children = 50 +pm.start_servers = 5 +pm.min_spare_servers = 5 +pm.max_spare_servers = 35 + +php_value[session.save_handler] = files +php_value[session.save_path] = {{ zabbix_php_fpm_session }} + +php_value[max_execution_time] = {{ zabbix_web_max_execution_time | default('300') }} +php_value[memory_limit] = {{ zabbix_web_memory_limit | default('128M') }} +php_value[post_max_size] = {{ zabbix_web_post_max_size | default('16M') }} +php_value[upload_max_filesize] = {{ zabbix_web_upload_max_filesize | default('2M') }} +php_value[max_input_time] = {{ zabbix_web_max_input_time | default('300') }} +php_value[max_input_vars] = {{ zabbix_web_max_input_vars | default('10000') }} +php_value[date.timezone] = {{ zabbix_timezone }} diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2 new file mode 100644 index 000000000..880ed36f0 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2 @@ -0,0 +1,55 @@ +<?php +// Zabbix GUI configuration file +{% if zabbix_server_history_url is defined %} +global $DB, $HISTORY; +{% else %} +global $DB; +{% endif %} + +$DB['TYPE'] = '{{ zabbix_server_database_long | upper() }}'; +$DB['SERVER'] = '{{ zabbix_server_dbhost }}'; +$DB['PORT'] = '{{ zabbix_server_dbport }}'; +$DB['DATABASE'] = '{{ zabbix_server_dbname }}'; +$DB['USER'] = '{{ zabbix_server_dbuser }}'; +$DB['PASSWORD'] = '{{ zabbix_server_dbpassword }}'; +$DB['ENCRYPTION'] = {{ 'true' if zabbix_server_dbencryption else 'false' }}; +$DB['VERIFY_HOST'] = {{ 'true' if zabbix_server_dbverifyhost else 'false' }}; + +// Schema name. Used for IBM DB2 and PostgreSQL. +$DB['SCHEMA'] = '{{ zabbix_server_dbschema }}'; +{% if not zabbix_web_connect_ha_backend %} +$ZBX_SERVER = '{{ zabbix_server_hostname }}'; +$ZBX_SERVER_PORT = '{{ zabbix_server_listenport }}'; +{% endif %} +$ZBX_SERVER_NAME = '{{ zabbix_server_name }}'; + +$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG; + +{% if zabbix_server_history_url is defined %} +$HISTORY['url'] = {{ zabbix_server_history_url }}; +$HISTORY['types'] = {{ zabbix_server_history_types | to_json }}; +{% endif %} + +{% if zabbix_web_doubleprecision is defined and zabbix_web_doubleprecision %} +// Use IEEE754 compatible value range for 64-bit Numeric (float) history values. +// This option is enabled by default for new Zabbix installations. +// For upgraded installations, please read database upgrade notes before enabling this option. +$DB['DOUBLE_IEEE754'] = true; +{% endif %} + +{% if zabbix_web_env is defined %} +{% for env,val in zabbix_web_env.items() %} +putenv("{{env}}={{val}}"); +{% endfor %} +{% endif %} + +{% if zabbix_saml_idp_crt is defined %} +$SSO['IDP_CERT'] = '{{ zabbix_saml_idp_crt }}'; +{% endif %} +{% if zabbix_saml_sp_crt is defined %} +$SSO['SP_CERT'] = '{{ zabbix_saml_sp_crt }}'; +{% endif %} +{% if zabbix_saml_sp_key is defined %} +$SSO['SP_KEY'] = '{{ zabbix_saml_sp_key }}'; +{% endif %} +?> diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml new file mode 100644 index 000000000..8ed439680 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 7.2 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml new file mode 100644 index 000000000..9d28ef9e3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 7.4 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml new file mode 100644 index 000000000..b4537abdf --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 7.3 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml new file mode 100644 index 000000000..9d28ef9e3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 7.4 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml new file mode 100644 index 000000000..9840e6505 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml @@ -0,0 +1,47 @@ +--- +_apache_user: www-data +_apache_group: www-data +_apache_log: apache2 +_apache_service: apache2 + +_php_fpm_dir: /etc/php/{{ _zabbix_php_version }}/fpm/pool.d +_php_fpm_session: /tmp +_php_fpm_listen: /run/php/zabbix.sock +_zabbix_php_fpm_mode: "0666" +_zabbix_php_fpm_allowed_clients: 127.0.0.1 + +_nginx_user: www-data +_nginx_group: www-data +_nginx_config_path: /etc/nginx/conf.d +_nginx_log_path: /var/log/nginx +_nginx_service: nginx +_nginx_tls_crt: /etc/ssl/certs/ssl-cert-snakeoil.pem +_nginx_tls_key: /etc/ssl/private/ssl-cert-snakeoil.key +_nginx_tls_dhparam: /etc/ssl/private/dhparams.pem + +zabbix_valid_web_versions: + # Debian + "11": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "10": + - 6.0 + - 5.0 + - 4.0 + "9": + - 4.0 + # Ubuntu + "22": + - 6.4 + - 6.0 + "20": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "18": + - 6.0 + - 5.0 + - 4.0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml new file mode 100644 index 000000000..5109c4793 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml @@ -0,0 +1,8 @@ +--- +_php_fpm_dir: /etc/opt/rh/rh-php72/php-fpm.d/ +_php_fpm_session: /var/lib/php/session +_php_fpm_listen: "/run/php-fpm/zabbix.sock" + +_zabbix_php_version: 7.2 +_zabbix_php_fpm_session: /var/opt/rh/rh-php72/lib/php/session/ +_zabbix_php_fpm_listen: /var/opt/rh/rh-php72/run/php-fpm/zabbix.sock diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml new file mode 100644 index 000000000..72022a460 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml @@ -0,0 +1,8 @@ +--- +_php_fpm_dir: /etc/php-fpm.d +_php_fpm_session: /var/lib/php/session +_php_fpm_listen: "/run/php-fpm/zabbix.sock" + +_zabbix_php_version: 7.4 +_zabbix_php_fpm_session: /var/opt/rh/rh-php72/lib/php/session/ +_zabbix_php_fpm_listen: /var/opt/rh/rh-php72/run/php-fpm/zabbix.sock diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml new file mode 100644 index 000000000..bfcca82d3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml @@ -0,0 +1,8 @@ +--- +_php_fpm_dir: /etc/php-fpm.d +_php_fpm_session: /var/lib/php/session +_php_fpm_listen: "/run/php-fpm/zabbix.sock" + +_zabbix_php_version: 8.0 +_zabbix_php_fpm_session: /var/lib/php/session +_zabbix_php_fpm_listen: /run/php-fpm/zabbix.sock diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml new file mode 100644 index 000000000..89a950683 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml @@ -0,0 +1,31 @@ +--- +_apache_user: apache +_apache_group: apache +_apache_log: httpd +_apache_service: httpd + +_php_fpm_dir: /etc/php-fpm.d +_php_fpm_session: /var/opt/rh/rh-php72/lib/php/session/ +_php_fpm_listen: /run/php-fpm/zabbix.sock + +_nginx_user: nginx +_nginx_group: nginx +_nginx_config_path: /etc/nginx/conf.d +_nginx_log_path: /var/log/nginx +_nginx_service: nginx +_nginx_tls_crt: /etc/pki/server.crt +_nginx_tls_key: /etc/pki/server.key +_nginx_tls_dhparam: /etc/pki/dhparam-server.pem + +zabbix_valid_web_versions: + "9": + - 6.4 + - 6.0 + "8": + - 6.4 + - 6.0 + - 5.0 + - 4.0 + "7": + - 5.0 + - 4.0 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml new file mode 100644 index 000000000..8ed439680 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 7.2 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml new file mode 100644 index 000000000..9d28ef9e3 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 7.4 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml new file mode 100644 index 000000000..39525f373 --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml @@ -0,0 +1,3 @@ +--- + +_zabbix_php_version: 8.1 diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml new file mode 100644 index 000000000..6de493b2e --- /dev/null +++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml @@ -0,0 +1,258 @@ +--- +sign_keys: + "64": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "62": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "60": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + jammy: + sign_key: E709712C + "54": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "52": + # bullseye: not available upstream + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "50": + bullseye: + sign_key: E709712C + buster: + sign_key: E709712C + jessie: + sign_key: E709712C + stretch: + sign_key: E709712C + focal: + sign_key: E709712C + bionic: + sign_key: E709712C + xenial: + sign_key: E709712C + trusty: + sign_key: E709712C + tricia: + sign_key: E709712C + "44": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "42": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + eoan: + sign_key: A14FE591 + cosmic: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "40": + bullseye: + sign_key: A14FE591 + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + focal: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "34": + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: A14FE591 + bionic: + sign_key: A14FE591 + sonya: + sign_key: A14FE591 + serena: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "32": + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + sonya: + sign_key: 79EA5ED4 + serena: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "30": + buster: + sign_key: A14FE591 + jessie: + sign_key: 79EA5ED4 + stretch: + sign_key: A14FE591 + wheezy: + sign_key: 79EA5ED4 + bionic: + sign_key: A14FE591 + trusty: + sign_key: 79EA5ED4 + xenial: + sign_key: E709712C + "24": + jessie: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + "22": + squeeze: + sign_key: 79EA5ED4 + wheezy: + sign_key: 79EA5ED4 + precise: + sign_key: 79EA5ED4 + trusty: + sign_key: 79EA5ED4 + lucid: + sign_key: 79EA5ED4 + +suse: + "openSUSE Leap": + "42": + name: server:monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/ + "openSUSE": + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }} + "SLES": + "11": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/ + "12": + name: server_monitoring + url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP3/ diff --git a/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini b/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini new file mode 100644 index 000000000..ead19b62d --- /dev/null +++ b/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini @@ -0,0 +1,20 @@ +# Ansible Zabbix external inventory script settings +# + +[zabbix] + +# Server location +server = http://zabbix.example.com/zabbix + +# Login +username = admin +password = zabbix + +# Verify the server's SSL certificate +validate_certs = True + +# Read zabbix inventory per host +read_host_inventory = True + +# Set ansible_ssh_host based on first interface settings +use_host_interface = True
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/scripts/inventory/zabbix.py b/ansible_collections/community/zabbix/scripts/inventory/zabbix.py new file mode 100644 index 000000000..767012848 --- /dev/null +++ b/ansible_collections/community/zabbix/scripts/inventory/zabbix.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python + +# (c) 2013, Greg Buehler +# (c) 2018, Filippo Ferrazini +# +# This file is part of Ansible, +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +###################################################################### + +""" +Zabbix Server external inventory script. +======================================== + +Returns hosts and hostgroups from Zabbix Server. +If you want to run with --limit against a host group with space in the +name, use asterisk. For example --limit="Linux*servers". + +Configuration is read from `zabbix.ini`. + +Tested with Zabbix Server 2.0.6, 3.2.3 and 3.4. +""" + +from __future__ import print_function + +import os +import sys +import argparse +from ansible.module_utils.six.moves import configparser + +try: + from zabbix_api import ZabbixAPI +except Exception: + print("Error: Zabbix API library must be installed: pip install zabbix-api.", + file=sys.stderr) + sys.exit(1) + +import json + + +class ZabbixInventory(object): + + def read_settings(self): + config = configparser.ConfigParser() + conf_path = './zabbix.ini' + if not os.path.exists(conf_path): + conf_path = os.path.dirname(os.path.realpath(__file__)) + '/zabbix.ini' + if os.path.exists(conf_path): + config.read(conf_path) + # server + if config.has_option('zabbix', 'server'): + self.zabbix_server = config.get('zabbix', 'server') + + # login + if config.has_option('zabbix', 'username'): + self.zabbix_username = config.get('zabbix', 'username') + if config.has_option('zabbix', 'password'): + self.zabbix_password = config.get('zabbix', 'password') + # ssl certs + if config.has_option('zabbix', 'validate_certs'): + if config.get('zabbix', 'validate_certs') in ['false', 'False', False]: + self.validate_certs = False + # host inventory + if config.has_option('zabbix', 'read_host_inventory'): + if config.get('zabbix', 'read_host_inventory') in ['true', 'True', True]: + self.read_host_inventory = True + # host interface + if config.has_option('zabbix', 'use_host_interface'): + if config.get('zabbix', 'use_host_interface') in ['false', 'False', False]: + self.use_host_interface = False + + def read_cli(self): + parser = argparse.ArgumentParser() + parser.add_argument('--host') + parser.add_argument('--list', action='store_true') + self.options = parser.parse_args() + + def hoststub(self): + return { + 'hosts': [] + } + + def get_host(self, api, name): + api_query = {'output': 'extend', 'selectGroups': 'extend', "filter": {"host": [name]}} + if self.use_host_interface: + api_query['selectInterfaces'] = ['useip', 'ip', 'dns'] + if self.read_host_inventory: + api_query['selectInventory'] = "extend" + + data = {'ansible_ssh_host': name} + if self.use_host_interface or self.read_host_inventory: + try: + hosts_data = api.host.get(api_query)[0] + # check if zabbix api returned a interfaces element + if 'interfaces' in hosts_data: + # check for a interfaces list that contains at least interface + if len(hosts_data['interfaces']) >= 1: + # use first interface only + if hosts_data['interfaces'][0]['useip'] == 0: + data['ansible_ssh_host'] = hosts_data['interfaces'][0]['dns'] + else: + data['ansible_ssh_host'] = hosts_data['interfaces'][0]['ip'] + if ('inventory' in hosts_data) and (hosts_data['inventory']): + data.update(hosts_data['inventory']) + except IndexError: + # Host not found in zabbix + pass + return data + + def get_list(self, api): + api_query = {'output': 'extend', 'selectGroups': 'extend'} + if self.use_host_interface: + api_query['selectInterfaces'] = ['useip', 'ip', 'dns'] + if self.read_host_inventory: + api_query['selectInventory'] = "extend" + + hosts_data = api.host.get(api_query) + data = {'_meta': {'hostvars': {}}} + + data[self.defaultgroup] = self.hoststub() + for host in hosts_data: + hostname = host['name'] + hostvars = dict() + data[self.defaultgroup]['hosts'].append(hostname) + + for group in host['groups']: + groupname = group['name'] + + if groupname not in data: + data[groupname] = self.hoststub() + + data[groupname]['hosts'].append(hostname) + # check if zabbix api returned a interfaces element + if 'interfaces' in host: + # check for a interfaces list that contains at least interface + if len(host['interfaces']) >= 1: + # use first interface only + if host['interfaces'][0]['useip'] == 0: + hostvars['ansible_ssh_host'] = host['interfaces'][0]['dns'] + else: + hostvars['ansible_ssh_host'] = host['interfaces'][0]['ip'] + if ('inventory' in host) and (host['inventory']): + hostvars.update(host['inventory']) + data['_meta']['hostvars'][hostname] = hostvars + + return data + + def __init__(self): + + self.defaultgroup = 'group_all' + self.zabbix_server = None + self.zabbix_username = None + self.zabbix_password = None + self.validate_certs = True + self.read_host_inventory = False + self.use_host_interface = True + + self.meta = {} + + self.read_settings() + self.read_cli() + + if self.zabbix_server and self.zabbix_username: + try: + api = ZabbixAPI(server=self.zabbix_server, validate_certs=self.validate_certs) + api.login(user=self.zabbix_username, password=self.zabbix_password) + # zabbix_api tries to exit if it cannot parse what the zabbix server returned + # so we have to use SystemExit here + except (Exception, SystemExit) as e: + print("Error: Could not login to Zabbix server. Check your zabbix.ini.", file=sys.stderr) + sys.exit(1) + + if self.options.host: + data = self.get_host(api, self.options.host) + print(json.dumps(data, indent=2)) + + elif self.options.list: + data = self.get_list(api) + print(json.dumps(data, indent=2)) + + else: + print("usage: --list ..OR.. --host <hostname>", file=sys.stderr) + sys.exit(1) + + else: + print("Error: Configuration of server and credentials are required. See zabbix.ini.", file=sys.stderr) + sys.exit(1) + + +ZabbixInventory() diff --git a/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/defaults/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/defaults/main.yml new file mode 100644 index 000000000..813b5c684 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/defaults/main.yml @@ -0,0 +1,4 @@ +--- +zabbix_api_server_url: http://127.0.0.1:8080 +zabbix_api_login_user: Admin +zabbix_api_login_pass: zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml new file mode 100644 index 000000000..ba4c30311 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml @@ -0,0 +1,74 @@ +--- +- name: get zabbix version + uri: + url: "{{ zabbix_api_server_url }}/api_jsonrpc.php" + method: POST + body: + jsonrpc: "2.0" + method: "apiinfo.version" + params: [] + id: "1" + body_format: json + status_code: 200 + retries: 60 + delay: 5 + until: zabbix_version_result is defined and 'json' in zabbix_version_result and 'result' in zabbix_version_result.json + register: zabbix_version_result + +- name: set zabbix_version variable + set_fact: + zabbix_version: >- + {{ [0,1] + | map('extract', zabbix_version_result.json.result.split('.')) + | list + | join('.') + }} + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + # ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + ansible_host: 127.0.0.1 + ansible_zabbix_url_path: '' + ansible_httpapi_port: 8080 + ansible_httpapi_use_ssl: false + ansible_httpapi_validate_certs: false + ansible_user: Admin + ansible_httpapi_pass: zabbix + +- debug: var=zabbix_version +- name: check login to zabbix for Zabbix < 6.4 + uri: + url: "{{ zabbix_api_server_url }}/api_jsonrpc.php" + method: POST + body: + jsonrpc: "2.0" + method: "user.login" + params: + user: "{{ zabbix_api_login_user }}" + password: "{{ zabbix_api_login_pass }}" + id: "1" + body_format: json + status_code: 200 + retries: 60 + delay: 5 + until: check_login_result is defined and 'json' in check_login_result and 'result' in check_login_result.json + register: check_login_result + when: zabbix_version is version('6.4', '<') + +- name: check login to zabbix for Zabbix >= 6.4 + uri: + url: "{{ zabbix_api_server_url }}/api_jsonrpc.php" + method: POST + body: + jsonrpc: "2.0" + method: "user.login" + params: + username: "{{ zabbix_api_login_user }}" + password: "{{ zabbix_api_login_pass }}" + id: "1" + body_format: json + status_code: 200 + retries: 60 + delay: 5 + until: check_login_result is defined and 'json' in check_login_result and 'result' in check_login_result.json + register: check_login_result + when: zabbix_version is version('6.4', '>=') diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml new file mode 100644 index 000000000..6893dfd56 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml @@ -0,0 +1,1393 @@ +--- +- name: test - do not run tests for Zabbix 3.0 + meta: end_play + when: zabbix_version is version('3.0', '=') + +- name: test - prepare example template for zabbix_action module + zabbix_template: + server_url: "{{ zabbix_api_server_url }} " + login_user: "{{ zabbix_api_login_user }}" + login_password: "{{ zabbix_api_login_pass }}" + template_name: ExampleTemplateForActionModule + template_groups: + - Templates + state: present + register: zbxaction_prep_template + +- name: test - prepare example mediatype for zabbix_action module + zabbix_mediatype: + server_url: "{{ zabbix_api_server_url }} " + login_user: "{{ zabbix_api_login_user }}" + login_password: "{{ zabbix_api_login_pass }}" + name: ExampleMediaTypeForActionModule + smtp_email: zabbix@example.com + type: email + state: present + register: zbxaction_prep_mediatype + +- name: test - simple actions + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleTriggerAction + event_source: trigger + esc_period: 60 + conditions: + - type: trigger_severity + operator: '>=' + value: Information + operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + + block: + - name: test - create new action + zabbix_action: + register: zbxaction_new + + - assert: + that: zbxaction_new.changed is sameas True + + - name: test - create new action (again) + zabbix_action: + register: zbxaction_new + + - assert: + that: zbxaction_new.changed is sameas False + + - when: zabbix_version is version('3.4', '>=') + block: + - name: test - update action with esc_period as string + zabbix_action: + esc_period: 2m + register: zbxaction_escperiod_str + + - assert: + that: zbxaction_escperiod_str.changed is sameas True + + - name: test - update action with esc_period as string (again) + zabbix_action: + esc_period: 2m + register: zbxaction_escperiod_str + + - assert: + that: zbxaction_escperiod_str.changed is sameas False + + - name: test - update action with esc_period as macro + zabbix_action: + esc_period: '{$MYMACRO}' + register: zbxaction_escperiod_macro + + - assert: + that: zbxaction_escperiod_macro.changed is sameas True + + - name: test - update action with esc_period as macro (again) + zabbix_action: + esc_period: '{$MYMACRO}' + register: zbxaction_escperiod_macro + + - assert: + that: zbxaction_escperiod_macro.changed is sameas False + + - name: test - update action with esc_period + zabbix_action: + esc_period: 120 + register: zbxaction_escperiod + + - assert: + that: zbxaction_escperiod.changed is sameas True + + - name: test - update action with esc_period (again) + zabbix_action: + esc_period: 120 + register: zbxaction_escperiod + + - assert: + that: zbxaction_escperiod.changed is sameas False + + - name: test - update action with pause_in_maintenance + zabbix_action: + esc_period: 120 + pause_in_maintenance: false + register: zbxaction_maintpause + + - assert: + that: zbxaction_maintpause.changed is sameas True + + - name: test - update action with pause_in_maintenance (again) + zabbix_action: + esc_period: 120 + pause_in_maintenance: false + register: zbxaction_maintpause + + - assert: + that: zbxaction_maintpause.changed is sameas False + + - name: test - reset action to default + zabbix_action: + register: zbxaction_reset + + - assert: + that: zbxaction_reset.changed is sameas True + + - when: zabbix_version is version('5.0', '<') + block: + - name: test - update action with default_subject and default_message + zabbix_action: + default_subject: Example default subject + default_message: Example default message + register: zbxaction_def_msgsubj + + - assert: + that: zbxaction_def_msgsubj.changed is sameas True + + - name: test - update action with default_subject and default_message (again) + zabbix_action: + default_subject: Example default subject + default_message: Example default message + register: zbxaction_def_msgsubj + + - assert: + that: zbxaction_def_msgsubj.changed is sameas False + + - when: + - zabbix_version is version('3.2', '>=') + - zabbix_version is version('5.0', '<') + block: + - name: test - update action with recovery_default_subject and recovery_default_message + zabbix_action: + default_subject: Example default subject + default_message: Example default message + recovery_default_subject: Example recovery subject + recovery_default_message: Example recovery message + register: zbxaction_rec_msgsubj + + - assert: + that: zbxaction_rec_msgsubj.changed is sameas True + + - name: test - update action with recovery_default_subject and recovery_default_message (again) + zabbix_action: + default_subject: Example default subject + default_message: Example default message + recovery_default_subject: Example recovery subject + recovery_default_message: Example recovery message + register: zbxaction_rec_msgsubj + + - assert: + that: zbxaction_rec_msgsubj.changed is sameas False + + - when: + - zabbix_version is version('3.4', '>=') + - zabbix_version is version('5.0', '<') + block: + - name: test - update action with acknowledge_default_subject and acknowledge_default_message + zabbix_action: + default_subject: Example default subject + default_message: Example default message + recovery_default_subject: Example recovery subject + recovery_default_message: Example recovery message + acknowledge_default_subject: Example acknowledge subject + acknowledge_default_message: Example acknowledge message + register: zbxaction_ack_msgsubj + + - assert: + that: zbxaction_ack_msgsubj.changed is sameas True + + - name: test - update action with acknowledge_default_subject and acknowledge_default_message (again) + zabbix_action: + default_subject: Example default subject + default_message: Example default message + recovery_default_subject: Example recovery subject + recovery_default_message: Example recovery message + acknowledge_default_subject: Example acknowledge subject + acknowledge_default_message: Example acknowledge message + register: zbxaction_ack_msgsubj + + - assert: + that: zbxaction_ack_msgsubj.changed is sameas False + + - name: test - reset action to default + zabbix_action: + register: zbxaction_reset + + - assert: + that: zbxaction_reset.changed is sameas True + + - name: test - disable action + zabbix_action: + status: disabled + register: zbxaction_disable + + - assert: + that: zbxaction_disable.changed is sameas True + + - name: test - disable action (again) + zabbix_action: + status: disabled + register: zbxaction_disable + + - assert: + that: zbxaction_disable.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + + - name: test - delete action (again) + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas False + +- name: test - trigger actions with conditions + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleTriggerActionConditions + event_source: trigger + esc_period: 60 + operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + + block: + - name: test - create new action with multiple conditions + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + - type: trigger_severity + operator: '>=' + value: Average + - type: event_tag_value + value: MyTag + operator: '=' + value2: MyTagValue + - type: time_period + operator: not in + value: 6-7,00:00-24:00 + register: zbxaction_conditions + + - assert: + that: zbxaction_conditions.changed is sameas True + + - name: test - create new action with multiple conditions (again) + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + - type: trigger_severity + operator: '>=' + value: Average + - type: event_tag_value + value: MyTag + operator: '=' + value2: MyTagValue + - type: time_period + operator: not in + value: 6-7,00:00-24:00 + register: zbxaction_conditions + + - assert: + that: zbxaction_conditions.changed is sameas False + + - name: test - create new action with multiple conditions (reorder) + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + - type: event_tag_value + value: MyTag + operator: '=' + value2: MyTagValue + - type: trigger_severity + operator: '>=' + value: Average + - type: time_period + operator: not in + value: 6-7,00:00-24:00 + register: zbxaction_conditions_reorder + + - assert: + that: zbxaction_conditions_reorder.changed is sameas False + + - name: test - update action with multiple conditions by removing one condition + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + - type: event_tag_value + value: MyTag + operator: '=' + value2: MyTagValue + - type: trigger_severity + operator: '>=' + value: Average + register: zbxaction_conditions_delone + + - assert: + that: zbxaction_conditions_delone.changed is sameas True + + - name: test - update action with multiple conditions by changing operators + zabbix_action: + conditions: + - type: host_group + operator: '<>' + value: Linux servers + - type: event_tag_value + value: MyTag + operator: '<>' + value2: MyTagValue + - type: trigger_severity + operator: '<=' + value: Average + register: zbxaction_conditions_operators + + - assert: + that: zbxaction_conditions_operators.changed is sameas True + + - name: test - update action with multiple conditions with operator aliases + zabbix_action: + conditions: + - type: host_group + operator: does not equal + value: Linux servers + - type: event_tag_value + value: MyTag + operator: contains + value2: MyTagValue + - type: trigger_severity + operator: is less than or equals + value: Average + register: zbxaction_conditions_operator_aliases + + - assert: + that: zbxaction_conditions_operator_aliases.changed is sameas True + + - name: test - update action with multiple conditions and evaltype + zabbix_action: + conditions: + - type: host_group + operator: '<>' + value: Linux servers + - type: event_tag_value + value: MyTag + operator: '<>' + value2: MyTagValue + - type: trigger_severity + operator: '<=' + value: Average + eval_type: and + register: zbxaction_conditions_eval + + - assert: + that: zbxaction_conditions_eval.changed is sameas True + + - name: test - update action with multiple conditions and evaltype (again) + zabbix_action: + conditions: + - type: host_group + operator: '<>' + value: Linux servers + - type: event_tag_value + value: MyTag + operator: '<>' + value2: MyTagValue + - type: trigger_severity + operator: '<=' + value: Average + eval_type: and + register: zbxaction_conditions_eval + + - assert: + that: zbxaction_conditions_eval.changed is sameas False + + - name: test - update action with reduced conditions and formula + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + formulaid: A + - type: trigger_severity + operator: '>=' + value: Average + formulaid: B + - type: event_tag_value + value: MyTag + operator: '<>' + value2: MyTagValue + formulaid: C + formula: A and (B or C) + register: zbxaction_conditions_formula + + - assert: + that: zbxaction_conditions_formula.changed is sameas True + + - name: test - update formula used in action with reduced conditions + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + formulaid: A + - type: trigger_severity + operator: '>=' + value: Average + formulaid: B + - type: event_tag_value + value: MyTag + operator: '<>' + value2: MyTagValue + formulaid: C + formula: (A or B) or C + register: zbxaction_conditions_formula + + - assert: + that: zbxaction_conditions_formula.changed is sameas True + + - name: test - update formula used in action with reduced conditions (again) + zabbix_action: + conditions: + - type: host_group + operator: '=' + value: Linux servers + formulaid: A + - type: trigger_severity + operator: '>=' + value: Average + formulaid: B + - type: event_tag_value + value: MyTag + operator: '<>' + value2: MyTagValue + formulaid: C + formula: (A or B) or C + register: zbxaction_conditions_formula + + - assert: + that: zbxaction_conditions_formula.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - trigger actions with message operations + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleTriggerActionOperations + event_source: trigger + esc_period: 60 + conditions: + - type: trigger_severity + operator: '>=' + value: Average + + block: + - name: test - create new action with send_message operations + zabbix_action: + operations: + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: ExampleMediaTypeForActionModule + operation_condition: not_acknowledged + esc_step_from: 1 + esc_step_to: 2 + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: SMS + operation_condition: not_acknowledged + esc_step_from: 2 + esc_step_to: 0 + esc_period: 300 + register: zbxaction_ops + + - assert: + that: zbxaction_ops.changed is sameas True + + - name: test - create new action with send_message operations (again) + zabbix_action: + operations: + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: ExampleMediaTypeForActionModule + operation_condition: not_acknowledged + esc_step_from: 1 + esc_step_to: 2 + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: SMS + operation_condition: not_acknowledged + esc_step_from: 2 + esc_step_to: 0 + esc_period: 300 + register: zbxaction_ops + + - assert: + that: zbxaction_ops.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + + - name: test - create new action with escalation steps 1-1 + zabbix_action: + operations: + - type: send_message + send_to_users: + - Admin + media_type: ExampleMediaTypeForActionModule + esc_step_from: 1 + esc_step_to: 1 + register: zbxaction_esc11 + + - assert: + that: zbxaction_esc11.changed is sameas True + + - name: test - create new action with escalation steps 1-1 (again) + zabbix_action: + operations: + - type: send_message + send_to_users: + - Admin + media_type: ExampleMediaTypeForActionModule + esc_step_from: 1 + esc_step_to: 1 + register: zbxaction_esc11_again + + - assert: + that: zbxaction_esc11_again.changed is sameas False + + + - name: test - update action with escalation steps 2-2 + zabbix_action: + operations: + - type: send_message + send_to_users: + - Admin + media_type: ExampleMediaTypeForActionModule + esc_step_from: 2 + esc_step_to: 2 + register: zbxaction_esc22 + + - assert: + that: zbxaction_esc22.changed is sameas True + + - name: test - create new action with escalation steps 2-2 (again) + zabbix_action: + operations: + - type: send_message + send_to_users: + - Admin + media_type: ExampleMediaTypeForActionModule + esc_step_from: 2 + esc_step_to: 2 + register: zbxaction_esc22_again + + - assert: + that: zbxaction_esc11_again.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True +- name: test - trigger actions with remote_script operations with < Zabbix 6.0 + when: zabbix_version is version('6.0', '<') + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleTriggerActionOperations + event_source: trigger + esc_period: 60 + conditions: + - type: trigger_severity + operator: '>=' + value: Average + + block: + - name: test - create new action with remote_command operations + zabbix_action: + operations: + - type: remote_command + command_type: custom_script + command: /usr/local/bin/do_something.sh + execute_on: agent + run_on_hosts: 0 + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: password + username: root + password: zabbix + - type: remote_command + command_type: global_script + script_name: Ping + run_on_hosts: 0 + register: zbxaction_rmtcmd + + - assert: + that: zbxaction_rmtcmd.changed is sameas True + + - name: test - create new action with remote_command operations (again) + zabbix_action: + operations: + - type: remote_command + command_type: custom_script + command: /usr/local/bin/do_something.sh + execute_on: agent + run_on_hosts: 0 + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: password + username: root + password: zabbix + - type: remote_command + command_type: global_script + script_name: Ping + run_on_hosts: 0 + register: zbxaction_rmtcmd + + - assert: + that: zbxaction_rmtcmd.changed is sameas False + + - name: test - update ssh remote_command auth in action with remote_command operations + zabbix_action: + operations: + - type: remote_command + command_type: custom_script + command: /usr/local/bin/do_something.sh + execute_on: agent + run_on_hosts: 0 + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: public_key + username: root + ssh_privatekey_file: /etc/zabbix/.ssh/id_test + ssh_publickey_file: /etc/zabbix/.ssh/id_test.pub + - type: remote_command + command_type: global_script + script_name: Ping + run_on_hosts: 0 + register: zbxaction_rmtcmd + + - assert: + that: zbxaction_rmtcmd.changed is sameas True + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - discovery actions + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleDiscoveryActionOperations + event_source: discovery + esc_period: 60 + + block: + - name: test - create new discovery action + zabbix_action: + conditions: + - type: host_IP + operator: '=' + value: '192.168.0.1-127' + - type: discovery_object + operator: '=' + value: host + - type: discovery_status + operator: '=' + value: 'discovered' + - type: uptime_or_downtime_duration + operator: '>=' + value: 1800 + operations: + - type: add_host + - type: add_to_host_group + host_groups: + - Linux servers + - type: link_to_template + templates: + - ExampleTemplateForActionModule + - type: enable_host + - type: set_host_inventory_mode + inventory: automatic + register: zbxaction_discovery + + - assert: + that: zbxaction_discovery.changed is sameas True + + - name: test - create new discovery action (again) + zabbix_action: + conditions: + - type: host_IP + operator: '=' + value: '192.168.0.1-127' + - type: discovery_object + operator: '=' + value: host + - type: discovery_status + operator: '=' + value: 'discovered' + - type: uptime_or_downtime_duration + operator: '>=' + value: 1800 + operations: + - type: add_host + - type: add_to_host_group + host_groups: + - Linux servers + - type: link_to_template + templates: + - ExampleTemplateForActionModule + - type: enable_host + - type: set_host_inventory_mode + inventory: automatic + register: zbxaction_discovery + + - assert: + that: zbxaction_discovery.changed is sameas False + + - name: test - update discovery action conditions and operations + zabbix_action: + conditions: + - type: host_IP + operator: '=' + value: '192.168.1.1-127' + - type: discovery_object + operator: '=' + value: host + - type: discovery_status + operator: '=' + value: 'discovered' + - type: uptime_or_downtime_duration + operator: '>=' + value: 2200 + operations: + - type: add_host + - type: add_to_host_group + host_groups: + - Linux servers + - Discovered hosts + - type: link_to_template + templates: + - ExampleTemplateForActionModule + - type: enable_host + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: ExampleMediaTypeForActionModule + operation_condition: not_acknowledged + esc_step_from: 1 + esc_step_to: 2 + register: zbxaction_discovery_update + + - assert: + that: zbxaction_discovery_update.changed is sameas True + + - name: test - update discovery action conditions and operations (again) + zabbix_action: + conditions: + - type: host_IP + operator: '=' + value: '192.168.1.1-127' + - type: discovery_object + operator: '=' + value: host + - type: discovery_status + operator: '=' + value: 'discovered' + - type: uptime_or_downtime_duration + operator: '>=' + value: 2200 + operations: + - type: add_host + - type: add_to_host_group + host_groups: + - Linux servers + - Discovered hosts + - type: link_to_template + templates: + - ExampleTemplateForActionModule + - type: enable_host + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: ExampleMediaTypeForActionModule + operation_condition: not_acknowledged + esc_step_from: 1 + esc_step_to: 2 + register: zbxaction_discovery_update + + - assert: + that: zbxaction_discovery_update.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - auto registration actions + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleAutoRegActionOperations + event_source: auto_registration + esc_period: 60 + + block: + - name: test - create new auto registration action + zabbix_action: + conditions: + - type: host_name + operator: like + value: zabbix + - type: host_metadata + operator: not like + value: somemetadata + operations: + - type: add_host + register: zbxaction_autoreg + + - assert: + that: zbxaction_autoreg.changed is sameas True + + - name: test - create new auto registration action (again) + zabbix_action: + conditions: + - type: host_name + operator: like + value: zabbix + - type: host_metadata + operator: not like + value: somemetadata + operations: + - type: add_host + register: zbxaction_autoreg + + - assert: + that: zbxaction_autoreg.changed is sameas False + + - name: test - update auto registration action + zabbix_action: + conditions: + - type: host_name + operator: like + value: zabbix + - type: host_metadata + operator: not like + value: somemetadata + - type: host_metadata + operator: like + value: somemetadata2 + operations: + - type: add_host + register: zbxaction_autoreg_update + + - assert: + that: zbxaction_autoreg_update.changed is sameas True + + - name: test - update auto registration action (again) + zabbix_action: + conditions: + - type: host_name + operator: like + value: zabbix + - type: host_metadata + operator: not like + value: somemetadata + - type: host_metadata + operator: like + value: somemetadata2 + operations: + - type: add_host + register: zbxaction_autoreg_update + + - assert: + that: zbxaction_autoreg_update.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - internal actions + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleInternalActionOperations + event_source: internal + esc_period: 60 + operations: + - type: send_message + send_to_users: + - Admin + subject: test_subject + message: test_message + media_type: ExampleMediaTypeForActionModule + + block: + - name: test - create new internal action + zabbix_action: + conditions: + - type: host_template + operator: '=' + value: ExampleTemplateForActionModule + - type: event_type + operator: '=' + value: item in not supported state + register: zbxaction_internal + + - assert: + that: zbxaction_internal.changed is sameas True + + - name: test - create new internal action (again) + zabbix_action: + conditions: + - type: host_template + operator: '=' + value: ExampleTemplateForActionModule + - type: event_type + operator: '=' + value: item in not supported state + register: zbxaction_internal + + - assert: + that: zbxaction_internal.changed is sameas False + + - name: test - update internal action conditions + zabbix_action: + conditions: + - type: host_template + operator: '=' + value: ExampleTemplateForActionModule + - type: event_type + operator: '=' + value: item in not supported state + - type: event_type + operator: '=' + value: trigger in unknown state + register: zbxaction_internal_update + + - assert: + that: zbxaction_internal_update.changed is sameas True + + - name: test - update internal action conditions (again) + zabbix_action: + conditions: + - type: host_template + operator: '=' + value: ExampleTemplateForActionModule + - type: event_type + operator: '=' + value: item in not supported state + - type: event_type + operator: '=' + value: trigger in unknown state + register: zbxaction_internal_update + + - assert: + that: zbxaction_internal_update.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - actions with recovery and acknowledge operations with < Zabbix 6.0 + when: + - zabbix_version is version('3.4', '>=') + - zabbix_version is version('6.0', '<') + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleTriggerActionRecAckOps + event_source: trigger + esc_period: 60 + conditions: + - type: trigger_severity + operator: '>=' + value: Information + operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + + block: + - name: test - create new action with recovery and acknowledge operations + zabbix_action: + recovery_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: remote_command + command_type: custom_script + command: /usr/local/bin/do_something.sh + execute_on: agent + run_on_hosts: 0 + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: password + username: root + password: zabbix + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + acknowledge_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: public_key + username: root + ssh_privatekey_file: /etc/zabbix/.ssh/id_test + ssh_publickey_file: /etc/zabbix/.ssh/id_test.pub + - type: remote_command + command_type: global_script + script_name: Ping + run_on_hosts: 0 + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + media_type: ExampleMediaTypeForActionModule + register: zbxaction_recack_new + + - assert: + that: zbxaction_recack_new.changed is sameas True + + - name: test - create new action with recovery and acknowledge operations (again) + zabbix_action: + recovery_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: remote_command + command_type: custom_script + command: /usr/local/bin/do_something.sh + execute_on: agent + run_on_hosts: 0 + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: password + username: root + password: zabbix + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + acknowledge_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: remote_command + command_type: ssh + command: /usr/local/bin/do_something.sh + run_on_hosts: 0 + ssh_auth_type: public_key + username: root + ssh_privatekey_file: /etc/zabbix/.ssh/id_test + ssh_publickey_file: /etc/zabbix/.ssh/id_test.pub + - type: remote_command + command_type: global_script + script_name: Ping + run_on_hosts: 0 + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + media_type: ExampleMediaTypeForActionModule + register: zbxaction_recack_new + + - assert: + that: zbxaction_recack_new.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - actions with recovery and acknowledge operations with >= Zabbx 6.0 + when: + - zabbix_version is version('6.0', '>=') + module_defaults: + community.zabbix.zabbix_action: + state: present + status: enabled + name: ExampleTriggerActionRecAckOps + event_source: trigger + esc_period: 60 + conditions: + - type: trigger_severity + operator: '>=' + value: Information + operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + + block: + - name: test - create new action with recovery and acknowledge operations + zabbix_action: + recovery_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + acknowledge_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + media_type: ExampleMediaTypeForActionModule + register: zbxaction_recack_new + + - assert: + that: zbxaction_recack_new.changed is sameas True + + - name: test - create new action with recovery and acknowledge operations (again) + zabbix_action: + recovery_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + acknowledge_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + media_type: ExampleMediaTypeForActionModule + register: zbxaction_recack_new + + - assert: + that: zbxaction_recack_new.changed is sameas False + + - when: zabbix_version is version('6.4', '>=') + block: + - name: test - update action with pause_symptoms off + zabbix_action: + recovery_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + acknowledge_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + media_type: ExampleMediaTypeForActionModule + pause_symptoms: False + register: zbxaction_pause_symptoms + + - assert: + that: zbxaction_pause_symptoms.changed is sameas True + + - name: test - update action with pause_symptoms off (again) + zabbix_action: + recovery_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + acknowledge_operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + - type: notify_all_involved + subject: RecoverySubject + message: RecoveryMessage + media_type: ExampleMediaTypeForActionModule + pause_symptoms: False + register: zbxaction_pause_symptoms + + - assert: + that: zbxaction_pause_symptoms.changed is sameas False + + - name: test - delete action + zabbix_action: + state: absent + register: zbxaction_delete + + - assert: + that: zbxaction_delete.changed is sameas True + +- name: test - Output error message when user sets application to conditions with >= Zabbix 5.4 + community.zabbix.zabbix_action: + name: ExampleApplicationAction + event_source: trigger + esc_period: 60 + conditions: + - type: application + operator: like + value: AnsibleTest + operations: + - type: send_message + subject: ExampleSubject + message: ExampleMessage + media_type: ExampleMediaTypeForActionModule + send_to_users: + - Admin + ignore_errors: true + register: zbxaction_application + +- assert: + that: + - zbxaction_application.failed is sameas True + - zbxaction_application.msg == "'application' is disabled for condition type since 5.4 version." + when: zabbix_version is version('5.4', '>=') + +- name: delete ExampleApplicationAction action + community.zabbix.zabbix_action: + name: ExampleApplicationAction + state: absent + +- name: test - cleanup example template for zabbix_action module + zabbix_template: + template_name: ExampleTemplateForActionModule + timeout: 20 + state: absent + register: zbxaction_prep_template + +- name: test - cleanup example mediatype for zabbix_action module + zabbix_mediatype: + name: ExampleMediaTypeForActionModule + type: email + state: absent + register: zbxaction_prep_mediatype diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml new file mode 100644 index 000000000..f6364f35a --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- block: + - include_tasks: zabbix_authentication_tests.yml + + always: + - name: Cleanup + zabbix_user_directory: + name: TestUserDirectory + state: absent + ignore_errors: true diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml new file mode 100644 index 000000000..effc1b900 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml @@ -0,0 +1,439 @@ +--- +- name: test - do not run tests with < Zabbix 4.0 + meta: end_play + when: zabbix_version is version('4.0', '<') + +- when: zabbix_version is version('5.4', '<') + name: Unsupport Zabbix version (<5.4) + block: + - name: test - fail to update authentication setting + zabbix_authentication: + authentication_type: internal + ignore_errors: true + register: zbxauth_update + + - assert: + that: zbxauth_update.failed is sameas True + +- when: + - zabbix_version is version('5.4', '>=') + - zabbix_version is version('6.0', '<=') + name: support Zabbix version (>=5.4 <=6.0) + block: + - name: test - update ldap_configured without mandatory paramters + zabbix_authentication: + ldap_configured: true + ignore_errors: true + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: + - zbxauth_update.failed is sameas True + - zbxauth_update.msg == "Please set ldap_host, ldap_search_attribute and ldap_base_dn when you change a value of ldap_configured to true." + + - name: test - update saml_auth_enabled without mandatory paramters + zabbix_authentication: + saml_auth_enabled: true + ignore_errors: true + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: + - zbxauth_update.failed is sameas True + - zbxauth_update.msg == "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid when you change a value of saml_auth_enabled to true." + + - name: test - update all authentication setting + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: 'comp,any' + http_case_sensitive: true + ldap_configured: true + ldap_host: 'ldap://localhost' + ldap_port: 389 + ldap_base_dn: 'ou=Users,ou=system' + ldap_search_attribute: 'uid' + ldap_bind_dn: 'uid=ldap_search,ou=system' + ldap_case_sensitive: true + ldap_bind_password: 'password' + saml_auth_enabled: true + saml_idp_entityid: '' + saml_sso_url: 'https://localhost/SAML2/SSO' + saml_slo_url: 'https://localhost/SAML2/SLO' + saml_username_attribute: 'uid' + saml_sp_entityid: 'https://localhost' + saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' + saml_sign_messages: true + saml_sign_assertions: true + saml_sign_authn_requests: true + saml_sign_logout_requests: true + saml_sign_logout_responses: true + saml_encrypt_nameid: true + saml_encrypt_assertions: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was updated + assert: + that: zbxauth_update.changed is sameas True + + - name: test - update all authentication setting (again) + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: + - comp + - any + http_case_sensitive: true + ldap_configured: true + ldap_host: 'ldap://localhost' + ldap_port: 389 + ldap_base_dn: 'ou=Users,ou=system' + ldap_search_attribute: 'uid' + ldap_bind_dn: 'uid=ldap_search,ou=system' + ldap_case_sensitive: true + ldap_bind_password: 'password' + saml_auth_enabled: true + saml_idp_entityid: '' + saml_sso_url: 'https://localhost/SAML2/SSO' + saml_slo_url: 'https://localhost/SAML2/SLO' + saml_username_attribute: 'uid' + saml_sp_entityid: 'https://localhost' + saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' + saml_sign_messages: true + saml_sign_assertions: true + saml_sign_authn_requests: true + saml_sign_logout_requests: true + saml_sign_logout_responses: true + saml_encrypt_nameid: true + saml_encrypt_assertions: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: zbxauth_update.changed is sameas False + + - name: test - initialize all authentication setting + zabbix_authentication: + authentication_type: internal + http_auth_enabled: false + http_login_form: zabbix_login_form + http_strip_domains: [] + http_case_sensitive: true + ldap_configured: false + ldap_host: '' + ldap_port: 389 + ldap_base_dn: '' + ldap_search_attribute: '' + ldap_bind_dn: '' + ldap_case_sensitive: true + ldap_bind_password: '' + saml_auth_enabled: false + saml_idp_entityid: '' + saml_sso_url: '' + saml_slo_url: '' + saml_username_attribute: '' + saml_sp_entityid: '' + saml_nameid_format: '' + saml_sign_messages: false + saml_sign_assertions: false + saml_sign_authn_requests: false + saml_sign_logout_requests: false + saml_sign_logout_responses: false + saml_encrypt_nameid: false + saml_encrypt_assertions: false + saml_case_sensitive: false + passwd_min_length: 8 + passwd_check_rules: + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was updated + assert: + that: zbxauth_update.changed is sameas True + +- when: + - zabbix_version is version('6.2', '=') + name: support Zabbix version (=6.2) + block: + - name: test - create user directory + zabbix_user_directory: + name: TestUserDirectory + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + + - name: test - update ldap_configured without mandatory paramters + zabbix_authentication: + ldap_configured: true + ignore_errors: true + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: + - zbxauth_update.failed is sameas True + - zbxauth_update.msg == "Please set ldap_userdirectory when you change a value of ldap_configured to true." + + - name: test - update saml_auth_enabled without mandatory paramters + zabbix_authentication: + saml_auth_enabled: true + ignore_errors: true + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: + - zbxauth_update.failed is sameas True + - zbxauth_update.msg == "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid when you change a value of saml_auth_enabled to true." + + - name: test - update all authentication setting + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: 'comp,any' + http_case_sensitive: true + ldap_configured: true + ldap_case_sensitive: true + ldap_userdirectory: TestUserDirectory + saml_auth_enabled: true + saml_idp_entityid: '' + saml_sso_url: 'https://localhost/SAML2/SSO' + saml_slo_url: 'https://localhost/SAML2/SLO' + saml_username_attribute: 'uid' + saml_sp_entityid: 'https://localhost' + saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' + saml_sign_messages: true + saml_sign_assertions: true + saml_sign_authn_requests: true + saml_sign_logout_requests: true + saml_sign_logout_responses: true + saml_encrypt_nameid: true + saml_encrypt_assertions: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was updated + assert: + that: zbxauth_update.changed is sameas True + + - name: test - update all authentication setting (again) + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: + - comp + - any + http_case_sensitive: true + ldap_configured: true + ldap_case_sensitive: true + ldap_userdirectory: TestUserDirectory + saml_auth_enabled: true + saml_idp_entityid: '' + saml_sso_url: 'https://localhost/SAML2/SSO' + saml_slo_url: 'https://localhost/SAML2/SLO' + saml_username_attribute: 'uid' + saml_sp_entityid: 'https://localhost' + saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' + saml_sign_messages: true + saml_sign_assertions: true + saml_sign_authn_requests: true + saml_sign_logout_requests: true + saml_sign_logout_responses: true + saml_encrypt_nameid: true + saml_encrypt_assertions: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: zbxauth_update.changed is sameas False + + - name: test - initialize all authentication setting + zabbix_authentication: + authentication_type: internal + http_auth_enabled: false + http_login_form: zabbix_login_form + http_strip_domains: [] + http_case_sensitive: true + ldap_configured: false + ldap_case_sensitive: true + saml_auth_enabled: false + saml_idp_entityid: '' + saml_sso_url: '' + saml_slo_url: '' + saml_username_attribute: '' + saml_sp_entityid: '' + saml_nameid_format: '' + saml_sign_messages: false + saml_sign_assertions: false + saml_sign_authn_requests: false + saml_sign_logout_requests: false + saml_sign_logout_responses: false + saml_encrypt_nameid: false + saml_encrypt_assertions: false + saml_case_sensitive: false + passwd_min_length: 8 + passwd_check_rules: + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was updated + assert: + that: zbxauth_update.changed is sameas True + + - name: test - delete user directory + zabbix_user_directory: + name: TestUserDirectory + state: absent + +- when: zabbix_version is version('6.4', '>=') + name: support Zabbix version (>=6.4) + block: + - name: test - update ldap_configured without mandatory paramters + zabbix_authentication: + ldap_auth_enabled: true + ignore_errors: true + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: + - zbxauth_update.failed is sameas True + - zbxauth_update.msg == "Please set ldap_userdirectory when you change a value of ldap_auth_enabled to true." + + - name: test - create LDAP user directory + zabbix_user_directory: + name: TestUserDirectory + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + provision_status: True + group_name: cn + group_basedn: ou=Group,dc=example,dc=org + group_member: member + user_ref_attr: uid + group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)' + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + + - name: test - update all authentication setting + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: 'comp,any' + http_case_sensitive: true + ldap_auth_enabled: true + ldap_case_sensitive: true + ldap_userdirectory: TestUserDirectory + saml_auth_enabled: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + ldap_jit_status: true + saml_jit_status: true + jit_provision_interval: 2h + disabled_usrgroup: Disabled + register: zbxauth_update + + - name: assert that authentication was updated + assert: + that: zbxauth_update.changed is sameas True + + - name: test - update all authentication setting (again) + zabbix_authentication: + authentication_type: internal + http_auth_enabled: true + http_login_form: zabbix_login_form + http_strip_domains: 'comp,any' + http_case_sensitive: true + ldap_auth_enabled: true + ldap_case_sensitive: true + ldap_userdirectory: TestUserDirectory + saml_auth_enabled: true + saml_case_sensitive: true + passwd_min_length: 70 + passwd_check_rules: + - contain_uppercase_and_lowercase_letters + - contain_digits + - contain_special_characters + - avoid_easy_to_guess + ldap_jit_status: true + saml_jit_status: true + jit_provision_interval: 2h + disabled_usrgroup: Disabled + register: zbxauth_update + + - name: assert that authentication was NOT updated + assert: + that: zbxauth_update.changed is sameas False + + - name: test - initialize all authentication setting + zabbix_authentication: + authentication_type: internal + http_auth_enabled: false + http_login_form: zabbix_login_form + http_strip_domains: [] + http_case_sensitive: false + ldap_auth_enabled: false + ldap_case_sensitive: false + saml_auth_enabled: false + saml_case_sensitive: false + ldap_jit_status: false + saml_jit_status: false + passwd_min_length: 8 + passwd_check_rules: + - avoid_easy_to_guess + register: zbxauth_update + + - name: assert that authentication was updated + assert: + that: zbxauth_update.changed is sameas True diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml new file mode 100644 index 000000000..3dcf93dbe --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml @@ -0,0 +1,108 @@ +--- +- name: test - do not run tests with < Zabbix 4.0 + meta: end_play + when: zabbix_version is version('4.0', '<') + +- when: zabbix_version is version('4.4', '<') + name: Unsupport Zabbix version (<4.4) + block: + - name: test fail to update autoregistration + community.zabbix.zabbix_autoregister: + tls_accept: "tls_with_psk" + tls_psk_identity: 'PSK 001' + tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478" + register: zbxautoregister_update_result + ignore_errors: true + + - assert: + that: zbxautoregister_update_result.failed is sameas True + +- when: zabbix_version is version('4.4', '>=') + name: Support Zabbix version (>=4.4) + block: + - name: test update autoregistration with no parameter + community.zabbix.zabbix_autoregister: + register: zbxautoregister_update_result + ignore_errors: true + + - assert: + that: zbxautoregister_update_result.failed is sameas True + + - name: test update autoregistration with all parameters + community.zabbix.zabbix_autoregister: + tls_accept: + - unsecure + - tls_with_psk + tls_psk_identity: 'PSK 001' + tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478" + register: zbxautoregister_update_result + + - assert: + that: zbxautoregister_update_result.changed is sameas True + + - name: test update autoregistration with all parameters (again) + community.zabbix.zabbix_autoregister: + tls_accept: + - unsecure + - tls_with_psk + tls_psk_identity: 'PSK 001' + tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478" + register: zbxautoregister_update_result + + - assert: + that: zbxautoregister_update_result.changed is sameas True + + - name: test update autoregistration with only tls_accept + community.zabbix.zabbix_autoregister: + tls_accept: "tls_with_psk" + register: zbxautoregister_update_result + + - assert: + that: zbxautoregister_update_result.changed is sameas True + + - name: test update autoregistration with only tls_accept (again) + community.zabbix.zabbix_autoregister: + tls_accept: + - tls_with_psk + register: zbxautoregister_update_result + + - assert: + that: zbxautoregister_update_result.changed is sameas False + + - name: test update autoregistration with only tls_accept (unsecure) + community.zabbix.zabbix_autoregister: + tls_accept: + - unsecure + register: zbxautoregister_update_result + + - assert: + that: zbxautoregister_update_result.changed is sameas True + + - name: test fail to update autoregistration with only tls_accept (tls_with_psk) + community.zabbix.zabbix_autoregister: + tls_accept: "tls_with_psk" + register: zbxautoregister_update_result + ignore_errors: true + + - assert: + that: zbxautoregister_update_result.failed is sameas True + + - name: test fail to update autoregistration with only tls_accept and tls_psk_identity (tls_with_psk) + community.zabbix.zabbix_autoregister: + tls_accept: "tls_with_psk" + tls_psk_identity: 'PSK 001' + register: zbxautoregister_update_result + ignore_errors: true + + - assert: + that: zbxautoregister_update_result.failed is sameas True + + - name: test fail to update autoregistration with only tls_accept and tls_psk (tls_with_psk) + community.zabbix.zabbix_autoregister: + tls_accept: "tls_with_psk" + tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478" + register: zbxautoregister_update_result + ignore_errors: true + + - assert: + that: zbxautoregister_update_result.failed is sameas True diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml new file mode 100644 index 000000000..16062a52e --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml @@ -0,0 +1,280 @@ +--- +- name: test - do not run tests for Zabbix 3.0 + meta: end_play + when: zabbix_version is version('3.0', '=') + +- name: test - Zabbix discovery rule + module_defaults: + community.zabbix.zabbix_discovery_rule: + name: ACME + state: present + iprange: 192.168.1.1-255 + dchecks: + - type: ICMP + delay: "{{ 3600 if zabbix_version is version('3.4', '<=') else omit }}" + + block: + - name: test - create new Zabbix discovery rule (checkmode) + zabbix_discovery_rule: + check_mode: true + register: drule_new_checkmode + + - name: assert that drule will be created (checkmode) + assert: + that: drule_new_checkmode is changed + + - name: test - create new Zabbix discovery rule + zabbix_discovery_rule: + register: drule_new + + - name: assert that drule was created + assert: + that: drule_new is changed + + - name: test - create same Zabbix discovery rule + zabbix_discovery_rule: + register: drule_exists + + - name: assert that nothing has been changed + assert: + that: not drule_exists is changed + + - name: test - update Zabbix discovery rule iprange (checkmode) + zabbix_discovery_rule: + iprange: + - 192.168.1.1-255 + - 10.0.0.1-255 + check_mode: true + register: drule_iprange_update_checkmode + + - name: assert that iprange will be changed + assert: + that: drule_iprange_update_checkmode is changed + + - name: test - update Zabbix discovery rule iprange + zabbix_discovery_rule: + iprange: + - 192.168.1.1-255 + - 10.0.0.1-255 + register: drule_iprange_update + + - name: assert that iprange has been changed + assert: + that: drule_iprange_update is changed + + - name: test - reset Zabbix discovery rule to default + zabbix_discovery_rule: + register: drule_reset + + - name: assert that iprange has been changed + assert: + that: drule_reset is changed + + - name: test - update Zabbix discovery rule status + zabbix_discovery_rule: + status: disabled + register: drule_status_update + + - name: assert that iprange has been changed + assert: + that: drule_status_update is changed + + - name: test - reset Zabbix discovery rule to default + zabbix_discovery_rule: + register: drule_reset + + - name: assert that iprange has been changed + assert: + that: drule_reset is changed + + - name: test - update Zabbix discovery rule dchecks + zabbix_discovery_rule: + dchecks: + - type: ICMP + - type: Zabbix + key: "system.hostname" + ports: "10050" + uniq: true + host_source: discovery + register: drule_dchecks_update + + - name: assert that dcheck has been changed + assert: + that: drule_dchecks_update is changed + + - name: test - update Zabbix discovery rule dchecks ssh + zabbix_discovery_rule: + dchecks: + - type: ICMP + - type: SSH + ports: "22" + register: drule_dchecks_ssh_update + + - name: assert that dcheck has been changed + assert: + that: drule_dchecks_ssh_update is changed + + - name: test - update Zabbix discovery rule dchecks ldap + zabbix_discovery_rule: + dchecks: + - type: ICMP + - type: SSH + ports: "22" + - type: LDAP + ports: "389" + register: drule_dchecks_ldap_update + + - name: assert that dcheck has been changed + assert: + that: drule_dchecks_ldap_update is changed + + - name: test - update Zabbix discovery rule dchecks smtp + zabbix_discovery_rule: + dchecks: + - type: ICMP + - type: SSH + ports: "22" + - type: LDAP + ports: "389" + - type: SMTP + ports: 25,465,587 + register: drule_dchecks_smtp_update + + - name: assert that dcheck has been changed + assert: + that: drule_dchecks_smtp_update is changed + + - name: test - update Zabbix discovery rule dchecks http + zabbix_discovery_rule: + dchecks: + - type: ICMP + - type: SSH + ports: "22" + - type: LDAP + ports: "389" + - type: SMTP + ports: 25,465,587 + - type: HTTP + ports: 80,8080 + register: drule_dchecks_http_update + + - name: assert that dcheck has been changed + assert: + that: drule_dchecks_http_update is changed + + - name: test - remove Zabbix discovery rule dchecks + zabbix_discovery_rule: + dchecks: + - type: ICMP + register: drule_dchecks_remove_update + + - name: assert that dcheck has been changed + assert: + that: drule_dchecks_remove_update is changed + + - name: test - update Zabbix discovery rule snmp dcheck + zabbix_discovery_rule: + dchecks: + - type: SNMPv2 + snmp_community: CUSTOMER@snmp-readonly + ports: "161" + key: iso.3.6.1.2.1.1.1.0 + uniq: false + host_source: discovery + name_source: discovery + register: drule_snmp_update + + - name: assert that snmp dcheck has been changed + assert: + that: drule_snmp_update is changed + + - name: test - update Zabbix discovery rule snmp3 dcheck + zabbix_discovery_rule: + dchecks: + - type: SNMPv3 + snmp_community: CUSTOMER@snmp3-readonly + ports: "161" + key: iso.3.6.1.2.1.1.1.0 + snmpv3_contextname: "ContextName" + snmpv3_securityname: "SecurityName" + snmpv3_securitylevel: authPriv + snmpv3_authprotocol: SHA + snmpv3_authpassphrase: "SeCrEt" + snmpv3_privprotocol: AES + snmpv3_privpassphrase: "TopSecret" + uniq: false + host_source: DNS + name_source: None + register: drule_snmp3_update + + - name: assert that snmp3 dcheck has been changed + assert: + that: drule_snmp3_update is changed + + - name: test - reset Zabbix discovery rule to default + zabbix_discovery_rule: + register: drule_reset + + - name: assert that iprange has been changed + assert: + that: drule_reset is changed + + - name: test - create new active Zabbix proxy server + zabbix_proxy: + proxy_name: ACME_proxy + status: active + state: present + register: zbxproxy_active + + - name: assert that proxy was created + assert: + that: zbxproxy_active is changed + + - name: test - update Zabbix discovery rule proxy + zabbix_discovery_rule: + proxy: ACME_proxy + register: drule_proxy_update + + - name: assert that proxy has been changed + assert: + that: drule_proxy_update is changed + + - name: test - update Zabbix discovery rule proxy (again) + zabbix_discovery_rule: + proxy: ACME_proxy + register: drule_proxy_update_again + + - name: assert that nothing has been changed + assert: + that: not drule_proxy_update_again is changed + +- name: test - delete Zabbix discovery rule + zabbix_discovery_rule: + name: ACME + state: absent + register: drule_delete + +- name: assert that proxy has been deleted + assert: + that: drule_delete is changed + +- name: test - delete Zabbix discovery rule (again) + zabbix_discovery_rule: + name: ACME + state: absent + register: drule_delete_again + +- name: assert that nothing has been changed + assert: + that: not drule_delete_again is changed + +# Cleanup +- name: delete active Zabbix proxy server + zabbix_proxy: + proxy_name: ACME_proxy + state: absent + register: zbxproxy_delete + +- name: assert that proxy has been deleted + assert: + that: zbxproxy_delete is changed diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml new file mode 100644 index 000000000..ce49f0f86 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml @@ -0,0 +1,174 @@ +--- +- name: test - attempt to create new global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test01 + macro_value: 123 + macro_type: text + macro_description: Global Macro description + register: zbxgmacro_new + +- name: assert that macro was created + assert: + that: zbxgmacro_new is changed + +- name: test - attempt to create same global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test01 + macro_value: 123 + macro_type: text + macro_description: Global Macro description + register: zbxgmacro_existing + +- name: assert that nothing has been changed + assert: + that: not zbxgmacro_existing is changed + +- name: test - attempt to create same global macro in zabbix native format + zabbix_globalmacro: + macro_name: "{$zbxgmacro_test01}" + macro_value: 123 + macro_type: text + macro_description: Global Macro description + register: zbxgmacro_existing_native + +- name: assert that nothing has been changed + assert: + that: not zbxgmacro_existing_native is changed + +- name: test - attempt to create new global macro in zabbix native format + zabbix_globalmacro: + macro_name: "{$ZBXGMACRO_TEST02}" + macro_value: abcd + macro_type: text + register: zbxgmacro_new_native + +- name: assert that nothing macro was created + assert: + that: zbxgmacro_new_native is changed + +- name: test - attempt to update global macro with string value while force=no + zabbix_globalmacro: + macro_name: zbxgmacro_test01 + macro_value: abc + macro_type: text + force: false + register: zbxgmacro_update_noforce + +- name: assert that nothing has been changed + assert: + that: not zbxgmacro_update_noforce is changed + +- name: test - attempt to update global macro with string value + zabbix_globalmacro: + macro_name: zbxgmacro_test01 + macro_value: abc + macro_type: text + register: zbxgmacro_update + +- name: assert that global macro was updated + assert: + that: zbxgmacro_update is changed + +- name: test - attempt to create global macro with context + zabbix_globalmacro: + macro_name: low_space_limit:/home + macro_value: 10 + macro_type: text + register: zbxgmacro_context_new + +- name: assert that macro was created + assert: + that: zbxgmacro_context_new is changed + +- name: test - attempt to create same global macro with context and verify that it was converted to uppercase + zabbix_globalmacro: + macro_name: LOW_SPACE_LIMIT:/home + macro_value: 10 + macro_type: text + register: zbxgmacro_context_existing + +- name: assert that nothing has been changed + assert: + that: not zbxgmacro_context_existing is changed + +- name: test - attempt to delete all global macros + zabbix_globalmacro: + macro_name: "{{ item }}" + state: absent + loop: + - zbxgmacro_test01 + - LOW_SPACE_LIMIT:/home + - "{$ZBXGMACRO_TEST02}" + register: zbxgmacro_delete_existing + +- name: assert that all macros have been deleted + assert: + that: item.changed is sameas True + loop: "{{ zbxgmacro_delete_existing.results }}" + +- name: test - attempt to delete non-existing global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test01 + state: absent + register: zbxgmacro_delete_missing + +- name: assert that nothing has been changed + assert: + that: not zbxgmacro_delete_missing is changed + +- name: test - attempt to create secret global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test_secret + macro_value: 123 + macro_type: secret + macro_description: Global Macro description + register: zbxgmacro_secret + +- assert: + that: zbxgmacro_secret.changed is sameas True + +- name: test - attempt to create same global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test_secret + macro_value: 123 + macro_type: secret + macro_description: Global Macro description + register: zbxgmacro_secret + +- assert: + that: zbxgmacro_secret.changed is sameas True + when: zabbix_version is version('5.0', '>=') + +- assert: + that: zbxgmacro_secret.changed is sameas False + when: zabbix_version is version('5.0', '<') + +- name: test - attempt to create vault global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test_vault + macro_value: path/to/vault:zabbix + macro_type: vault + macro_description: Global Macro description + register: zbxgmacro_vault + +- assert: + that: zbxgmacro_vault.changed is sameas True + +- name: test - attempt to create same global macro + zabbix_globalmacro: + macro_name: zbxgmacro_test_vault + macro_value: path/to/vault:zabbix + macro_type: vault + macro_description: Global Macro description + register: zbxgmacro_vault + +- assert: + that: zbxgmacro_vault.changed is sameas False + +- name: delete all global macros + zabbix_globalmacro: + macro_name: "{{ item }}" + state: absent + loop: + - zbxgmacro_test_secret + - zbxgmacro_test_vault diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml new file mode 100644 index 000000000..0f099d7c1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml @@ -0,0 +1,88 @@ +--- +- name: test - create new Zabbix group + zabbix_group: + host_groups: + - zbxgrp_example_group01 + state: present + register: zbxgrp_new + +- name: assert that group was created + assert: + that: zbxgrp_new is changed + +- name: test - create simple zabbix host to assign to group + zabbix_host: + host_name: zbxgrp_example_host01 + host_groups: + - zbxgrp_example_group01 + interfaces: + - type: agent + main: 1 + dns: zbxgrp_example_host01 + state: present + register: zbxgrp_host_assignement + +- name: assert that host was assigned successfully + assert: + that: zbxgrp_host_assignement is changed + +- name: test - create same Zabbix group once again + zabbix_group: + host_groups: + - zbxgrp_example_group01 + state: present + register: zbxgrp_existing + +- name: assert that nothing has been changed + assert: + that: not zbxgrp_existing is changed + +- name: test - attempt to create new Zabbix group matching name of default Zabbix group + zabbix_group: + host_groups: + - Linux servers + state: present + register: zbxgrp_default_existing + +- name: assert that nothing has been changed + assert: + that: not zbxgrp_default_existing is changed + +- name: test - attempt to delete host group while its only group host has assigned + zabbix_group: + host_groups: + - zbxgrp_example_group01 + state: absent + register: zbxgrp_existing_delete_failed + ignore_errors: true + +- name: assert that group deletion failed + assert: + that: zbxgrp_existing_delete_failed is failed + +- name: delete helper zabbix host + zabbix_host: + host_name: zbxgrp_example_host01 + state: absent + +- name: test - attempt to delete previously created zabbix group + zabbix_group: + host_groups: + - zbxgrp_example_group01 + state: absent + register: zbxgrp_existing_delete + +- name: assert that group was deleted + assert: + that: zbxgrp_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix group + zabbix_group: + host_groups: + - zbxgrp_example_group01 + state: absent + register: zbxgrp_missing_delete + +- name: assert that nothing has been changed + assert: + that: not zbxgrp_missing_delete is changed diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml new file mode 100644 index 000000000..624679603 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml @@ -0,0 +1,50 @@ +--- +- name: test - create new Zabbix group + zabbix_group: + host_groups: + - zbxgrp_example_group01 + - zbxgrp_example_group02 + state: present + register: zbxgrp_new + +- name: assert that group was created + assert: + that: zbxgrp_new is changed + +- name: test - get one hostgroup info + zabbix_group_info: + hostgroup_name: + - zbxgrp_example_group01 + register: get_hostgorup_info_result + +- name: assert that one group was get + assert: + that: + - get_hostgorup_info_result.host_groups | length == 1 + - get_hostgorup_info_result.host_groups.0.name == 'zbxgrp_example_group01' + +- name: test - get two hostgroup info + zabbix_group_info: + hostgroup_name: + - zbxgrp_example_group01 + - zbxgrp_example_group02 + register: get_hostgorup_info_result + +- name: assert that two group was get + assert: + that: + - get_hostgorup_info_result.host_groups | length == 2 + - get_hostgorup_info_result.host_groups.0.name == 'zbxgrp_example_group01' + - get_hostgorup_info_result.host_groups.1.name == 'zbxgrp_example_group02' + +- name: test - delete Zabbix group + zabbix_group: + host_groups: + - zbxgrp_example_group01 + - zbxgrp_example_group02 + state: absent + register: delete_zbxgrp + +- name: assert that group was deleted + assert: + that: delete_zbxgrp is changed diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml new file mode 100644 index 000000000..20755061f --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- block: + # setup stuff not testing zabbix_host + - include_tasks: zabbix_host_setup.yml + + # zabbix_host module tests + - include_tasks: zabbix_host_tests.yml + + # documentation example tests + - include_tasks: zabbix_host_doc.yml + + # tear down stuff set up earlier + - include_tasks: zabbix_host_teardown.yml + always: + - name: "cleanup if tests failed" + zabbix_host: + host_name: ExampleHost + state: absent + ignore_errors: true diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml new file mode 100644 index 000000000..4415e2ca1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml @@ -0,0 +1,77 @@ +--- +# These two tests are close to documentation example + +- name: Create a new host or update an existing host's info + zabbix_host: + host_name: ExampleHost1 + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + - Zabbix servers + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + status: enabled + state: present + inventory_mode: manual + inventory_zabbix: + tag: test-tag + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw + ipmi_authtype: 2 + ipmi_privilege: 4 + ipmi_username: username + ipmi_password: password + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + macros: + - macro: '{$EXAMPLEMACRO}' + value: ExampleMacroValue + - macro: EXAMPLEMACRO2 + value: ExampleMacroValue2 + description: Example desc that work only with Zabbix 4.4 and higher + tags: + - tag: ExampleHostsTag + - tag: ExampleHostsTag2 + value: ExampleTagValue + register: zabbix_host1 + +- name: Update an existing host's tls settings + zabbix_host: + host_name: ExampleHost2 + visible_name: ExampleName2 + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.2 + dns: "" + port: "10050" + host_groups: + - Linux servers + tls_psk_identity: test + tls_connect: 2 + tls_psk: 123456789abcdef123456789abcdef12 + register: zabbix_host2 + +- name: expect both to succeed + assert: + that: + - "zabbix_host1 is changed" + - "zabbix_host2 is changed" diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml new file mode 100644 index 000000000..15e3e2fa5 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml @@ -0,0 +1,29 @@ +--- +# set up a zabbix proxy to test zabbix_host with + +- name: Create a new proxy + zabbix_proxy: + proxy_name: ExampleProxy + description: ExampleProxy + status: active + state: present + interface: + type: 0 + main: 1 + useip: 1 + ip: 10.5.6.7 + dns: "" + port: 10050 + register: zabbix_proxy + +- name: Create Templates + zabbix_template: + template_name: "{{ item }}" + template_groups: + - Templates + with_items: + - IMAP Service + - NTP Service + - HTTP Service + - LDAP Service + when: zabbix_version | float >= 6.4 diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml new file mode 100644 index 000000000..7eedcf12d --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml @@ -0,0 +1,18 @@ +--- +# remove zabbix_proxy (hopefully) created earlier + +- name: remove proxy + zabbix_proxy: + proxy_name: ExampleProxy + state: absent + +- name: remove Templates + zabbix_template: + template_name: "{{ item }}" + state: absent + with_items: + - IMAP Service + - NTP Service + - HTTP Service + - LDAP Service + when: zabbix_version | float >= 6.4 diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml new file mode 100644 index 000000000..d72dbe318 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml @@ -0,0 +1,1385 @@ +--- +- name: "test: create host with many options set" + zabbix_host: + timeout: 30 # slower with py2.7 + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + - Zabbix servers + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + status: enabled + state: present + inventory_mode: manual + inventory_zabbix: + tag: test-tag + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + - type: 1 + main: 0 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "{$MACRO}" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + proxy: ExampleProxy + macros: + - macro: MACRO1 + value: test1 + - macro: '{$MACRO2}' + value: test2 + tags: + - tag: Tag1 + - tag: Tag2 + value: test2 + register: zabbix_host1 + +- name: expect to succeed and that things changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: try to create the same host with the same settings" + zabbix_host: + timeout: 30 # slower with py2.7 + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + - Zabbix servers + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + status: enabled + state: present + inventory_mode: manual + inventory_zabbix: + tag: test-tag + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + - type: 1 + main: 0 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "{$MACRO}" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + proxy: ExampleProxy + macros: + - macro: MACRO1 + value: test1 + - macro: '{$MACRO2}' + value: test2 + tags: + - tag: Tag1 + - tag: Tag2 + value: test2 + register: zabbix_host1 + +- name: updating with same values should be idempotent + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: try to create the same host with the same settings and force false" + zabbix_host: + force: false + timeout: 30 # slower with py2.7 + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + - Zabbix servers + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + status: enabled + state: present + inventory_mode: manual + inventory_zabbix: + tag: test-tag + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + - type: 1 + main: 0 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "{$MACRO}" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + proxy: ExampleProxy + register: zabbix_host1 + +- name: updating with same values and force false should be idempotent + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: try to create the same host changing one parameter in the inventory with force false" + zabbix_host: + force: false + timeout: 30 # slower with py2.7 + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + - Zabbix servers + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + status: enabled + state: present + inventory_mode: manual + inventory_zabbix: + tag: test-tag + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw-modified + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + - type: 1 + main: 0 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "{$MACRO}" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + proxy: ExampleProxy + register: zabbix_host1 + +- name: changing the value of an already defined inventory should work and mark task as changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change visible_name" + zabbix_host: + host_name: ExampleHost + visible_name: "ExampleName Changed" + register: zabbix_host1 + +- name: expect to succeed and that things changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change visible_name (again)" + zabbix_host: + host_name: ExampleHost + visible_name: "ExampleName Changed" + register: zabbix_host1 + +- name: updating with same values should be idempotent + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change description" + zabbix_host: + host_name: ExampleHost + description: "My ExampleHost Description Changed" + register: zabbix_host1 + +- name: expect to succeed and that things changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change description (again)" + zabbix_host: + host_name: ExampleHost + description: "My ExampleHost Description Changed" + register: zabbix_host1 + +- name: updating with same values should be idempotent + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host groups (adding one group)" + zabbix_host: + host_name: ExampleHost + host_groups: + - Linux servers + - Zabbix servers + - Virtual machines + register: zabbix_host1 + +- name: expect to succeed and that things changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host groups (remove one group)" + zabbix_host: + host_name: ExampleHost + host_groups: + - Linux servers + - Zabbix servers + register: zabbix_host1 + +- name: expect to succeed and that things changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host groups (add one group using force=no)" + zabbix_host: + host_name: ExampleHost + host_groups: + - Virtual machines + force: false + register: zabbix_host1 + +- name: expect to succeed and that things changed + assert: + that: + - "zabbix_host1 is changed" + + +- name: "test: change host groups (check whether we are at three groups)" + zabbix_host: + host_name: ExampleHost + host_groups: + - Linux servers + - Zabbix servers + - Virtual machines + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host groups (attempt to remove all host groups)" + zabbix_host: + host_name: ExampleHost + # list with empty value, expected: + host_groups: + - + register: zabbix_host1 + ignore_errors: true + +- name: expect to fail + assert: + that: + - "zabbix_host1 is failed" + +- name: "test: change host linked templates (same as before)" + zabbix_host: + host_name: ExampleHost + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host linked templates (add one template)" + zabbix_host: + host_name: ExampleHost + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + - "{{ 'HTTP Service' if zabbix_version | float >= 5.2 else 'Template App HTTP Service' }}" + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host linked templates (add one template, using force=no)" + zabbix_host: + host_name: ExampleHost + link_templates: + - "{{ 'LDAP Service' if zabbix_version | float >= 5.2 else 'Template App LDAP Service' }}" + force: false + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host linked templates (make sure we are at 4 templates)" + zabbix_host: + host_name: ExampleHost + link_templates: + - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}" + - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}" + - "{{ 'HTTP Service' if zabbix_version | float >= 5.2 else 'Template App HTTP Service' }}" + - "{{ 'LDAP Service' if zabbix_version | float >= 5.2 else 'Template App LDAP Service' }}" + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host linked templates (remove all templates)" + zabbix_host: + timeout: 60 # slower with py2.7 + host_name: ExampleHost + link_templates: + - + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host linked templates (check we have no templates left)" + zabbix_host: + host_name: ExampleHost + link_templates: + - + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host status" + zabbix_host: + host_name: ExampleHost + status: disabled + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host status (again)" + zabbix_host: + host_name: ExampleHost + status: disabled + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host inventory mode" + zabbix_host: + host_name: ExampleHost + inventory_mode: automatic + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host inventory mode" + zabbix_host: + host_name: ExampleHost + inventory_mode: automatic + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change host inventory data (one field)" + zabbix_host: + host_name: ExampleHost + inventory_zabbix: + tag: test-tag-two + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host inventory data (again)" + zabbix_host: + host_name: ExampleHost + inventory_zabbix: + tag: test-tag-two + alias: test-alias + notes: "Special Informations: test-info" + location: test-location + site_rack: test-rack + os: test-os + hardware: test-hw + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: remove host proxy" + zabbix_host: + host_name: ExampleHost + proxy: '' + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add host proxy" + zabbix_host: + host_name: ExampleHost + proxy: ExampleProxy + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add host proxy (again)" + zabbix_host: + host_name: ExampleHost + proxy: ExampleProxy + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change tls certificate settings" + zabbix_host: + host_name: ExampleHost + tls_connect: 4 + tls_accept: 4 + tls_issuer: AcmeCorp + tls_subject: AcmeCorpServer + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change tls certificate settings (again)" + zabbix_host: + host_name: ExampleHost + tls_connect: 4 + tls_accept: 4 + tls_issuer: AcmeCorp + tls_subject: AcmeCorpServer + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change tls psk (write-only) settings" + zabbix_host: + host_name: ExampleHost + tls_connect: 2 + tls_accept: 2 + tls_psk_identity: test + tls_psk: 123456789abcdef123456789abcdef12 + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: zabbix_host1 is changed + +- name: "test: change tls psk (write-only) settings (again)" + zabbix_host: + host_name: ExampleHost + tls_connect: 2 + tls_accept: 2 + tls_psk_identity: test + tls_psk: 123456789abcdef123456789abcdef12 + register: zabbix_host1 + +- name: expect to succeed and that things have changed (tls_psk makes module non-idempotent) + assert: + that: zabbix_host1 is changed + when: zabbix_version is version('5.4', '>=') + +- name: expect to succeed and that things have not changed + assert: + that: zabbix_host1 is not changed + when: zabbix_version is version('5.4', '<') + +- name: "test: change interface settings (remove one)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change interface settings (again)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: change interface settings (add one interface using force=no)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + force: false + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change interface settings (verify that we are at two interfaces)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "12345" + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "not zabbix_host1 is changed" + +- name: "test: configure interface to useip=1 but provide no ip" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + port: "10050" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "12345" + register: zabbix_host1 + ignore_errors: true + +- name: expect to fail + assert: + that: + - "zabbix_host1 is failed" + +- name: "test: configure interface to useip=0 but provide no dns" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 0 + ip: 10.1.1.1 + port: "10050" + - type: 4 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "12345" + register: zabbix_host1 + ignore_errors: true + +- name: expect to fail + assert: + that: + - "zabbix_host1 is failed" + +- when: zabbix_version is version("5.0", ">=") + block: + - name: "test: configure SNMPv2 interface without details (fail)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + register: zabbix_host1 + ignore_errors: true + + - name: expect to fail + assert: + that: + - "zabbix_host1 is failed" + + - name: "test: configure details for SNMPv2 interface" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 2 + community: Community String + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: configure details for SNMPv2 interface (again)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 2 + community: Community String + register: zabbix_host1 + + - name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + + - name: "test: configure SNMPv2 interface with the same options and force=False " + zabbix_host: + host_name: ExampleHost + force: False + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 2 + community: Community String + register: zabbix_host1 + + - name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + + - name: "test: update details for SNMPv2 interface with bulk sub option" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 2 + community: Community String + bulk: 0 + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: configure details for SNMPv3 interface" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 3 + contextname: snmp_context + securityname: SNMP3 sec name + securitylevel: 0 + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: configure details for SNMPv3 interface (again)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 3 + contextname: snmp_context + securityname: SNMP3 sec name + securitylevel: 0 + register: zabbix_host1 + + - name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + + - name: "test: update details for SNMPv3 interface" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "10050" + - type: 2 + main: 1 + useip: 1 + ip: 10.1.1.1 + port: "161" + details: + version: 3 + contextname: snmp_context + securityname: SNMP3 sec name + securitylevel: 2 + authprotocol: "{{ 2 if zabbix_version | float >= 5.4 else 0 }}" + authpassphrase: secret_auth_passphrase + privprotocol: "{{ 2 if zabbix_version | float >= 5.4 else 0 }}" + privpassphrase: secret_priv_passphrase + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +# https://github.com/ansible-collections/community.zabbix/pull/391 +- name: "reset interfaces to two of the same type" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: "1" + main: 1 + useip: 1 + ip: 127.0.0.1 + - type: "1" + useip: 1 + ip: 127.0.1.1 + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "reset interfaces to two of the same type (again)" + zabbix_host: + host_name: ExampleHost + interfaces: + - type: "1" + main: 1 + useip: 1 + ip: 127.0.0.1 + - type: "1" + useip: 1 + ip: 127.0.1.1 + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: add IPMI settings" + zabbix_host: + host_name: ExampleHost + ipmi_authtype: 2 + ipmi_privilege: 4 + ipmi_username: username + ipmi_password: password + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add IPMI settings again" + zabbix_host: + host_name: ExampleHost + ipmi_authtype: 2 + ipmi_privilege: 4 + ipmi_username: username + ipmi_password: password + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: verify that an empty change is idempotent" + zabbix_host: + host_name: ExampleHost + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: IPMI set default values" + zabbix_host: + host_name: ExampleHost + ipmi_authtype: -1 + ipmi_privilege: 2 + ipmi_username: "" + ipmi_password: "" + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: IPMI set default values (again)" + zabbix_host: + host_name: ExampleHost + ipmi_authtype: -1 + ipmi_privilege: 2 + ipmi_username: "" + ipmi_password: "" + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: change host inventory mode to disabled" + zabbix_host: + host_name: ExampleHost + inventory_mode: disabled + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: change host inventory mode to manual" + zabbix_host: + host_name: ExampleHost + inventory_mode: manual + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add new set of user macros to the host" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACRO1}' + value: test123 + - macro: NEWMACRO2 + value: abc + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add new set of user macros to the host (again - lowercase)" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$newmacro1}' + value: test123 + - macro: newmacro2 + value: abc + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: update one of the user macros present on the host" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACRO1}' + value: test1234 + - macro: NEWMACRO2 + value: abc + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +# The description of tag is available since Zabbix version 4.4 +- when: zabbix_version is version("4.4", ">=") + block: + - name: "test: update one of the user macros with description" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACRO1}' + value: test1234 + description: Example Description + - macro: NEWMACRO2 + value: abc + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: update one of the user macros with description (again)" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACRO1}' + value: test1234 + description: Example Description + - macro: NEWMACRO2 + value: abc + register: zabbix_host1 + + - name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + + - name: "test: update one of the user macros by removing description" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACRO1}' + value: test1234 + - macro: NEWMACRO2 + value: abc + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add user macro while keeping previous ones with force=no" + zabbix_host: + host_name: ExampleHost + force: false + macros: + - macro: '{$NEWMACRO3}' + value: testing + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: add user macro while keeping previous ones with force=no (again)" + zabbix_host: + host_name: ExampleHost + force: false + macros: + - macro: '{$NEWMACRO3}' + value: testing + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: add the same user macros (again)" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACRO1}' + value: test1234 + - macro: NEWMACRO2 + value: abc + - macro: '{$NEWMACRO3}' + value: testing + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +# type for macros added in 5.0 +- when: zabbix_version is version("5.0", ">=") + block: + - name: "test: add new user macro with type secret" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACROSECRET}' + value: secretvalue + type: secret + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: add new user macro with type secret (again)" + zabbix_host: + host_name: ExampleHost + macros: + - macro: '{$NEWMACROSECRET}' + value: secretvalue + type: secret + register: zabbix_host1 + + - name: expect to succeed and that things have changed as it has secret value + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: wipe out all of the user macros" + zabbix_host: + host_name: ExampleHost + macros: [] + register: zabbix_host1 + +- name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: wipe out all of the user macros (again)" + zabbix_host: + host_name: ExampleHost + macros: [] + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +# The tag function is available since Zabbix version 4.4 +- when: zabbix_version is version("4.4", ">=") + block: + - name: "test: add new set of tags to the host" + zabbix_host: + host_name: ExampleHost + tags: + - tag: NEWTAG1 + - tag: NewTag2 + value: abc + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: add new set of tags to the host (again)" + zabbix_host: + host_name: ExampleHost + tags: + - tag: NEWTAG1 + - tag: NewTag2 + value: abc + register: zabbix_host1 + + - name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + + - name: "test: update one of the tags present on the host" + zabbix_host: + host_name: ExampleHost + tags: + - tag: NEWTAG1 + - tag: NewTag2 + value: abcd + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: add tag while keeping previous ones with force=no" + zabbix_host: + host_name: ExampleHost + force: false + tags: + - tag: newtag3 + value: testing + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + + - name: "test: add the same tags (again)" + zabbix_host: + host_name: ExampleHost + tags: + - tag: NEWTAG1 + - tag: NewTag2 + value: abcd + - tag: newtag3 + value: testing + register: zabbix_host1 + + - name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + + - name: "test: wipe out all of the tags" + zabbix_host: + host_name: ExampleHost + tags: [] + register: zabbix_host1 + + - name: expect to succeed and that things have changed + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: wipe out all of the tags (again)" + zabbix_host: + host_name: ExampleHost + tags: [] + register: zabbix_host1 + +- name: expect to succeed and that things have not changed + assert: + that: + - "zabbix_host1 is not changed" + +- name: "test: attempt to delete host created earlier" + zabbix_host: + host_name: ExampleHost + state: absent + register: zabbix_host1 + +- name: deleting a host is a change, right? + assert: + that: + - "zabbix_host1 is changed" + +- name: "test: attempt deleting a non-existant host" + zabbix_host: + host_name: ExampleHost + state: absent + register: zabbix_host1 + +- name: deleting a non-existant host is not a change, right? + assert: + that: + - "not zabbix_host1 is changed" + +- when: zabbix_version is version('5.2', '>=') + block: + - name: "test: create host without host interfaces" + zabbix_host: + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + status: disabled + state: present + register: zbx_host_create_interfaceless + + - name: verify host was created without interfaces + assert: + that: zbx_host_create_interfaceless is changed + + - name: "test: create host without host interfaces (again)" + zabbix_host: + server_url: "{{ zabbix_api_server_url }}" + login_user: "{{ zabbix_api_login_user }}" + login_password: "{{ zabbix_api_login_pass }}" + host_name: ExampleHost + visible_name: ExampleName + description: My ExampleHost Description + host_groups: + - Linux servers + status: disabled + state: present + register: zbx_host_create_interfaceless + + - name: expect to succeed and that things have not changed + assert: + that: zbx_host_create_interfaceless is not changed + + - name: "cleanup" + zabbix_host: + host_name: ExampleHost + state: absent diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml new file mode 100644 index 000000000..dfcaf097d --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml @@ -0,0 +1,185 @@ +--- +- name: "test - Prepare host for zabbix_host_info module" + zabbix_host: + host_name: ExampleHostForHostInfoModule + visible_name: ExampleHostForHostInfoModuleName + description: Test Host + host_groups: + - Linux servers + - Hypervisors + link_templates: + - "{{ 'Zabbix server health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Server' }}" + status: enabled + inventory_mode: manual + inventory_zabbix: + tag: tag1 + os: Linux + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 192.168.0.1 + dns: "" + port: 10050 + state: present + register: prepare_host_result + +- assert: + that: + - prepare_host_result.changed is sameas true + +- name: "test - Gather zabbix host facts using environment variables" + community.zabbix.zabbix_host_info: + host_name: ExampleHostForHostInfoModule + register: env_vars_usage + environment: + ZABBIX_VALIDATE_CERTS: false + +- assert: + that: + - env_vars_usage.hosts[0].name == "ExampleHostForHostInfoModuleName" + +- name: "test - Set default parameters to zabbix_host_info" + module_defaults: + community.zabbix.zabbix_host_info: + host_name: ExampleHostForHostInfoModule + + block: + - name: "test - Gather all facts of zabbix host" + zabbix_host_info: + register: gather_all_facts_result + + - when: zabbix_version is version('4.0', '<=') + assert: + that: + - gather_all_facts_result.hosts | length == 1 + - gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule" + - gather_all_facts_result.hosts.0.name == "ExampleHostForHostInfoModuleName" + - gather_all_facts_result.hosts.0.description == "Test Host" + - gather_all_facts_result.hosts.0.groups.0.name == "Linux servers" + - gather_all_facts_result.hosts.0.groups.1.name == "Hypervisors" + - gather_all_facts_result.hosts.0.parentTemplates.0.name == "Template App Zabbix Server" + - gather_all_facts_result.hosts.0.status == "0" + - gather_all_facts_result.hosts.0.inventory.inventory_mode == "0" + - gather_all_facts_result.hosts.0.inventory.tag == "tag1" + - gather_all_facts_result.hosts.0.inventory.os == "Linux" + - gather_all_facts_result.hosts.0.hostinterfaces.0.dns == "" + - gather_all_facts_result.hosts.0.hostinterfaces.0.ip == "192.168.0.1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.main == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.port == "10050" + - gather_all_facts_result.hosts.0.hostinterfaces.0.type == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1" + + - when: zabbix_version is version('4.4', '>=') and zabbix_version is version('5.0', '<=') + assert: + that: + - gather_all_facts_result.hosts | length == 1 + - gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule" + - gather_all_facts_result.hosts.0.name == "ExampleHostForHostInfoModuleName" + - gather_all_facts_result.hosts.0.description == "Test Host" + - gather_all_facts_result.hosts.0.groups.0.name == "Linux servers" + - gather_all_facts_result.hosts.0.groups.1.name == "Hypervisors" + - gather_all_facts_result.hosts.0.parentTemplates.0.name == "Template App Zabbix Server" + - gather_all_facts_result.hosts.0.status == "0" + - gather_all_facts_result.hosts.0.inventory_mode == "0" + - gather_all_facts_result.hosts.0.inventory.tag == "tag1" + - gather_all_facts_result.hosts.0.inventory.os == "Linux" + - gather_all_facts_result.hosts.0.hostinterfaces.0.dns == "" + - gather_all_facts_result.hosts.0.hostinterfaces.0.ip == "192.168.0.1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.main == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.port == "10050" + - gather_all_facts_result.hosts.0.hostinterfaces.0.type == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1" + + - when: zabbix_version is version('5.4', '>=') and zabbix_version is version('6.2', '<') + assert: + that: + - gather_all_facts_result.hosts | length == 1 + - gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule" + - gather_all_facts_result.hosts.0.name == "ExampleHostForHostInfoModuleName" + - gather_all_facts_result.hosts.0.description == "Test Host" + - gather_all_facts_result.hosts.0.groups.0.name == "Linux servers" + - gather_all_facts_result.hosts.0.groups.1.name == "Hypervisors" + - gather_all_facts_result.hosts.0.parentTemplates.0.name == "Zabbix server health" + - gather_all_facts_result.hosts.0.status == "0" + - gather_all_facts_result.hosts.0.inventory_mode == "0" + - gather_all_facts_result.hosts.0.inventory.tag == "tag1" + - gather_all_facts_result.hosts.0.inventory.os == "Linux" + - gather_all_facts_result.hosts.0.hostinterfaces.0.dns == "" + - gather_all_facts_result.hosts.0.hostinterfaces.0.ip == "192.168.0.1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.main == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.port == "10050" + - gather_all_facts_result.hosts.0.hostinterfaces.0.type == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1" + + - when: zabbix_version is version('6.2', '>=') + assert: + that: + - gather_all_facts_result.hosts | length == 1 + - gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule" + - gather_all_facts_result.hosts.0.name == "ExampleHostForHostInfoModuleName" + - gather_all_facts_result.hosts.0.description == "Test Host" + - gather_all_facts_result.hosts.0.groups.0.name == "Hypervisors" + - gather_all_facts_result.hosts.0.groups.1.name == "Linux servers" + - gather_all_facts_result.hosts.0.parentTemplates.0.name == "Zabbix server health" + - gather_all_facts_result.hosts.0.status == "0" + - gather_all_facts_result.hosts.0.inventory_mode == "0" + - gather_all_facts_result.hosts.0.inventory.tag == "tag1" + - gather_all_facts_result.hosts.0.inventory.os == "Linux" + - gather_all_facts_result.hosts.0.hostinterfaces.0.dns == "" + - gather_all_facts_result.hosts.0.hostinterfaces.0.ip == "192.168.0.1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.main == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.port == "10050" + - gather_all_facts_result.hosts.0.hostinterfaces.0.type == "1" + - gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1" + + - name: "test - Gather facts of zabbix host with host_inventory" + zabbix_host_info: + host_inventory: + - tag + - os + register: gather_facts_with_host_inventory_result + + - when: zabbix_version is version('3.4', '<=') + assert: + that: + - gather_facts_with_host_inventory_result.hosts.0.inventory | length == 3 + - gather_facts_with_host_inventory_result.hosts.0.inventory.tag == "tag1" + - gather_facts_with_host_inventory_result.hosts.0.inventory.os == "Linux" + + - when: zabbix_version is version('4.0', '>=') + assert: + that: + - gather_facts_with_host_inventory_result.hosts.0.inventory | length == 2 + - gather_facts_with_host_inventory_result.hosts.0.inventory.tag == "tag1" + - gather_facts_with_host_inventory_result.hosts.0.inventory.os == "Linux" + + - name: "test - Partial match of zabbix host name" + zabbix_host_info: + host_name: HostForHostInfo + exact_match: false + register: partial_match_result + + - assert: + that: + - partial_match_result.hosts | length == 1 + + - name: "test - Exact match of zabbix host name" + zabbix_host_info: + exact_match: true + register: exact_match_result + + - assert: + that: + - exact_match_result.hosts | length == 1 + + - name: "test - Exact match of zabbix host name(expectations - host not found)" + zabbix_host_info: + host_name: HostForHostInfo + exact_match: true + register: exact_match_host_not_found_result + ignore_errors: true + + - assert: + that: + - exact_match_host_not_found_result.failed is sameas true diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml new file mode 100644 index 000000000..1a9d81eff --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml @@ -0,0 +1,171 @@ +--- +- name: create helper zabbix host + zabbix_host: + host_name: zbx_hmacro_host01 + host_groups: + - Linux servers + interfaces: + - type: agent + main: 1 + dns: zbx_hmacro_host01 + +- name: test - attempt to create new host macro + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test01 + macro_value: 123 + register: zbxhmacro_new + +- name: assert that macro was created + assert: + that: zbxhmacro_new is changed + +- name: test - attempt to create same host macro + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test01 + macro_value: 123 + register: zbxhmacro_existing + +- name: assert that nothing has been changed + assert: + that: not zbxhmacro_existing is changed + +- name: test - attempt to create same host macro in zabbix native format + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: "{$ZBXHMACRO_TEST01}" + macro_value: 123 + register: zbxhmacro_existing_native + +- name: assert that nothing has been changed + assert: + that: not zbxhmacro_existing_native is changed + +- name: test - attempt to create new host macro in zabbix native format + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: "{$ZBXHMACRO_TEST02}" + macro_value: abcd + register: zbxhmacro_new_native + +- name: assert that nothing macro was created + assert: + that: zbxhmacro_new_native is changed + +- name: test - attempt to update host macro with string value while force=no + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test01 + macro_value: abc + force: false + register: zbxhmacro_update_noforce + +- name: assert that nothing has been changed + assert: + that: not zbxhmacro_update_noforce is changed + +- name: test - attempt to update host macro with string value + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test01 + macro_value: abc + register: zbxhmacro_update + ignore_errors: true + +- name: assert that host macro was updated + assert: + that: zbxhmacro_update is changed + +- name: test - attempt to create host macro with context + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: low_space_limit:/home + macro_value: 10 + register: zbxhmacro_context_new + +- name: assert that macro was created + assert: + that: zbxhmacro_context_new is changed + +- name: test - attempt to create same host macro with context and verify that it was converted to uppercase + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: LOW_SPACE_LIMIT:/home + macro_value: 10 + register: zbxhmacro_context_existing + +- name: assert that nothing has been changed + assert: + that: not zbxhmacro_context_existing is changed + +- name: test - attempt to delete all host macros + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: "{{ item }}" + state: absent + loop: + - zbxhmacro_test01 + - LOW_SPACE_LIMIT:/home + - "{$ZBXHMACRO_TEST02}" + register: zbxhmacro_delete_existing + +- name: assert that all macros have been deleted + assert: + that: item.changed is sameas True + loop: "{{ zbxhmacro_delete_existing.results }}" + +- name: test - attempt to delete non-existing host macro + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test01 + state: absent + register: zbxhmacro_delete_missing + +- name: assert that nothing has been changed + assert: + that: not zbxhmacro_delete_missing is changed + +- name: test - do not run host macro secret tests for Zabbix < 5.0 + meta: end_play + when: zabbix_version is version('5.0', '<') + +- name: test - attempt to create host macro with type secret + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test03 + macro_value: abcd + macro_type: secret + register: zbxhmacro_update + ignore_errors: true + +- name: assert that host macro was updated + assert: + that: zbxhmacro_update is changed + +- name: test - attempt to update host macro with type secret with same value + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: zbxhmacro_test03 + macro_value: abcd + macro_type: secret + register: zbxhmacro_update + ignore_errors: true + +- name: assert that host macro was updated + assert: + that: zbxhmacro_update is changed + +- name: test - attempt to delete host macros type secret + zabbix_hostmacro: + host_name: zbx_hmacro_host01 + macro_name: "{{ item }}" + state: absent + loop: + - zbxhmacro_test03 + register: zbxhmacro_delete_existing + +- name: assert that all macros have been deleted + assert: + that: item.changed is sameas True + loop: "{{ zbxhmacro_delete_existing.results }}" diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml new file mode 100644 index 000000000..6189c1d77 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml @@ -0,0 +1,96 @@ +--- +- name: test - do not run tests with < Zabbix 4.0 + meta: end_play + when: zabbix_version is version('4.0', '<') + +- when: zabbix_version is version('5.2', '<') + name: Unsupport Zabbix version (<5.2) + block: + - name: test fail to update housekeeping + community.zabbix.zabbix_housekeeping: + hk_events_mode: true + register: zbxhk_update_result + ignore_errors: true + + - assert: + that: zbxhk_update_result.failed is sameas True + +- when: zabbix_version is version('5.2', '>=') + name: Support Zabbix version (>=5.2) + block: + - name: test update housekeeping parameters. + community.zabbix.zabbix_housekeeping: + hk_events_mode: yes + hk_events_trigger: 365d + hk_events_service: 1w + hk_events_internal: 86400s + hk_events_discovery: 48h + hk_events_autoreg: 1440m + hk_services_mode: yes + hk_services: 365d + hk_audit_mode: yes + hk_audit: 365d + hk_sessions_mode: yes + hk_sessions: 365d + hk_history_mode: yes + hk_history_global: yes + hk_history: 365d + hk_trends_mode: yes + hk_trends_global: yes + hk_trends: 365d + compression_status: off + compress_older: 7d + register: zbxhk_update_result + + - assert: + that: zbxhk_update_result.changed is sameas True + + - name: test update housekeeping parameters (again). + community.zabbix.zabbix_housekeeping: + hk_events_mode: yes + hk_events_trigger: 365d + hk_events_service: 1w + hk_events_internal: 86400s + hk_events_discovery: 48h + hk_events_autoreg: 1440m + hk_services_mode: yes + hk_services: 365d + hk_audit_mode: yes + hk_audit: 365d + hk_sessions_mode: yes + hk_sessions: 365d + hk_history_mode: yes + hk_history_global: yes + hk_history: 365d + hk_trends_mode: yes + hk_trends_global: yes + hk_trends: 365d + compression_status: off + compress_older: 7d + register: zbxhk_update_result + + - assert: + that: zbxhk_update_result.changed is sameas False + + - name: initialize housekeeping setting. + community.zabbix.zabbix_housekeeping: + hk_events_mode: yes + hk_events_trigger: 365d + hk_events_service: 1d + hk_events_internal: 1d + hk_events_discovery: 1d + hk_events_autoreg: 1d + hk_services_mode: yes + hk_services: 365d + hk_audit_mode: yes + hk_audit: 365d + hk_sessions_mode: yes + hk_sessions: 365d + hk_history_mode: yes + hk_history_global: no + hk_history: 365d + hk_trends_mode: yes + hk_trends_global: no + hk_trends: 365d + compression_status: off + compress_older: 7d diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml new file mode 100644 index 000000000..0daca8d13 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml @@ -0,0 +1,305 @@ +--- +# New host create test from here +- name: "test - Create a new host" + zabbix_host: + host_name: example + host_groups: + - Linux servers + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: 10050 + register: create_host_result + +- assert: + that: + - create_host_result.changed is sameas true + +- name: "test - Create maintenance with a host_name param" + zabbix_maintenance: + name: maintenance + host_name: example + state: present + register: create_maintenance_host_name_result + +- assert: + that: + - create_maintenance_host_name_result.changed is sameas true + +# This check doesn't modify maintenace object and thus will be changed=false unless there are hosts without visible name defined +- name: "test - Create maintenance with a host_name param and disabled visible_name" + zabbix_maintenance: + name: maintenance + host_name: example + visible_name: false + state: present + register: create_maintenance_host_name_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - create_maintenance_host_name_result.changed is sameas false + +- name: "test - Create maintenance with a host_name param(again - expectations: false change will occur)" + zabbix_maintenance: + name: maintenance + host_name: example + state: present + register: create_maintenance_host_name_again_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - create_maintenance_host_name_again_result.changed is sameas false + +- name: "test - Update maintenance with a desc param" + zabbix_maintenance: + name: maintenance + host_name: example + desc: "test description" + state: present + register: update_maintenance_desc_result + +- debug: msg="{{ update_maintenance_desc_result }}" + +- assert: + that: + - update_maintenance_desc_result.changed is sameas true + +- name: "test - Update maintenance with a desc param(again - expectations: no change will occur)" + zabbix_maintenance: + name: maintenance + host_name: example + desc: "test description" + state: present + register: update_maintenance_desc_again_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - update_maintenance_desc_again_result.changed is sameas false + +- name: "test - Update maintenance with a collect_data" + zabbix_maintenance: + name: maintenance + host_name: example + desc: "test description" + collect_data: false + state: present + register: update_maintenance_collect_data_result + +- assert: + that: + - update_maintenance_collect_data_result.changed is sameas true + +- name: "test - Update maintenance with a collect_data(again - expectations: no change will occur)" + zabbix_maintenance: + name: maintenance + host_name: example + desc: "test description" + collect_data: false + state: present + register: update_maintenance_collect_data_again_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - update_maintenance_collect_data_again_result.changed is sameas false + +- name: "test - Update maintenance with a minutes param" + zabbix_maintenance: + name: maintenance + host_name: example + desc: "test description" + collect_data: false + minutes: 90 + state: present + register: update_maintenance_minutes_result + +- assert: + that: + - update_maintenance_minutes_result.changed is sameas true + +- name: "test - Update maintenance with a minutes param(again - expectations: no change will occur)" + zabbix_maintenance: + name: maintenance + host_name: example + desc: "test description" + collect_data: false + minutes: 90 + state: present + register: update_maintenance_minutes_again_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - update_maintenance_minutes_again_result.changed is sameas false + +- name: "test - Update maintenance with a host_groups param" + zabbix_maintenance: + name: maintenance + host_name: example + host_groups: + - Linux servers + - Hypervisors + desc: "test description" + collect_data: false + minutes: 90 + state: present + register: update_maintenance_host_groups_result + +- assert: + that: + - update_maintenance_host_groups_result.changed is sameas true + +- name: "test - Update maintenance with a host_groups param(again - expectations: no change will occur)" + zabbix_maintenance: + name: maintenance + host_name: example + host_groups: + - Linux servers + - Hypervisors + desc: "test description" + collect_data: false + minutes: 90 + state: present + register: update_maintenance_host_groups_again_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - update_maintenance_host_groups_again_result.changed is sameas false + +- name: "test - Update maintenance with change host_name to host_names param" + zabbix_maintenance: + name: maintenance + host_names: + - example + - Zabbix server + host_groups: + - Linux servers + - Hypervisors + desc: "test description" + collect_data: false + minutes: 90 + state: present + register: update_maintenance_host_names_result + +- assert: + that: + - update_maintenance_host_names_result.changed is sameas true + +- name: "test - Update maintenance with change host_name to host_names param(again - expectations: no change will occur)" + zabbix_maintenance: + name: maintenance + host_names: + - example + - Zabbix server + host_groups: + - Linux servers + - Hypervisors + desc: "test description" + collect_data: false + minutes: 90 + state: present + register: update_maintenance_host_names_again_result + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +# - assert: +# that: +# - update_maintenance_host_names_again_result.changed is sameas false + +- name: "test - Update maintenance with tags" + zabbix_maintenance: + name: maintenance + host_names: + - example + - Zabbix server + host_groups: + - Linux servers + - Hypervisors + desc: "test description" + collect_data: yes # required for tags + minutes: 90 + state: present + tags: + - tag: ExampleHostsTag + - tag: ExampleHostsTag2 + value: ExampleTagValue + - tag: ExampleHostsTag3 + value: ExampleTagValue + operator: 0 + register: update_maintenance_host_tags + +- assert: + that: + - update_maintenance_host_tags.changed is sameas true + +- name: "test - Update maintenance with tags (again)" + zabbix_maintenance: + name: maintenance + host_names: + - example + - Zabbix server + host_groups: + - Linux servers + - Hypervisors + desc: "test description" + collect_data: yes + minutes: 90 + state: present + tags: + - tag: ExampleHostsTag + - tag: ExampleHostsTag2 + value: ExampleTagValue + - tag: ExampleHostsTag3 + value: ExampleTagValue + operator: 0 + register: update_maintenance_host_tags + +# BUGGED: sometimes when test "lags" and some time passes since previous tasks, +# maintenance_start will not match and be updated, thus resulting in changed +#- assert: +# that: +# - update_maintenance_host_tags.changed is sameas false + +- name: "test - Delete maintenance" + zabbix_maintenance: + name: maintenance + host_name: example + state: absent + register: delete_maintenance_result + tags: + - cleanup + +- assert: + that: + - delete_maintenance_result.changed is sameas true + +- name: "test - Delete maintenance(again - expectations: no change will occur)" + zabbix_maintenance: + name: maintenance + host_name: example + state: absent + register: delete_maintenance_again_result + +- assert: + that: + - delete_maintenance_again_result.changed is sameas false + +- name: "test - Delete testing host" + zabbix_host: + host_name: example + state: absent + tags: + - cleanup diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml new file mode 100644 index 000000000..4daffebdd --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml @@ -0,0 +1,678 @@ +--- +- name: test - email mediatypes + module_defaults: + community.zabbix.zabbix_mediatype: + state: present + name: Example email + type: email + smtp_email: zabbix@example.com + + block: + - name: test - create new email mediatype without authentication + zabbix_mediatype: + register: zbxmediatype_new + + - assert: + that: zbxmediatype_new.changed is sameas True + + - name: test - create new email mediatype without authentication (again) + zabbix_mediatype: + register: zbxmediatype_new + + - assert: + that: zbxmediatype_new.changed is sameas False + + - name: test - update email mediatype smtp information + zabbix_mediatype: + smtp_helo: example.com + smtp_server: mail.example.com + smtp_server_port: 465 + register: zbxmediatype_smtp + + - assert: + that: zbxmediatype_smtp.changed is sameas True + + - name: test - update email mediatype smtp information (again) + zabbix_mediatype: + smtp_helo: example.com + smtp_server: mail.example.com + smtp_server_port: 465 + register: zbxmediatype_smtp + + - assert: + that: zbxmediatype_smtp.changed is sameas False + + - name: test - reset email mediatype smtp information to default + zabbix_mediatype: + register: zbxmediatype_reset + + - assert: + that: zbxmediatype_reset.changed is sameas True + + - name: test - update email mediatype with authentication without credentials (fail) + zabbix_mediatype: + smtp_authentication: true + smtp_security: STARTTLS + register: zbxmediatype_auth_fail + ignore_errors: true + + - assert: + that: zbxmediatype_auth_fail.failed is sameas True + + - name: test - update email mediatype with authentication + zabbix_mediatype: + smtp_authentication: true + smtp_security: STARTTLS + username: zabbix + password: Ex4mP!3 + register: zbxmediatype_auth + + - assert: + that: zbxmediatype_auth.changed is sameas True + + - name: test - update email mediatype with authentication (again) + zabbix_mediatype: + smtp_authentication: true + smtp_security: STARTTLS + username: zabbix + password: Ex4mP!3 + register: zbxmediatype_auth + + - assert: + that: zbxmediatype_auth.changed is sameas False + + - name: test - update email mediatype with SSL/TLS and host/peer verification + zabbix_mediatype: + smtp_authentication: true + smtp_security: SSL/TLS + smtp_verify_host: true + smtp_verify_peer: true + username: zabbix + password: Ex4mP!3 + register: zbxmediatype_verif + + - assert: + that: zbxmediatype_verif.changed is sameas True + + - name: test - update email mediatype with SSL/TLS and host/peer verification (again) + zabbix_mediatype: + smtp_authentication: true + smtp_security: SSL/TLS + smtp_verify_host: true + smtp_verify_peer: true + username: zabbix + password: Ex4mP!3 + register: zbxmediatype_verif + + - assert: + that: zbxmediatype_verif.changed is sameas False + + - when: zabbix_version is version('3.4', '>=') + block: + - name: test - reset email mediatype smtp information to default + zabbix_mediatype: + register: zbxmediatype_reset + + - assert: + that: zbxmediatype_reset.changed is sameas True + + - name: test - update email mediatype concurrent settings + zabbix_mediatype: + max_sessions: 99 + max_attempts: 10 + attempt_interval: 30s + register: zbxmediatype_concur + + - assert: + that: zbxmediatype_concur.changed is sameas True + + - name: test - update email mediatype concurrent settings (again) + zabbix_mediatype: + max_sessions: 99 + max_attempts: 10 + attempt_interval: 30s + register: zbxmediatype_concur + + - assert: + that: zbxmediatype_concur.changed is sameas False + + - name: test - update email mediatype concurrent settings above range (fail) + zabbix_mediatype: + max_sessions: 102 + max_attempts: 101 + attempt_interval: 61m + register: zbxmediatype_concur_fail + ignore_errors: true + + - assert: + that: zbxmediatype_concur_fail.failed is sameas True + + - when: zabbix_version is version('5.0', '>=') + block: + - name: test - reset email mediatype smtp information to default + zabbix_mediatype: + register: zbxmediatype_reset + + - assert: + that: zbxmediatype_reset.changed is sameas True + + - name: test - update email mediatype with message templates + zabbix_mediatype: + message_templates: + - eventsource: triggers + recovery: operations + subject: "Problem: {EVENT.NAME}" + body: "Problem started at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: discovery + recovery: operations + subject: "Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}" + body: "Discovery rule: {DISCOVERY.RULE.NAME}\r\n\r\nDevice IP: {DISCOVERY.DEVICE.IPADDRESS}" + - eventsource: autoregistration + recovery: operations + subject: "Autoregistration: {HOST.HOST}" + body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}" + - eventsource: internal + recovery: operations + subject: "Internal: {EVENT.NAME}" + body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n" + register: zbxmediatype_msg_templates + + - assert: + that: zbxmediatype_msg_templates.changed is sameas True + + - name: test - update email mediatype with message templates (again) + zabbix_mediatype: + message_templates: + - eventsource: triggers + recovery: operations + subject: "Problem: {EVENT.NAME}" + body: "Problem started at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: discovery + recovery: operations + subject: "Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}" + body: "Discovery rule: {DISCOVERY.RULE.NAME}\r\n\r\nDevice IP: {DISCOVERY.DEVICE.IPADDRESS}" + - eventsource: autoregistration + recovery: operations + subject: "Autoregistration: {HOST.HOST}" + body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}" + - eventsource: internal + recovery: operations + subject: "Internal: {EVENT.NAME}" + body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n" + register: zbxmediatype_msg_templates + + - assert: + that: zbxmediatype_msg_templates.changed is sameas False + + - name: test - update subject of message template in email mediatype + zabbix_mediatype: + message_templates: + - eventsource: triggers + recovery: operations + subject: "Problem: {EVENT.NAME} - test change" + body: "Problem started at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: discovery + recovery: operations + subject: "Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}" + body: "Discovery rule: {DISCOVERY.RULE.NAME}\r\n\r\nDevice IP: {DISCOVERY.DEVICE.IPADDRESS}" + - eventsource: autoregistration + recovery: operations + subject: "Autoregistration: {HOST.HOST}" + body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}" + - eventsource: internal + recovery: operations + subject: "Internal: {EVENT.NAME}" + body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n" + register: zbxmediatype_msg_templates + + - assert: + that: zbxmediatype_msg_templates.changed is sameas True + + - name: test - update message of message template in email mediatype + zabbix_mediatype: + message_templates: + - eventsource: triggers + recovery: operations + subject: "Problem: {EVENT.NAME} - test change" + body: "Problem started at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: discovery + recovery: operations + subject: "Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}" + body: "Discovery rule: {DISCOVERY.RULE.NAME}\r\n\r\nDevice IP: {DISCOVERY.DEVICE.IPADDRESS} - test" + - eventsource: autoregistration + recovery: operations + subject: "Autoregistration: {HOST.HOST}" + body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}" + - eventsource: internal + recovery: operations + subject: "Internal: {EVENT.NAME}" + body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n" + register: zbxmediatype_msg_templates + + - assert: + that: zbxmediatype_msg_templates.changed is sameas True + + - name: test - update subject and message of message template in email mediatype (again) + zabbix_mediatype: + message_templates: + - eventsource: triggers + recovery: operations + subject: "Problem: {EVENT.NAME} - test change" + body: "Problem started at {EVENT.TIME} on {EVENT.DATE}\r\nProblem name: {EVENT.NAME}\r\n" + - eventsource: discovery + recovery: operations + subject: "Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}" + body: "Discovery rule: {DISCOVERY.RULE.NAME}\r\n\r\nDevice IP: {DISCOVERY.DEVICE.IPADDRESS} - test" + - eventsource: autoregistration + recovery: operations + subject: "Autoregistration: {HOST.HOST}" + body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}" + - eventsource: internal + recovery: operations + subject: "Internal: {EVENT.NAME}" + body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n" + register: zbxmediatype_msg_templates + + - assert: + that: zbxmediatype_msg_templates.changed is sameas False + + - name: test - disable email mediatype + zabbix_mediatype: + status: disabled + register: zbxmediatype_disable + + - assert: + that: zbxmediatype_disable.changed is sameas True + + - name: test - disable email mediatype (again) + zabbix_mediatype: + status: disabled + register: zbxmediatype_disable + + - assert: + that: zbxmediatype_disable.changed is sameas False + + - name: test - delete email mediatype + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas True + + - name: test - delete email mediatype (again) + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas False + +- name: test - script mediatypes + module_defaults: + community.zabbix.zabbix_mediatype: + state: present + name: Example script + type: script + + block: + - name: test - create new script mediatype + zabbix_mediatype: + script_name: /usr/local/bin/script.sh + register: zbxmediatype_script_new + + - assert: + that: zbxmediatype_script_new.changed is sameas True + + - name: test - create new script mediatype (again) + zabbix_mediatype: + script_name: /usr/local/bin/script.sh + register: zbxmediatype_script_new + + - assert: + that: zbxmediatype_script_new.changed is sameas False + + - name: test - update script mediatype with script parameters + zabbix_mediatype: + script_name: /usr/local/bin/script.sh + script_params: + - '-p test' + - '-q' + register: zbxmediatype_script_params + + - assert: + that: zbxmediatype_script_params.changed is sameas True + + - name: test - update script mediatype with script parameters (again) + zabbix_mediatype: + script_name: /usr/local/bin/script.sh + script_params: + - '-p test' + - '-q' + register: zbxmediatype_script_params + + - assert: + that: zbxmediatype_script_params.changed is sameas False + + - name: test - remove script mediatype parameters + zabbix_mediatype: + script_name: /usr/local/bin/script.sh + register: zbxmediatype_script_params_rev + + - assert: + that: zbxmediatype_script_params_rev.changed is sameas True + + - name: test - delete script mediatype + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas True + +- name: test - sms mediatypes + module_defaults: + community.zabbix.zabbix_mediatype: + state: present + name: Example sms + type: sms + + block: + - name: test - create new sms mediatype + zabbix_mediatype: + gsm_modem: /dev/ttyS0 + register: zbxmediatype_sms_new + + - assert: + that: zbxmediatype_sms_new.changed is sameas True + + - name: test - create new sms mediatype (again) + zabbix_mediatype: + gsm_modem: /dev/ttyS0 + register: zbxmediatype_sms_new + + - assert: + that: zbxmediatype_sms_new.changed is sameas False + + - when: zabbix_version is version('3.4', '>=') + block: + - name: test - update sms mediatype with concurrent settings + zabbix_mediatype: + gsm_modem: /dev/ttyS0 + max_sessions: 1 + max_attempts: 3 + attempt_interval: 30 + register: zbxmediatype_sms_concur + + - assert: + that: zbxmediatype_sms_concur.changed is sameas True + + - name: test - update sms mediatype with concurrent settings (again) + zabbix_mediatype: + gsm_modem: /dev/ttyS0 + max_sessions: 1 + max_attempts: 3 + attempt_interval: 30 + register: zbxmediatype_sms_concur + + - assert: + that: zbxmediatype_sms_concur.changed is sameas False + + - name: test - update sms mediatype with invalid max sessions (fail) + zabbix_mediatype: + gsm_modem: /dev/ttyS0 + max_sessions: 2 + register: zbxmediatype_sms_fail + ignore_errors: true + + - assert: + that: zbxmediatype_sms_fail.failed is sameas True + + - name: test - delete sms mediatype + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas True + +- name: test - jabber mediatypes + when: zabbix_version is version('4.2', '<=') + module_defaults: + community.zabbix.zabbix_mediatype: + state: present + name: Example jabber + type: jabber + + block: + - name: test - create new jabber mediatype + zabbix_mediatype: + username: zabbix + password: Ex4mP!3 + register: zbxmediatype_jabber_new + + - assert: + that: zbxmediatype_jabber_new.changed is sameas True + + - name: test - create new jabber mediatype (again) + zabbix_mediatype: + username: zabbix + password: Ex4mP!3 + register: zbxmediatype_jabber_new + + - assert: + that: zbxmediatype_jabber_new.changed is sameas False + + - name: test - delete jabber mediatype + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas True + +- name: test - ez_texting mediatypes + when: zabbix_version is version('4.2', '<=') + module_defaults: + community.zabbix.zabbix_mediatype: + state: present + name: Example ez_texting + type: ez_texting + + block: + - name: test - create new ez_texting mediatype + zabbix_mediatype: + username: zabbix + password: Ex4mP!3 + message_text_limit: USA + register: zbxmediatype_ez_texting_new + + - assert: + that: zbxmediatype_ez_texting_new.changed is sameas True + + - name: test - create new ez_texting mediatype (again) + zabbix_mediatype: + username: zabbix + password: Ex4mP!3 + message_text_limit: USA + register: zbxmediatype_ez_texting_new + + - assert: + that: zbxmediatype_ez_texting_new.changed is sameas False + + - name: test - update ez_texting mediatype with text limit + zabbix_mediatype: + username: zabbix + password: Ex4mP!3 + message_text_limit: Canada + register: zbxmediatype_ez_texting_update + + - assert: + that: zbxmediatype_ez_texting_update.changed is sameas True + + - name: test - delete ez_texting mediatype + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas True + +- name: test - email mediatypes + when: zabbix_version is version('4.4', '>=') + module_defaults: + community.zabbix.zabbix_mediatype: + state: present + name: Example webhook + type: webhook + webhook_script: "return 'Hello, world!';" + + block: + - name: test - create new webhook mediatype + zabbix_mediatype: + register: zbxmediatype_webhook_new + + - assert: + that: zbxmediatype_webhook_new.changed is sameas True + + - name: test - create new webhook mediatype (again) + zabbix_mediatype: + register: zbxmediatype_webhook_new + + - assert: + that: zbxmediatype_webhook_new.changed is sameas False + + - name: test - update webhook mediatype with process_tags + zabbix_mediatype: + process_tags: true + register: zbxmediatype_webhook_tags + + - assert: + that: zbxmediatype_webhook_tags.changed is sameas True + + - name: test - update webhook mediatype with process_tags (again) + zabbix_mediatype: + process_tags: true + register: zbxmediatype_webhook_tags + + - assert: + that: zbxmediatype_webhook_tags.changed is sameas False + + # supported since 4.4 + - name: test - update webhook mediatype with description + zabbix_mediatype: + process_tags: true + description: My custom webhook mediatype + register: zbxmediatype_webhook_desc + + - assert: + that: zbxmediatype_webhook_desc.changed is sameas True + + - name: test - update webhook mediatype with description (again) + zabbix_mediatype: + process_tags: true + description: My custom webhook mediatype + register: zbxmediatype_webhook_desc + + - assert: + that: zbxmediatype_webhook_desc.changed is sameas False + + - name: test - update webhook mediatype with event_menu without name and url (fail) + zabbix_mediatype: + process_tags: true + description: My custom webhook mediatype + event_menu: true + register: zbxmediatype_webhook_eventmenu + ignore_errors: true + + - assert: + that: zbxmediatype_webhook_eventmenu.failed is sameas True + + - name: test - update webhook mediatype with event_menu + zabbix_mediatype: + process_tags: true + description: My custom webhook mediatype + event_menu: true + event_menu_name: Example entry name + event_menu_url: '{EVENT.TAGS.__message_link}' + register: zbxmediatype_webhook_eventmenu + + - assert: + that: zbxmediatype_webhook_eventmenu.changed is sameas True + + - name: test - update webhook mediatype with event_menu (again) + zabbix_mediatype: + process_tags: true + description: My custom webhook mediatype + event_menu: true + event_menu_name: Example entry name + event_menu_url: '{EVENT.TAGS.__message_link}' + register: zbxmediatype_webhook_eventmenu + + - assert: + that: zbxmediatype_webhook_eventmenu.changed is sameas False + + - name: test - reset webhook mediatype to default + zabbix_mediatype: + register: zbxmediatype_reset + + - assert: + that: zbxmediatype_reset.changed is sameas True + + - name: test - update webhook mediatype with webhook_params + zabbix_mediatype: + webhook_params: + - name: param1 + value: value1 + register: zbxmediatype_webhook_params + + - assert: + that: zbxmediatype_webhook_params.changed is sameas True + + - name: test - update webhook mediatype with webhook_params (again) + zabbix_mediatype: + webhook_params: + - name: param1 + value: value1 + register: zbxmediatype_webhook_params + + - assert: + that: zbxmediatype_webhook_params.changed is sameas False + + - name: test - update webhook mediatype with webhook_params (reorder) + zabbix_mediatype: + webhook_params: + - name: z.param2 + value: xyz + - name: param1 + value: value1 + - name: b.param3 + - name: a.param4 + value: abc + register: zbxmediatype_webhook_params + + - assert: + that: zbxmediatype_webhook_params.changed is sameas True + + - name: test - update webhook mediatype with webhook_params (reorder again) + zabbix_mediatype: + webhook_params: + - name: param1 + value: value1 + - name: a.param4 + value: abc + - name: b.param3 + - name: z.param2 + value: xyz + register: zbxmediatype_webhook_params + + - assert: + that: zbxmediatype_webhook_params.changed is sameas False + + - name: test - delete webhook mediatype + zabbix_mediatype: + state: absent + register: zbxmediatype_delete + + - assert: + that: zbxmediatype_delete.changed is sameas True diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml new file mode 100644 index 000000000..5b861810a --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml @@ -0,0 +1,48 @@ +--- +- name: Test module_defaults applied to a group during creation + module_defaults: + group/community.zabbix.zabbix: + host_groups: + - Example Group + state: present + block: + - name: Create host group + zabbix_group: + register: _grp + + - name: Create host + zabbix_host: + host_name: Example Host + interfaces: + - type: agent + main: 1 + dns: example-host01.local + register: _host + + - name: Assert that resources were correctly created + assert: + that: + - _grp is changed + - _host is changed + +- name: Test module_defaults applied to a group during deletion + module_defaults: + group/community.zabbix.zabbix: + host_groups: + - Example Group + state: absent + block: + - name: Delete host + zabbix_host: + host_name: Example Host + register: _host + + - name: Delete host group + zabbix_group: + register: _grp + + - name: Assert that resources were correctly deleted + assert: + that: + - _grp is changed + - _host is changed diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml new file mode 100644 index 000000000..ee96e6e80 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml @@ -0,0 +1,313 @@ +--- +- name: test - create new passive Zabbix proxy server + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: passive + interface: + useip: 0 + ip: 10.1.1.2 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_new + +- name: assert that proxy was created + assert: + that: zbxproxy_new is changed + +- name: test - create same passive Zabbix proxy server + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: passive + interface: + useip: 0 + ip: 10.1.1.2 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_existing + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_existing is changed + +- name: test - update Zabbix proxy server description + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 0 + ip: 10.1.1.2 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_desc_update + +- name: assert that description has been updated + assert: + that: zbxproxy_desc_update is changed + +- name: test - update Zabbix proxy server interface + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 0 + ip: 10.1.1.3 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_interface_update + +- name: assert that interface has been updated + assert: + that: zbxproxy_interface_update is changed + +- name: test - update Zabbix proxy server description & interface (again) + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 0 + ip: 10.1.1.3 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_desc_interface_update + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_desc_interface_update is changed + +- name: test - update Zabbix proxy server interface to use only ip + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 1 + ip: 10.1.1.3 + port: 10051 + register: zbxproxy_interface_onlyip + +- name: assert that interface has been updated + assert: + that: zbxproxy_interface_onlyip is changed + +- name: test - update Zabbix proxy server interface to use only ip again + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 1 + ip: 10.1.1.3 + port: 10051 + register: zbxproxy_interface_onlyip_again + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_interface_onlyip_again is changed + +- name: test - update Zabbix proxy server interface to use only dns + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 0 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_interface_onlydns + +- name: assert that interface has been updated + assert: + that: zbxproxy_interface_onlydns is changed + +- name: test - update Zabbix proxy server interface to use only dns again + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 0 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_interface_onlydns_again + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_interface_onlydns_again is changed + +- name: test - update Zabbix proxy server interface to fail + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy desc + state: present + status: passive + interface: + useip: 1 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_interface_fail + ignore_errors: true + +- name: assert that module has failed + assert: + that: zbxproxy_interface_fail is failed + +- name: test - update Zabbix proxy server to be active + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + register: zbxproxy_active_update + +- name: assert that proxy was updated + assert: + that: zbxproxy_active_update is changed + +- name: test - update Zabbix proxy server to be active (again) + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + register: zbxproxy_active_update_again + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_active_update_again is changed + +# proxy_address available on zabbix 4.0 and above +- block: + - name: test - update Zabbix proxy server to be active and use proxy_address + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + proxy_address: 10.1.1.0/24,zabbix.example.com + register: zbxproxy_active_proxyaddress + + - name: assert that proxy was updated + assert: + that: zbxproxy_active_proxyaddress is changed + + - name: test - update Zabbix proxy server to be active use proxy_address (again) + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + proxy_address: 10.1.1.0/24,zabbix.example.com + register: zbxproxy_active_proxyaddress_again + + - name: assert that nothing has been changed + assert: + that: not zbxproxy_active_proxyaddress_again is changed + + when: zabbix_version != "3.0" + +- name: test - update Zabbix proxy server to use encryption + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + tls_psk_identity: test + tls_connect: PSK + tls_accept: PSK + tls_psk: 123456789abcdef123456789abcdef12 + register: zbxproxy_encryption + +- name: assert that encryption has been enabled + assert: + that: zbxproxy_encryption is changed + +- name: test - update Zabbix proxy server to use encryption (again) + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + tls_psk_identity: test + tls_connect: PSK + tls_accept: PSK + tls_psk: 123456789abcdef123456789abcdef12 + register: zbxproxy_encryption_again + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_encryption_again is changed + when: zabbix_version < "6.0" + +# With Zabbix >= 6.0 tls_psk and tls_psk_identity cannot be read +# thus there is no way to check idempotency +- name: assert that nothing has been changed + assert: + that: zbxproxy_encryption_again is changed + when: zabbix_version >= "6.0" + +- name: test - update Zabbix proxy server encryption settings + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: active + tls_connect: certificate + tls_accept: certificate + tls_issuer: AcmeCorp + tls_subject: AcmeCorpServer + register: zbxproxy_encryption_update + +- name: assert that encryption has been updated + assert: + that: zbxproxy_encryption_update is changed + +- name: test - update Zabbix proxy server back to being passive + zabbix_proxy: + proxy_name: zbxproxy_example01 + description: Example Zabbix Proxy + state: present + status: passive + interface: + useip: 0 + ip: 10.1.1.2 + dns: zbxproxy_example01 + port: 10051 + register: zbxproxy_passive_update + +- name: assert that proxy was updated + assert: + that: zbxproxy_passive_update is changed + +- name: test - delete Zabbix proxy server + zabbix_proxy: + proxy_name: zbxproxy_example01 + state: absent + register: zbxproxy_delete + +- name: assert that proxy has been deleted + assert: + that: zbxproxy_delete is changed + +- name: test - delete Zabbix proxy server (again) + zabbix_proxy: + proxy_name: zbxproxy_example01 + state: absent + register: zbxproxy_delete_again + +- name: assert that nothing has been changed + assert: + that: not zbxproxy_delete_again is changed diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml new file mode 100644 index 000000000..a5feb2731 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml @@ -0,0 +1,65 @@ +--- +- name: test - Create new Zabbix proxy + zabbix_proxy: + state: present + proxy_name: ExampleProxy + description: ExampleProxy + status: passive + interface: + useip: 1 + ip: 10.1.1.2 + port: 10051 + dns: ExampleProxy.local + register: create_proxy_result + +- assert: + that: + - create_proxy_result.changed is sameas true + +- name: test - Create new Zabbix host monitored by the proxy + zabbix_host: + state: present + host_name: ExampleHost + host_groups: + - Linux servers + status: enabled + proxy: ExampleProxy + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.3 + dns: "" + port: "10050" + register: create_host_result + +- assert: + that: + - create_host_result.changed is sameas true + +- name: test - Get zabbix proxy information + zabbix_proxy_info: + proxy_name: ExampleProxy + proxy_hosts: true + register: get_proxy_info_result + +- assert: + that: + - get_proxy_info_result["zabbix_proxy"].host == "ExampleProxy" + - get_proxy_info_result["zabbix_proxy"].hosts | length > 0 + - get_proxy_info_result["zabbix_proxy"].hosts[0].host == "ExampleHost" + - get_proxy_info_result["zabbix_proxy"].interface | length > 0 + - get_proxy_info_result["zabbix_proxy"].interface.ip == "10.1.1.2" + - get_proxy_info_result["zabbix_proxy"].interface.useip == "1" + - get_proxy_info_result["zabbix_proxy"].interface.port == "10051" + - get_proxy_info_result["zabbix_proxy"].interface.dns == "ExampleProxy.local" + +- name: test - cleanup test Zabbix host + zabbix_host: + state: absent + host_name: ExampleHost + +- name: test - cleanup test Zabbix proxy + zabbix_proxy: + state: absent + proxy_name: ExampleProxy diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml new file mode 100644 index 000000000..82d1e5f0e --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml @@ -0,0 +1,149 @@ +--- + +- name: ensure zabbix server is being monitored + community.zabbix.zabbix_host: + host_name: Zabbix server + status: enabled + +- name: "Screen got removed with 5.4" + block: + - name: test - Check if screen fails on Zabbix >= 5.4 + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreenFail54 + host_group: Zabbix servers + state: present + graph_names: + - 'Zabbix cache usage, % used' + - 'Zabbix internal process busy %' + graph_width: 200 + graph_height: 100 + graphs_in_row: 5 + register: result + ignore_errors: true + when: zabbix_version is version('5.4', '>=') + + - name: expect to fail + assert: + that: + - "result is failed" + when: zabbix_version is version('5.4', '>=') + + - name: End play if Zabbix >= 5.4 + meta: end_play + when: zabbix_version is version('5.4', '>=') + +- name: test - delete the screen again + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + state: absent + +# ################################################# +# Test screen creation +# ################################################# + +- name: test - Create a new screen + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + host_group: Zabbix servers + state: present + graph_names: + - 'Zabbix cache usage, % used' + - 'Zabbix internal process busy %' + graph_width: 200 + graph_height: 100 + graphs_in_row: 5 + register: result + +- assert: + that: + - result.changed + +- name: test - Create a new screen again + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + host_group: Zabbix servers + state: present + graph_names: + - 'Zabbix cache usage, % used' + - 'Zabbix internal process busy %' + graph_width: 200 + graph_height: 100 + graphs_in_row: 5 + register: result + +- assert: + that: + - not result.changed + +# ################################################# +# Test screen editing +# ################################################# + +- name: test - Adding new graph + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + host_group: Zabbix servers + state: present + graph_names: + - 'Zabbix cache usage, % used' + - 'Zabbix internal process busy %' + - 'Zabbix internal queues' + - 'Zabbix server performance' + - 'Zabbix data gathering process busy %' + graph_width: 200 + graph_height: 100 + graphs_in_row: 5 + register: result + +- assert: + that: + - result.changed + +- name: test - Removing graph + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + host_group: Zabbix servers + state: present + graph_names: + - 'Zabbix cache usage, % used' + - 'Zabbix internal queues' + graph_width: 200 + graph_height: 100 + graphs_in_row: 5 + register: result + +- assert: + that: + - result.changed + +# ################################################# +# Test screen deletion +# ################################################# + +- name: test - delete the screen + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + state: absent + register: result + +- assert: + that: + - result.changed + +- name: test - delete the screen again + community.zabbix.zabbix_screen: + screens: + - screen_name: TestScreen1 + state: absent + register: result + +- assert: + that: + - not result.changed diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml new file mode 100644 index 000000000..fe5c40519 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml @@ -0,0 +1,523 @@ +--- +- name: test - do not run tests for Zabbix < 6.0 + meta: end_play + when: zabbix_version is version('6.0', '<') + +- name: test - Test action operation script + module_defaults: + community.zabbix.zabbix_script: + name: Test action operation script + scope: action_operation + script_type: webhook + command: 'return 0' + description: "Test action operation script" + state: present + + block: + - name: test - Create new action operation script to execute webhook check mode + zabbix_script: + check_mode: true + register: create_action_check_mode_result + + - assert: + that: + - create_action_check_mode_result.changed is sameas true + + - name: test - Create new action operation script to execute webhook + zabbix_script: + register: create_action_result + + - assert: + that: + - create_action_result.changed is sameas true + + - name: test - Create new action operation script to execute webhook again + zabbix_script: + register: create_action_again_result + + - assert: + that: + - create_action_again_result.changed is sameas false + + - name: test - Update action operation script to execute webhook with host group + zabbix_script: + host_group: 'Discovered hosts' + register: update_action_host_group_result + + - assert: + that: + - update_action_host_group_result.changed is sameas true + + - name: test - Update action operation script to execute webhook with host group again + zabbix_script: + host_group: 'Discovered hosts' + register: update_action_host_group_again_result + + - assert: + that: + - update_action_host_group_again_result.changed is sameas false + + - name: test - Update action operation script to execute webhook with parameters + zabbix_script: + host_group: 'Discovered hosts' + parameters: + - name: param_name1 + register: update_action_param_result + + - assert: + that: + - update_action_param_result.changed is sameas true + + - name: test - Update action operation script to execute webhook with parameters again + zabbix_script: + host_group: 'Discovered hosts' + parameters: + - name: param_name1 + register: update_action_param_again_result + + - assert: + that: + - update_action_param_again_result.changed is sameas false + + - name: test - Update action operation script to execute webhook with parameters and value + zabbix_script: + host_group: 'Discovered hosts' + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: update_action_param_value_result + + - assert: + that: + - update_action_param_value_result.changed is sameas true + + - name: test - Update action operation script to execute webhook with parameters and value again + zabbix_script: + host_group: 'Discovered hosts' + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: update_action_param_value_again_result + + - assert: + that: + - update_action_param_value_again_result.changed is sameas false + + - name: test - Update action operation script remove host group + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: update_action_no_host_group_result + + - assert: + that: + - update_action_no_host_group_result.changed is sameas true + + - name: test - Update action operation script remove host group again + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: update_action_no_host_group_again_result + + - assert: + that: + - update_action_no_host_group_again_result.changed is sameas false + + - name: test - Update action operation script to type Script + zabbix_script: + script_type: script + execute_on: zabbix_agent + command: echo 1 + register: update_action_script_result + + - assert: + that: + - update_action_script_result.changed is sameas true + + - name: test - Update action operation script to type Script again + zabbix_script: + script_type: script + execute_on: zabbix_agent + command: echo 1 + register: update_action_script_again_result + + - assert: + that: + - update_action_script_again_result.changed is sameas false + + - name: test - Update action operation script to execute on server + zabbix_script: + script_type: script + execute_on: zabbix_server + command: echo 1 + register: update_action_script_server_result + + - assert: + that: + - update_action_script_server_result.changed is sameas true + + - name: test - Update action operation script to execute on server again + zabbix_script: + script_type: script + execute_on: zabbix_server + command: echo 1 + register: update_action_script_server_again_result + + - assert: + that: + - update_action_script_server_again_result.changed is sameas false + + - name: test - Update action operation script to execute on server or proxy + zabbix_script: + script_type: script + execute_on: zabbix_server_proxy + command: echo 1 + register: update_action_script_server_proxy_result + + - assert: + that: + - update_action_script_server_proxy_result.changed is sameas true + + - name: test - Update action operation script to execute on server or proxy again + zabbix_script: + script_type: script + execute_on: zabbix_server_proxy + command: echo 1 + register: update_action_script_server_proxy_again_result + + - assert: + that: + - update_action_script_server_proxy_again_result.changed is sameas false + + - name: test - Update action operation script to type SSH + zabbix_script: + script_type: ssh + authtype: password + username: bla + password: blabla + command: echo 2 + register: update_action_script_ssh_result + + - assert: + that: + - update_action_script_ssh_result.changed is sameas true + + - name: test - Update action operation script to type SSH again + zabbix_script: + script_type: ssh + authtype: password + username: bla + password: blabla + command: echo 2 + register: update_action_script_ssh_again_result + + - assert: + that: + - update_action_script_ssh_again_result.changed is sameas false + + - name: test - Update action operation script type SSH key auth + zabbix_script: + script_type: ssh + authtype: public_key + username: bla + publickey: blabla + privatekey: blablabla + command: echo 3 + register: update_action_script_ssh_authkey_result + + - assert: + that: + - update_action_script_ssh_authkey_result.changed is sameas true + + - name: test - Update action operation script type SSH key auth again + zabbix_script: + script_type: ssh + authtype: public_key + username: bla + publickey: blabla + privatekey: blablabla + command: echo 3 + register: update_action_script_ssh_authkey_again_result + + - assert: + that: + - update_action_script_ssh_authkey_again_result.changed is sameas false + + - name: test - Update action operation script type SSH add port + zabbix_script: + script_type: ssh + authtype: public_key + username: bla + publickey: blabla + privatekey: blablabla + command: echo 3 + port: 222 + register: update_action_script_ssh_port_result + + - assert: + that: + - update_action_script_ssh_port_result.changed is sameas true + + - name: test - Update action operation script type SSH add port again + zabbix_script: + script_type: ssh + authtype: public_key + username: bla + publickey: blabla + privatekey: blablabla + command: echo 3 + port: 222 + register: update_action_script_ssh_port_again_result + + - assert: + that: + - update_action_script_ssh_port_again_result.changed is sameas false + + - name: test - Update action operation script to type Telnet + zabbix_script: + script_type: telnet + username: bla1 + password: blabla1 + command: echo 4 + port: 223 + register: update_action_script_telnet_result + + - assert: + that: + - update_action_script_telnet_result.changed is sameas true + + - name: test - Update action operation script to type Telnet again + zabbix_script: + script_type: telnet + username: bla1 + password: blabla1 + command: echo 4 + port: 223 + register: update_action_script_telnet_again_result + + - assert: + that: + - update_action_script_telnet_again_result.changed is sameas false + + - name: test - Update action operation script to type IPMI + zabbix_script: + script_type: ipmi + command: echo 5 + register: update_action_script_ipmi_result + + - assert: + that: + - update_action_script_ipmi_result.changed is sameas true + + - name: test - Update action operation script to type IPMI again + zabbix_script: + script_type: ipmi + command: echo 5 + register: update_action_script_ipmi_again_result + + - assert: + that: + - update_action_script_ipmi_again_result.changed is sameas false + + - name: test - Delete action operation script + zabbix_script: + state: absent + register: delete_action_result + + - assert: + that: + - delete_action_result.changed is sameas true + + - name: test - Delete action operation script again + zabbix_script: + state: absent + register: delete_action_again_result + + - assert: + that: + - delete_action_again_result.changed is sameas false + +- name: test - Test manual host action script + module_defaults: + community.zabbix.zabbix_script: + name: Test manual host action script + scope: manual_host_action + script_type: webhook + command: 'return 0' + description: "Test manual host action script" + state: present + + block: + - name: test - Create new manual host action script to execute webhook check mode + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + check_mode: true + register: create_action_check_mode_result + + - assert: + that: + - create_action_check_mode_result.changed is sameas true + + - name: test - Create new manual host action script to execute webhook + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: create_action_result + + - assert: + that: + - create_action_result.changed is sameas true + + - name: test - Create new manual host action script to execute webhook again + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: create_action_again_result + + - assert: + that: + - create_action_again_result.changed is sameas false + + - name: test - Update manual host action script with menu path + zabbix_script: + menu_path: menu/submenu + register: update_action_result + + - assert: + that: + - update_action_result.changed is sameas true + + - name: test - Update manual host action script with menu path again + zabbix_script: + menu_path: menu/submenu + register: update_action_again_result + + - assert: + that: + - update_action_again_result.changed is sameas false + + - name: test - Update manual host action script with user group + zabbix_script: + menu_path: menu/submenu + user_group: Guests + register: update_action_usrgrp_result + + - assert: + that: + - update_action_usrgrp_result.changed is sameas true + + - name: test - Update manual host action script with user group again + zabbix_script: + menu_path: menu/submenu + user_group: Guests + register: update_action_usrgrp_again_result + + - assert: + that: + - update_action_usrgrp_again_result.changed is sameas false + + - name: test - Update manual host action script with Write permissions + zabbix_script: + host_access: write + register: update_action_host_perms_result + + - assert: + that: + - update_action_host_perms_result.changed is sameas true + + - name: test - Update manual host action script with Write permissions again + zabbix_script: + host_access: write + register: update_action_host_perms_again_result + + - assert: + that: + - update_action_host_perms_again_result.changed is sameas false + + - name: test - Update manual host action script with confirmation + zabbix_script: + confirmation: 'Are you sure?' + register: update_action_host_confirm_result + + - assert: + that: + - update_action_host_confirm_result.changed is sameas true + + - name: test - Update manual host action script with confirmation again + zabbix_script: + confirmation: 'Are you sure?' + register: update_action_host_confirm_again_result + + - assert: + that: + - update_action_host_confirm_again_result.changed is sameas false + + - name: test - Delete manual host action script + zabbix_script: + state: absent + +- name: test - Test manual event action script + module_defaults: + community.zabbix.zabbix_script: + name: Test manual event action script + scope: manual_event_action + script_type: webhook + command: 'return 0' + description: "Test manual event action script" + state: present + + block: + - name: test - Create new manual event action script to execute webhook check mode + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + check_mode: true + register: create_action_check_mode_result + + - assert: + that: + - create_action_check_mode_result.changed is sameas true + + - name: test - Create new manual event action script to execute webhook + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + register: create_action_result + + - assert: + that: + - create_action_result.changed is sameas true + + - name: test - Create new manual event action script to execute webhook again + zabbix_script: + parameters: + - name: param_name1 + - name: param_name2 + value: value2 + diff: true + register: create_action_again_result + + - assert: + that: + - create_action_again_result.changed is sameas false + + - name: test - Delete manual host action script + zabbix_script: + state: absent diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/defaults/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/defaults/main.yml new file mode 100644 index 000000000..2a50fa6ae --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/defaults/main.yml @@ -0,0 +1,2 @@ +--- +service_example_trigger: "Zabbix http poller processes more than 75% busy" diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml new file mode 100644 index 000000000..f4fc761b1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml @@ -0,0 +1,900 @@ +--- +- when: zabbix_version is version('6.0', '<') + module_defaults: + community.zabbix.zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.99 + sortorder: 0 + state: present + + block: + - name: "test - Create a new service with check_mode" + zabbix_service: + check_mode: true + register: create_service_check_mode_result + + - assert: + that: + - create_service_check_mode_result.changed is sameas true + + - name: "test - Create a new service" + zabbix_service: + register: create_service_result + + - assert: + that: + - create_service_result.changed is sameas true + + - name: "test - Create a new service (idempotency check)" + zabbix_service: + register: create_service_idempotency_check_result + + - assert: + that: + - create_service_idempotency_check_result.changed is sameas false + + - name: "test - Update a sla with check_mode" + zabbix_service: + sla: 99.999 + check_mode: true + register: update_sla_check_mode_result + + - assert: + that: + - update_sla_check_mode_result.changed is sameas true + + - name: "test - Update a sla" + zabbix_service: + sla: 99.999 + register: update_sla_result + + - assert: + that: + - update_sla_result.changed is sameas true + + - name: "test - Update a sla (idempotency check)" + zabbix_service: + sla: 99.999 + register: update_sla_idempotency_check_result + + - assert: + that: + - update_sla_idempotency_check_result.changed is sameas false + + - name: "test - Update a calculate_sla with check_mode" + zabbix_service: + sla: 99.999 + calculate_sla: true + check_mode: true + register: update_calculate_sla_check_mode_result + + - assert: + that: + - update_calculate_sla_check_mode_result.changed is sameas true + + - name: "test - Update a calculate_sla" + zabbix_service: + sla: 99.999 + calculate_sla: true + register: update_calculate_sla_result + + - assert: + that: + - update_calculate_sla_result.changed is sameas true + + - name: "test - Update a calculate_sla (idempotency check)" + zabbix_service: + sla: 99.999 + calculate_sla: true + register: update_calculate_sla_idempotency_check_result + + - assert: + that: + - update_calculate_sla_idempotency_check_result.changed is sameas false + + - name: "Override trigger_name for different version of Zabbix" + set_fact: + service_example_trigger: "Zabbix server: Utilization of http poller processes over 75%" + when: zabbix_version is version("5.0", "==") + + - name: "test - Update trigger_host and trigger_name with check_mode" + zabbix_service: + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + check_mode: true + register: update_trigger_name_check_mode_result + + - assert: + that: + - update_trigger_name_check_mode_result.changed is sameas true + + - name: "test - Update trigger_host and trigger_name" + zabbix_service: + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + register: update_trigger_name_result + + - assert: + that: + - update_trigger_name_result.changed is sameas true + + - name: "test - Update trigger_host and trigger_name (idempotency check)" + zabbix_service: + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + register: update_trigger_name_idempotency_check_result + + - assert: + that: + - update_trigger_name_idempotency_check_result.changed is sameas false + + - name: "test - Update a algorithm of service with check_mode" + zabbix_service: + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + algorithm: all_children + check_mode: true + register: update_algorithm_check_mode_result + + - assert: + that: + - update_algorithm_check_mode_result.changed is sameas true + + - name: "test - Update a algorithm of service" + zabbix_service: + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + algorithm: all_children + register: update_algorithm_result + + - assert: + that: + - update_algorithm_result.changed is sameas true + + - name: "test - Update a algorithm of service (idempotency check)" + zabbix_service: + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + algorithm: all_children + register: update_algorithm_idempotency_check_result + + - assert: + that: + - update_algorithm_idempotency_check_result.changed is sameas false + + - name: "test - Create a new root service for parent test" + zabbix_service: + name: ExampleServiceForServiceModuleRoot + sla: 99.99 + register: create_child_service_result + + - assert: + that: + - create_child_service_result.changed is sameas true + + - name: "test - Update a parent of child service with check_mode" + zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + algorithm: all_children + parent: ExampleServiceForServiceModuleRoot + check_mode: true + register: create_parent_child_service_check_mode_result + + - assert: + that: + - create_parent_child_service_check_mode_result.changed is sameas true + + - name: "test - Update a parent of child service" + zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + algorithm: all_children + parent: ExampleServiceForServiceModuleRoot + register: create_parent_child_service_result + + - assert: + that: + - create_parent_child_service_result.changed is sameas true + + - name: "test - Update a parent of child service (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.999 + calculate_sla: true + trigger_host: "Zabbix server" + trigger_name: "{{ service_example_trigger }}" + algorithm: all_children + parent: ExampleServiceForServiceModuleRoot + register: create_parent_child_service_idempotency_check_result + + - assert: + that: + - create_parent_child_service_idempotency_check_result.changed is sameas false + + - name: "test - Remove ExampleServiceForServiceModule service with check_mode" + zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.999 + state: absent + check_mode: true + register: remove_service_with_check_mode_result + + - assert: + that: + - remove_service_with_check_mode_result.changed is sameas true + + - name: "test - Remove ExampleServiceForServiceModule service" + zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.999 + state: absent + register: remove_service_result + + - assert: + that: + - remove_service_result.changed is sameas true + + - name: "test - Remove ExampleServiceForServiceModule service (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + sla: 99.999 + state: absent + register: remove_service_idempotency_check_result + + - assert: + that: + - remove_service_idempotency_check_result.changed is sameas false + + - name: "test - Remove ExampleServiceForServiceModuleRoot service with check_mode" + zabbix_service: + name: ExampleServiceForServiceModuleRoot + sla: 99.999 + state: absent + check_mode: true + register: remove_root_service_with_check_mode_result + + - assert: + that: + - remove_root_service_with_check_mode_result.changed is sameas true + + - name: "test - Remove ExampleServiceForServiceModuleRoot service" + zabbix_service: + name: ExampleServiceForServiceModuleRoot + sla: 99.999 + state: absent + register: remove_root_service_result + + - assert: + that: + - remove_root_service_result.changed is sameas true + + - name: "test - Remove ExampleServiceForServiceModuleRoot service (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModuleRoot + sla: 99.999 + state: absent + register: remove_root_service_idempotency_check_result + + - assert: + that: + - remove_root_service_idempotency_check_result.changed is sameas false + +- name: test - service for Zabbix >= 6.0 + when: zabbix_version is version('6.0', '>=') + module_defaults: + community.zabbix.zabbix_service: + description: "Example Service for Service Module" + sortorder: 0 + propagation_rule: increase + propagation_value: warning + state: present + + block: + - name: "test - Create a new service with check_mode" + zabbix_service: + name: ExampleServiceForServiceModule + check_mode: true + register: create_service_check_mode_result + + - assert: + that: + - create_service_check_mode_result.changed is sameas true + + - name: "test - Create a new service" + zabbix_service: + name: ExampleServiceForServiceModule + register: create_service_result + + - assert: + that: + - create_service_result.changed is sameas true + + - name: "test - Create a new service (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + register: create_service_idempotency_check_result + + - assert: + that: + - create_service_idempotency_check_result.changed is sameas false + + - name: "test - Update service add service tags" + zabbix_service: + name: ExampleServiceForServiceModule + tags: + - tag: TagName1 + value: TagValue1 + register: update_service_stags_result + + - assert: + that: + - update_service_stags_result.changed is sameas true + + - name: "test - Update service with service tags (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + tags: + - tag: TagName1 + value: TagValue1 + register: update_service_stags_idempotency_check_result + + - assert: + that: + - update_service_stags_idempotency_check_result.changed is sameas false + + - name: "test - Update service add more service tags" + zabbix_service: + name: ExampleServiceForServiceModule + tags: + - tag: TagName1 + value: TagValue1 + - tag: TagName2 + value: TagValue2 + register: update_service_more_stags_result + + - assert: + that: + - update_service_more_stags_result.changed is sameas true + + - name: "test - Update service add more service tags (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + tags: + - tag: TagName1 + value: TagValue1 + - tag: TagName2 + value: TagValue2 + register: update_service_more_stags_idempotency_check_result + + - assert: + that: + - update_service_more_stags_idempotency_check_result.changed is sameas false + + - name: "test - Update service remove service tags" + zabbix_service: + name: ExampleServiceForServiceModule + tags: + - tag: TagName2 + value: TagValue2 + register: update_service_less_stags_result + + - assert: + that: + - update_service_less_stags_result.changed is sameas true + + - name: "test - Update service remove service tags (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + tags: + - tag: TagName2 + value: TagValue2 + register: update_service_less_stags_idempotency_check_result + + - assert: + that: + - update_service_less_stags_idempotency_check_result.changed is sameas false + + - name: "test - Delete service" + zabbix_service: + name: ExampleServiceForServiceModule + state: absent + + - name: "test - Create service with one problem tag" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + register: create_service_with_ptag_result + + - assert: + that: + - create_service_with_ptag_result.changed is sameas true + + - name: "test - Create service with one problem tag (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + register: create_service_with_ptag_idempotency_check_result + + - name: "test - Update service with problem tag without operator" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName2 + value: TagValue2 + register: update_service_with_ptag_woop_result + + - assert: + that: + - update_service_with_ptag_woop_result.changed is sameas true + + - name: "test - Update service with problem tag without operator (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName2 + value: TagValue2 + register: update_service_with_ptag_woop_idempotency_check_result + + - assert: + that: + - update_service_with_ptag_woop_idempotency_check_result.changed is sameas false + + - name: "test - Update service with problem tag with like operator" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName2 + value: TagValue2 + - tag: TagName3 + operator: like + value: TagValue3 + register: update_service_with_ptag_wlikeop_result + + - assert: + that: + - update_service_with_ptag_wlikeop_result.changed is sameas true + + - name: "test - Update service with problem tag with like operator (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName2 + value: TagValue2 + - tag: TagName3 + operator: like + value: TagValue3 + register: update_service_with_ptag_wlikeop_idempotency_check_result + + - assert: + that: + - update_service_with_ptag_wlikeop_idempotency_check_result.changed is sameas false + + - name: "test - Update service with problem tag without operator and without value" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName2 + value: TagValue2 + - tag: TagName3 + operator: like + value: TagValue3 + - tag: TagName4 + register: update_service_with_ptag_woov_result + + - assert: + that: + - update_service_with_ptag_woov_result.changed is sameas true + + - name: "test - Update service with problem tag without operator and without value (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName2 + value: TagValue2 + - tag: TagName3 + operator: like + value: TagValue3 + - tag: TagName4 + register: update_service_with_ptag_woov_idempotency_check_result + + - assert: + that: + - update_service_with_ptag_woov_idempotency_check_result.changed is sameas false + + - name: "test - Update service remove problem tags" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName3 + operator: like + value: TagValue3 + register: update_service_remove_tags_result + + - assert: + that: + - update_service_remove_tags_result.changed is sameas true + + - name: "test - Update service remove problem tags (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + problem_tags: + - tag: TagName1 + operator: equals + value: TagValue1 + - tag: TagName3 + operator: like + value: TagValue3 + register: update_service_remove_tags_idempotency_check_result + + - assert: + that: + - update_service_remove_tags_idempotency_check_result.changed is sameas false + + - name: "test - Update service remove all problem tags" + zabbix_service: + name: ExampleServiceForServiceModule + register: update_service_remove_all_tags_result + + - assert: + that: + - update_service_remove_all_tags_result.changed is sameas true + + - name: "test - Update service remove all problem tags (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + register: update_service_remove_all_tags_idempotency_check_result + + - assert: + that: + - update_service_remove_all_tags_idempotency_check_result.changed is sameas false + + - name: "test - Create a new child service" + zabbix_service: + name: ExampleChildServiceForServiceModule + sortorder: 10 + parents: + - ExampleServiceForServiceModule + register: create_child_service_result + + - assert: + that: + - create_child_service_result.changed is sameas true + + - name: "test - Create a new child service (idempotency check)" + zabbix_service: + name: ExampleChildServiceForServiceModule + sortorder: 10 + parents: + - ExampleServiceForServiceModule + register: create_child_service_idempotency_check_result + + - assert: + that: + - create_child_service_idempotency_check_result.changed is sameas false + + - name: "test - Update child service to remove parent" + zabbix_service: + name: ExampleChildServiceForServiceModule + parents: [] + register: update_child_service_delete_parent_result + + - assert: + that: + - update_child_service_delete_parent_result.changed is sameas true + + - name: "test - Create a new parent service" + zabbix_service: + name: ExampleParentServiceForServiceModule + + - name: "test - Delete child service" + zabbix_service: + name: ExampleChildServiceForServiceModule + state: absent + + - name: "test - Create a new child service with two parents" + zabbix_service: + name: ExampleChildServiceForServiceModule + parents: + - ExampleServiceForServiceModule + - ExampleParentServiceForServiceModule + register: create_child_service_two_parents_result + + - assert: + that: + - create_child_service_two_parents_result.changed is sameas true + + - name: "test - Create a new child service with two parents (idempotency check)" + zabbix_service: + name: ExampleChildServiceForServiceModule + parents: + - ExampleServiceForServiceModule + - ExampleParentServiceForServiceModule + register: create_child_service_two_parents_idempotency_check_result + + - assert: + that: + - create_child_service_two_parents_idempotency_check_result.changed is sameas false + + - name: "test - Remove one parent from new child service" + zabbix_service: + name: ExampleChildServiceForServiceModule + parents: + - ExampleParentServiceForServiceModule + register: update_child_service_remove_parent_result + + - assert: + that: + - update_child_service_remove_parent_result.changed is sameas true + + - name: "test - Remove one parent from new child service (idempotency check)" + zabbix_service: + name: ExampleChildServiceForServiceModule + parents: + - ExampleParentServiceForServiceModule + register: update_child_service_remove_parent_idempotency_check_result + + - assert: + that: + - update_child_service_remove_parent_idempotency_check_result.changed is sameas false + + - name: "test - Delete parent service 2" + zabbix_service: + name: ExampleParentServiceForServiceModule + state: absent + + - name: "test - Create parent service with child service" + zabbix_service: + name: ExampleParentServiceForServiceModule + children: + - ExampleChildServiceForServiceModule + register: create_parent_service_with_child_result + + - assert: + that: + - create_parent_service_with_child_result.changed is sameas true + + - name: "test - Create parent service with child service (idempotency check)" + zabbix_service: + name: ExampleParentServiceForServiceModule + children: + - ExampleChildServiceForServiceModule + register: create_parent_service_with_child_result_idempotency_check_result + + - assert: + that: + - create_parent_service_with_child_result_idempotency_check_result.changed is sameas false + + - name: "test - Create second chile service" + zabbix_service: + name: ExampleChildServiceForServiceModule2 + + - name: "test - Update parent service with the second child service" + zabbix_service: + name: ExampleParentServiceForServiceModule + children: + - ExampleChildServiceForServiceModule + - ExampleChildServiceForServiceModule2 + register: update_parent_service_with_second_child_result + + - assert: + that: + - update_parent_service_with_second_child_result.changed is sameas true + + - name: "test - Update parent service with the second child service (idempotency check)" + zabbix_service: + name: ExampleParentServiceForServiceModule + children: + - ExampleChildServiceForServiceModule + - ExampleChildServiceForServiceModule2 + register: update_parent_service_with_second_child_result_idempotency_check_result + + - assert: + that: + - update_parent_service_with_second_child_result_idempotency_check_result.changed is sameas false + + - name: "test - Delete parent service" + zabbix_service: + name: ExampleParentServiceForServiceModule + state: absent + + - name: "test - Create parent service with two child services" + zabbix_service: + name: ExampleParentServiceForServiceModule + children: + - ExampleChildServiceForServiceModule + - ExampleChildServiceForServiceModule2 + register: create_parent_service_with_two_children_result + + - assert: + that: + - create_parent_service_with_two_children_result.changed is sameas true + + - name: "test - Create parent service with child services (idempotency check)" + zabbix_service: + name: ExampleParentServiceForServiceModule + children: + - ExampleChildServiceForServiceModule + - ExampleChildServiceForServiceModule2 + register: create_parent_service_with_two_children_idempotency_check_result + + - assert: + that: + - create_parent_service_with_two_children_idempotency_check_result.changed is sameas false + + - name: "test - Delete parent service" + zabbix_service: + name: ExampleParentServiceForServiceModule + state: absent + + - name: "test - Delete child service" + zabbix_service: + name: ExampleChildServiceForServiceModule + state: absent + - name: "test - Delete child servicei 2" + zabbix_service: + name: ExampleChildServiceForServiceModule2 + state: absent + + - name: "test - Delete new service" + zabbix_service: + name: ExampleServiceForServiceModule + state: absent + register: delete_service_result + + - assert: + that: + - delete_service_result.changed is sameas true + + - name: "test - Delete new service (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + state: absent + register: delete_service_idempotency_check_result + + - assert: + that: + - delete_service_idempotency_check_result.changed is sameas false + + - name: "test - Create a new service with status rule" + zabbix_service: + name: ExampleServiceForServiceModule + status_rules: + - type: at_least_n_child_services_have_status_or_above + limit_value: 4242 + limit_status: ok + new_status: not_classified + register: create_service_sr_result + + - assert: + that: + - create_service_sr_result.changed is sameas true + + - name: "test - Create a new service with status rule (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + status_rules: + - type: at_least_n_child_services_have_status_or_above + limit_value: 4242 + limit_status: ok + new_status: not_classified + register: create_service_sr_idempotency_check_result + + - assert: + that: + - create_service_sr_idempotency_check_result.changed is sameas false + + - name: "test - Update service with the second status rule" + zabbix_service: + name: ExampleServiceForServiceModule + status_rules: + - type: at_least_n_child_services_have_status_or_above + limit_value: 4242 + limit_status: ok + new_status: not_classified + - type: at_least_npct_child_services_have_status_or_above + limit_value: 42 + limit_status: information + new_status: warning + register: update_service_add_sr_result + + - assert: + that: + - update_service_add_sr_result.changed is sameas true + + - name: "test - Update service with the second status rule (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + status_rules: + - type: at_least_n_child_services_have_status_or_above + limit_value: 4242 + limit_status: ok + new_status: not_classified + - type: at_least_npct_child_services_have_status_or_above + limit_value: 42 + limit_status: information + new_status: warning + register: update_service_add_sr_idempotency_check_result + + - assert: + that: + - update_service_add_sr_idempotency_check_result.changed is sameas false + + - name: "test - Update service remove status rule" + zabbix_service: + name: ExampleServiceForServiceModule + status_rules: + - type: at_least_npct_child_services_have_status_or_above + limit_value: 42 + limit_status: information + new_status: warning + register: update_service_remove_sr_result + + - assert: + that: + - update_service_remove_sr_result.changed is sameas true + + - name: "test - Update service remove status rule (idempotency check)" + zabbix_service: + name: ExampleServiceForServiceModule + status_rules: + - type: at_least_npct_child_services_have_status_or_above + limit_value: 42 + limit_status: information + new_status: warning + register: update_service_remove_sr_idempotency_check_result + + - assert: + that: + - update_service_remove_sr_idempotency_check_result.changed is sameas false + + - name: "test - Delete new service" + zabbix_service: + name: ExampleServiceForServiceModule + state: absent + register: delete_service_result diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/defaults/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/defaults/main.yml new file mode 100644 index 000000000..6f736db53 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/defaults/main.yml @@ -0,0 +1,2 @@ +--- +template_groups_key: "{{ 'template_groups' if zabbix_version is version('6.2', '>=') else 'groups' }}" diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1-changed_50_lower.json b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1-changed_50_lower.json new file mode 100644 index 000000000..adb0e977f --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1-changed_50_lower.json @@ -0,0 +1,51 @@ +{ + "zabbix_export": { + "date": "2020-05-29T15:22:11Z", + "templates": [ + { + "template": "ExampleHost", + "name": "ExampleHost", + "description": "", + "groups": [ + { + "name": "Templates" + }, + { + "name": "Templates/Applications" + } + ], + "macros": [ + { + "macro": "{$EXAMPLE_MACRO1}", + "value": "1000" + }, + { + "macro": "{$EXAMPLE_MACRO2}", + "value": "text" + }, + { + "macro": "{$EXAMPLE_MACRO3}", + "value": "text2" + } + ], + "templates": [ + { + "name": "Template App FTP Service" + }, + { + "name": "Template App Zabbix Proxy" + } + ] + } + ], + "version": "3.0", + "groups": [ + { + "name": "Templates" + }, + { + "name": "Templates/Applications" + } + ] + } +} diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1_50_higher_decode_unicode.json b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1_50_higher_decode_unicode.json new file mode 100644 index 000000000..bd1ef8286 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1_50_higher_decode_unicode.json @@ -0,0 +1,29 @@ +{ + "zabbix_export": { + "version": "5.0", + "groups": [ + { + "name": "Templates" + } + ], + "templates": [ + { + "template": "ExampleTemplate314", + "name": "ExampleTemplate314", + "description": "\u30c6\u30b9\u30c8\u30b3\u30e1\u30f3\u30c8", + "groups": [ + { + "name": "Templates" + } + ], + "items": [ + { + "name": "test", + "type": "ZABBIX_ACTIVE", + "key": "logrt[\"/test.*test.log\",\"test.*total=([0-9.]+)\",,,skip,\\1]" + } + ], + } + ], + } +} diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1_50_lower.json b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1_50_lower.json new file mode 100644 index 000000000..b0ff06fb1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template1_50_lower.json @@ -0,0 +1,47 @@ +{ + "zabbix_export": { + "date": "2020-05-29T15:22:11Z", + "templates": [ + { + "template": "ExampleHost", + "name": "ExampleHost", + "description": "", + "groups": [ + { + "name": "Templates" + }, + { + "name": "Templates/Applications" + } + ], + "macros": [ + { + "macro": "{$EXAMPLE_MACRO1}", + "value": "1000" + }, + { + "macro": "{$EXAMPLE_MACRO2}", + "value": "text" + } + ], + "templates": [ + { + "name": "Template App FTP Service" + }, + { + "name": "Template App Zabbix Proxy" + } + ] + } + ], + "version": "3.0", + "groups": [ + { + "name": "Templates" + }, + { + "name": "Templates/Applications" + } + ] + } +} diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml new file mode 100644 index 000000000..93a32f0c5 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<zabbix_export> + <date>2020-05-29T15:22:11Z</date> + <templates> + <template> + <template>ExampleHost</template> + <name>ExampleHost</name> + <description></description> + <groups> + <group> + <name>Templates</name> + </group> + <group> + <name>Templates/Applications</name> + </group> + </groups> + <macros> + <macro> + <macro>{$EXAMPLE_MACRO1}</macro> + <value>1000</value> + </macro> + <macro> + <macro>{$EXAMPLE_MACRO2}</macro> + <value>text</value> + </macro> + <macro> + <macro>{$EXAMPLE_MACRO3}</macro> + <value>text2</value> + </macro> + </macros> + <templates> + <template> + <name>Template App FTP Service</name> + </template> + <template> + <name>Template App Zabbix Proxy</name> + </template> + <template> + <name>Template App HTTP Service</name> + </template> + </templates> + </template> + </templates> + <version>3.0</version> + <groups> + <group> + <name>Templates</name> + </group> + <group> + <name>Templates/Applications</name> + </group> + </groups> +</zabbix_export> diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3-changed_54_higher.json b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3-changed_54_higher.json new file mode 100644 index 000000000..d1854e8a9 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3-changed_54_higher.json @@ -0,0 +1,53 @@ +{ + "zabbix_export": { + "date": "2022-01-23T15:13:26Z", + "groups": [ + { + "name": "Templates", + "uuid": "7df96b18c230490a9a0a9e2307226338" + }, + { + "name": "Templates/Applications", + "uuid": "a571c0d144b14fd4a87a9d9b2aa9fcd6" + } + ], + "templates": [ + { + "groups": [ + { + "name": "Templates" + }, + { + "name": "Templates/Applications" + } + ], + "macros": [ + { + "macro": "{$EXAMPLE_MACRO1}", + "value": "1000" + }, + { + "macro": "{$EXAMPLE_MACRO2}", + "value": "text" + }, + { + "macro": "{$EXAMPLE_MACRO3}", + "value": "text2" + } + ], + "name": "ExampleHost", + "template": "ExampleHost", + "templates": [ + { + "name": "FTP Service" + }, + { + "name": "Zabbix proxy health" + } + ], + "uuid": "cd837ef0edb14e4e875f409bc90af546" + } + ], + "version": "5.4" + } +}
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3_54_higher.json b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3_54_higher.json new file mode 100644 index 000000000..ce56f8262 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3_54_higher.json @@ -0,0 +1,49 @@ +{ + "zabbix_export": { + "date": "2022-01-23T15:13:26Z", + "groups": [ + { + "name": "Templates", + "uuid": "7df96b18c230490a9a0a9e2307226338" + }, + { + "name": "Templates/Applications", + "uuid": "a571c0d144b14fd4a87a9d9b2aa9fcd6" + } + ], + "templates": [ + { + "groups": [ + { + "name": "Templates" + }, + { + "name": "Templates/Applications" + } + ], + "macros": [ + { + "macro": "{$EXAMPLE_MACRO1}", + "value": "1000" + }, + { + "macro": "{$EXAMPLE_MACRO2}", + "value": "text" + } + ], + "name": "ExampleHost", + "template": "ExampleHost", + "templates": [ + { + "name": "FTP Service" + }, + { + "name": "Zabbix proxy health" + } + ], + "uuid": "cd837ef0edb14e4e875f409bc90af546" + } + ], + "version": "5.4" + } +}
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3_54_higher.xml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3_54_higher.xml new file mode 100644 index 000000000..e45b3fd67 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template3_54_higher.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<zabbix_export> + <version>5.4</version> + <date>2022-01-23T15:24:01Z</date> + <groups> + <group> + <uuid>7df96b18c230490a9a0a9e2307226338</uuid> + <name>Templates</name> + </group> + <group> + <uuid>a571c0d144b14fd4a87a9d9b2aa9fcd6</uuid> + <name>Templates/Applications</name> + </group> + </groups> + <templates> + <template> + <uuid>cd837ef0edb14e4e875f409bc90af546</uuid> + <template>ExampleHost</template> + <name>ExampleHost</name> + <templates> + <template> + <name>FTP Service</name> + </template> + <template> + <name>Zabbix proxy health</name> + </template> + </templates> + <groups> + <group> + <name>Templates</name> + </group> + <group> + <name>Templates/Applications</name> + </group> + </groups> + <macros> + <macro> + <macro>{$EXAMPLE_MACRO1}</macro> + <value>1000</value> + </macro> + <macro> + <macro>{$EXAMPLE_MACRO2}</macro> + <value>text</value> + </macro> + </macros> + </template> + </templates> +</zabbix_export>
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml new file mode 100644 index 000000000..8ce7a51e1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml @@ -0,0 +1,126 @@ +--- + +# +# For Zabbix lower than 5.4 we test against the ExampleHost which was created in the +# main.yml tests. Due to changes in the Zabbix API (mainly because UUIDs) this is +# not possible for 5.4 onwards - so there we first delete the example hosts. +# + +- name: Delete Zabbix template. + zabbix_template: + template_name: ExampleHost + state: absent + register: delete_zabbix_template_result + +- assert: + that: + - delete_zabbix_template_result.changed is sameas true + +- name: Delete Zabbix template (idempotency check). + zabbix_template: + template_name: ExampleHost + state: absent + register: delete_zabbix_template_result + +- assert: + that: + - delete_zabbix_template_result.changed is sameas false + +# +# JSON Tests +# + +- block: + - name: Import Zabbix template from JSON file (idempotency check) - >= Zabbix 5.4. + zabbix_template: + template_json: "{{ lookup('file', 'template3_54_higher.json') }}" + state: present + register: import_template_json + + - name: Assert Zabbix template from JSON file (idempotency check) - >= Zabbix 5.4. + assert: + that: + - import_template_json.changed is sameas true + + - name: Import Zabbix template from JSON file with matching values (idempotency check) - >= Zabbix 5.4. + zabbix_template: + template_json: "{{ lookup('file', 'template3_54_higher.json') }}" + state: present + register: import_template_json + + - name: Assert Zabbix template from JSON file with matching values (idempotency check) - >= Zabbix 5.4. + assert: + that: + - import_template_json.changed is sameas false + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +- block: + - assert: + that: + - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates' + - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications' + - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health' + - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}' + - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text' + +- block: + - name: Import Zabbix template from JSON file with updated values. + zabbix_template: + template_json: "{{ lookup('file', 'template3-changed_54_higher.json') }}" + state: present + register: import_template_json + + - assert: + that: + - import_template_json.changed is sameas true + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +- assert: + that: + - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}' + - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text' + - gather_template_result.template_json[template_export_key].templates.0.macros.2.macro == '{$EXAMPLE_MACRO3}' + - gather_template_result.template_json[template_export_key].templates.0.macros.2.value == 'text2' + +# +# xml +# + +- block: + - name: Import Zabbix template from XML file with updated values. + zabbix_template: + template_xml: "{{ lookup('file', 'template3_54_higher.xml') }}" + state: present + register: import_template_xml + + - assert: + that: + - import_template_xml.changed is sameas true + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +# zabbix returns values sorted alphabetically so HTTP Service template comes before Zabbix Proxy template +- block: + - assert: + that: + - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health' diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml new file mode 100644 index 000000000..48d180210 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml @@ -0,0 +1,120 @@ +--- + +# +# For Zabbix lower than 5.4 we test against the ExampleHost which was created in the +# main.yml tests. Due to changes in the Zabbix API (mainly because UUIDs) this is +# not possible for 5.4 onwards - so there we first delete the Example host. +# + +# +# JSON Tests +# + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +- block: + - assert: + that: + - gather_template_result.template_json[template_export_key].groups.0.name == 'Templates' + - gather_template_result.template_json[template_export_key].groups.1.name == 'Templates/Applications' + - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'Template App FTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Template App Zabbix Proxy' + - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}' + - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text' + +- block: + - name: Import Zabbix template from JSON file with matching values (idempotency check) - < Zabbix 5.4. + zabbix_template: + template_json: "{{ lookup('file', 'template1_50_lower.json') }}" + state: present + register: import_template_json + + - name: Assert Zabbix template from JSON file with matching values (idempotency check) - < Zabbix 5.4. + assert: + that: + - import_template_json.changed is sameas false + +- block: + - name: Import Zabbix template from JSON file with updated values. + zabbix_template: + template_json: "{{ lookup('file', 'template1-changed_50_lower.json') }}" + state: present + register: import_template_json + + - assert: + that: + - import_template_json.changed is sameas true + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +- assert: + that: + - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}' + - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}' + - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text' + - gather_template_result.template_json[template_export_key].templates.0.macros.2.macro == '{$EXAMPLE_MACRO3}' + - gather_template_result.template_json[template_export_key].templates.0.macros.2.value == 'text2' + +- name: Dump Zabbix template to JSON format. + zabbix_template: + template_name: ExampleHost + dump_format: json + state: dump + register: template_dump_result + +- assert: + that: + - template_dump_result.deprecations is defined + - template_dump_result.deprecations.0.version == '3.0.0' + +# +# XML Tests +# + +- block: + - name: Import Zabbix template from XML file with updated values. + zabbix_template: + template_xml: "{{ lookup('file', 'template2_50_lower.xml') }}" + state: present + register: import_template_xml + + - assert: + that: + - import_template_xml.changed is sameas true + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +# zabbix returns values sorted alphabetically so HTTP Service template comes before Zabbix Proxy template +- block: + - assert: + that: + - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'Template App FTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Template App HTTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.2.name == 'Template App Zabbix Proxy' + +- name: Dump Zabbix template to XML format. + zabbix_template: + template_name: ExampleHost + dump_format: xml + state: dump + register: template_dump_result + +- assert: + that: + - template_dump_result.deprecations is defined + - template_dump_result.deprecations.0.version == '3.0.0' diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml new file mode 100644 index 000000000..66505f9a7 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml @@ -0,0 +1,330 @@ +--- +- name: Create FTP Service Template + zabbix_template: + template_name: FTP Service + template_groups: + - 'Templates' + state: present + +- name: Create a new Zabbix template (check mode). + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + state: present + register: create_zabbix_template_result + check_mode: true + +- assert: + that: + - create_zabbix_template_result.changed is sameas true + +- name: Create a new Zabbix template. + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + state: present + register: create_zabbix_template_result + +- assert: + that: + - create_zabbix_template_result.changed is sameas true + +- name: Create a new Zabbix template (idempotency check). + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + state: present + register: create_zabbix_template_result + +- assert: + that: + - create_zabbix_template_result.changed is sameas false + +- name: Create a new Zabbix template with linked templates. + zabbix_template: + template_name: ExampleHostWithLinked + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + state: present + register: create_zabbix_template_linked_result + +- assert: + that: + - create_zabbix_template_linked_result.changed is sameas true + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +- name: "test - Set key to template_export_key variable(This deals with the key being masked)" + set_fact: + template_export_key: "{{ item }}" + loop: "{{ gather_template_result.template_json.keys() | list }}" + when: + - item | regex_search('_export') + +- assert: + that: + - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates' + - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications' + +- name: Add link_templates to Zabbix template. + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + state: present + register: update_zabbix_template_result + +- assert: + that: + - update_zabbix_template_result.changed is sameas true + +- name: Add link_templates to Zabbix template (idempotency check). + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + state: present + register: update_zabbix_template_result + +- assert: + that: + - update_zabbix_template_result.changed is sameas false + +- name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleHost + format: json + register: gather_template_result + +- when: zabbix_version is version('5.4', '<') + block: + - assert: + that: + - gather_template_result.template_json[template_export_key].groups.0.name == 'Templates' + - gather_template_result.template_json[template_export_key].groups.1.name == 'Templates/Applications' + - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'Template App FTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Template App Zabbix Proxy' + +- when: zabbix_version is version('5.4', '>=') + block: + - assert: + that: + - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates' + - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications' + - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service' + - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health' + +- name: Add macros to Zabbix template. + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + macros: + - macro: '{$EXAMPLE_MACRO1}' + value: 1000 + - macro: '{$EXAMPLE_MACRO2}' + value: 'text' + state: present + register: update_zabbix_template_result + +- assert: + that: + - update_zabbix_template_result.changed is sameas true + +- name: Add macros to Zabbix template (idempotency check). + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + macros: + - macro: '{$EXAMPLE_MACRO1}' + value: 1000 + - macro: '{$EXAMPLE_MACRO2}' + value: 'text' + state: present + register: update_zabbix_template_result + +- assert: + that: + - update_zabbix_template_result.changed is sameas false + +- name: Add tags to Zabbix template. + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + macros: + - macro: '{$EXAMPLE_MACRO1}' + value: 1000 + - macro: '{$EXAMPLE_MACRO2}' + value: 'text' + tags: + - tag: tag1 + value: 1000 + - tag: tag2 + value: text + state: present + register: update_zabbix_template_result + when: zabbix_version is version('4.2', '>=') + +- assert: + that: update_zabbix_template_result is changed + when: zabbix_version is version('4.2', '>=') + +- name: Add tags to Zabbix template (idempotency check). + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + macros: + - macro: '{$EXAMPLE_MACRO1}' + value: 1000 + - macro: '{$EXAMPLE_MACRO2}' + value: 'text' + tags: + - tag: tag1 + value: 1000 + - tag: tag2 + value: text + state: present + register: update_zabbix_template_result + when: zabbix_version is version('4.2', '>=') + +- assert: + that: update_zabbix_template_result is not changed + when: zabbix_version is version('4.2', '>=') + +- name: Remove tags from Zabbix template. + zabbix_template: + template_name: ExampleHost + template_groups: + - 'Templates' + - 'Templates/Applications' + link_templates: + - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}" + - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}" + macros: + - macro: '{$EXAMPLE_MACRO1}' + value: 1000 + - macro: '{$EXAMPLE_MACRO2}' + value: 'text' + tags: [] + state: present + register: update_zabbix_template_result + when: zabbix_version is version('4.2', '>=') + +- assert: + that: update_zabbix_template_result is changed + when: zabbix_version is version('4.2', '>=') + +# #### +# Import template tests +# #### + +- include_tasks: import_54_lower.yml + when: zabbix_version is version('5.4', '<') + +- include_tasks: import_54_higher.yml + when: zabbix_version is version('5.4', '>=') + +# +# Cleanup again +# + +- name: Delete Zabbix template. + zabbix_template: + template_name: ExampleHost + state: absent + register: delete_zabbix_template_result + +- assert: + that: + - delete_zabbix_template_result.changed is sameas true + +- name: Delete Zabbix template (idempotency check). + zabbix_template: + template_name: ExampleHost + state: absent + register: delete_zabbix_template_result + +- assert: + that: + - delete_zabbix_template_result.changed is sameas false + +# +# Unicode stuff +# + +- when: zabbix_version is version('5.0', '>=') + block: + # The test if decode Unicode correctly and to be imported the template. + # https://github.com/ansible-collections/community.zabbix/issues/314 + - name: Import Zabbix template from JSON file with unicode. + zabbix_template: + template_json: "{{ lookup('file', 'template1_50_higher_decode_unicode.json') }}" + state: present + register: import_template_json + + - name: Gather Zabbix template infomation. + zabbix_template_info: + template_name: ExampleTemplate314 + format: json + register: gather_template_result + + - assert: + that: + - import_template_json.changed is sameas true + - gather_template_result.template_json.zabbix_export.templates.0.description == "\u30c6\u30b9\u30c8\u30b3\u30e1\u30f3\u30c8" + + - name: Delete Zabbix template. + zabbix_template: + template_name: ExampleTemplate314 + state: absent + register: delete_zabbix_template_result + + - assert: + that: + - delete_zabbix_template_result.changed is sameas true + +- name: Clean up ExampleHostWithLinked template + zabbix_template: + template_name: ExampleHostWithLinked + state: absent diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/defaults/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/defaults/main.yml new file mode 100644 index 000000000..6f736db53 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/defaults/main.yml @@ -0,0 +1,2 @@ +--- +template_groups_key: "{{ 'template_groups' if zabbix_version is version('6.2', '>=') else 'groups' }}" diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml new file mode 100644 index 000000000..3146c04b3 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml @@ -0,0 +1,117 @@ +--- +- name: "test - Prepare integration tests for zabbix_template_info module" + zabbix_template: + template_name: ExampleTemplateForTempleteInfoModule + template_groups: + - Templates + state: present + register: prepare_result + +- assert: + that: + - prepare_result.changed is sameas true + +- name: "test - Fetch template info as a JSON format from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: json + register: fetch_template_json_format_result + +- name: "test - Set key to template_export_key variable(This deals with the key being masked)" + set_fact: + template_export_key: "{{ item }}" + loop: "{{ fetch_template_json_format_result.template_json.keys() | list }}" + when: + - item | regex_search('_export') + +- assert: + that: + - fetch_template_json_format_result.template_json[template_export_key].date is defined + when: zabbix_version is version('6.2', '<=') + +- assert: + that: + - fetch_template_json_format_result.template_json[template_export_key][template_groups_key].0.name == "Templates" + - fetch_template_json_format_result.template_json[template_export_key].templates.0.name == "ExampleTemplateForTempleteInfoModule" + - fetch_template_json_format_result.template_json[template_export_key].templates.0.template == "ExampleTemplateForTempleteInfoModule" + +- name: "test - Fetch template info as a JSON format with omit_date parameter from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: json + omit_date: true + register: fetch_template_json_format_omit_date_result + +- assert: + that: + - fetch_template_json_format_omit_date_result.template_json[template_export_key].date is not defined + - fetch_template_json_format_omit_date_result.template_json[template_export_key][template_groups_key].0.name == "Templates" + - fetch_template_json_format_omit_date_result.template_json[template_export_key].templates.0.name == "ExampleTemplateForTempleteInfoModule" + - fetch_template_json_format_omit_date_result.template_json[template_export_key].templates.0.template == "ExampleTemplateForTempleteInfoModule" + +- name: "test - Fetch template info as a XML format from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: xml + register: fetch_template_xml_format_result + +- assert: + that: + - fetch_template_xml_format_result.template_xml | regex_search('<date>.*</date>') is defined + - fetch_template_xml_format_result.template_xml | regex_search('</date><groups><group><name>Templates</name></group></groups><templates>') is defined + - fetch_template_xml_format_result.template_xml | regex_search('<templates><template><template>ExampleTemplateForTempleteInfoModule</template><name>ExampleTemplateForTempleteInfoModule</name><groups><group><name>Templates</name></group></groups></template></templates>') is defined + +- name: "test - Fetch template info as a XML format with omit_date parameter from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: xml + omit_date: true + register: fetch_template_xml_format_omit_date_result + +- assert: + that: + - fetch_template_xml_format_omit_date_result.template_xml | regex_search('<date>.*</date>') is none + - fetch_template_xml_format_omit_date_result.template_xml | regex_search('</date><groups><group><name>Templates</name></group></groups><templates>') is defined + - fetch_template_xml_format_omit_date_result.template_xml | regex_search('<templates><template><template>ExampleTemplateForTempleteInfoModule</template><name>ExampleTemplateForTempleteInfoModule</name><groups><group><name>Templates</name></group></groups></template></templates>') is defined + +- name: "test - Fetch template info as a YAML format from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: yaml + register: fetch_template_yaml_format_result + when: zabbix_version is version('5.2', '>=') + +- assert: + that: + - fetch_template_yaml_format_result.template_yaml | regex_search('date: .+') is defined + - fetch_template_yaml_format_result.template_yaml | regex_search('name: Templates') is defined + - fetch_template_yaml_format_result.template_yaml | regex_search('template: ExampleTemplateForTempleteInfoModule') is defined + when: zabbix_version is version('5.2', '>=') + +- name: "test - Fetch template info as a YAML format with omit_date parameter from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: yaml + omit_date: true + register: fetch_template_yaml_format_omit_date_result + when: zabbix_version is version('5.2', '>=') + +- assert: + that: + - fetch_template_yaml_format_result.template_yaml | regex_search('date: .+') is not defined + - fetch_template_yaml_format_result.template_yaml | regex_search('name: Templates') is defined + - fetch_template_yaml_format_result.template_yaml | regex_search('template: ExampleTemplateForTempleteInfoModule') is defined + when: zabbix_version is version('5.2', '>=') + +- name: "test - Fetch template info with none format from Zabbix Server" + zabbix_template_info: + template_name: ExampleTemplateForTempleteInfoModule + format: none + register: fetch_template_none_format_result + +- assert: + that: + - fetch_template_none_format_result.template_id is defined + - fetch_template_none_format_result.template_json is not defined + - fetch_template_none_format_result.template_xml is not defined + - fetch_template_none_format_result.template_yaml is not defined diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml new file mode 100644 index 000000000..b658e970a --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml @@ -0,0 +1,1044 @@ +--- +# New user create test from here +- name: test - Create a new Zabbix user with check_mode and diff + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + passwd: password + check_mode: true + diff: true + register: create_zabbix_user_result + +- assert: + that: + - create_zabbix_user_result.changed is sameas true + +- name: test - Create a new Zabbix user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + passwd: password + register: create_zabbix_user_result + +- assert: + that: + - create_zabbix_user_result.changed is sameas true + +- name: test - Create a new Zabbix user(again) + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + passwd: password + register: create_zabbix_user_result + +- assert: + that: + - not create_zabbix_user_result.changed is sameas true + +# Parameter add test from here to existing user +- name: test - Add user group to existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: password + register: add_usergroup_to_existing_user_result + +- assert: + that: + - add_usergroup_to_existing_user_result.changed is sameas true + +- name: test - Add user medias(Email) to existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: password + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: add_user_medias_to_existing_user_result + +- assert: + that: + - add_user_medias_to_existing_user_result.changed is sameas true + +- name: test - Add multiple user medias(Email and SMS) to existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: password + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: add_user_medias_to_existing_user_result + +- assert: + that: + - add_user_medias_to_existing_user_result.changed is sameas true + +# Existing parameter updates test from here +- name: test - Update password parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + override_passwd: true + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_password_parameter_existing_user_result + +- assert: + that: + - update_password_parameter_existing_user_result.changed is sameas true + +- name: test - Update autologin parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologin: true + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_autologin_parameter_existing_user_result + +- assert: + that: + - update_autologin_parameter_existing_user_result.changed is sameas true + +- name: test - Update autologout parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_autologout_parameter_existing_user_result + +- assert: + that: + - update_autologout_parameter_existing_user_result.changed is sameas true + +- name: test - Update refresh parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_refresh_parameter_existing_user_result + +- assert: + that: + - update_refresh_parameter_existing_user_result.changed is sameas true + +- name: test - Update rows_per_page parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_rows_per_page_parameter_existing_user_result + +- assert: + that: + - update_rows_per_page_parameter_existing_user_result.changed is sameas true + +- name: test - Update after_login_url parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_after_login_url_parameter_existing_user_result + +- assert: + that: + - update_after_login_url_parameter_existing_user_result.changed is sameas true + +- name: test - Update theme parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: "{{ item }}" + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + loop: + - blue-theme + - dark-theme + register: update_theme_parameter_existing_user_result + +- assert: + that: + - item.changed is sameas true + loop: "{{ update_theme_parameter_existing_user_result.results }}" + +- name: test - Update type parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: "{{ item }}" + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + loop: + - Zabbix admin + - Zabbix super admin + register: update_type_parameter_existing_user_result + +- assert: + that: + - item.changed is sameas true + loop: "{{ update_type_parameter_existing_user_result.results }}" + +- name: test - Update lang parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_US + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_lang_parameter_existing_user_result + +- assert: + that: + - update_lang_parameter_existing_user_result.changed is sameas true + +- name: test - Update name and surname parameter for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_US + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_name_and_surname_parameter_existing_user_result + +- assert: + that: + - update_name_and_surname_parameter_existing_user_result.changed is sameas true + +- name: test - Update lang parameter for existing user with check_mode and diff + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + check_mode: true + diff: true + register: update_lang_parameter_existing_user_with_check_mode_diff_result + +- assert: + that: + - update_lang_parameter_existing_user_with_check_mode_diff_result.changed is sameas true + +- name: test - Update lang parameter for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_lang_parameter_existing_user_result + +- assert: + that: + - update_lang_parameter_existing_user_result.changed is sameas true + +- name: test - Update lang parameter for existing user(again) + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_lang_parameter_existing_user_result + +- assert: + that: + - not update_lang_parameter_existing_user_result.changed is sameas true + +# Parameter delete test from here from existing user +- name: test - Delete user medias(SMS) for existing user with check_mode and diff + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + check_mode: true + diff: true + register: delete_user_medias_existing_user_result + +- assert: + that: + - delete_user_medias_existing_user_result.changed is sameas true + +- name: test - Delete user medias(SMS) for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: delete_user_medias_existing_user_result + +- assert: + that: + - delete_user_medias_existing_user_result.changed is sameas true + +- name: test - Delete user group for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: delete_user_group_existing_user_result + +- assert: + that: + - delete_user_group_existing_user_result.changed is sameas true + +- name: test - optional user_medias + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + type: Zabbix super admin + lang: en_GB + register: update_user_optional_user_medias_existing_user_result + +- assert: + that: + - update_user_optional_user_medias_existing_user_result.changed is sameas False + +- name: test - Delete existing user with check_mode and diff + zabbix_user: + alias: example1 + state: absent + check_mode: true + diff: true + register: delete_existing_user_result + +- assert: + that: + - delete_existing_user_result.changed is sameas true + +- name: test - Delete existing user + zabbix_user: + alias: example1 + state: absent + register: delete_existing_user_result + +- assert: + that: + - delete_existing_user_result.changed is sameas true + +- name: test - Delete existing user(again) + zabbix_user: + alias: example1 + state: absent + register: delete_existing_user_result + +- assert: + that: + - not delete_existing_user_result.changed is sameas true + +- when: zabbix_version is version('4.0', '<') + block: + - name: test - Create new password-less user without LDAP group (fail, <4.0) + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - Guests + register: create_zabbix_user_ldap_fail + ignore_errors: true + + - assert: + that: + - create_zabbix_user_ldap_fail.failed is sameas True + +- when: zabbix_version is version('4.0', '>=') + block: + - name: test prepare - Create LDAP user group + zabbix_usergroup: + name: testLDAPgrp + gui_access: LDAP + register: zbxuser_create_ldap_group + + - assert: + that: + - zbxuser_create_ldap_group.changed is sameas True + + - name: test - Create new password-less user without LDAP group (fail) + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - Guests + register: create_zabbix_user_ldap_fail + ignore_errors: true + + - assert: + that: + - create_zabbix_user_ldap_fail.failed is sameas True + + - name: test - Create new password-less user as member in LDAP group + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - testLDAPgrp + register: create_zabbix_user_ldap_result + + - assert: + that: + - create_zabbix_user_ldap_result.changed is sameas True + + - name: test - Create new password-less user as member in LDAP group (again) + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - testLDAPgrp + register: create_zabbix_user_ldap_result + + - assert: + that: + - create_zabbix_user_ldap_result.changed is sameas False + + - name: test - Delete existing user + zabbix_user: + alias: example2alias + state: absent + register: delete_existing_user_result + + - assert: + that: + - delete_existing_user_result.changed is sameas true + +# The tests are to check the patch for PR hasn't a problem. +# https://github.com/ansible-collections/community.zabbix/pull/382 +- name: test - Create a zabbix user with minimum parameters + zabbix_user: + alias: example2 + usrgrps: + - Guests + passwd: password + register: create_zabbix_user_with_minimum_params_result + +- assert: + that: + - create_zabbix_user_with_minimum_params_result.changed is sameas true + +- name: test - Create a zabbix user with minimum parameters(again) + zabbix_user: + alias: example2 + usrgrps: + - Guests + passwd: password + register: create_zabbix_user_with_minimum_params_result + +- assert: + that: + - create_zabbix_user_with_minimum_params_result.changed is sameas false + +- name: test - Update the parameters without role_name + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: password + register: update_params_without_role_name_result + +- assert: + that: + - update_params_without_role_name_result.changed is sameas true + +- name: test - Update the parameters without role_name(again) + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: password + register: update_params_without_role_name_result + +- assert: + that: + - update_params_without_role_name_result.changed is sameas false + +- name: test - Add user medias(Email) as list to existing user + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + user_medias: + - mediatype: Email + sendto: + - example@example.com + - example1@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: add_user_email_media_as_list_to_existing_user_result + +- assert: + that: + - add_user_email_media_as_list_to_existing_user_result.changed is sameas true + +- name: test - Add user medias(Email) as list to existing user(again) + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + user_medias: + - mediatype: Email + sendto: + - example@example.com + - example1@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: add_user_email_media_as_list_to_existing_user_result + +- assert: + that: + - add_user_email_media_as_list_to_existing_user_result.changed is sameas false + +- name: test - Delete existing user + zabbix_user: + alias: example2 + state: absent + +- name: test prepare - Delete LDAP user group + zabbix_usergroup: + name: testLDAPgrp + state: absent diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml new file mode 100644 index 000000000..9d3d913ce --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml @@ -0,0 +1,1100 @@ +--- +# New user create test from here +- name: test - Create a new Zabbix user with check_mode and diff + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + check_mode: true + diff: true + register: create_zabbix_user_result + +- assert: + that: + - create_zabbix_user_result.changed is sameas true + +- name: test - Create a new Zabbix user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + register: create_zabbix_user_result + +- assert: + that: + - create_zabbix_user_result.changed is sameas true + +- name: test - Create a new Zabbix user(again) + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + register: create_zabbix_user_result + +- assert: + that: + - not create_zabbix_user_result.changed is sameas true + +# Parameter add test from here to existing user +- name: test - Add user group to existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: G$jd_79!jw + register: add_usergroup_to_existing_user_result + +- assert: + that: + - add_usergroup_to_existing_user_result.changed is sameas true + +- name: test - Add user medias(Email) to existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: G$jd_79!jw + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: add_user_medias_to_existing_user_result + +- assert: + that: + - add_user_medias_to_existing_user_result.changed is sameas true + +- name: test - Add multiple user medias(Email and SMS) to existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: G$jd_79!jw + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: add_user_medias_to_existing_user_result + +- assert: + that: + - add_user_medias_to_existing_user_result.changed is sameas true + +# Existing parameter updates test from here +- name: test - Update password parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + override_passwd: true + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_password_parameter_existing_user_result + +- assert: + that: + - update_password_parameter_existing_user_result.changed is sameas true + +- name: test - Update autologin parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologin: true + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_autologin_parameter_existing_user_result + +- assert: + that: + - update_autologin_parameter_existing_user_result.changed is sameas true + +- name: test - Update autologout parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_autologout_parameter_existing_user_result + +- assert: + that: + - update_autologout_parameter_existing_user_result.changed is sameas true + +- name: test - Update refresh parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_refresh_parameter_existing_user_result + +- assert: + that: + - update_refresh_parameter_existing_user_result.changed is sameas true + +- name: test - Update rows_per_page parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_rows_per_page_parameter_existing_user_result + +- assert: + that: + - update_rows_per_page_parameter_existing_user_result.changed is sameas true + +- name: test - Update after_login_url parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_after_login_url_parameter_existing_user_result + +- assert: + that: + - update_after_login_url_parameter_existing_user_result.changed is sameas true + +- name: test - Update theme parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: "{{ item }}" + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + loop: + - blue-theme + - dark-theme + register: update_theme_parameter_existing_user_result + +- assert: + that: + - item.changed is sameas true + loop: "{{ update_theme_parameter_existing_user_result.results }}" + +- name: test - Update role_name parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: "{{ item }}" + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + loop: + - Guest role + - Admin role + register: update_type_parameter_existing_user_result + +- assert: + that: + - item.changed is sameas true + loop: "{{ update_type_parameter_existing_user_result.results }}" + +- name: test - Update lang parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + lang: en_US + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_lang_parameter_existing_user_result + +- assert: + that: + - update_lang_parameter_existing_user_result.changed is sameas true + +- name: test - Update timezone parameter for existing user + zabbix_user: + alias: example1 + name: example + surname: test + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: en_US + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_timezone_parameter_existing_user_result + +- assert: + that: + - update_timezone_parameter_existing_user_result.changed is sameas true + +- name: test - Update name and surname parameter for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: en_US + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_name_and_surname_parameter_existing_user_result + +- assert: + that: + - update_name_and_surname_parameter_existing_user_result.changed is sameas true + +- name: test - Update lang parameter for existing user with check_mode and diff + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + check_mode: true + diff: true + register: update_lang_parameter_existing_user_with_check_mode_diff_result + +- assert: + that: + - update_lang_parameter_existing_user_with_check_mode_diff_result.changed is sameas true + +- name: test - Update lang parameter for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_lang_parameter_existing_user_result + +- assert: + that: + - update_lang_parameter_existing_user_result.changed is sameas true + +- name: test - Update lang parameter for existing user(again) + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + - mediatype: SMS + sendto: example@example.com + period: 1-5,01:00-23:00 + severity: + not_classified: false + information: true + warning: true + average: false + high: true + disaster: true + active: true + register: update_lang_parameter_existing_user_result + +- assert: + that: + - not update_lang_parameter_existing_user_result.changed is sameas true + +# Parameter delete test from here from existing user +- name: test - Delete user medias(SMS) for existing user with check_mode and diff + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + check_mode: true + diff: true + register: delete_user_medias_existing_user_result + +- assert: + that: + - delete_user_medias_existing_user_result.changed is sameas true + +- name: test - Delete user medias(SMS) for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Guests + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: delete_user_medias_existing_user_result + +- assert: + that: + - delete_user_medias_existing_user_result.changed is sameas true + +- name: test - Delete user group for existing user + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: delete_user_group_existing_user_result + +- assert: + that: + - delete_user_group_existing_user_result.changed is sameas true + +- name: test - optional user_medias + zabbix_user: + alias: example1 + name: example2 + surname: test2 + usrgrps: + - Zabbix administrators + passwd: update_password + autologout: 500 + refresh: 60 + rows_per_page: 300 + after_login_url: http://example.com + theme: dark-theme + role_name: Admin role + timezone: Asia/Tokyo + lang: fr_FR + register: update_user_optional_user_medias_existing_user_result + +- assert: + that: + - update_user_optional_user_medias_existing_user_result.changed is sameas False + +- name: test - Delete existing user with check_mode and diff + zabbix_user: + alias: example1 + state: absent + check_mode: true + diff: true + register: delete_existing_user_result + +- assert: + that: + - delete_existing_user_result.changed is sameas true + +- name: test - Delete existing user + zabbix_user: + alias: example1 + state: absent + register: delete_existing_user_result + +- assert: + that: + - delete_existing_user_result.changed is sameas true + +- name: test - Delete existing user(again) + zabbix_user: + alias: example1 + state: absent + register: delete_existing_user_result + +- assert: + that: + - not delete_existing_user_result.changed is sameas true + +- when: zabbix_version is version('4.0', '<') + block: + - name: test - Create new password-less user without LDAP group (fail, <4.0) + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - Guests + register: create_zabbix_user_ldap_fail + ignore_errors: true + + - assert: + that: + - create_zabbix_user_ldap_fail.failed is sameas True + +- when: zabbix_version is version('4.0', '>=') + block: + - name: test prepare - Create LDAP user group + zabbix_usergroup: + name: testLDAPgrp + gui_access: LDAP + register: zbxuser_create_ldap_group + + - assert: + that: + - zbxuser_create_ldap_group.changed is sameas True + + - name: test - Create new password-less user without LDAP group (fail) + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - Guests + register: create_zabbix_user_ldap_fail + ignore_errors: true + + - assert: + that: + - create_zabbix_user_ldap_fail.failed is sameas True + + - name: test - Create new password-less user as member in LDAP group + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - testLDAPgrp + register: create_zabbix_user_ldap_result + + - assert: + that: + - create_zabbix_user_ldap_result.changed is sameas True + + - name: test - Create new password-less user as member in LDAP group (again) + zabbix_user: + alias: example2alias + name: example2 + surname: testldap + usrgrps: + - testLDAPgrp + register: create_zabbix_user_ldap_result + + - assert: + that: + - create_zabbix_user_ldap_result.changed is sameas False + + - name: test - Delete existing user + zabbix_user: + alias: example2alias + state: absent + register: delete_existing_user_result + + - assert: + that: + - delete_existing_user_result.changed is sameas true + +# The tests are to check the patch for PR hasn't a problem. +# https://github.com/ansible-collections/community.zabbix/pull/382 +- name: test - Create a zabbix user with minimum parameters + zabbix_user: + alias: example2 + usrgrps: + - Guests + passwd: G$jd_79!jw + role_name: "User role" + register: create_zabbix_user_with_minimum_params_result + +- assert: + that: + - create_zabbix_user_with_minimum_params_result.changed is sameas true + +- name: test - Create a zabbix user with minimum parameters(again) + zabbix_user: + alias: example2 + usrgrps: + - Guests + passwd: G$jd_79!jw + role_name: "User role" + register: create_zabbix_user_with_minimum_params_result + +- assert: + that: + - create_zabbix_user_with_minimum_params_result.changed is sameas false + +- name: test - Update the parameters without role_name + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + register: update_params_without_role_name_result + +- assert: + that: + - update_params_without_role_name_result.changed is sameas true + +- name: test - Update the parameters without role_name(again) + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + register: update_params_without_role_name_result + +- assert: + that: + - update_params_without_role_name_result.changed is sameas false + +- name: test - Add user medias(Email) as list to existing user + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + user_medias: + - mediatype: Email + sendto: + - example@example.com + - example1@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: add_user_email_media_as_list_to_existing_user_result + +- assert: + that: + - add_user_email_media_as_list_to_existing_user_result.changed is sameas true + +- name: test - Add user medias(Email) as list to existing user(again) + zabbix_user: + alias: example2 + name: example2 + surname: test + usrgrps: + - Guests + passwd: G$jd_79!jw + user_medias: + - mediatype: Email + sendto: + - example@example.com + - example1@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: true + register: add_user_email_media_as_list_to_existing_user_result + +- assert: + that: + - add_user_email_media_as_list_to_existing_user_result.changed is sameas false + +- name: test - Delete existing user + zabbix_user: + alias: example2 + state: absent + +- name: test prepare - Delete LDAP user group + zabbix_usergroup: + name: testLDAPgrp + state: absent diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml new file mode 100644 index 000000000..f762591cf --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- name: Execute the integration test for Zabbix 5.0 and lower + include_tasks: for_zabbix_50_lower.yml + when: + - zabbix_version | float <= 5.0 + +- name: Execute the integration test for Zabbix 5.4 and higher + include_tasks: for_zabbix_54_higher.yml + when: + - zabbix_version | float >= 5.4 diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml new file mode 100644 index 000000000..6c697a2e5 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- block: + - include_tasks: zabbix_user_directory_tests.yml + + always: + - name: Cleanup + zabbix_user_directory: + name: TestUserDirectory + state: absent + ignore_errors: true diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml new file mode 100644 index 000000000..db057a5d0 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml @@ -0,0 +1,437 @@ +--- +- name: test - do not run tests for Zabbix < 6.2 + meta: end_play + when: zabbix_version is version('6.2', '<') + +- name: test - user directory for Zabbix < 6.4 + module_defaults: + community.zabbix.zabbix_user_directory: + state: present + name: TestUserDirectory + + block: + - name: test - create new user directory in check mode + zabbix_user_directory: + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + check_mode: true + register: directory_check_result + + - assert: + that: directory_check_result.changed is sameas True + + - name: test - attempt to create new user directory with not all mandatory parameters + zabbix_user_directory: + host: 'test.com' + port: 389 + ignore_errors: true + register: directory_expect_fail_result + + - assert: + that: directory_expect_fail_result.failed is sameas True + + - name: test - create new user directory withoud bind_password + zabbix_user_directory: + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + register: directory_result + + - assert: + that: directory_result.changed is sameas True + + - name: test - create new user directory without bind_password again + zabbix_user_directory: + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + register: directory_again_result + + - assert: + that: directory_again_result.changed is sameas False + + - name: test - delete user directory + zabbix_user_directory: + state: absent + register: directory_delete_result + + - assert: + that: directory_delete_result.changed is sameas True + + - name: test - create new user directory with bind_password + zabbix_user_directory: + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + bind_password: 'password' + register: directory_result + + - assert: + that: directory_result.changed is sameas True + + - name: test - create new user directory with bind_password again + zabbix_user_directory: + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + bind_password: 'password' + register: directory_again_result + + - assert: + that: directory_again_result.changed is sameas True + + - name: test - update only host parameter in user directory + zabbix_user_directory: + host: 'test.ca' + register: directory_update_result + + - assert: + that: directory_update_result.changed is sameas True + + - name: test - update only host parameter in user directory again + zabbix_user_directory: + host: 'test.ca' + register: directory_update_again_result + + - assert: + that: directory_update_again_result.changed is sameas False + + when: zabbix_version is version('6.4', '<') + +- name: test - user directory for Zabbix >= 6.4 + module_defaults: + community.zabbix.zabbix_user_directory: + state: present + name: TestUserDirectory + + block: + - name: test - create new LDAP user directory in check mode + zabbix_user_directory: + idp_type: ldap + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + check_mode: true + register: directory_check_result + + - assert: + that: directory_check_result.changed is sameas True + + - name: test - attempt to create new LDAP user directory with not all mandatory parameters + zabbix_user_directory: + idp_type: ldap + host: 'test.com' + port: 389 + ignore_errors: true + register: directory_expect_fail_result + + - assert: + that: directory_expect_fail_result.failed is sameas True + + - name: test - create new LDAP user directory withoud bind_password + zabbix_user_directory: + idp_type: ldap + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + register: directory_result + + - assert: + that: directory_result.changed is sameas True + + - name: test - create new LDAP user directory without bind_password again + zabbix_user_directory: + idp_type: ldap + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + register: directory_again_result + + - assert: + that: directory_again_result.changed is sameas False + + - name: test - delete LDAP user directory + zabbix_user_directory: + state: absent + register: directory_delete_result + + - assert: + that: directory_delete_result.changed is sameas True + + - name: test - create new LDAP user directory with bind_password + zabbix_user_directory: + idp_type: ldap + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + bind_password: 'password' + register: directory_result + + - assert: + that: directory_result.changed is sameas True + + - name: test - create new LDAP user directory with bind_password again + zabbix_user_directory: + idp_type: ldap + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + bind_password: 'password' + register: directory_again_result + + - assert: + that: directory_again_result.changed is sameas True + + - name: test - update host parameter in LDAP user directory + zabbix_user_directory: + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + register: directory_update_result + + - assert: + that: directory_update_result.changed is sameas True + + - name: test - update host parameter in LDAP user directory again + zabbix_user_directory: + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + register: directory_update_again_result + + - assert: + that: directory_update_again_result.changed is sameas False + + - name: test - add media type mapping with non-existing media type + zabbix_user_directory: + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + provision_status: True + provision_media: + - name: Media1 + mediatype: EmailX + attribute: email + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + ignore_errors: True + register: directory_update_media_fail_result + + - assert: + that: directory_update_media_fail_result.failed is sameas True + + - name: test - add mappings + zabbix_user_directory: + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + provision_status: True + group_name: cn + group_basedn: ou=Group,dc=example,dc=org + group_member: member + user_ref_attr: uid + group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)' + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + register: directory_update_media_result + + - assert: + that: directory_update_media_result.changed is sameas True + + - name: test - add mappings again + zabbix_user_directory: + idp_type: ldap + host: 'test.ca' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + provision_status: True + group_name: cn + group_basedn: ou=Group,dc=example,dc=org + group_member: member + user_ref_attr: uid + group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)' + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + register: directory_update_media_again_result + + - assert: + that: directory_update_media_again_result.changed is sameas False + + - name: test - delete LDAP user directory + zabbix_user_directory: + state: absent + + - name: test - create new SAML user directory in check mode + zabbix_user_directory: + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + check_mode: true + register: directory_check_result + + - assert: + that: directory_check_result.changed is sameas True + + - name: test - attempt to create new SAML user directory with not all mandatory parameters + zabbix_user_directory: + idp_type: saml + ignore_errors: true + register: directory_expect_fail_result + + - assert: + that: directory_expect_fail_result.failed is sameas True + + - name: test - create new SAML user directory + zabbix_user_directory: + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + register: directory_create_result + + - assert: + that: directory_create_result.changed is sameas True + + - name: test - update SAML user directory with all optional parameters + zabbix_user_directory: + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + slo_url: http://yyyy.okta.com + nameid_format: 'urn:oasis' + scim_status: true + encrypt_nameid: true + encrypt_assertions: true + sign_messages: true + sign_assertions: true + sign_authn_requests: true + sign_logout_requests: true + sign_logout_responses: true + register: directory_create_all_result + + - assert: + that: directory_create_all_result.changed is sameas True + + - name: test - update SAML user directory with all optional parameters again + zabbix_user_directory: + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + slo_url: http://yyyy.okta.com + nameid_format: 'urn:oasis' + scim_status: true + encrypt_nameid: true + encrypt_assertions: true + sign_messages: true + sign_assertions: true + sign_authn_requests: true + sign_logout_requests: true + sign_logout_responses: true + register: directory_create_all_again_result + + - assert: + that: directory_create_all_again_result.changed is sameas False + + - name: test - delete SAML user directory + zabbix_user_directory: + state: absent + + - name: test - create new SAML user directory with mappings + zabbix_user_directory: + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + provision_status: True + group_name: cn + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + register: directory_create_mappings_result + + - assert: + that: directory_create_mappings_result.changed is sameas True + + - name: test - create new SAML user directory with mappings again + zabbix_user_directory: + idp_type: saml + idp_entityid: http://okta.com/xxxxx + sp_entityid: zabbix + sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3 + username_attribute: usrEmail + provision_status: True + group_name: cn + user_username: first_name + user_lastname: last_name + provision_media: + - name: Media1 + mediatype: Email + attribute: email1 + provision_groups: + - name: idpname1 + role: Guest role + user_groups: + - Guests + register: directory_create_mappings_again_result + + - assert: + that: directory_create_mappings_again_result.changed is sameas False + + when: zabbix_version is version('6.4', '>=') diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml new file mode 100644 index 000000000..7228e12eb --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml @@ -0,0 +1,199 @@ +--- +# New user create test from here +- when: zabbix_version is version('5.4', '<') + block: + - name: test - Create a new Zabbix user + zabbix_user: + alias: example + name: user name + surname: user surname + usrgrps: + - Guests + - Disabled + passwd: G$jd_79!jw + lang: en_US + theme: blue-theme + autologin: false + autologout: '0' + refresh: '30' + rows_per_page: '200' + after_login_url: '' + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: false + type: Zabbix super admin + state: present + register: create_zabbix_user_result + + - assert: + that: + - create_zabbix_user_result.changed is sameas true + + - name: test - Set definition_of_results variable of Zabbix 5.0 and lower + set_fact: + definition_of_results: + - get_user_info_result[user_info_key].alias == "example" + - get_user_info_result[user_info_key].autologin is defined + - get_user_info_result[user_info_key].autologout is defined + - get_user_info_result[user_info_key].lang is defined + - get_user_info_result[user_info_key].medias.0.active is defined + - get_user_info_result[user_info_key].medias.0.mediaid is defined + - get_user_info_result[user_info_key].medias.0.period is defined + - get_user_info_result[user_info_key].medias.0.sendto is defined + - get_user_info_result[user_info_key].medias.0.severity is defined + - get_user_info_result[user_info_key].medias.0.userid is defined + - get_user_info_result[user_info_key].name is defined + - get_user_info_result[user_info_key].refresh is defined + - get_user_info_result[user_info_key].rows_per_page is defined + - get_user_info_result[user_info_key].surname is defined + - get_user_info_result[user_info_key].theme is defined + - get_user_info_result[user_info_key].type is defined + - get_user_info_result[user_info_key].url is defined + - get_user_info_result[user_info_key].userid is defined + - get_user_info_result[user_info_key].users_status is defined + - get_user_info_result[user_info_key].usrgrps | length == 2 + - get_user_info_result[user_info_key].usrgrps.0.debug_mode is defined + - get_user_info_result[user_info_key].usrgrps.0.gui_access is defined + - get_user_info_result[user_info_key].usrgrps.0.name is defined + - get_user_info_result[user_info_key].usrgrps.0.users_status is defined + - get_user_info_result[user_info_key].usrgrps.0.usrgrpid is defined + - get_user_info_result[user_info_key].usrgrps.1.debug_mode is defined + - get_user_info_result[user_info_key].usrgrps.1.gui_access is defined + - get_user_info_result[user_info_key].usrgrps.1.name is defined + - get_user_info_result[user_info_key].usrgrps.1.users_status is defined + - get_user_info_result[user_info_key].usrgrps.1.usrgrpid is defined + +- when: zabbix_version is version('5.4', '>=') + block: + - name: test - Create a new Zabbix user + zabbix_user: + alias: example + name: user name + surname: user surname + usrgrps: + - Guests + - Disabled + passwd: G$jd_79!jw + lang: en_US + theme: blue-theme + autologin: false + autologout: '0' + refresh: '30' + rows_per_page: '200' + after_login_url: '' + user_medias: + - mediatype: Email + sendto: example@example.com + period: 1-7,00:00-24:00 + severity: + not_classified: false + information: true + warning: true + average: true + high: true + disaster: true + active: false + role_name: Super admin role + timezone: Asia/Tokyo + state: present + register: create_zabbix_user_result + + - assert: + that: + - create_zabbix_user_result.changed is sameas true + + - name: test - Set definition_of_results variable of Zabbix 5.4 and higher + set_fact: + definition_of_results: + - get_user_info_result[user_info_key].alias == "example" + - get_user_info_result[user_info_key].autologin is defined + - get_user_info_result[user_info_key].autologout is defined + - get_user_info_result[user_info_key].lang is defined + - get_user_info_result[user_info_key].medias.0.active is defined + - get_user_info_result[user_info_key].medias.0.mediaid is defined + - get_user_info_result[user_info_key].medias.0.period is defined + - get_user_info_result[user_info_key].medias.0.sendto is defined + - get_user_info_result[user_info_key].medias.0.severity is defined + - get_user_info_result[user_info_key].medias.0.userid is defined + - get_user_info_result[user_info_key].name is defined + - get_user_info_result[user_info_key].refresh is defined + - get_user_info_result[user_info_key].rows_per_page is defined + - get_user_info_result[user_info_key].surname is defined + - get_user_info_result[user_info_key].theme is defined + - get_user_info_result[user_info_key].roleid is defined + - get_user_info_result[user_info_key].url is defined + - get_user_info_result[user_info_key].userid is defined + - get_user_info_result[user_info_key].users_status is defined + - get_user_info_result[user_info_key].timezone is defined + - get_user_info_result[user_info_key].usrgrps | length == 2 + - get_user_info_result[user_info_key].usrgrps.0.debug_mode is defined + - get_user_info_result[user_info_key].usrgrps.0.gui_access is defined + - get_user_info_result[user_info_key].usrgrps.0.name is defined + - get_user_info_result[user_info_key].usrgrps.0.users_status is defined + - get_user_info_result[user_info_key].usrgrps.0.usrgrpid is defined + - get_user_info_result[user_info_key].usrgrps.1.debug_mode is defined + - get_user_info_result[user_info_key].usrgrps.1.gui_access is defined + - get_user_info_result[user_info_key].usrgrps.1.name is defined + - get_user_info_result[user_info_key].usrgrps.1.users_status is defined + - get_user_info_result[user_info_key].usrgrps.1.usrgrpid is defined + +- name: "test - Get a zabbix user information" + zabbix_user_info: + alias: example + register: get_user_info_result + +- name: "test - Set key to user_info_key variable(This deals with the key being masked)" + set_fact: + user_info_key: "{{ item }}" + loop: "{{ get_user_info_result.keys() | list }}" + when: + - item | regex_search('_user') + +- assert: + that: definition_of_results + + +- name: test - Create a new Zabbix user + zabbix_user: + alias: example2 + usrgrps: + - Guests + - Disabled + passwd: G$jd_79!jw + state: present + register: create_zabbix_user_result2 + +- assert: + that: + - create_zabbix_user_result2.changed is sameas true + +- name: "test - Get a zabbix user information" + zabbix_user_info: + alias: example2 + register: get_user_info_result2 + +- name: "test - Set key to user_info_key variable(This deals with the key being masked)" + set_fact: + user_info_key: "{{ item }}" + loop: "{{ get_user_info_result2.keys() | list }}" + when: + - item | regex_search('_user') + +- assert: + that: + - get_user_info_result2[user_info_key].alias == "example2" + when: zabbix_version is version('5.4', '<') + +- assert: + that: + - get_user_info_result2[user_info_key].username == "example2" + when: zabbix_version is version('5.4', '>=') diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml new file mode 100644 index 000000000..799bef30b --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml @@ -0,0 +1,106 @@ +--- +# New user role create test from here, only 6.0 and higher +- when: zabbix_version is version('6.0', '>=') + block: + - name: test - Create a new Zabbix role + zabbix_user_role: + state: present + name: Operators + type: User + rules: + ui.default_access: 0 + ui: + - name: "monitoring.hosts" + status: 0 + - name: "monitoring.maps" + status: 1 + register: create_zabbix_user_role_result + + - assert: + that: + - create_zabbix_user_role_result.changed is sameas true + + # Check user role idempotency + - name: test - Update a Zabbix role with same rules + zabbix_user_role: + state: present + name: Operators + type: User + rules: + ui.default_access: 0 + ui: + - name: "monitoring.hosts" + status: 0 + - name: "monitoring.maps" + status: 1 + register: create_zabbix_user_role_result + + - assert: + that: + - create_zabbix_user_role_result.changed is sameas false + + # Check user role change + - name: test - Update a Zabbix role with new rules + zabbix_user_role: + state: present + name: Operators + type: User + rules: + ui.default_access: 0 + ui: + - name: "monitoring.hosts" + status: 1 + - name: "monitoring.maps" + status: 0 + register: create_zabbix_user_role_result + + - assert: + that: + - create_zabbix_user_role_result.changed is sameas true + + # Check user role remove + - name: test - Remove Zabbix role + zabbix_user_role: + state: absent + name: Operators + register: create_zabbix_user_role_result + + - assert: + that: + - create_zabbix_user_role_result.changed is sameas true + + - name: test - Create a new Zabbix role type Admin + zabbix_user_role: + state: present + name: Admins + type: Admin + rules: + ui.default_access: 0 + register: create_zabbix_user_role_admin_result + + - assert: + that: + - create_zabbix_user_role_admin_result.changed is sameas true + + - name: test - Remove Zabbix role type Admin + zabbix_user_role: + state: absent + name: Admins + + - name: test - Create a new Zabbix role type Super Admin + zabbix_user_role: + state: present + name: Super Admins + type: Super Admin + rules: + ui.default_access: 0 + register: create_zabbix_user_role_super_admin_result + + - assert: + that: + - create_zabbix_user_role_super_admin_result.changed is sameas true + + - name: test - Remove Zabbix role type Super Admin + zabbix_user_role: + state: absent + name: Super Admins diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml new file mode 100644 index 000000000..f7a6aa60e --- /dev/null +++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml @@ -0,0 +1,278 @@ +--- +- name: test - do not run tests for Zabbix 3.0 + meta: end_play + when: zabbix_version is version('3.0', '=') + +- name: test - Zabbix user group + module_defaults: + community.zabbix.zabbix_usergroup: + name: ACME + + block: + - name: test - create new Zabbix user group + zabbix_usergroup: + state: present + register: usergroup_new + + - name: assert that user group was created + assert: + that: usergroup_new is changed + + - name: test - create new Zabbix user group (again) + zabbix_usergroup: + state: present + register: usergroup_again + + - name: assert that user group was created + assert: + that: not usergroup_again is changed + + - name: test - update Zabbix user group with disabled gui_access + zabbix_usergroup: + gui_access: disable + register: usergroup_updated + + - name: assert that user group was updated + assert: + that: usergroup_updated is changed + + - name: test - update Zabbix user group with disabled gui_access (again) + zabbix_usergroup: + gui_access: disable + register: usergroup_updated_again + + - name: assert that user group was updated + assert: + that: not usergroup_updated_again is changed + + - name: test - reset Zabbix user group to default + zabbix_usergroup: + register: usergroup_reset + + - name: assert that user group was created + assert: + that: usergroup_reset is changed + + - when: zabbix_version is version('6.2', '<') + block: + - name: test - update Zabbix user group with one right + zabbix_usergroup: + rights: + - host_group: Discovered hosts + permission: read-only + register: usergroup_updated_right + + - name: assert that user group was updated + assert: + that: usergroup_updated_right is changed + + - name: test - update Zabbix user group with multiple rights + zabbix_usergroup: + rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + register: usergroup_updated_rights + + - name: assert that user group was updated + assert: + that: usergroup_updated_rights is changed + + - name: test - update Zabbix user group with multiple rights (again) + zabbix_usergroup: + rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + register: usergroup_updated_rights_again + + - name: assert that user group was not updated + assert: + that: not usergroup_updated_rights_again is changed + + - when: zabbix_version is version('6.2', '>=') + block: + - name: test - update Zabbix user group with one hostgroup right + zabbix_usergroup: + hostgroup_rights: + - host_group: Discovered hosts + permission: read-only + register: usergroup_updated_hostgroup_right + + - name: assert that user group was updated + assert: + that: usergroup_updated_hostgroup_right is changed + + - name: test - update Zabbix user group with multiple hostgroup rights + zabbix_usergroup: + hostgroup_rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + register: usergroup_updated_hostgroup_rights + + - name: assert that user group was updated + assert: + that: usergroup_updated_hostgroup_rights is changed + + - name: test - update Zabbix user group with multiple hostgroup rights (again) + zabbix_usergroup: + hostgroup_rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + register: usergroup_updated_hostgroup_rights_again + + - name: assert that user group was not updated + assert: + that: not usergroup_updated_hostgroup_rights_again is changed + + - name: test - update Zabbix user group with one template group right + zabbix_usergroup: + hostgroup_rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + templategroup_rights: + - template_group: Templates + permission: read-only + register: usergroup_updated_templategroup_right + + - name: assert that user group was updated + assert: + that: usergroup_updated_templategroup_right is changed + + - name: test - update Zabbix user group with multiple template group rights + zabbix_usergroup: + hostgroup_rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + templategroup_rights: + - template_group: Templates + permission: read-only + - template_group: Templates/Applications + permission: read-write + register: usergroup_updated_templategroup_rights + + - name: assert that user group was updated + assert: + that: usergroup_updated_templategroup_right is changed + + - name: test - update Zabbix user group with multiple template group rights (again) + zabbix_usergroup: + hostgroup_rights: + - host_group: Discovered hosts + permission: read-only + - host_group: Zabbix servers + permission: read-write + templategroup_rights: + - template_group: Templates + permission: read-only + - template_group: Templates/Applications + permission: read-write + register: usergroup_updated_templategroup_rights_again + + - name: assert that user group was not updated + assert: + that: not usergroup_updated_templategroup_rights_again is changed + + - name: test - reset Zabbix user group to default + zabbix_usergroup: + register: usergroup_reset + + - name: assert that user group was created + assert: + that: usergroup_reset is changed + + - name: test - update Zabbix user group with one tag_filter + zabbix_usergroup: + tag_filters: + - host_group: Discovered hosts + tag: Service + value: JIRA + register: usergroup_updated_tag_filter + + - name: assert that user group was updated + assert: + that: usergroup_updated_tag_filter is changed + + - name: test - update Zabbix user group with multiple tag_filters + zabbix_usergroup: + tag_filters: + - host_group: Discovered hosts + tag: Service + value: JIRA + - host_group: Discovered hosts + tag: Service + value: Zabbix + register: usergroup_updated_tag_filters + + - name: assert that user group was updated + assert: + that: usergroup_updated_tag_filters is changed + + - name: test - reset Zabbix user group to default + zabbix_usergroup: + + - when: zabbix_version is version('6.2', '>=') + block: + - name: test - create new user directory + zabbix_user_directory: + name: LDAP infra 1 + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + when: zabbix_version is version('6.4', '<') + + - name: test - create new user directory + zabbix_user_directory: + name: LDAP infra 1 + idp_type: ldap + host: 'test.com' + port: 389 + base_dn: 'ou=Users,dc=example,dc=org' + search_attribute: 'uid' + when: zabbix_version is version('6.4', '>=') + + - name: test - update Zabbix user group with user directory + zabbix_usergroup: + userdirectory: LDAP infra 1 + register: usergroup_create_userdir + + - name: assert that user group was updated + assert: + that: usergroup_create_userdir is changed + + - name: test - update Zabbix user group with user directory (again) + zabbix_usergroup: + userdirectory: LDAP infra 1 + register: usergroup_create_userdir_again + + - name: assert that user group was not updated + assert: + that: not usergroup_create_userdir_again is changed + + - name: test - delete Zabbix user group + zabbix_usergroup: + state: absent + register: usergroup_delete + + - name: assert that Zabbix user group has been deleted + assert: + that: usergroup_delete is changed + + + - name: test - delete user directory + zabbix_user_directory: + name: LDAP infra 1 + host: 'test.com' + state: absent + when: zabbix_version is version('6.2', '>=') diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt new file mode 100644 index 000000000..8854fcd2d --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt @@ -0,0 +1,34 @@ +scripts/inventory/zabbix.py future-import-boilerplate +scripts/inventory/zabbix.py metaclass-boilerplate +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements +plugins/doc_fragments/zabbix.py future-import-boilerplate +plugins/doc_fragments/zabbix.py metaclass-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_agent.py future-import-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_default.py future-import-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_agent.py metaclass-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_default.py metaclass-boilerplate
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt new file mode 100644 index 000000000..8854fcd2d --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt @@ -0,0 +1,34 @@ +scripts/inventory/zabbix.py future-import-boilerplate +scripts/inventory/zabbix.py metaclass-boilerplate +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements +plugins/doc_fragments/zabbix.py future-import-boilerplate +plugins/doc_fragments/zabbix.py metaclass-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_agent.py future-import-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_default.py future-import-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_agent.py metaclass-boilerplate +roles/zabbix_agent/molecule/with-server/tests/test_default.py metaclass-boilerplate
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt new file mode 100644 index 000000000..628f32ff1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt @@ -0,0 +1,26 @@ +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt new file mode 100644 index 000000000..628f32ff1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt @@ -0,0 +1,26 @@ +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt new file mode 100644 index 000000000..628f32ff1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt @@ -0,0 +1,26 @@ +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt new file mode 100644 index 000000000..628f32ff1 --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt @@ -0,0 +1,26 @@ +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt new file mode 100644 index 000000000..0b5abb56b --- /dev/null +++ b/ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt @@ -0,0 +1,30 @@ +scripts/inventory/zabbix.py future-import-boilerplate +scripts/inventory/zabbix.py metaclass-boilerplate +plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec +plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch +plugins/modules/zabbix_action.py validate-modules:invalid-argument-name +plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs +plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented +plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc +plugins/modules/zabbix_action.py validate-modules:undocumented-parameter +plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements +plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch +plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements +plugins/doc_fragments/zabbix.py future-import-boilerplate +plugins/doc_fragments/zabbix.py metaclass-boilerplate
\ No newline at end of file diff --git a/ansible_collections/community/zabbix/tox.ini b/ansible_collections/community/zabbix/tox.ini new file mode 100644 index 000000000..a5124d0e5 --- /dev/null +++ b/ansible_collections/community/zabbix/tox.ini @@ -0,0 +1,40 @@ +[tox] +minversion = 1.4.2 +envlist = linters +skipsdist = True + +[testenv] +#deps = -r{toxinidir}/requirements.txt +# -r{toxinidir}/test-requirements.txt + +[testenv:venv] +# This env is used to push new release on Galaxy +install_command = pip install {opts} {packages} +deps = ansible +commands = {posargs} + +[testenv:linters-py2] +install_command = pip install {opts} {packages} +deps = + flake8 +commands = + flake8 plugins {posargs} + +[testenv:linters-py3] +install_command = pip install {opts} {packages} +deps = + flake8 + antsibull-changelog +commands = + flake8 plugins {posargs} + antsibull-changelog lint + +[flake8] +per-file-ignores = + plugins/module_utils/version.py: F401 + +show-source = True +ignore = E123,E125,E402,E501,E741,W503 +max-line-length = 160 +builtins = _ +exclude = .git,.tox,tests/unit/compat/ |