diff --git a/test/integration/targets/apt/tasks/apt.yml b/test/integration/targets/apt/tasks/apt.yml index abeb2e5dd80..ac79ac21d90 100644 --- a/test/integration/targets/apt/tasks/apt.yml +++ b/test/integration/targets/apt/tasks/apt.yml @@ -76,6 +76,45 @@ - "dpkg_result.rc == 1" - "'Auto-installing missing dependency without updating cache: {{ python_apt }}' in apt_result.warnings" +- name: Test installing fnmatch package + apt: + name: + - hel?o + - he?lo + register: apt_install_fnmatch + +- name: Test uninstalling fnmatch package + apt: + name: + - hel?o + - he?lo + state: absent + register: apt_uninstall_fnmatch + +- name: verify fnmatch + assert: + that: + - apt_install_fnmatch is changed + - apt_uninstall_fnmatch is changed + +- name: Test update_cache 1 + apt: + update_cache: true + cache_valid_time: 10 + register: apt_update_cache_1 + +- name: Test update_cache 2 + apt: + update_cache: true + cache_valid_time: 10 + register: apt_update_cache_2 + +- name: verify update_cache + assert: + that: + - apt_update_cache_1 is changed + - apt_update_cache_2 is not changed + - name: uninstall {{ python_apt }} with apt again apt: pkg: "{{ python_apt }}" diff --git a/test/integration/targets/apt_key/tasks/file.yml b/test/integration/targets/apt_key/tasks/file.yml index db66d22617e..8e9a0b7bea2 100644 --- a/test/integration/targets/apt_key/tasks/file.yml +++ b/test/integration/targets/apt_key/tasks/file.yml @@ -28,3 +28,20 @@ - 'both_file_keyserver is failed' - 'only_file.changed' - 'not only_keyserver.changed' + +- name: remove fedora.gpg + apt_key: + id: 97A1AE57C3A2372CCA3A4ABA6C13026D12C944D0 + state: absent + register: remove_fedora + +- name: add key from url + apt_key: + url: https://getfedora.org/static/fedora.gpg + register: apt_key_url + +- name: verify key from url + assert: + that: + - remove_fedora is changed + - apt_key_url is changed diff --git a/test/integration/targets/apt_repository/tasks/apt.yml b/test/integration/targets/apt_repository/tasks/apt.yml index eca103ca6d9..0dc25afd598 100644 --- a/test/integration/targets/apt_repository/tasks/apt.yml +++ b/test/integration/targets/apt_repository/tasks/apt.yml @@ -142,11 +142,17 @@ apt_repository: repo='{{test_ppa_spec}}' state=present register: result +- name: update the cache + apt: + update_cache: true + register: result_cache + - assert: that: - 'result.changed' - 'result.state == "present"' - 'result.repo == "{{test_ppa_spec}}"' + - result_cache is not changed - name: 'examine apt cache mtime' stat: path='/var/cache/apt/pkgcache.bin' @@ -157,6 +163,10 @@ that: - 'cache_before.stat.mtime != cache_after.stat.mtime' +- name: remove repo by spec + apt_repository: repo='{{test_ppa_spec}}' state=absent + register: result + # When installing a repo with the spec, the key is *NOT* added - name: 'ensure ppa key is absent (expect: pass)' apt_key: id='{{test_ppa_key}}' state=absent diff --git a/test/integration/targets/incidental_setup_mysql_db/aliases b/test/integration/targets/incidental_setup_mysql_db/aliases deleted file mode 100644 index 136c05e0d02..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/aliases +++ /dev/null @@ -1 +0,0 @@ -hidden diff --git a/test/integration/targets/incidental_setup_mysql_db/defaults/main.yml b/test/integration/targets/incidental_setup_mysql_db/defaults/main.yml deleted file mode 100644 index 47712dc266b..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/defaults/main.yml +++ /dev/null @@ -1,18 +0,0 @@ -mysql_service: mysqld - -mysql_packages: - - mysql-server - - MySQL-python - - bzip2 - -mysql_cleanup_packages: - - mysql-community-client - - mysql-community-common - - mysql-community-libs - - mysql-community-libs-compat - - mysql-community-server - - mysql80-community-release - -mysql_data_dirs: - - /var/lib/mysql - - /usr/mysql diff --git a/test/integration/targets/incidental_setup_mysql_db/handlers/main.yml b/test/integration/targets/incidental_setup_mysql_db/handlers/main.yml deleted file mode 100644 index abcd488ef23..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/handlers/main.yml +++ /dev/null @@ -1,25 +0,0 @@ -- name: stop mysql service - service: - name: "{{ mysql_service }}" - state: stopped - listen: cleanup mysql - -- name: remove mysql packages - action: '{{ ansible_pkg_mgr }}' - args: - name: "{{ item }}" - state: absent - loop: "{{ mysql_packages | union(mysql_cleanup_packages) }}" - listen: cleanup mysql - -- name: remove mysql data - file: - path: "{{ item }}" - state: absent - loop: "{{ mysql_data_dirs }}" - listen: cleanup mysql - -- name: remove pip packages - pip: - name: mysql-python - state: absent diff --git a/test/integration/targets/incidental_setup_mysql_db/tasks/main.yml b/test/integration/targets/incidental_setup_mysql_db/tasks/main.yml deleted file mode 100644 index d9367b4d9a6..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/tasks/main.yml +++ /dev/null @@ -1,112 +0,0 @@ -# setup code for the mysql_db module -# (c) 2014, Wayne Rosario - -# 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 . - -# ============================================================ -- name: python 2 - set_fact: - python_suffix: "" - when: ansible_python_version is version('3', '<') - -- name: python 3 - set_fact: - python_suffix: "-py3" - when: ansible_python_version is version('3', '>=') - -- name: Include distribution specific variables - include_vars: "{{ lookup('first_found', params) }}" - vars: - params: - files: - - '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}{{ python_suffix }}.yml' - - '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml' - - '{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}{{ python_suffix }}.yml' - - '{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml' - - '{{ ansible_facts.distribution }}{{ python_suffix }}.yml' - - '{{ ansible_facts.os_family }}{{ python_suffix }}.yml' - - 'default{{ python_suffix }}.yml' - paths: "{{ role_path }}/vars" - -- name: install mysqldb_test rpm dependencies - yum: - name: "{{ mysql_packages }}" - state: latest - when: ansible_pkg_mgr == 'yum' - notify: cleanup mysql - -- name: install mysqldb_test rpm dependencies - dnf: - name: '{{ mysql_packages }}' - state: latest - install_weak_deps: False # mariadb-server has a weak dep on python2 which break Python 3 test environments - when: ansible_pkg_mgr == 'dnf' - notify: cleanup mysql - -- name: install mysqldb_test debian dependencies - apt: - name: "{{ mysql_packages }}" - state: latest - when: ansible_pkg_mgr == 'apt' - notify: cleanup mysql - -- name: install mysqldb_test opensuse dependencies - zypper: - name: "{{ mysql_packages }}" - state: latest - when: ansible_pkg_mgr == 'zypper' - notify: cleanup mysql - -- name: install mysqldb_test FreeBSD dependencies - package: - name: "{{ mysql_packages }}" - state: present - when: ansible_os_family == "FreeBSD" - notify: cleanup mysql - -- name: install mysql-python package via pip (FreeBSD) - pip: - name: mysql-python - state: present - when: ansible_os_family == "FreeBSD" - notify: - - cleanup mysql - - remove pip packages - -- name: enable mysql-server service (FreeBSD) - lineinfile: - path: /etc/rc.conf - line: 'mysql_server_enable="YES"' - when: ansible_os_family == "FreeBSD" - -- name: apply work-around for OverlayFS issue - # https://github.com/docker/for-linux/issues/72#issuecomment-319904698 - command: find {{ mysql_data_dirs[0] }} -type f -exec touch {} ; - # find will fail if mysql has never been started, as the directory won't exist - ignore_errors: yes - -- name: restart mysql_db service - service: - name: "{{ mysql_service }}" - state: restarted - -- name: Detect socket path - shell: 'echo "show variables like ''socket''\G" | mysql | grep ''Value: '' | sed ''s/[ ]\+Value: //''' - register: _socket_path - -- name: Set socket path - set_fact: - mysql_socket: '{{ _socket_path["stdout"] }}' diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/Debian.yml b/test/integration/targets/incidental_setup_mysql_db/vars/Debian.yml deleted file mode 100644 index 52062c703d5..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/Debian.yml +++ /dev/null @@ -1,16 +0,0 @@ -mysql_service: 'mysql' - -mysql_packages: - - mysql-server - - python-mysqldb - - bzip2 - -mysql_cleanup_packages: - - mysql-client* - - mysql-server* - - mysql-common - - mysql-sandbox - -mysql_data_dirs: - - /var/lib/mysql - - /usr/share/mysql diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/Fedora-py3.yml b/test/integration/targets/incidental_setup_mysql_db/vars/Fedora-py3.yml deleted file mode 100644 index fa7d06e52a9..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/Fedora-py3.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mariadb' - -mysql_packages: - - mariadb-server - - python3-PyMySQL - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/Fedora.yml b/test/integration/targets/incidental_setup_mysql_db/vars/Fedora.yml deleted file mode 100644 index 718326ae084..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/Fedora.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mariadb' - -mysql_packages: - - mariadb-server - - python-PyMySQL - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/FreeBSD.yml b/test/integration/targets/incidental_setup_mysql_db/vars/FreeBSD.yml deleted file mode 100644 index af45ebfd40d..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/FreeBSD.yml +++ /dev/null @@ -1,5 +0,0 @@ -mysql_service: 'mysql-server' - -mysql_packages: - - mariadb101-server - - py-pymysql diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/RedHat-7.yml b/test/integration/targets/incidental_setup_mysql_db/vars/RedHat-7.yml deleted file mode 100644 index f8b29fd7a16..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/RedHat-7.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mariadb' - -mysql_packages: - - mariadb-server - - MySQL-python - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/RedHat-8.yml b/test/integration/targets/incidental_setup_mysql_db/vars/RedHat-8.yml deleted file mode 100644 index fa7d06e52a9..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/RedHat-8.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mariadb' - -mysql_packages: - - mariadb-server - - python3-PyMySQL - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/RedHat.yml b/test/integration/targets/incidental_setup_mysql_db/vars/RedHat.yml deleted file mode 100644 index 742c35225b6..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/RedHat.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mysqld' - -mysql_packages: - - mysql-server - - MySQL-python - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/Suse-py3.yml b/test/integration/targets/incidental_setup_mysql_db/vars/Suse-py3.yml deleted file mode 100644 index adf2754d75a..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/Suse-py3.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mysql' - -mysql_packages: - - mariadb - - python3-PyMySQL - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/Suse.yml b/test/integration/targets/incidental_setup_mysql_db/vars/Suse.yml deleted file mode 100644 index a48a2e13302..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/Suse.yml +++ /dev/null @@ -1,6 +0,0 @@ -mysql_service: 'mysql' - -mysql_packages: - - mariadb - - python-PyMySQL - - bzip2 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/Ubuntu-py3.yml b/test/integration/targets/incidental_setup_mysql_db/vars/Ubuntu-py3.yml deleted file mode 100644 index 77282442525..00000000000 --- a/test/integration/targets/incidental_setup_mysql_db/vars/Ubuntu-py3.yml +++ /dev/null @@ -1,16 +0,0 @@ -mysql_service: 'mysql' - -mysql_packages: - - mysql-server - - python3-pymysql - - bzip2 - -mysql_cleanup_packages: - - mysql-client* - - mysql-server* - - mysql-common - - mysql-sandbox - -mysql_data_dirs: - - /var/lib/mysql - - /usr/share/mysql diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/default-py3.yml b/test/integration/targets/incidental_setup_mysql_db/vars/default-py3.yml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/integration/targets/incidental_setup_mysql_db/vars/default.yml b/test/integration/targets/incidental_setup_mysql_db/vars/default.yml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/integration/targets/incidental_setup_zabbix/aliases b/test/integration/targets/incidental_setup_zabbix/aliases deleted file mode 100644 index e4fb0c8f029..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/aliases +++ /dev/null @@ -1,7 +0,0 @@ -destructive -shippable/posix/group1 -skip/osx -skip/macos -skip/freebsd -skip/rhel -hidden diff --git a/test/integration/targets/incidental_setup_zabbix/defaults/main.yml b/test/integration/targets/incidental_setup_zabbix/defaults/main.yml deleted file mode 100644 index d6437a75685..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/defaults/main.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -db_name: 'zabbix' -db_user: 'zabbix' -db_password: 'fLhijUs3PgekNhwJ' - -zabbix_version: 4.4 -zabbix_apt_repository: 'deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/ {{ ansible_distribution_release }} main' -zabbix_apt_repository_key: 'http://repo.zabbix.com/zabbix-official-repo.key' - -zabbix_packages: - - zabbix-server-mysql - - zabbix-frontend-php - - zabbix-apache-conf diff --git a/test/integration/targets/incidental_setup_zabbix/handlers/main.yml b/test/integration/targets/incidental_setup_zabbix/handlers/main.yml deleted file mode 100644 index a39556215a6..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/handlers/main.yml +++ /dev/null @@ -1,15 +0,0 @@ -- name: remove zabbix repository - apt_repository: - repo: "{{ zabbix_apt_repository }}" - filename: zabbix - state: absent - -- name: remove zabbix packages - apt: - name: "{{ zabbix_packages }}" - state: absent - -- name: remove zabbix pip packages - pip: - name: zabbix-api - state: absent diff --git a/test/integration/targets/incidental_setup_zabbix/meta/main.yml b/test/integration/targets/incidental_setup_zabbix/meta/main.yml deleted file mode 100644 index bf750af3907..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/meta/main.yml +++ /dev/null @@ -1,2 +0,0 @@ -dependencies: - - incidental_setup_mysql_db diff --git a/test/integration/targets/incidental_setup_zabbix/tasks/main.yml b/test/integration/targets/incidental_setup_zabbix/tasks/main.yml deleted file mode 100644 index 6d082fff219..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/tasks/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -- include: setup.yml - when: ansible_os_family == 'Debian' diff --git a/test/integration/targets/incidental_setup_zabbix/tasks/setup.yml b/test/integration/targets/incidental_setup_zabbix/tasks/setup.yml deleted file mode 100644 index 2af51f9431b..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/tasks/setup.yml +++ /dev/null @@ -1,89 +0,0 @@ -# sets up and starts Zabbix with default settings using a MySQL database. - -- name: install zabbix repository key - apt_key: - url: "{{ zabbix_apt_repository_key }}" - state: present - -- name: install zabbix repository - apt_repository: - repo: "{{ zabbix_apt_repository }}" - filename: zabbix - state: present - notify: remove zabbix repository - -- name: check if dpkg is set to exclude specific destinations - stat: - path: /etc/dpkg/dpkg.cfg.d/excludes - register: dpkg_excludes - -- name: ensure documentation installations are allowed for zabbix - lineinfile: - path: /etc/dpkg/dpkg.cfg.d/excludes - regexp: '^path-include=/usr/share/doc/zabbix*$' - line: 'path-include=/usr/share/doc/zabbix*' - state: present - when: dpkg_excludes.stat.exists - -- name: install zabbix apt dependencies - apt: - name: "{{ zabbix_packages }}" - state: latest - update_cache: yes - notify: remove zabbix packages - -- name: install zabbix-api python package - pip: - name: zabbix-api - state: latest - notify: remove zabbix pip packages - -- name: create mysql user {{ db_user }} - mysql_user: - name: "{{ db_user }}" - password: "{{ db_password }}" - state: present - priv: "{{ db_name }}.*:ALL" - login_unix_socket: '{{ mysql_socket }}' - -- name: import initial zabbix database - mysql_db: - name: "{{ db_name }}" - login_user: "{{ db_user }}" - login_password: "{{ db_password }}" - state: import - target: /usr/share/doc/zabbix-server-mysql/create.sql.gz - -- name: deploy zabbix-server configuration - template: - src: zabbix_server.conf.j2 - dest: /etc/zabbix/zabbix_server.conf - owner: root - group: zabbix - mode: 0640 - -- name: deploy zabbix web frontend configuration - template: - src: zabbix.conf.php.j2 - dest: /etc/zabbix/web/zabbix.conf.php - mode: 0644 - -- name: Create proper run directory for zabbix-server - file: - path: /var/run/zabbix - state: directory - owner: zabbix - group: zabbix - mode: 0775 - -- name: restart zabbix-server - service: - name: zabbix-server - state: restarted - enabled: yes - -- name: restart apache2 - service: - name: apache2 - state: restarted - enabled: yes diff --git a/test/integration/targets/incidental_setup_zabbix/templates/zabbix.conf.php.j2 b/test/integration/targets/incidental_setup_zabbix/templates/zabbix.conf.php.j2 deleted file mode 100644 index ad0a8328d2f..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/templates/zabbix.conf.php.j2 +++ /dev/null @@ -1,20 +0,0 @@ - diff --git a/test/integration/targets/incidental_setup_zabbix/templates/zabbix_server.conf.j2 b/test/integration/targets/incidental_setup_zabbix/templates/zabbix_server.conf.j2 deleted file mode 100644 index f4c201af594..00000000000 --- a/test/integration/targets/incidental_setup_zabbix/templates/zabbix_server.conf.j2 +++ /dev/null @@ -1,7 +0,0 @@ -PidFile=/var/run/zabbix/zabbix_server.pid -LogFile=/tmp/zabbix_server.log -DBName={{ db_name }} -DBUser={{ db_user }} -DBPassword={{ db_password }} -Timeout=4 -LogSlowQueries=3000 diff --git a/test/integration/targets/incidental_zabbix_host/aliases b/test/integration/targets/incidental_zabbix_host/aliases deleted file mode 100644 index 212427eb969..00000000000 --- a/test/integration/targets/incidental_zabbix_host/aliases +++ /dev/null @@ -1,7 +0,0 @@ -destructive -shippable/posix/incidental -skip/aix -skip/osx -skip/macos -skip/freebsd -skip/rhel diff --git a/test/integration/targets/incidental_zabbix_host/defaults/main.yml b/test/integration/targets/incidental_zabbix_host/defaults/main.yml deleted file mode 100644 index 5482107368d..00000000000 --- a/test/integration/targets/incidental_zabbix_host/defaults/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- - -zabbix_server_url: http://127.0.0.1/zabbix/ -zabbix_login_user: Admin -zabbix_login_password: zabbix diff --git a/test/integration/targets/incidental_zabbix_host/meta/main.yml b/test/integration/targets/incidental_zabbix_host/meta/main.yml deleted file mode 100644 index df12e5e7855..00000000000 --- a/test/integration/targets/incidental_zabbix_host/meta/main.yml +++ /dev/null @@ -1,2 +0,0 @@ -dependencies: - - incidental_setup_zabbix diff --git a/test/integration/targets/incidental_zabbix_host/tasks/main.yml b/test/integration/targets/incidental_zabbix_host/tasks/main.yml deleted file mode 100644 index 914c1e5fcf2..00000000000 --- a/test/integration/targets/incidental_zabbix_host/tasks/main.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -# setup stuff not testing zabbix_host -- block: - - include: zabbix_host_setup.yml - - # zabbix_host module tests - - include: zabbix_host_tests.yml - - # documentation example tests - - include: zabbix_host_doc.yml - - # tear down stuff set up earlier - - include: zabbix_host_teardown.yml - - when: - - ansible_distribution == 'Ubuntu' diff --git a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_doc.yml b/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_doc.yml deleted file mode 100644 index 40f702bb451..00000000000 --- a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_doc.yml +++ /dev/null @@ -1,83 +0,0 @@ ---- -# These two tests are close to documentation example - -- name: Create a new host or update an existing host's info - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost1 - visible_name: ExampleName - description: My ExampleHost Description - host_groups: - - Linux servers - - Zabbix servers - link_templates: - - Template App IMAP Service - - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_setup.yml b/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_setup.yml deleted file mode 100644 index 498a725f294..00000000000 --- a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_setup.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -# set up a zabbix proxy to test zabbix_host with - -- name: Create a new proxy - zabbix_proxy: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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 diff --git a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_teardown.yml b/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_teardown.yml deleted file mode 100644 index 1d76c516c79..00000000000 --- a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_teardown.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -# remove zabbix_proxy (hopefully) created earlier - -- name: remove proxy - zabbix_proxy: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - proxy_name: ExampleProxy - state: absent diff --git a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_tests.yml b/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_tests.yml deleted file mode 100644 index 63be018988d..00000000000 --- a/test/integration/targets/incidental_zabbix_host/tasks/zabbix_host_tests.yml +++ /dev/null @@ -1,1169 +0,0 @@ ---- - -- name: "test: create host with many options set" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - visible_name: ExampleName - description: My ExampleHost Description - host_groups: - - Linux servers - - Zabbix servers - link_templates: - - Template App IMAP Service - - 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 - tls_psk_identity: test - tls_connect: 2 - tls_psk: 123456789abcdef123456789abcdef12 - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - visible_name: ExampleName - description: My ExampleHost Description - host_groups: - - Linux servers - - Zabbix servers - link_templates: - - Template App IMAP Service - - 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 - tls_psk_identity: test - tls_connect: 2 - tls_psk: 123456789abcdef123456789abcdef12 - 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 - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - visible_name: ExampleName - description: My ExampleHost Description - host_groups: - - Linux servers - - Zabbix servers - link_templates: - - Template App IMAP Service - - 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 - tls_psk_identity: test - tls_connect: 2 - tls_psk: 123456789abcdef123456789abcdef12 - 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 - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - visible_name: ExampleName - description: My ExampleHost Description - host_groups: - - Linux servers - - Zabbix servers - link_templates: - - Template App IMAP Service - - 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 - tls_psk_identity: test - tls_connect: 2 - tls_psk: 123456789abcdef123456789abcdef12 - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - host_groups: - - Virtual machines - force: no - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - host_groups: - - - register: zabbix_host1 - ignore_errors: yes - -- name: expect to fail - assert: - that: - - "zabbix_host1 is failed" - -- name: "test: change host linked templates (same as before)" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - link_templates: - - Template App IMAP Service - - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - link_templates: - - Template App IMAP Service - - Template App NTP Service - - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - link_templates: - - Template App LDAP Service - force: no - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - link_templates: - - Template App IMAP Service - - Template App NTP Service - - Template App HTTP Service - - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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 settings" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - tls_psk_identity: test2 - tls_connect: 4 - tls_accept: 7 - tls_psk: 123456789abcdef123456789abcdef13 - 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 settings (again)" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - tls_psk_identity: test2 - tls_connect: 4 - tls_accept: 7 - tls_psk: 123456789abcdef123456789abcdef13 - 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 interface settings (remove one)" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - interfaces: - - type: 4 - main: 1 - useip: 1 - ip: 10.1.1.1 - dns: "" - port: "12345" - force: no - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: add IPMI settings" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: update one of the user macros with description" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - force: no - 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 the same user macros (again)" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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" - -- name: "test: wipe out all of the user macros" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - macros: [] - register: zabbix_host1 - -- name: expect to succeed and that things have not changed - assert: - that: - - "zabbix_host1 is not changed" - -- name: "test: add new set of tags to the host" - zabbix_host: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - host_name: ExampleHost - force: no - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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: - server_url: "{{ zabbix_server_url }}" - login_user: "{{ zabbix_login_user }}" - login_password: "{{ zabbix_login_password }}" - 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" diff --git a/test/integration/targets/systemd/tasks/main.yml b/test/integration/targets/systemd/tasks/main.yml index 1d98da8db73..867a554deae 100644 --- a/test/integration/targets/systemd/tasks/main.yml +++ b/test/integration/targets/systemd/tasks/main.yml @@ -25,6 +25,12 @@ failed_when: False register: systemctl_check +- meta: end_host + when: systemctl_check.rc != 0 + +- set_fact: + ssh_service: '{{ "ssh" if ansible_os_family == "Debian" else "sshd" }}' + - block: - name: get a list of running services shell: systemctl | fgrep 'running' | awk '{print $1}' | sed 's/\.service//g' | fgrep -v '.' | egrep ^[a-z] @@ -57,7 +63,7 @@ - assert: that: - result is failed - - result is search("Could not find the requested service {{ fake_service }}") + - 'result is search("Could not find the requested service {{ fake_service }}")' - name: the module must fail in check_mode as well when a service is not found systemd: @@ -70,7 +76,7 @@ - assert: that: - result is failed - - result is search("Could not find the requested service {{ fake_service }}") + - 'result is search("Could not find the requested service {{ fake_service }}")' - name: check that the module works even when systemd is offline (eg in chroot) systemd: @@ -79,4 +85,32 @@ environment: SYSTEMD_OFFLINE: 1 - when: 'systemctl_check.rc == 0' +- name: Disable ssh 1 + systemd: + name: '{{ ssh_service }}' + enabled: false + register: systemd_disable_ssh_1 + +- name: Disable ssh 2 + systemd: + name: '{{ ssh_service }}' + enabled: false + register: systemd_disable_ssh_2 + +- name: Enable ssh 1 + systemd: + name: '{{ ssh_service }}' + enabled: true + register: systemd_enable_ssh_1 + +- name: Enable ssh 2 + systemd: + name: '{{ ssh_service }}' + enabled: true + register: systemd_enable_ssh_2 + +- assert: + that: + - systemd_disable_ssh_2 is not changed + - systemd_enable_ssh_1 is changed + - systemd_enable_ssh_2 is not changed diff --git a/test/support/integration/plugins/modules/mysql_db.py b/test/support/integration/plugins/modules/mysql_db.py deleted file mode 100644 index 58bcca78324..00000000000 --- a/test/support/integration/plugins/modules/mysql_db.py +++ /dev/null @@ -1,617 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2012, Mark Theunissen -# Sponsored by Four Kitchens http://fourkitchens.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 - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = r''' ---- -module: mysql_db -short_description: Add or remove MySQL databases from a remote host -description: -- Add or remove MySQL databases from a remote host. -version_added: '0.6' -options: - name: - description: - - Name of the database to add or remove. - - I(name=all) may only be provided if I(state) is C(dump) or C(import). - - List of databases is provided with I(state=dump), I(state=present) and I(state=absent). - - If I(name=all) it works like --all-databases option for mysqldump (Added in 2.0). - required: true - type: list - elements: str - aliases: [db] - state: - description: - - The database state - type: str - default: present - choices: ['absent', 'dump', 'import', 'present'] - collation: - description: - - Collation mode (sorting). This only applies to new table/databases and - does not update existing ones, this is a limitation of MySQL. - type: str - default: '' - encoding: - description: - - Encoding mode to use, examples include C(utf8) or C(latin1_swedish_ci), - at creation of database, dump or importation of sql script. - type: str - default: '' - target: - description: - - Location, on the remote host, of the dump file to read from or write to. - - Uncompressed SQL files (C(.sql)) as well as bzip2 (C(.bz2)), gzip (C(.gz)) and - xz (Added in 2.0) compressed files are supported. - type: path - single_transaction: - description: - - Execute the dump in a single transaction. - type: bool - default: no - version_added: '2.1' - quick: - description: - - Option used for dumping large tables. - type: bool - default: yes - version_added: '2.1' - ignore_tables: - description: - - A list of table names that will be ignored in the dump - of the form database_name.table_name. - type: list - elements: str - required: no - default: [] - version_added: '2.7' - hex_blob: - description: - - Dump binary columns using hexadecimal notation. - required: no - default: no - type: bool - version_added: '2.10' - force: - description: - - Continue dump or import even if we get an SQL error. - - Used only when I(state) is C(dump) or C(import). - required: no - type: bool - default: no - version_added: '2.10' - master_data: - description: - - Option to dump a master replication server to produce a dump file - that can be used to set up another server as a slave of the master. - - C(0) to not include master data. - - C(1) to generate a 'CHANGE MASTER TO' statement - required on the slave to start the replication process. - - C(2) to generate a commented 'CHANGE MASTER TO'. - - Can be used when I(state=dump). - required: no - type: int - choices: [0, 1, 2] - default: 0 - version_added: '2.10' - skip_lock_tables: - description: - - Skip locking tables for read. Used when I(state=dump), ignored otherwise. - required: no - type: bool - default: no - version_added: '2.10' - dump_extra_args: - description: - - Provide additional arguments for mysqldump. - Used when I(state=dump) only, ignored otherwise. - required: no - type: str - version_added: '2.10' -seealso: -- module: mysql_info -- module: mysql_variables -- module: mysql_user -- module: mysql_replication -- name: MySQL command-line client reference - description: Complete reference of the MySQL command-line client documentation. - link: https://dev.mysql.com/doc/refman/8.0/en/mysql.html -- name: mysqldump reference - description: Complete reference of the ``mysqldump`` client utility documentation. - link: https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html -- name: CREATE DATABASE reference - description: Complete reference of the CREATE DATABASE command documentation. - link: https://dev.mysql.com/doc/refman/8.0/en/create-database.html -- name: DROP DATABASE reference - description: Complete reference of the DROP DATABASE command documentation. - link: https://dev.mysql.com/doc/refman/8.0/en/drop-database.html -author: "Ansible Core Team" -requirements: - - mysql (command line binary) - - mysqldump (command line binary) -notes: - - Requires the mysql and mysqldump binaries on the remote host. - - This module is B(not idempotent) when I(state) is C(import), - and will import the dump file each time if run more than once. -extends_documentation_fragment: mysql -''' - -EXAMPLES = r''' -- name: Create a new database with name 'bobdata' - mysql_db: - name: bobdata - state: present - -- name: Create new databases with names 'foo' and 'bar' - mysql_db: - name: - - foo - - bar - state: present - -# Copy database dump file to remote host and restore it to database 'my_db' -- name: Copy database dump file - copy: - src: dump.sql.bz2 - dest: /tmp - -- name: Restore database - mysql_db: - name: my_db - state: import - target: /tmp/dump.sql.bz2 - -- name: Restore database ignoring errors - mysql_db: - name: my_db - state: import - target: /tmp/dump.sql.bz2 - force: yes - -- name: Dump multiple databases - mysql_db: - state: dump - name: db_1,db_2 - target: /tmp/dump.sql - -- name: Dump multiple databases - mysql_db: - state: dump - name: - - db_1 - - db_2 - target: /tmp/dump.sql - -- name: Dump all databases to hostname.sql - mysql_db: - state: dump - name: all - target: /tmp/dump.sql - -- name: Dump all databases to hostname.sql including master data - mysql_db: - state: dump - name: all - target: /tmp/dump.sql - master_data: 1 - -# Import of sql script with encoding option -- name: > - Import dump.sql with specific latin1 encoding, - similar to mysql -u --default-character-set=latin1 -p < dump.sql - mysql_db: - state: import - name: all - encoding: latin1 - target: /tmp/dump.sql - -# Dump of database with encoding option -- name: > - Dump of Databse with specific latin1 encoding, - similar to mysqldump -u --default-character-set=latin1 -p - mysql_db: - state: dump - name: db_1 - encoding: latin1 - target: /tmp/dump.sql - -- name: Delete database with name 'bobdata' - mysql_db: - name: bobdata - state: absent - -- name: Make sure there is neither a database with name 'foo', nor one with name 'bar' - mysql_db: - name: - - foo - - bar - state: absent - -# Dump database with argument not directly supported by this module -# using dump_extra_args parameter -- name: Dump databases without including triggers - mysql_db: - state: dump - name: foo - target: /tmp/dump.sql - dump_extra_args: --skip-triggers -''' - -RETURN = r''' -db: - description: Database names in string format delimited by white space. - returned: always - type: str - sample: "foo bar" -db_list: - description: List of database names. - returned: always - type: list - sample: ["foo", "bar"] - version_added: '2.9' -executed_commands: - description: List of commands which tried to run. - returned: if executed - type: list - sample: ["CREATE DATABASE acme"] - version_added: '2.10' -''' - -import os -import subprocess -import traceback - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.database import mysql_quote_identifier -from ansible.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg -from ansible.module_utils.six.moves import shlex_quote -from ansible.module_utils._text import to_native - -executed_commands = [] - -# =========================================== -# MySQL module specific support methods. -# - - -def db_exists(cursor, db): - res = 0 - for each_db in db: - res += cursor.execute("SHOW DATABASES LIKE %s", (each_db.replace("_", r"\_"),)) - return res == len(db) - - -def db_delete(cursor, db): - if not db: - return False - for each_db in db: - query = "DROP DATABASE %s" % mysql_quote_identifier(each_db, 'database') - executed_commands.append(query) - cursor.execute(query) - return True - - -def db_dump(module, host, user, password, db_name, target, all_databases, port, - config_file, socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None, - single_transaction=None, quick=None, ignore_tables=None, hex_blob=None, - encoding=None, force=False, master_data=0, skip_lock_tables=False, dump_extra_args=None): - cmd = module.get_bin_path('mysqldump', True) - # If defined, mysqldump demands --defaults-extra-file be the first option - if config_file: - cmd += " --defaults-extra-file=%s" % shlex_quote(config_file) - if user is not None: - cmd += " --user=%s" % shlex_quote(user) - if password is not None: - cmd += " --password=%s" % shlex_quote(password) - if ssl_cert is not None: - cmd += " --ssl-cert=%s" % shlex_quote(ssl_cert) - if ssl_key is not None: - cmd += " --ssl-key=%s" % shlex_quote(ssl_key) - if ssl_ca is not None: - cmd += " --ssl-ca=%s" % shlex_quote(ssl_ca) - if force: - cmd += " --force" - if socket is not None: - cmd += " --socket=%s" % shlex_quote(socket) - else: - cmd += " --host=%s --port=%i" % (shlex_quote(host), port) - - if all_databases: - cmd += " --all-databases" - elif len(db_name) > 1: - cmd += " --databases {0}".format(' '.join(db_name)) - else: - cmd += " %s" % shlex_quote(' '.join(db_name)) - - if skip_lock_tables: - cmd += " --skip-lock-tables" - if (encoding is not None) and (encoding != ""): - cmd += " --default-character-set=%s" % shlex_quote(encoding) - if single_transaction: - cmd += " --single-transaction=true" - if quick: - cmd += " --quick" - if ignore_tables: - for an_ignored_table in ignore_tables: - cmd += " --ignore-table={0}".format(an_ignored_table) - if hex_blob: - cmd += " --hex-blob" - if master_data: - cmd += " --master-data=%s" % master_data - if dump_extra_args is not None: - cmd += " " + dump_extra_args - - path = None - if os.path.splitext(target)[-1] == '.gz': - path = module.get_bin_path('gzip', True) - elif os.path.splitext(target)[-1] == '.bz2': - path = module.get_bin_path('bzip2', True) - elif os.path.splitext(target)[-1] == '.xz': - path = module.get_bin_path('xz', True) - - if path: - cmd = '%s | %s > %s' % (cmd, path, shlex_quote(target)) - else: - cmd += " > %s" % shlex_quote(target) - - executed_commands.append(cmd) - rc, stdout, stderr = module.run_command(cmd, use_unsafe_shell=True) - return rc, stdout, stderr - - -def db_import(module, host, user, password, db_name, target, all_databases, port, config_file, - socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None, encoding=None, force=False): - if not os.path.exists(target): - return module.fail_json(msg="target %s does not exist on the host" % target) - - cmd = [module.get_bin_path('mysql', True)] - # --defaults-file must go first, or errors out - if config_file: - cmd.append("--defaults-extra-file=%s" % shlex_quote(config_file)) - if user: - cmd.append("--user=%s" % shlex_quote(user)) - if password: - cmd.append("--password=%s" % shlex_quote(password)) - if ssl_cert is not None: - cmd.append("--ssl-cert=%s" % shlex_quote(ssl_cert)) - if ssl_key is not None: - cmd.append("--ssl-key=%s" % shlex_quote(ssl_key)) - if ssl_ca is not None: - cmd.append("--ssl-ca=%s" % shlex_quote(ssl_ca)) - if force: - cmd.append("-f") - if socket is not None: - cmd.append("--socket=%s" % shlex_quote(socket)) - else: - cmd.append("--host=%s" % shlex_quote(host)) - cmd.append("--port=%i" % port) - if (encoding is not None) and (encoding != ""): - cmd.append("--default-character-set=%s" % shlex_quote(encoding)) - if not all_databases: - cmd.append("--one-database") - cmd.append(shlex_quote(''.join(db_name))) - - comp_prog_path = None - if os.path.splitext(target)[-1] == '.gz': - comp_prog_path = module.get_bin_path('gzip', required=True) - elif os.path.splitext(target)[-1] == '.bz2': - comp_prog_path = module.get_bin_path('bzip2', required=True) - elif os.path.splitext(target)[-1] == '.xz': - comp_prog_path = module.get_bin_path('xz', required=True) - if comp_prog_path: - # The line above is for returned data only: - executed_commands.append('%s -dc %s | %s' % (comp_prog_path, target, ' '.join(cmd))) - p1 = subprocess.Popen([comp_prog_path, '-dc', target], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p2 = subprocess.Popen(cmd, stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout2, stderr2) = p2.communicate() - p1.stdout.close() - p1.wait() - if p1.returncode != 0: - stderr1 = p1.stderr.read() - return p1.returncode, '', stderr1 - else: - return p2.returncode, stdout2, stderr2 - else: - cmd = ' '.join(cmd) - cmd += " < %s" % shlex_quote(target) - executed_commands.append(cmd) - rc, stdout, stderr = module.run_command(cmd, use_unsafe_shell=True) - return rc, stdout, stderr - - -def db_create(cursor, db, encoding, collation): - if not db: - return False - query_params = dict(enc=encoding, collate=collation) - res = 0 - for each_db in db: - query = ['CREATE DATABASE %s' % mysql_quote_identifier(each_db, 'database')] - if encoding: - query.append("CHARACTER SET %(enc)s") - if collation: - query.append("COLLATE %(collate)s") - query = ' '.join(query) - res += cursor.execute(query, query_params) - try: - executed_commands.append(cursor.mogrify(query, query_params)) - except AttributeError: - executed_commands.append(cursor._executed) - except Exception: - executed_commands.append(query) - return res > 0 - - -# =========================================== -# Module execution. -# - - -def main(): - module = AnsibleModule( - argument_spec=dict( - login_user=dict(type='str'), - login_password=dict(type='str', no_log=True), - login_host=dict(type='str', default='localhost'), - login_port=dict(type='int', default=3306), - login_unix_socket=dict(type='str'), - name=dict(type='list', required=True, aliases=['db']), - encoding=dict(type='str', default=''), - collation=dict(type='str', default=''), - target=dict(type='path'), - state=dict(type='str', default='present', choices=['absent', 'dump', 'import', 'present']), - client_cert=dict(type='path', aliases=['ssl_cert']), - client_key=dict(type='path', aliases=['ssl_key']), - ca_cert=dict(type='path', aliases=['ssl_ca']), - connect_timeout=dict(type='int', default=30), - config_file=dict(type='path', default='~/.my.cnf'), - single_transaction=dict(type='bool', default=False), - quick=dict(type='bool', default=True), - ignore_tables=dict(type='list', default=[]), - hex_blob=dict(default=False, type='bool'), - force=dict(type='bool', default=False), - master_data=dict(type='int', default=0, choices=[0, 1, 2]), - skip_lock_tables=dict(type='bool', default=False), - dump_extra_args=dict(type='str'), - ), - supports_check_mode=True, - ) - - if mysql_driver is None: - module.fail_json(msg=mysql_driver_fail_msg) - - db = module.params["name"] - if not db: - module.exit_json(changed=False, db=db, db_list=[]) - db = [each_db.strip() for each_db in db] - - encoding = module.params["encoding"] - collation = module.params["collation"] - state = module.params["state"] - target = module.params["target"] - socket = module.params["login_unix_socket"] - login_port = module.params["login_port"] - if login_port < 0 or login_port > 65535: - module.fail_json(msg="login_port must be a valid unix port number (0-65535)") - ssl_cert = module.params["client_cert"] - ssl_key = module.params["client_key"] - ssl_ca = module.params["ca_cert"] - connect_timeout = module.params['connect_timeout'] - config_file = module.params['config_file'] - login_password = module.params["login_password"] - login_user = module.params["login_user"] - login_host = module.params["login_host"] - ignore_tables = module.params["ignore_tables"] - for a_table in ignore_tables: - if a_table == "": - module.fail_json(msg="Name of ignored table cannot be empty") - single_transaction = module.params["single_transaction"] - quick = module.params["quick"] - hex_blob = module.params["hex_blob"] - force = module.params["force"] - master_data = module.params["master_data"] - skip_lock_tables = module.params["skip_lock_tables"] - dump_extra_args = module.params["dump_extra_args"] - - if len(db) > 1 and state == 'import': - module.fail_json(msg="Multiple databases are not supported with state=import") - db_name = ' '.join(db) - - all_databases = False - if state in ['dump', 'import']: - if target is None: - module.fail_json(msg="with state=%s target is required" % state) - if db == ['all']: - all_databases = True - else: - if db == ['all']: - module.fail_json(msg="name is not allowed to equal 'all' unless state equals import, or dump.") - try: - cursor, db_conn = mysql_connect(module, login_user, login_password, config_file, ssl_cert, ssl_key, ssl_ca, - connect_timeout=connect_timeout) - except Exception as e: - if os.path.exists(config_file): - module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. " - "Exception message: %s" % (config_file, to_native(e))) - else: - module.fail_json(msg="unable to find %s. Exception message: %s" % (config_file, to_native(e))) - - changed = False - if not os.path.exists(config_file): - config_file = None - - existence_list = [] - non_existence_list = [] - - if not all_databases: - for each_database in db: - if db_exists(cursor, [each_database]): - existence_list.append(each_database) - else: - non_existence_list.append(each_database) - - if state == "absent": - if module.check_mode: - module.exit_json(changed=bool(existence_list), db=db_name, db_list=db) - try: - changed = db_delete(cursor, existence_list) - except Exception as e: - module.fail_json(msg="error deleting database: %s" % to_native(e)) - module.exit_json(changed=changed, db=db_name, db_list=db, executed_commands=executed_commands) - elif state == "present": - if module.check_mode: - module.exit_json(changed=bool(non_existence_list), db=db_name, db_list=db) - changed = False - if non_existence_list: - try: - changed = db_create(cursor, non_existence_list, encoding, collation) - except Exception as e: - module.fail_json(msg="error creating database: %s" % to_native(e), - exception=traceback.format_exc()) - module.exit_json(changed=changed, db=db_name, db_list=db, executed_commands=executed_commands) - elif state == "dump": - if non_existence_list and not all_databases: - module.fail_json(msg="Cannot dump database(s) %r - not found" % (', '.join(non_existence_list))) - if module.check_mode: - module.exit_json(changed=True, db=db_name, db_list=db) - rc, stdout, stderr = db_dump(module, login_host, login_user, - login_password, db, target, all_databases, - login_port, config_file, socket, ssl_cert, ssl_key, - ssl_ca, single_transaction, quick, ignore_tables, - hex_blob, encoding, force, master_data, skip_lock_tables, - dump_extra_args) - if rc != 0: - module.fail_json(msg="%s" % stderr) - module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout, - executed_commands=executed_commands) - elif state == "import": - if module.check_mode: - module.exit_json(changed=True, db=db_name, db_list=db) - if non_existence_list and not all_databases: - try: - db_create(cursor, non_existence_list, encoding, collation) - except Exception as e: - module.fail_json(msg="error creating database: %s" % to_native(e), - exception=traceback.format_exc()) - rc, stdout, stderr = db_import(module, login_host, login_user, - login_password, db, target, - all_databases, - login_port, config_file, - socket, ssl_cert, ssl_key, ssl_ca, encoding, force) - if rc != 0: - module.fail_json(msg="%s" % stderr) - module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout, - executed_commands=executed_commands) - - -if __name__ == '__main__': - main() diff --git a/test/support/integration/plugins/modules/mysql_user.py b/test/support/integration/plugins/modules/mysql_user.py deleted file mode 100644 index f39982ed418..00000000000 --- a/test/support/integration/plugins/modules/mysql_user.py +++ /dev/null @@ -1,815 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2012, Mark Theunissen -# Sponsored by Four Kitchens http://fourkitchens.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 - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = r''' ---- -module: mysql_user -short_description: Adds or removes a user from a MySQL database -description: - - Adds or removes a user from a MySQL database. -version_added: "0.6" -options: - name: - description: - - Name of the user (role) to add or remove. - type: str - required: true - password: - description: - - Set the user's password.. - type: str - encrypted: - description: - - Indicate that the 'password' field is a `mysql_native_password` hash. - type: bool - default: no - version_added: "2.0" - host: - description: - - The 'host' part of the MySQL username. - type: str - default: localhost - host_all: - description: - - Override the host option, making ansible apply changes to all hostnames for a given user. - - This option cannot be used when creating users. - type: bool - default: no - version_added: "2.1" - priv: - description: - - "MySQL privileges string in the format: C(db.table:priv1,priv2)." - - "Multiple privileges can be specified by separating each one using - a forward slash: C(db.table:priv/db.table:priv)." - - The format is based on MySQL C(GRANT) statement. - - Database and table names can be quoted, MySQL-style. - - If column privileges are used, the C(priv1,priv2) part must be - exactly as returned by a C(SHOW GRANT) statement. If not followed, - the module will always report changes. It includes grouping columns - by permission (C(SELECT(col1,col2)) instead of C(SELECT(col1),SELECT(col2))). - - Can be passed as a dictionary (see the examples). - type: raw - append_privs: - description: - - Append the privileges defined by priv to the existing ones for this - user instead of overwriting existing ones. - type: bool - default: no - version_added: "1.4" - sql_log_bin: - description: - - Whether binary logging should be enabled or disabled for the connection. - type: bool - default: yes - version_added: "2.1" - state: - description: - - Whether the user should exist. - - When C(absent), removes the user. - type: str - choices: [ absent, present ] - default: present - check_implicit_admin: - description: - - Check if mysql allows login as root/nopassword before trying supplied credentials. - type: bool - default: no - version_added: "1.3" - update_password: - description: - - C(always) will update passwords if they differ. - - C(on_create) will only set the password for newly created users. - type: str - choices: [ always, on_create ] - default: always - version_added: "2.0" - plugin: - description: - - User's plugin to authenticate (``CREATE USER user IDENTIFIED WITH plugin``). - type: str - version_added: '2.10' - plugin_hash_string: - description: - - User's plugin hash string (``CREATE USER user IDENTIFIED WITH plugin AS plugin_hash_string``). - type: str - version_added: '2.10' - plugin_auth_string: - description: - - User's plugin auth_string (``CREATE USER user IDENTIFIED WITH plugin BY plugin_auth_string``). - type: str - version_added: '2.10' - -notes: - - "MySQL server installs with default login_user of 'root' and no password. To secure this user - as part of an idempotent playbook, you must create at least two tasks: the first must change the root user's password, - without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing - the new root credentials. Subsequent runs of the playbook will then succeed by reading the new credentials from - the file." - - Currently, there is only support for the `mysql_native_password` encrypted password hash module. - -seealso: -- module: mysql_info -- name: MySQL access control and account management reference - description: Complete reference of the MySQL access control and account management documentation. - link: https://dev.mysql.com/doc/refman/8.0/en/access-control.html -- name: MySQL provided privileges reference - description: Complete reference of the MySQL provided privileges documentation. - link: https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html - -author: -- Jonathan Mainguy (@Jmainguy) -- Benjamin Malynovytch (@bmalynovytch) -- Lukasz Tomaszkiewicz (@tomaszkiewicz) -extends_documentation_fragment: mysql -''' - -EXAMPLES = r''' -- name: Removes anonymous user account for localhost - mysql_user: - name: '' - host: localhost - state: absent - -- name: Removes all anonymous user accounts - mysql_user: - name: '' - host_all: yes - state: absent - -- name: Create database user with name 'bob' and password '12345' with all database privileges - mysql_user: - name: bob - password: 12345 - priv: '*.*:ALL' - state: present - -- name: Create database user using hashed password with all database privileges - mysql_user: - name: bob - password: '*EE0D72C1085C46C5278932678FBE2C6A782821B4' - encrypted: yes - priv: '*.*:ALL' - state: present - -- name: Create database user with password and all database privileges and 'WITH GRANT OPTION' - mysql_user: - name: bob - password: 12345 - priv: '*.*:ALL,GRANT' - state: present - -- name: Create user with password, all database privileges and 'WITH GRANT OPTION' in db1 and db2 - mysql_user: - state: present - name: bob - password: 12345dd - priv: - 'db1.*': 'ALL,GRANT' - 'db2.*': 'ALL,GRANT' - -# Note that REQUIRESSL is a special privilege that should only apply to *.* by itself. -- name: Modify user to require SSL connections. - mysql_user: - name: bob - append_privs: yes - priv: '*.*:REQUIRESSL' - state: present - -- name: Ensure no user named 'sally'@'localhost' exists, also passing in the auth credentials. - mysql_user: - login_user: root - login_password: 123456 - name: sally - state: absent - -- name: Ensure no user named 'sally' exists at all - mysql_user: - name: sally - host_all: yes - state: absent - -- name: Specify grants composed of more than one word - mysql_user: - name: replication - password: 12345 - priv: "*.*:REPLICATION CLIENT" - state: present - -- name: Revoke all privileges for user 'bob' and password '12345' - mysql_user: - name: bob - password: 12345 - priv: "*.*:USAGE" - state: present - -# Example privileges string format -# mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanotherdb.*:ALL - -- name: Example using login_unix_socket to connect to server - mysql_user: - name: root - password: abc123 - login_unix_socket: /var/run/mysqld/mysqld.sock - -- name: Example of skipping binary logging while adding user 'bob' - mysql_user: - name: bob - password: 12345 - priv: "*.*:USAGE" - state: present - sql_log_bin: no - -- name: Create user 'bob' authenticated with plugin 'AWSAuthenticationPlugin' - mysql_user: - name: bob - plugin: AWSAuthenticationPlugin - plugin_hash_string: RDS - priv: '*.*:ALL' - state: present - -# Example .my.cnf file for setting the root password -# [client] -# user=root -# password=n<_665{vS43y -''' - -import re -import string - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.database import SQLParseError -from ansible.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg -from ansible.module_utils.six import iteritems -from ansible.module_utils._text import to_native - - -VALID_PRIVS = frozenset(('CREATE', 'DROP', 'GRANT', 'GRANT OPTION', - 'LOCK TABLES', 'REFERENCES', 'EVENT', 'ALTER', - 'DELETE', 'INDEX', 'INSERT', 'SELECT', 'UPDATE', - 'CREATE TEMPORARY TABLES', 'TRIGGER', 'CREATE VIEW', - 'SHOW VIEW', 'ALTER ROUTINE', 'CREATE ROUTINE', - 'EXECUTE', 'FILE', 'CREATE TABLESPACE', 'CREATE USER', - 'PROCESS', 'PROXY', 'RELOAD', 'REPLICATION CLIENT', - 'REPLICATION SLAVE', 'SHOW DATABASES', 'SHUTDOWN', - 'SUPER', 'ALL', 'ALL PRIVILEGES', 'USAGE', 'REQUIRESSL', - 'CREATE ROLE', 'DROP ROLE', 'APPLICATION_PASSWORD_ADMIN', - 'AUDIT_ADMIN', 'BACKUP_ADMIN', 'BINLOG_ADMIN', - 'BINLOG_ENCRYPTION_ADMIN', 'CLONE_ADMIN', 'CONNECTION_ADMIN', - 'ENCRYPTION_KEY_ADMIN', 'FIREWALL_ADMIN', 'FIREWALL_USER', - 'GROUP_REPLICATION_ADMIN', 'INNODB_REDO_LOG_ARCHIVE', - 'NDB_STORED_USER', 'PERSIST_RO_VARIABLES_ADMIN', - 'REPLICATION_APPLIER', 'REPLICATION_SLAVE_ADMIN', - 'RESOURCE_GROUP_ADMIN', 'RESOURCE_GROUP_USER', - 'ROLE_ADMIN', 'SESSION_VARIABLES_ADMIN', 'SET_USER_ID', - 'SYSTEM_USER', 'SYSTEM_VARIABLES_ADMIN', 'SYSTEM_USER', - 'TABLE_ENCRYPTION_ADMIN', 'VERSION_TOKEN_ADMIN', - 'XA_RECOVER_ADMIN', 'LOAD FROM S3', 'SELECT INTO S3')) - - -class InvalidPrivsError(Exception): - pass - -# =========================================== -# MySQL module specific support methods. -# - - -# User Authentication Management changed in MySQL 5.7 and MariaDB 10.2.0 -def use_old_user_mgmt(cursor): - cursor.execute("SELECT VERSION()") - result = cursor.fetchone() - version_str = result[0] - version = version_str.split('.') - - if 'mariadb' in version_str.lower(): - # Prior to MariaDB 10.2 - if int(version[0]) * 1000 + int(version[1]) < 10002: - return True - else: - return False - else: - # Prior to MySQL 5.7 - if int(version[0]) * 1000 + int(version[1]) < 5007: - return True - else: - return False - - -def get_mode(cursor): - cursor.execute('SELECT @@GLOBAL.sql_mode') - result = cursor.fetchone() - mode_str = result[0] - if 'ANSI' in mode_str: - mode = 'ANSI' - else: - mode = 'NOTANSI' - return mode - - -def user_exists(cursor, user, host, host_all): - if host_all: - cursor.execute("SELECT count(*) FROM mysql.user WHERE user = %s", ([user])) - else: - cursor.execute("SELECT count(*) FROM mysql.user WHERE user = %s AND host = %s", (user, host)) - - count = cursor.fetchone() - return count[0] > 0 - - -def user_add(cursor, user, host, host_all, password, encrypted, - plugin, plugin_hash_string, plugin_auth_string, new_priv, check_mode): - # we cannot create users without a proper hostname - if host_all: - return False - - if check_mode: - return True - - if password and encrypted: - cursor.execute("CREATE USER %s@%s IDENTIFIED BY PASSWORD %s", (user, host, password)) - elif password and not encrypted: - cursor.execute("CREATE USER %s@%s IDENTIFIED BY %s", (user, host, password)) - elif plugin and plugin_hash_string: - cursor.execute("CREATE USER %s@%s IDENTIFIED WITH %s AS %s", (user, host, plugin, plugin_hash_string)) - elif plugin and plugin_auth_string: - cursor.execute("CREATE USER %s@%s IDENTIFIED WITH %s BY %s", (user, host, plugin, plugin_auth_string)) - elif plugin: - cursor.execute("CREATE USER %s@%s IDENTIFIED WITH %s", (user, host, plugin)) - else: - cursor.execute("CREATE USER %s@%s", (user, host)) - if new_priv is not None: - for db_table, priv in iteritems(new_priv): - privileges_grant(cursor, user, host, db_table, priv) - return True - - -def is_hash(password): - ishash = False - if len(password) == 41 and password[0] == '*': - if frozenset(password[1:]).issubset(string.hexdigits): - ishash = True - return ishash - - -def user_mod(cursor, user, host, host_all, password, encrypted, - plugin, plugin_hash_string, plugin_auth_string, new_priv, append_privs, module): - changed = False - msg = "User unchanged" - grant_option = False - - if host_all: - hostnames = user_get_hostnames(cursor, [user]) - else: - hostnames = [host] - - for host in hostnames: - # Handle clear text and hashed passwords. - if bool(password): - # Determine what user management method server uses - old_user_mgmt = use_old_user_mgmt(cursor) - - # Get a list of valid columns in mysql.user table to check if Password and/or authentication_string exist - cursor.execute(""" - SELECT COLUMN_NAME FROM information_schema.COLUMNS - WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME IN ('Password', 'authentication_string') - ORDER BY COLUMN_NAME DESC LIMIT 1 - """) - colA = cursor.fetchone() - - cursor.execute(""" - SELECT COLUMN_NAME FROM information_schema.COLUMNS - WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME IN ('Password', 'authentication_string') - ORDER BY COLUMN_NAME ASC LIMIT 1 - """) - colB = cursor.fetchone() - - # Select hash from either Password or authentication_string, depending which one exists and/or is filled - cursor.execute(""" - SELECT COALESCE( - CASE WHEN %s = '' THEN NULL ELSE %s END, - CASE WHEN %s = '' THEN NULL ELSE %s END - ) - FROM mysql.user WHERE user = %%s AND host = %%s - """ % (colA[0], colA[0], colB[0], colB[0]), (user, host)) - current_pass_hash = cursor.fetchone()[0] - if isinstance(current_pass_hash, bytes): - current_pass_hash = current_pass_hash.decode('ascii') - - if encrypted: - encrypted_password = password - if not is_hash(encrypted_password): - module.fail_json(msg="encrypted was specified however it does not appear to be a valid hash expecting: *SHA1(SHA1(your_password))") - else: - if old_user_mgmt: - cursor.execute("SELECT PASSWORD(%s)", (password,)) - else: - cursor.execute("SELECT CONCAT('*', UCASE(SHA1(UNHEX(SHA1(%s)))))", (password,)) - encrypted_password = cursor.fetchone()[0] - - if current_pass_hash != encrypted_password: - msg = "Password updated" - if module.check_mode: - return (True, msg) - if old_user_mgmt: - cursor.execute("SET PASSWORD FOR %s@%s = %s", (user, host, encrypted_password)) - msg = "Password updated (old style)" - else: - try: - cursor.execute("ALTER USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, encrypted_password)) - msg = "Password updated (new style)" - except (mysql_driver.Error) as e: - # https://stackoverflow.com/questions/51600000/authentication-string-of-root-user-on-mysql - # Replacing empty root password with new authentication mechanisms fails with error 1396 - if e.args[0] == 1396: - cursor.execute( - "UPDATE user SET plugin = %s, authentication_string = %s, Password = '' WHERE User = %s AND Host = %s", - ('mysql_native_password', encrypted_password, user, host) - ) - cursor.execute("FLUSH PRIVILEGES") - msg = "Password forced update" - else: - raise e - changed = True - - # Handle plugin authentication - if plugin: - cursor.execute("SELECT plugin, authentication_string FROM mysql.user " - "WHERE user = %s AND host = %s", (user, host)) - current_plugin = cursor.fetchone() - - update = False - - if current_plugin[0] != plugin: - update = True - - if plugin_hash_string and current_plugin[1] != plugin_hash_string: - update = True - - if plugin_auth_string and current_plugin[1] != plugin_auth_string: - # this case can cause more updates than expected, - # as plugin can hash auth_string in any way it wants - # and there's no way to figure it out for - # a check, so I prefer to update more often than never - update = True - - if update: - if plugin_hash_string: - cursor.execute("ALTER USER %s@%s IDENTIFIED WITH %s AS %s", (user, host, plugin, plugin_hash_string)) - elif plugin_auth_string: - cursor.execute("ALTER USER %s@%s IDENTIFIED WITH %s BY %s", (user, host, plugin, plugin_auth_string)) - else: - cursor.execute("ALTER USER %s@%s IDENTIFIED WITH %s", (user, host, plugin)) - changed = True - - # Handle privileges - if new_priv is not None: - curr_priv = privileges_get(cursor, user, host) - - # If the user has privileges on a db.table that doesn't appear at all in - # the new specification, then revoke all privileges on it. - for db_table, priv in iteritems(curr_priv): - # If the user has the GRANT OPTION on a db.table, revoke it first. - if "GRANT" in priv: - grant_option = True - if db_table not in new_priv: - if user != "root" and "PROXY" not in priv and not append_privs: - msg = "Privileges updated" - if module.check_mode: - return (True, msg) - privileges_revoke(cursor, user, host, db_table, priv, grant_option) - changed = True - - # If the user doesn't currently have any privileges on a db.table, then - # we can perform a straight grant operation. - for db_table, priv in iteritems(new_priv): - if db_table not in curr_priv: - msg = "New privileges granted" - if module.check_mode: - return (True, msg) - privileges_grant(cursor, user, host, db_table, priv) - changed = True - - # If the db.table specification exists in both the user's current privileges - # and in the new privileges, then we need to see if there's a difference. - db_table_intersect = set(new_priv.keys()) & set(curr_priv.keys()) - for db_table in db_table_intersect: - priv_diff = set(new_priv[db_table]) ^ set(curr_priv[db_table]) - if len(priv_diff) > 0: - msg = "Privileges updated" - if module.check_mode: - return (True, msg) - if not append_privs: - privileges_revoke(cursor, user, host, db_table, curr_priv[db_table], grant_option) - privileges_grant(cursor, user, host, db_table, new_priv[db_table]) - changed = True - - return (changed, msg) - - -def user_delete(cursor, user, host, host_all, check_mode): - if check_mode: - return True - - if host_all: - hostnames = user_get_hostnames(cursor, [user]) - - for hostname in hostnames: - cursor.execute("DROP USER %s@%s", (user, hostname)) - else: - cursor.execute("DROP USER %s@%s", (user, host)) - - return True - - -def user_get_hostnames(cursor, user): - cursor.execute("SELECT Host FROM mysql.user WHERE user = %s", user) - hostnames_raw = cursor.fetchall() - hostnames = [] - - for hostname_raw in hostnames_raw: - hostnames.append(hostname_raw[0]) - - return hostnames - - -def privileges_get(cursor, user, host): - """ MySQL doesn't have a better method of getting privileges aside from the - SHOW GRANTS query syntax, which requires us to then parse the returned string. - Here's an example of the string that is returned from MySQL: - - GRANT USAGE ON *.* TO 'user'@'localhost' IDENTIFIED BY 'pass'; - - This function makes the query and returns a dictionary containing the results. - The dictionary format is the same as that returned by privileges_unpack() below. - """ - output = {} - cursor.execute("SHOW GRANTS FOR %s@%s", (user, host)) - grants = cursor.fetchall() - - def pick(x): - if x == 'ALL PRIVILEGES': - return 'ALL' - else: - return x - - for grant in grants: - res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\\6)? ?(.*)""", grant[0]) - if res is None: - raise InvalidPrivsError('unable to parse the MySQL grant string: %s' % grant[0]) - privileges = res.group(1).split(", ") - privileges = [pick(x) for x in privileges] - if "WITH GRANT OPTION" in res.group(7): - privileges.append('GRANT') - if "REQUIRE SSL" in res.group(7): - privileges.append('REQUIRESSL') - db = res.group(2) - output[db] = privileges - return output - - -def privileges_unpack(priv, mode): - """ Take a privileges string, typically passed as a parameter, and unserialize - it into a dictionary, the same format as privileges_get() above. We have this - custom format to avoid using YAML/JSON strings inside YAML playbooks. Example - of a privileges string: - - mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanother.*:ALL - - The privilege USAGE stands for no privileges, so we add that in on *.* if it's - not specified in the string, as MySQL will always provide this by default. - """ - if mode == 'ANSI': - quote = '"' - else: - quote = '`' - output = {} - privs = [] - for item in priv.strip().split('/'): - pieces = item.strip().rsplit(':', 1) - dbpriv = pieces[0].rsplit(".", 1) - - # Check for FUNCTION or PROCEDURE object types - parts = dbpriv[0].split(" ", 1) - object_type = '' - if len(parts) > 1 and (parts[0] == 'FUNCTION' or parts[0] == 'PROCEDURE'): - object_type = parts[0] + ' ' - dbpriv[0] = parts[1] - - # Do not escape if privilege is for database or table, i.e. - # neither quote *. nor .* - for i, side in enumerate(dbpriv): - if side.strip('`') != '*': - dbpriv[i] = '%s%s%s' % (quote, side.strip('`'), quote) - pieces[0] = object_type + '.'.join(dbpriv) - - if '(' in pieces[1]: - output[pieces[0]] = re.split(r',\s*(?=[^)]*(?:\(|$))', pieces[1].upper()) - for i in output[pieces[0]]: - privs.append(re.sub(r'\s*\(.*\)', '', i)) - else: - output[pieces[0]] = pieces[1].upper().split(',') - privs = output[pieces[0]] - new_privs = frozenset(privs) - if not new_privs.issubset(VALID_PRIVS): - raise InvalidPrivsError('Invalid privileges specified: %s' % new_privs.difference(VALID_PRIVS)) - - if '*.*' not in output: - output['*.*'] = ['USAGE'] - - # if we are only specifying something like REQUIRESSL and/or GRANT (=WITH GRANT OPTION) in *.* - # we still need to add USAGE as a privilege to avoid syntax errors - if 'REQUIRESSL' in priv and not set(output['*.*']).difference(set(['GRANT', 'REQUIRESSL'])): - output['*.*'].append('USAGE') - - return output - - -def privileges_revoke(cursor, user, host, db_table, priv, grant_option): - # Escape '%' since mysql db.execute() uses a format string - db_table = db_table.replace('%', '%%') - if grant_option: - query = ["REVOKE GRANT OPTION ON %s" % db_table] - query.append("FROM %s@%s") - query = ' '.join(query) - cursor.execute(query, (user, host)) - priv_string = ",".join([p for p in priv if p not in ('GRANT', 'REQUIRESSL')]) - query = ["REVOKE %s ON %s" % (priv_string, db_table)] - query.append("FROM %s@%s") - query = ' '.join(query) - cursor.execute(query, (user, host)) - - -def privileges_grant(cursor, user, host, db_table, priv): - # Escape '%' since mysql db.execute uses a format string and the - # specification of db and table often use a % (SQL wildcard) - db_table = db_table.replace('%', '%%') - priv_string = ",".join([p for p in priv if p not in ('GRANT', 'REQUIRESSL')]) - query = ["GRANT %s ON %s" % (priv_string, db_table)] - query.append("TO %s@%s") - if 'REQUIRESSL' in priv: - query.append("REQUIRE SSL") - if 'GRANT' in priv: - query.append("WITH GRANT OPTION") - query = ' '.join(query) - cursor.execute(query, (user, host)) - - -def convert_priv_dict_to_str(priv): - """Converts privs dictionary to string of certain format. - - Args: - priv (dict): Dict of privileges that needs to be converted to string. - - Returns: - priv (str): String representation of input argument. - """ - priv_list = ['%s:%s' % (key, val) for key, val in iteritems(priv)] - - return '/'.join(priv_list) - -# =========================================== -# Module execution. -# - - -def main(): - module = AnsibleModule( - argument_spec=dict( - login_user=dict(type='str'), - login_password=dict(type='str', no_log=True), - login_host=dict(type='str', default='localhost'), - login_port=dict(type='int', default=3306), - login_unix_socket=dict(type='str'), - user=dict(type='str', required=True, aliases=['name']), - password=dict(type='str', no_log=True), - encrypted=dict(type='bool', default=False), - host=dict(type='str', default='localhost'), - host_all=dict(type="bool", default=False), - state=dict(type='str', default='present', choices=['absent', 'present']), - priv=dict(type='raw'), - append_privs=dict(type='bool', default=False), - check_implicit_admin=dict(type='bool', default=False), - update_password=dict(type='str', default='always', choices=['always', 'on_create']), - connect_timeout=dict(type='int', default=30), - config_file=dict(type='path', default='~/.my.cnf'), - sql_log_bin=dict(type='bool', default=True), - client_cert=dict(type='path', aliases=['ssl_cert']), - client_key=dict(type='path', aliases=['ssl_key']), - ca_cert=dict(type='path', aliases=['ssl_ca']), - plugin=dict(default=None, type='str'), - plugin_hash_string=dict(default=None, type='str'), - plugin_auth_string=dict(default=None, type='str'), - ), - supports_check_mode=True, - ) - login_user = module.params["login_user"] - login_password = module.params["login_password"] - user = module.params["user"] - password = module.params["password"] - encrypted = module.boolean(module.params["encrypted"]) - host = module.params["host"].lower() - host_all = module.params["host_all"] - state = module.params["state"] - priv = module.params["priv"] - check_implicit_admin = module.params['check_implicit_admin'] - connect_timeout = module.params['connect_timeout'] - config_file = module.params['config_file'] - append_privs = module.boolean(module.params["append_privs"]) - update_password = module.params['update_password'] - ssl_cert = module.params["client_cert"] - ssl_key = module.params["client_key"] - ssl_ca = module.params["ca_cert"] - db = '' - sql_log_bin = module.params["sql_log_bin"] - plugin = module.params["plugin"] - plugin_hash_string = module.params["plugin_hash_string"] - plugin_auth_string = module.params["plugin_auth_string"] - if priv and not (isinstance(priv, str) or isinstance(priv, dict)): - module.fail_json(msg="priv parameter must be str or dict but %s was passed" % type(priv)) - - if priv and isinstance(priv, dict): - priv = convert_priv_dict_to_str(priv) - - if mysql_driver is None: - module.fail_json(msg=mysql_driver_fail_msg) - - cursor = None - try: - if check_implicit_admin: - try: - cursor, db_conn = mysql_connect(module, 'root', '', config_file, ssl_cert, ssl_key, ssl_ca, db, - connect_timeout=connect_timeout) - except Exception: - pass - - if not cursor: - cursor, db_conn = mysql_connect(module, login_user, login_password, config_file, ssl_cert, ssl_key, ssl_ca, db, - connect_timeout=connect_timeout) - except Exception as e: - module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. " - "Exception message: %s" % (config_file, to_native(e))) - - if not sql_log_bin: - cursor.execute("SET SQL_LOG_BIN=0;") - - if priv is not None: - try: - mode = get_mode(cursor) - except Exception as e: - module.fail_json(msg=to_native(e)) - try: - priv = privileges_unpack(priv, mode) - except Exception as e: - module.fail_json(msg="invalid privileges string: %s" % to_native(e)) - - if state == "present": - if user_exists(cursor, user, host, host_all): - try: - if update_password == 'always': - changed, msg = user_mod(cursor, user, host, host_all, password, encrypted, - plugin, plugin_hash_string, plugin_auth_string, - priv, append_privs, module) - else: - changed, msg = user_mod(cursor, user, host, host_all, None, encrypted, - plugin, plugin_hash_string, plugin_auth_string, - priv, append_privs, module) - - except (SQLParseError, InvalidPrivsError, mysql_driver.Error) as e: - module.fail_json(msg=to_native(e)) - else: - if host_all: - module.fail_json(msg="host_all parameter cannot be used when adding a user") - try: - changed = user_add(cursor, user, host, host_all, password, encrypted, - plugin, plugin_hash_string, plugin_auth_string, - priv, module.check_mode) - if changed: - msg = "User added" - - except (SQLParseError, InvalidPrivsError, mysql_driver.Error) as e: - module.fail_json(msg=to_native(e)) - elif state == "absent": - if user_exists(cursor, user, host, host_all): - changed = user_delete(cursor, user, host, host_all, module.check_mode) - msg = "User deleted" - else: - changed = False - msg = "User doesn't exist" - module.exit_json(changed=changed, user=user, msg=msg) - - -if __name__ == '__main__': - main() diff --git a/test/support/integration/plugins/modules/zabbix_host.py b/test/support/integration/plugins/modules/zabbix_host.py deleted file mode 100644 index a2954a1fe05..00000000000 --- a/test/support/integration/plugins/modules/zabbix_host.py +++ /dev/null @@ -1,1075 +0,0 @@ -#!/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 - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -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. -version_added: "2.0" -author: - - "Cove (@cove)" - - Tony Minfei Ding (!UNKNOWN) - - Harrison Gu (@harrisongu) - - Werner Dijkerman (@dj-wasabi) - - Eike Frost (@eikef) -requirements: - - "python >= 2.6" - - "zabbix-api >= 0.5.4" -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. - version_added: '2.3' - type: str - description: - description: - - Description of the host in Zabbix. - version_added: '2.5' - type: str - host_groups: - description: - - List of host groups the host is part of. - 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'] - version_added: '2.1' - 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) - version_added: '2.5' - 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) - suboptions: - type: - description: - - Interface type to add - - Numerical values are also accepted for interface type - - 1 = agent - - 2 = snmp - - 3 = ipmi - - 4 = jmx - choices: ['agent', 'snmp', 'ipmi', 'jmx'] - 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). - default: '' - dns: - type: str - description: - - DNS name of the host interface. - - Required if I(useip=0). - default: '' - 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. - - 0 (don't use bulk requests), 1 (use bulk requests) - choices: [0, 1] - default: 1 - 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 - default: 1 - version_added: '2.5' - 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 - default: 1 - version_added: '2.5' - 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 - version_added: '2.5' - 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 - version_added: '2.5' - type: str - ca_cert: - description: - - Required certificate issuer. - - Works only with >= Zabbix 3.0 - version_added: '2.5' - aliases: [ tls_issuer ] - type: str - tls_subject: - description: - - Required certificate subject. - - Works only with >= Zabbix 3.0 - version_added: '2.5' - 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. - version_added: '2.5' - 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 - version_added: '2.5' - type: int - ipmi_username: - description: - - IPMI username. - - also see the last note in the I(ipmi_authtype) documentation - version_added: '2.5' - type: str - ipmi_password: - description: - - IPMI password. - - also see the last note in the I(ipmi_authtype) documentation - version_added: '2.5' - type: str - force: - description: - - Overwrite the host configuration, even if already present. - type: bool - default: 'yes' - version_added: '2.0' - 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 - version_added: '2.10' - 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: '' - 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 - version_added: '2.10' - 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: - - zabbix -''' - -EXAMPLES = r''' -- name: Create a new host or update an existing host's info - local_action: - module: zabbix_host - server_url: http://monitor.example.com - login_user: username - login_password: password - 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 - local_action: - module: zabbix_host - server_url: http://monitor.example.com - login_user: username - login_password: password - host_name: ExampleHost - visible_name: ExampleName - host_groups: - - Example group1 - tls_psk_identity: test - tls_connect: 2 - tls_psk: 123456789abcdef123456789abcdef12 -''' - - -import atexit -import copy -import traceback - -try: - from zabbix_api import ZabbixAPI - HAS_ZABBIX_API = True -except ImportError: - ZBX_IMP_ERR = traceback.format_exc() - HAS_ZABBIX_API = False - -from distutils.version import LooseVersion -from ansible.module_utils.basic import AnsibleModule, missing_required_lib - - -class Host(object): - def __init__(self, module, zbx): - self._module = module - self._zapi = zbx - self._zbx_api_version = zbx.api_version()[:5] - - # 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, - 'tls_connect': tls_connect, 'tls_accept': tls_accept} - if proxy_id: - parameters['proxy_hostid'] = proxy_id - if visible_name: - parameters['name'] = visible_name - 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, 'tls_connect': tls_connect, - 'tls_accept': tls_accept} - if proxy_id >= 0: - parameters['proxy_hostid'] = proxy_id - if visible_name: - parameters['name'] = visible_name - 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 - - self._zapi.host.update(parameters) - interface_list_copy = exist_interface_list - if interfaces: - for interface in interfaces: - flag = False - interface_str = interface - for exist_interface in exist_interface_list: - interface_type = int(interface['type']) - exist_interface_type = int(exist_interface['type']) - if interface_type == exist_interface_type: - # update - interface_str['interfaceid'] = exist_interface['interfaceid'] - self._zapi.hostinterface.update(interface_str) - flag = True - interface_list_copy.remove(exist_interface) - break - if not flag: - # add - interface_str['hostid'] = host_id - self._zapi.hostinterface.create(interface_str) - # remove - remove_interface_ids = [] - for remove_interface in interface_list_copy: - interface_id = remove_interface['interfaceid'] - remove_interface_ids.append(interface_id) - if len(remove_interface_ids) > 0: - self._zapi.hostinterface.delete(remove_interface_ids) - 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': 'extend'}) - - 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': 'groupid', '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': 'groupid', '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 - - # check the exist_interfaces whether it equals the interfaces or not - def check_interface_properties(self, exist_interface_list, interfaces): - interfaces_port_list = [] - - if interfaces is not None: - if len(interfaces) >= 1: - for interface in interfaces: - interfaces_port_list.append(str(interface['port'])) - - exist_interface_ports = [] - if len(exist_interface_list) >= 1: - for exist_interface in exist_interface_list: - exist_interface_ports.append(str(exist_interface['port'])) - - if set(interfaces_port_list) != set(exist_interface_ports): - return True - - for exist_interface in exist_interface_list: - exit_interface_port = str(exist_interface['port']) - for interface in interfaces: - interface_port = str(interface['port']) - if interface_port == exit_interface_port: - for key in interface.keys(): - if str(exist_interface[key]) != str(interface[key]): - 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 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 - - 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: - existing_macros = sorted(host['macros'], key=lambda k: k['macro']) - for macro in existing_macros: - macro.pop('hostid', False) - macro.pop('hostmacroid', False) - - if sorted(macros, key=lambda k: k['macro']) != existing_macros: - 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, - 'tls_connect': tls_connect, 'tls_accept': tls_accept, 'ipmi_authtype': ipmi_authtype, - 'ipmi_privilege': ipmi_privilege, 'ipmi_username': ipmi_username, 'ipmi_password': ipmi_password} - 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) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - server_url=dict(type='str', required=True, aliases=['url']), - login_user=dict(type='str', required=True), - login_password=dict(type='str', required=True, no_log=True), - host_name=dict(type='str', required=True), - http_login_user=dict(type='str', required=False, default=None), - http_login_password=dict(type='str', required=False, default=None, no_log=True), - validate_certs=dict(type='bool', required=False, default=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', default=1), - tls_accept=dict(type='int', default=1), - tls_psk_identity=dict(type='str', required=False), - tls_psk=dict(type='str', required=False), - ca_cert=dict(type='str', required=False, aliases=['tls_issuer']), - tls_subject=dict(type='str', required=False), - inventory_zabbix=dict(type='dict', required=False), - timeout=dict(type='int', default=10), - interfaces=dict(type='list', required=False), - 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', required=False, default='') - ) - ), - tags=dict( - type='list', - elements='dict', - aliases=['host_tags'], - options=dict( - tag=dict(type='str', required=True), - value=dict(type='str', default='') - ) - ) - ), - supports_check_mode=True - ) - - 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) - - server_url = module.params['server_url'] - login_user = module.params['login_user'] - login_password = module.params['login_password'] - http_login_user = module.params['http_login_user'] - http_login_password = module.params['http_login_password'] - validate_certs = module.params['validate_certs'] - 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'] - timeout = module.params['timeout'] - 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 - - zbx = None - # login to zabbix - try: - zbx = ZabbixAPI(server_url, timeout=timeout, user=http_login_user, passwd=http_login_password, - validate_certs=validate_certs) - zbx.login(login_user, login_password) - atexit.register(zbx.logout) - except Exception as e: - module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) - - host = Host(module, zbx) - - 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) - - ip = "" - if interfaces: - # ensure interfaces are well-formed - for interface in interfaces: - if 'type' not in interface: - module.fail_json(msg="(interface) type needs to be specified for interface '%s'." % interface) - interfacetypes = {'agent': 1, 'snmp': 2, 'ipmi': 3, 'jmx': 4} - if interface['type'] in interfacetypes.keys(): - interface['type'] = interfacetypes[interface['type']] - if interface['type'] < 1 or interface['type'] > 4: - module.fail_json(msg="Interface type can only be 1-4 for interface '%s'." % interface) - if 'useip' not in interface: - interface['useip'] = 0 - if 'dns' not in interface: - if interface['useip'] == 0: - module.fail_json(msg="dns needs to be set if useip is 0 on interface '%s'." % interface) - interface['dns'] = '' - if 'ip' not in interface: - if interface['useip'] == 1: - module.fail_json(msg="ip needs to be set if useip is 1 on interface '%s'." % interface) - interface['ip'] = '' - if 'main' not in interface: - interface['main'] = 0 - if 'port' in interface and not isinstance(interface['port'], str): - try: - interface['port'] = str(interface['port']) - except ValueError: - module.fail_json(msg="port should be convertable to string on interface '%s'." % interface) - if 'port' not in interface: - if interface['type'] == 1: - interface['port'] = "10050" - elif interface['type'] == 2: - interface['port'] = "161" - elif interface['type'] == 3: - interface['port'] = "623" - elif interface['type'] == 4: - interface['port'] = "12345" - - if interface['type'] == 1: - ip = interface['ip'] - - if macros: - # convert macros to zabbix native format - {$MACRO} - for macro in macros: - macro['macro'] = macro['macro'].upper() - if not macro['macro'].startswith('{$'): - macro['macro'] = '{$' + macro['macro'] - if not macro['macro'].endswith('}'): - macro['macro'] = macro['macro'] + '}' - if LooseVersion(zbx.api_version()[:5]) <= LooseVersion('4.4.0'): - if 'description' in macro: - macro.pop('description', False) - - # 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}) - - # if no interfaces were specified with the module, start with an empty list - if not interfaces: - interfaces = [] - - # When force=no is specified, append existing interfaces to interfaces to update. When - # no interfaces have been specified, copy existing interfaces as specified from the API. - # Do the same with templates and host groups. - if not force or not interfaces: - for interface in copy.deepcopy(exist_interfaces): - # remove values not used during hostinterface.add/update calls - for key in tuple(interface.keys()): - if key in ['interfaceid', 'hostid', 'bulk']: - interface.pop(key, None) - - for index in interface.keys(): - if index in ['useip', 'main', 'type']: - interface[index] = int(interface[index]) - - if interface not in interfaces: - interfaces.append(interface) - - 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(): - provided_macros = [m['macro'] for m in macros] - existing_macros = zabbix_host_obj['macros'] - for macro in existing_macros: - if macro['macro'] not in provided_macros: - 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): - 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/test/support/integration/plugins/modules/zabbix_proxy.py b/test/support/integration/plugins/modules/zabbix_proxy.py deleted file mode 100644 index 96431293040..00000000000 --- a/test/support/integration/plugins/modules/zabbix_proxy.py +++ /dev/null @@ -1,472 +0,0 @@ -#!/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 . -# -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -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. -version_added: "2.5" -author: - - "Alen Komic (@akomic)" -requirements: - - "python >= 2.6" - - "zabbix-api >= 0.5.4" -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 - version_added: '2.10' - 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: - - zabbix -''' - -EXAMPLES = r''' -- name: Create or update a proxy with proxy type active - local_action: - module: zabbix_proxy - server_url: http://monitor.example.com - login_user: username - login_password: password - proxy_name: ExampleProxy - description: ExampleProxy - status: active - state: present - proxy_address: ExampleProxy.local - -- name: Create a new passive proxy using only it's IP - local_action: - module: zabbix_proxy - server_url: http://monitor.example.com - login_user: username - login_password: password - 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 - local_action: - module: zabbix_proxy - server_url: http://monitor.example.com - login_user: username - login_password: password - proxy_name: ExampleProxy - description: ExampleProxy - status: passive - state: present - interface: - dns: proxy.example.com - port: 10051 -''' - -RETURN = r''' # ''' - - -import traceback -import atexit - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -try: - from zabbix_api import ZabbixAPI - - HAS_ZABBIX_API = True -except ImportError: - ZBX_IMP_ERR = traceback.format_exc() - HAS_ZABBIX_API = False - - -class Proxy(object): - def __init__(self, module, zbx): - self._module = module - self._zapi = zbx - 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) - - 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 compile_interface_params(self, new_interface): - old_interface = {} - if 'interface' in self.existing_data and \ - len(self.existing_data['interface']) > 0: - old_interface = self.existing_data['interface'] - - for item in ['type', 'main']: - new_interface.pop(item, False) - - final_interface = old_interface.copy() - final_interface.update(new_interface) - final_interface = dict((k, str(v)) for k, v in final_interface.items()) - - if final_interface != old_interface: - return final_interface - else: - return {} - - def update_proxy(self, proxy_id, data): - try: - if self._module.check_mode: - self._module.exit_json(changed=True) - parameters = {'proxyid': proxy_id} - - for item in data: - if data[item] and item in self.existing_data and \ - self.existing_data[item] != data[item]: - parameters[item] = data[item] - - if 'interface' in parameters: - parameters.pop('interface') - - 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) - - if 'interface' in data and data['status'] == '6': - new_interface = self.compile_interface_params(data['interface']) - if len(new_interface) > 0: - parameters['interface'] = new_interface - - if len(parameters) > 1: - self._zapi.proxy.update(parameters) - self._module.exit_json( - changed=True, - result="Successfully updated proxy %s (%s)" % - (data['host'], proxy_id) - ) - else: - self._module.exit_json(changed=False) - except Exception as e: - self._module.fail_json(msg="Failed to update proxy %s: %s" % - (data['host'], e)) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - server_url=dict(type='str', required=True, aliases=['url']), - login_user=dict(type='str', required=True), - login_password=dict(type='str', required=True, no_log=True), - proxy_name=dict(type='str', required=True), - proxy_address=dict(type='str', required=False), - http_login_user=dict(type='str', required=False, default=None), - http_login_password=dict(type='str', required=False, - default=None, no_log=True), - validate_certs=dict(type='bool', required=False, default=True), - 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), - timeout=dict(type='int', default=10), - 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='2.14'), - main=dict(type='int', default=0, removed_in_version='2.14') - ), - ) - ), - supports_check_mode=True - ) - - 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) - - server_url = module.params['server_url'] - login_user = module.params['login_user'] - login_password = module.params['login_password'] - http_login_user = module.params['http_login_user'] - http_login_password = module.params['http_login_password'] - validate_certs = module.params['validate_certs'] - 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'] - timeout = module.params['timeout'] - 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 - - zbx = None - # login to zabbix - try: - zbx = ZabbixAPI(server_url, timeout=timeout, - user=http_login_user, - passwd=http_login_password, - validate_certs=validate_certs) - zbx.login(login_user, login_password) - atexit.register(zbx.logout) - except Exception as e: - module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) - - proxy = Proxy(module, zbx) - - # 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()