diff --git a/changelogs/fragments/1136.yml b/changelogs/fragments/1136.yml new file mode 100644 index 000000000..901a1f716 --- /dev/null +++ b/changelogs/fragments/1136.yml @@ -0,0 +1,3 @@ +minor_changes: + - 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_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. diff --git a/changelogs/fragments/1142.yml b/changelogs/fragments/1142.yml new file mode 100644 index 000000000..3fd77c8be --- /dev/null +++ b/changelogs/fragments/1142.yml @@ -0,0 +1,2 @@ +bugfixes: + - server role - typo in configuration var StasAllowedIP to StatsAllowedIP diff --git a/changelogs/fragments/pr_1104.yml b/changelogs/fragments/pr_1104.yml new file mode 100644 index 000000000..375f1c933 --- /dev/null +++ b/changelogs/fragments/pr_1104.yml @@ -0,0 +1,2 @@ +minor_changes: + - zabbix_templategroup module added diff --git a/changelogs/fragments/proxy_mysql.yml b/changelogs/fragments/proxy_mysql.yml new file mode 100644 index 000000000..23e3f3919 --- /dev/null +++ b/changelogs/fragments/proxy_mysql.yml @@ -0,0 +1,2 @@ +minor_changes: + - proxy role - Updated MariaDB version for Centos 7 to 10.11 diff --git a/docs/ZABBIX_PROXY_ROLE.md b/docs/ZABBIX_PROXY_ROLE.md index 13706a8a3..baec42155 100644 --- a/docs/ZABBIX_PROXY_ROLE.md +++ b/docs/ZABBIX_PROXY_ROLE.md @@ -115,6 +115,7 @@ The following is an overview of all available configuration default for this rol * `zabbix_proxy_dbname`: Default: zabbix_proxy. The database name which is used by the Zabbix Proxy. * `zabbix_proxy_dbuser`: Default: zabbix_proxy. The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. * `zabbix_proxy_dbpassword`: Default: zabbix_proxy. The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. +* `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`. * `zabbix_proxy_dbport`: The database port which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database. * `zabbix_proxy_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 diff --git a/docs/ZABBIX_SERVER_ROLE.md b/docs/ZABBIX_SERVER_ROLE.md index 7953d1eb7..f154f4951 100644 --- a/docs/ZABBIX_SERVER_ROLE.md +++ b/docs/ZABBIX_SERVER_ROLE.md @@ -133,6 +133,7 @@ The following is an overview of all available configuration default for this rol * `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_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_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_server_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False. diff --git a/plugins/modules/zabbix_templategroup.py b/plugins/modules/zabbix_templategroup.py new file mode 100644 index 000000000..7ab39d8fc --- /dev/null +++ b/plugins/modules/zabbix_templategroup.py @@ -0,0 +1,180 @@ +#!/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_templategroup +short_description: Create/delete Zabbix template groups +description: + - Create template groups if they do not exist. + - Delete existing template groups if they exist. +author: + - "Cove (@cove)" + - "Tony Minfei Ding (!UNKNOWN)" + - "Harrison Gu (@harrisongu)" +requirements: + - "python >= 2.6" +options: + state: + description: + - Create or delete template group. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + template_groups: + description: + - List of template groups to create or delete. + required: true + type: list + elements: str + aliases: [ "template_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 + ansible.builtin.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 + ansible.builtin.set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Base create template groups example +- name: Create template 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:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_group: + state: present + template_groups: + - Example group1 + - Example group2 + +# Limit the Zabbix group creations to one template since Zabbix can return an error when doing concurrent updates +- name: Create template 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:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_group: + state: present + template_groups: + - Example group1 + - Example group2 + when: inventory_hostname==groups['group_name'][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 TemplateGroup(ZabbixBase): + # create template group(s) if not exists + def create_template_group(self, group_names): + try: + group_add_list = [] + for group_name in group_names: + result = self._zapi.templategroup.get({'filter': {'name': group_name}}) + if not result: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.templategroup.create({'name': group_name}) + group_add_list.append(group_name) + return group_add_list + except Exception as e: + self._module.fail_json(msg="Failed to create template group(s): %s" % e) + + # delete template group(s) + def delete_template_group(self, group_ids): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.templategroup.delete(group_ids) + except Exception as e: + self._module.fail_json(msg="Failed to delete template group(s), Exception: %s" % e) + + # get group ids by name + def get_group_ids(self, template_groups): + group_ids = [] + + group_list = self._zapi.templategroup.get({'output': 'extend', 'filter': {'name': template_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( + template_groups=dict(type='list', required=True, aliases=['template_group'], elements='str'), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + template_groups = module.params['template_groups'] + state = module.params['state'] + + templateGroup = TemplateGroup(module) + + group_ids = [] + group_list = [] + if template_groups: + group_ids, group_list = templateGroup.get_group_ids(template_groups) + + if state == "absent": + # delete template groups + if group_ids: + delete_group_names = [] + templateGroup.delete_template_group(group_ids) + for group in group_list: + delete_group_names.append(group['name']) + module.exit_json(changed=True, + result="Successfully deleted template group(s): %s." % ",".join(delete_group_names)) + else: + module.exit_json(changed=False, result="No template group(s) to delete.") + else: + # create template groups + group_add_list = templateGroup.create_template_group(template_groups) + if len(group_add_list) > 0: + module.exit_json(changed=True, result="Successfully created template group(s): %s" % group_add_list) + else: + module.exit_json(changed=False) + + +if __name__ == '__main__': + main() diff --git a/roles/zabbix_proxy/defaults/main.yml b/roles/zabbix_proxy/defaults/main.yml index 5eded372c..f46c9c64e 100644 --- a/roles/zabbix_proxy/defaults/main.yml +++ b/roles/zabbix_proxy/defaults/main.yml @@ -20,6 +20,7 @@ zabbix_proxy_dbencoding: utf8 zabbix_proxy_dbhost: localhost zabbix_proxy_dbname: zabbix_proxy zabbix_proxy_dbpassword: zabbix_proxy +zabbix_proxy_dbpassword_hash_method: md5 zabbix_proxy_dbuser: zabbix_proxy zabbix_proxy_install_database_client: true diff --git a/roles/zabbix_proxy/tasks/RedHat.yml b/roles/zabbix_proxy/tasks/RedHat.yml index da389e0c8..f35b3c7b3 100644 --- a/roles/zabbix_proxy/tasks/RedHat.yml +++ b/roles/zabbix_proxy/tasks/RedHat.yml @@ -100,7 +100,7 @@ name: mariadb description: MariaDB 10.8 CentOS repository list file: mariadb - baseurl: "https://mirror.rackspace.com/mariadb/yum/10.8/centos{{ ansible_distribution_major_version }}-amd64" + baseurl: "https://mirror.rackspace.com/mariadb/yum/10.11/centos{{ ansible_distribution_major_version }}-amd64" gpgcheck: no when: ansible_distribution_major_version == '7' diff --git a/roles/zabbix_proxy/tasks/postgresql.yml b/roles/zabbix_proxy/tasks/postgresql.yml index 291052455..e71af9aba 100644 --- a/roles/zabbix_proxy/tasks/postgresql.yml +++ b/roles/zabbix_proxy/tasks/postgresql.yml @@ -29,7 +29,7 @@ community.postgresql.postgresql_user: db: "{{ zabbix_proxy_dbname }}" name: "{{ zabbix_proxy_dbuser }}" - password: "md5{{ (zabbix_proxy_dbpassword + zabbix_proxy_dbuser)|hash('md5') }}" + 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 @@ -61,7 +61,7 @@ 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') }}" + 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 diff --git a/roles/zabbix_server/defaults/main.yml b/roles/zabbix_server/defaults/main.yml index d54f92e9a..6aec202dd 100644 --- a/roles/zabbix_server/defaults/main.yml +++ b/roles/zabbix_server/defaults/main.yml @@ -17,6 +17,7 @@ zabbix_server_dbcollation: utf8_bin zabbix_server_dbschema: zabbix_server_dbuser: zabbix-server zabbix_server_dbpassword: zabbix-server +zabbix_server_dbpassword_hash_method: md5 zabbix_server_dbsocket: zabbix_server_dbport: 5432 zabbix_server_dbhost_run_install: true diff --git a/roles/zabbix_server/tasks/postgresql.yml b/roles/zabbix_server/tasks/postgresql.yml index 947a73462..5177a55be 100644 --- a/roles/zabbix_server/tasks/postgresql.yml +++ b/roles/zabbix_server/tasks/postgresql.yml @@ -29,7 +29,7 @@ community.postgresql.postgresql_user: db: "{{ zabbix_server_dbname }}" name: "{{ zabbix_server_dbuser }}" - password: "md5{{ (zabbix_server_dbpassword + zabbix_server_dbuser)|hash('md5') }}" + 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 @@ -68,7 +68,7 @@ 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') }}" + 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 diff --git a/roles/zabbix_server/templates/zabbix_server.conf.j2 b/roles/zabbix_server/templates/zabbix_server.conf.j2 index ac2264574..489e9c9f5 100644 --- a/roles/zabbix_server/templates/zabbix_server.conf.j2 +++ b/roles/zabbix_server/templates/zabbix_server.conf.j2 @@ -82,7 +82,7 @@ {{ (zabbix_server_starttimers is defined and zabbix_server_starttimers is not none) | ternary('', '# ') }}StartTimers={{ zabbix_server_starttimers | default('') }} {{ (zabbix_server_starttrappers is defined and zabbix_server_starttrappers is not none) | ternary('', '# ') }}StartTrappers={{ zabbix_server_starttrappers | default('') }} {{ (zabbix_server_startvmwarecollectors is defined and zabbix_server_startvmwarecollectors is not none) | ternary('', '# ') }}StartVMwareCollectors={{ zabbix_server_startvmwarecollectors | default('') }} -{{ (zabbix_server_statsallowedip is defined and zabbix_server_statsallowedip is not none) | ternary('', '# ') }}StasAllowedIP={{ zabbix_server_statsallowedip | default('') }} +{{ (zabbix_server_statsallowedip is defined and zabbix_server_statsallowedip is not none) | ternary('', '# ') }}StatsAllowedIP={{ zabbix_server_statsallowedip | default('') }} {{ (zabbix_server_timeout is defined and zabbix_server_timeout is not none) | ternary('', '# ') }}Timeout={{ zabbix_server_timeout | default('') }} {{ (zabbix_server_tlscafile is defined and zabbix_server_tlscafile is not none) | ternary('', '# ') }}TLSCAFile={{ zabbix_server_tlscafile | default('') }} {{ (zabbix_server_tlscertfile is defined and zabbix_server_tlscertfile is not none) | ternary('', '# ') }}TLSCertFile={{ zabbix_server_tlscertfile | default('') }} diff --git a/tests/integration/targets/test_zabbix_templategroup/meta/main.yml b/tests/integration/targets/test_zabbix_templategroup/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_templategroup/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml b/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml new file mode 100644 index 000000000..c04c20497 --- /dev/null +++ b/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml @@ -0,0 +1,59 @@ +--- +- name: test - do not run tests for Zabbix < 6.2 + meta: end_play + when: zabbix_version is version('6.2', '<') + +- name: test - create new Zabbix template group + community.zabbix.zabbix_templategroup: + template_groups: + - zbxtempgrp_example_group01 + state: present + register: zbxtempgrp_new + +- name: assert that group was created + ansible.builtin.assert: + that: zbxtempgrp_new is changed + +- name: test - create same Zabbix template group once again + community.zabbix.zabbix_templategroup: + template_groups: + - zbxtempgrp_example_group01 + state: present + register: zbxtempgrp_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempgrp_existing is changed + +- name: test - attempt to create new Zabbix template group matching name of default Zabbix template group + community.zabbix.zabbix_templategroup: + template_groups: + - Templates + state: present + register: zbxtempgrp_default_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempgrp_default_existing is changed + +- name: test - attempt to delete previously created zabbix template group + community.zabbix.zabbix_templategroup: + template_groups: + - zbxtempgrp_example_group01 + state: absent + register: zbxtempgrp_existing_delete + +- name: assert that group was deleted + ansible.builtin.assert: + that: zbxtempgrp_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix template group + community.zabbix.zabbix_templategroup: + template_groups: + - zbxtempgrp_example_group01 + state: absent + register: zbxtempgrp_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempgrp_missing_delete is changed