diff --git a/test/integration/targets/mongodb_user/aliases b/test/integration/targets/mongodb_user/aliases new file mode 100644 index 00000000000..e9fc78ee6de --- /dev/null +++ b/test/integration/targets/mongodb_user/aliases @@ -0,0 +1,6 @@ +destructive +shippable/posix/group1 +skip/osx +skip/freebsd +skip/rhel +needs/root diff --git a/test/integration/targets/mongodb_user/defaults/main.yml b/test/integration/targets/mongodb_user/defaults/main.yml new file mode 100644 index 00000000000..aac55526df6 --- /dev/null +++ b/test/integration/targets/mongodb_user/defaults/main.yml @@ -0,0 +1,21 @@ +--- +# defaults file for test_mongodb_user +mongodb_admin_user: test_root +mongodb_admin_password: saE_Rr9!gE6gh#e~R#nZ +mongod_auth: false +kill_signal: SIGTERM +# Should be one of +# --storageEngine wiredTiger --wiredTigerEngineConfigString="cache_size=200M" +# --storageEngine mmapv1 --nojournal +mongod_storage_engine_opts: "--storageEngine wiredTiger --wiredTigerEngineConfigString='cache_size=200M'" +mongodb_user: mongodb +mongodb_user_list: + - { "name": "user1", "password": "password1", "roles": "read", "database": "test" } + - { "name": "user2", "password": "password2", "roles": "readWrite", "database": "test" } + - { "name": "user3", "password": "password3", "roles": "dbAdmin", "database": "test" } + - { "name": "user4", "password": "password4", "roles": "userAdmin", "database": "test" } + - { "name": "user5", "password": "password5", "roles": "clusterAdmin", "database": "admin" } + - { "name": "user6", "password": "password6", "roles": "readAnyDatabase", "database": "admin" } + - { "name": "user7", "password": "password7", "roles": "readWriteAnyDatabase", "database": "admin" } + - { "name": "user8", "password": "password8", "roles": "userAdminAnyDatabase", "database": "admin" } + - { "name": "user9", "password": "password9", "roles": "dbAdminAnyDatabase", "database": "admin" } diff --git a/test/integration/targets/mongodb_user/files/js/is_primary.js b/test/integration/targets/mongodb_user/files/js/is_primary.js new file mode 100644 index 00000000000..7bb130614f2 --- /dev/null +++ b/test/integration/targets/mongodb_user/files/js/is_primary.js @@ -0,0 +1,13 @@ +var done = false; +var iterations = 0; +while(rs.status()['myState'] != 1) { + if (!done) { + //print("State is not yet PRIMARY. Waiting..."); + done = true + } + sleep(1000); + iterations++; + if (iterations == 100) { + throw new Error("Exceeded iterations limit."); + } + } diff --git a/test/integration/targets/mongodb_user/meta/main.yml b/test/integration/targets/mongodb_user/meta/main.yml new file mode 100644 index 00000000000..9d941be0bcc --- /dev/null +++ b/test/integration/targets/mongodb_user/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + - setup_mongodb + - setup_remote_tmp_dir diff --git a/test/integration/targets/mongodb_user/tasks/main.yml b/test/integration/targets/mongodb_user/tasks/main.yml new file mode 100644 index 00000000000..f2f061f2c42 --- /dev/null +++ b/test/integration/targets/mongodb_user/tasks/main.yml @@ -0,0 +1,226 @@ +# test code for the mongodb_user module +# (c) 2019, Rhys Campbell + +# 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 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: Ensure tests home exists + file: + path: "{{ remote_tmp_dir }}/tests" + state: directory + +- include_tasks: mongod_teardown.yml + +- set_fact: + current_replicaset: mongodb_user_tests_replicaset + +- set_fact: + mongodb_nodes: [ 3001, 3002, 3003 ] + +- include_tasks: mongod_replicaset.yml + +- name: Create current_replicaset with module + mongodb_replicaset: + login_port: 3001 + replica_set: "{{ current_replicaset }}" + members: + - "localhost:3001" + - "localhost:3002" + - "localhost:3003" + +- name: Ensure is_primary script exists on host + copy: + src: js/is_primary.js + dest: "{{ remote_tmp_dir }}/tests/is_primary.js" + +- name: Ensure host reaches primary before proceeding 3001 + command: mongo admin --port 3001 "{{ remote_tmp_dir }}/tests/is_primary.js" + +- name: Create admin user with module + mongodb_user: + login_port: 3001 + replica_set: "{{ current_replicaset }}" + database: admin + name: "{{ mongodb_admin_user }}" + password: "{{ mongodb_admin_password }}" + roles: root + state: present + register: mongodb_admin_user_created + +- assert: + that: + - mongodb_admin_user_created.changed == True + +- name: Kill all mongod processes + command: pkill -{{ kill_signal }} mongod + ignore_errors: true + +- name: Getting pids for mongod + pids: + name: mongod + register: pids_of_mongod + +- name: Wait for all mongod processes to exit + wait_for: + path: "/proc/{{ item }}/status" + state: absent + delay: 3 + with_items: "{{ pids_of_mongod }}" + +- set_fact: + mongod_auth: true + +- include_tasks: mongod_replicaset.yml +# Tests with auth enable + +- name: Ensure host reaches primary before proceeding 3001 + command: mongo admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" "{{ remote_tmp_dir }}/tests/is_primary.js" + +- name: Run admin user creation again + mongodb_user: + login_user: "{{ mongodb_admin_user }}" + login_password: "{{ mongodb_admin_password }}" + login_database: admin + login_port: 3001 + replica_set: "{{ current_replicaset }}" + database: admin + name: "{{ mongodb_admin_user }}" + password: "{{ mongodb_admin_password }}" + roles: root + state: present + update_password: on_create + register: mongodb_admin_user_created + +- assert: + that: + - mongodb_admin_user_created.changed == False + +- name: Run admin user creation again with forced pw update + mongodb_user: + login_user: "{{ mongodb_admin_user }}" + login_password: "{{ mongodb_admin_password }}" + login_database: admin + login_port: 3001 + replica_set: "{{ current_replicaset }}" + database: admin + name: "{{ mongodb_admin_user }}" + password: "{{ mongodb_admin_password }}" + roles: root + state: present + update_password: always + register: mongodb_admin_user_created + +- assert: + that: + - mongodb_admin_user_created.changed == True + +- name: Run user creation + mongodb_user: + login_user: "{{ mongodb_admin_user }}" + login_password: "{{ mongodb_admin_password }}" + login_database: admin + login_port: 3001 + replica_set: "{{ current_replicaset }}" + database: "{{ item.database }}" + name: "{{ item.name }}" + password: "{{ item.password }}" + roles: "{{ item.roles }}" + state: present + with_items: "{{ mongodb_user_list }}" + +- name: Test login for all users + shell: mongo "{{ item.database }}" --port 3001 --username "{{ item.name }}" --password "{{ item.password }}" --eval "printjson(db.getCollectionNames())" + with_items: "{{ mongodb_user_list }}" + register: login_test + +- name: Assert all logins successful + assert: + that: "{{ item.rc == 0 }}" + with_items: "{{ login_test.results }}" + +- name: Get admin db users + shell: mongo admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" + register: admin_db_users + +- name: Assert that roles exist in admin db output + assert: + that: + - "'clusterAdmin' in admin_db_users.stdout" + - "'readAnyDatabase' in admin_db_users.stdout" + - "'readWriteAnyDatabase' in admin_db_users.stdout" + - "'userAdminAnyDatabase' in admin_db_users.stdout" + - "'dbAdminAnyDatabase' in admin_db_users.stdout" + +- name: Get test db users + shell: mongo test --authenticationDatabase admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" + register: test_db_users + +- name: Assert that roles exist in test db output + assert: + that: + - "'\"read\"' in test_db_users.stdout" + - "'readWrite' in test_db_users.stdout" + - "'dbAdmin' in test_db_users.stdout" + - "'userAdmin' in test_db_users.stdout" + +- name: Drop users in test db + mongodb_user: + login_user: "{{ mongodb_admin_user }}" + login_password: "{{ mongodb_admin_password }}" + login_database: admin + login_port: 3001 + replica_set: "{{ current_replicaset }}" + database: "{{ item.database }}" + name: "{{ item.name }}" + state: absent + with_items: "{{ mongodb_user_list }}" + when: item.database == "test" + +- name: Get test db users + shell: mongo test --authenticationDatabase admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" + register: test_db_users + +- name: Assert that roles do not exist in test db output + assert: + that: + - "'user1' not in test_db_users.stdout" + - "'user2' not in test_db_users.stdout" + - "'user3' not in test_db_users.stdout" + - "'user4' not in test_db_users.stdout" + +- name: Create user with multiple roles in test db + mongodb_user: + login_user: "{{ mongodb_admin_user }}" + login_password: "{{ mongodb_admin_password }}" + login_database: admin + login_port: 3001 + replica_set: "{{ current_replicaset }}" + database: test + name: test_multiple_roles + password: secret + roles: readWrite,dbAdmin,userAdmin + state: present + +- name: Get test db users + shell: mongo test --authenticationDatabase admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" + register: test_db_users + +- debug: + var: test_db_users + +# Clean up +- include_tasks: mongod_teardown.yml diff --git a/test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml b/test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml new file mode 100644 index 00000000000..fe1c2ffe626 --- /dev/null +++ b/test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml @@ -0,0 +1,51 @@ +- name: Set mongodb_user user for redhat + set_fact: + mongodb_user: "mongod" + when: ansible_os_family == "RedHat" + +- name: Create directories for mongod processes + file: + path: "{{ remote_tmp_dir }}/mongod{{ item }}" + state: directory + owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + mode: 0755 + recurse: yes + with_items: "{{ mongodb_nodes }}" + +- name: Ensure {{ remote_tmp_dir }}/config dir exists + file: + path: "{{ remote_tmp_dir }}/config" + state: directory + owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + mode: 0755 + +- name: Create keyfile + copy: + dest: "{{ remote_tmp_dir }}/my.key" + content: | + fd2CUrbXBJpB4rt74A6F + owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + mode: 0600 + when: mongod_auth == True + +- name: Spawn mongod process without auth + command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork + args: + chdir: "{{ remote_tmp_dir }}" + with_items: "{{ mongodb_nodes | sort }}" + when: mongod_auth == False + +- name: Spawn mongod process with auth + command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork --auth --keyFile my.key + args: + chdir: "{{ remote_tmp_dir }}" + with_items: "{{ mongodb_nodes | sort }}" + when: mongod_auth == True + +- name: Wait for mongod to start responding + wait_for: + port: "{{ item }}" + with_items: "{{ mongodb_nodes }}" diff --git a/test/integration/targets/mongodb_user/tasks/mongod_teardown.yml b/test/integration/targets/mongodb_user/tasks/mongod_teardown.yml new file mode 100644 index 00000000000..7bc5d3d0a0a --- /dev/null +++ b/test/integration/targets/mongodb_user/tasks/mongod_teardown.yml @@ -0,0 +1,27 @@ +- name: Kill all mongod processes + command: pkill -{{ kill_signal }} mongod + ignore_errors: true + +- name: Getting pids for mongod + pids: + name: mongod + register: pids_of_mongod + +- name: Wait for all mongod processes to exit + wait_for: + path: "/proc/{{ item }}/status" + state: absent + delay: 1 + with_items: "{{ pids_of_mongod }}" + +- name: Remove all mongod folders + file: + path: "{{ remote_tmp_dir }}/{{ item }}" + state: absent + with_items: + - mongod3001 + - mongod3002 + - mongod3003 + +- name: Remove all mongod sock files + shell: rm -Rf /tmp/mongodb*.sock diff --git a/test/integration/targets/setup_mongodb/defaults/main.yml b/test/integration/targets/setup_mongodb/defaults/main.yml index a319bbf505d..ddf9ea5221e 100644 --- a/test/integration/targets/setup_mongodb/defaults/main.yml +++ b/test/integration/targets/setup_mongodb/defaults/main.yml @@ -41,4 +41,5 @@ redhat_packages_py3: pip_packages: - psutil + - requests[security] - pymongo diff --git a/test/integration/targets/setup_mongodb/tasks/main.yml b/test/integration/targets/setup_mongodb/tasks/main.yml index 3271f472869..04109c9718d 100644 --- a/test/integration/targets/setup_mongodb/tasks/main.yml +++ b/test/integration/targets/setup_mongodb/tasks/main.yml @@ -25,7 +25,7 @@ or (ansible_os_family == "RedHat" and ansible_distribution_major_version == '6') or ansible_os_family == "Suse" or ansible_distribution == 'Fedora' - or (ansible_distribution == 'CentOS' and ansible_distribution_version == '7') + or (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == '7') # Ubuntu - name: Import MongoDB public GPG Key