diff --git a/library/database/mysql_user b/library/database/mysql_user index db4b334716c..aaec05f99f5 100644 --- a/library/database/mysql_user +++ b/library/database/mysql_user @@ -209,7 +209,8 @@ def user_mod(cursor, user, host, password, new_priv, append_privs): for db_table in db_table_intersect: priv_diff = set(new_priv[db_table]) ^ set(curr_priv[db_table]) if (len(priv_diff) > 0): - privileges_revoke(cursor, user,host,db_table,grant_option) + if not append_privs: + privileges_revoke(cursor, user,host,db_table,grant_option) privileges_grant(cursor, user,host,db_table,new_priv[db_table]) changed = True diff --git a/test/integration/destructive.yml b/test/integration/destructive.yml index ae6041be9b6..29f65415109 100644 --- a/test/integration/destructive.yml +++ b/test/integration/destructive.yml @@ -8,3 +8,4 @@ - { role: test_apt, tags: test_apt } - { role: test_apt_repository, tags: test_apt_repository } - { role: test_mysql_db, tags: test_mysql_db} + - { role: test_mysql_user, tags: test_mysql_user} diff --git a/test/integration/roles/test_mysql_user/defaults/main.yml b/test/integration/roles/test_mysql_user/defaults/main.yml new file mode 100644 index 00000000000..ff7503f8f00 --- /dev/null +++ b/test/integration/roles/test_mysql_user/defaults/main.yml @@ -0,0 +1,16 @@ +--- +# defaults file for test_mysql_user +db_name: 'data' +user_name_1: 'db_user1' +user_name_2: 'db_user2' + +user_password_1: '12345' +user_password_2: '98765' + +db_names: + - clientdb + - employeedb + - providerdb + +tmp_dir: '/tmp' + diff --git a/test/integration/roles/test_mysql_user/meta/main.yml b/test/integration/roles/test_mysql_user/meta/main.yml new file mode 100644 index 00000000000..4aa170dc067 --- /dev/null +++ b/test/integration/roles/test_mysql_user/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_mysql_db diff --git a/test/integration/roles/test_mysql_user/tasks/assert_no_user.yml b/test/integration/roles/test_mysql_user/tasks/assert_no_user.yml new file mode 100644 index 00000000000..4d4a411fe2b --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/assert_no_user.yml @@ -0,0 +1,25 @@ +# test code to assert no mysql user +# (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: run command to query for mysql user + command: mysql "-e SELECT User FROM mysql.user where user='{{ user_name }}';" + register: result + +- name: assert mysql user is not present + assert: { that: "'{{ user_name }}' not in result.stdout" } diff --git a/test/integration/roles/test_mysql_user/tasks/assert_user.yml b/test/integration/roles/test_mysql_user/tasks/assert_user.yml new file mode 100644 index 00000000000..7b35a1f3506 --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/assert_user.yml @@ -0,0 +1,34 @@ +# test code to assert mysql user +# (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: run command to query for mysql user + command: mysql "-e SELECT User FROM mysql.user where user='{{ user_name }}';" + register: result + +- name: assert mysql user is present + assert: { that: "'{{ user_name }}' in result.stdout" } + +- name: run command to show privileges for user (expect privileges in stdout) + command: mysql "-e SHOW GRANTS FOR '{{ user_name }}'@'localhost';" + register: result + when: priv is defined + +- name: assert user has giving privileges + assert: { that: "'GRANT {{priv}} ON *.*' in result.stdout" } + when: priv is defined diff --git a/test/integration/roles/test_mysql_user/tasks/create_user.yml b/test/integration/roles/test_mysql_user/tasks/create_user.yml new file mode 100644 index 00000000000..6122098e1ed --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/create_user.yml @@ -0,0 +1,25 @@ +# test code to create mysql user +# (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: create mysql user {{user_name}} + mysql_user: name={{user_name}} password={{user_password}} state=present + register: result + +- name: assert output message mysql user was created {{state}} + assert: { that: "result.changed == true" } diff --git a/test/integration/roles/test_mysql_user/tasks/main.yml b/test/integration/roles/test_mysql_user/tasks/main.yml new file mode 100644 index 00000000000..7ad42d471b2 --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/main.yml @@ -0,0 +1,152 @@ +# test code for the mysql_user 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 dof 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 . + +# ============================================================ +# create mysql user and verify user is added to mysql database +# +- include: create_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }} + +- include: assert_user.yml user_name={{user_name_1}} + +- include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }} + +- include: assert_no_user.yml user_name={{user_name_1}} + +# ============================================================ +# Create mysql user that already exist on mysql database +# +- include: create_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }} + +- name: create mysql user that already exist (expect changed=false) + mysql_user: name={{user_name_1}} password={{user_password_1}} state=present + register: result + +- name: assert output message mysql user was not created + assert: { that: "result.changed == false" } + +# ============================================================ +# remove mysql user and verify user is removed from mysql database +# +- name: remove mysql user state=absent (expect changed=true) + mysql_user: name={{ user_name_1 }} password={{ user_password_1 }} state=absent + register: result + +- name: assert output message mysql user was removed + assert: { that: "result.changed == true" } + +- include: assert_no_user.yml user_name={{user_name_1}} + +# ============================================================ +# remove mysql user that does not exist on mysql database +# +- name: remove mysql user that does not exist state=absent (expect changed=false) + mysql_user: name={{ user_name_1 }} password={{ user_password_1 }} state=absent + register: result + +- name: assert output message mysql user that does not exist + assert: { that: "result.changed == false" } + +- include: assert_no_user.yml user_name={{user_name_1}} + +# ============================================================ +# Create user with no privileges and verify default privileges are assign +# +- name: create user with select privilege state=present (expect changed=true) + mysql_user: name={{ user_name_1 }} password={{ user_password_1 }} state=present + register: result + +- include: assert_user.yml user_name={{user_name_1}} priv=USAGE + +- include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }} + +- include: assert_no_user.yml user_name={{user_name_1}} + +# ============================================================ +# Create user with select privileges and verify select privileges are assign +# +- name: create user with select privilege state=present (expect changed=true) + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} state=present priv=*.*:SELECT + register: result + +- include: assert_user.yml user_name={{user_name_2}} priv=SELECT + +- include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_2 }} + +- include: assert_no_user.yml user_name={{user_name_2}} + +# ============================================================ +# Assert user has access to multiple databases +# +- name: give users access to multiple databases + mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password={{ user_password_1 }} + with_nested: + - [ '{{ user_name_1 }}' , '{{ user_name_2 }}'] + - db_names + +- name: show grants access for user1 on multiple database + command: mysql "-e SHOW GRANTS FOR '{{ user_name_1 }}'@'localhost';" + register: result + +- name: assert grant access for user1 on multiple database + assert: { that: "'{{ item }}' in result.stdout" } + with_items: db_names + +- name: show grants access for user2 on multiple database + command: mysql "-e SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost';" + register: result + +- name: assert grant access for user2 on multiple database + assert: { that: "'{{ item }}' in result.stdout" } + with_items: db_names + +- include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }} + +- include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_1 }} + +# ============================================================ +# Update user password for a user. +# Assert the user password is updated and old password can no longer be used. +# +- include: user_password_update_test.yml + +# ============================================================ +# Assert create user with SELECT privileges, attemp to create database and update privileges to create database +# +- include: test_privs.yml current_privilege=SELECT current_append_privs=no + +# ============================================================ +# Assert creating user with SELECT privileges, attemp to create database and append privileges to create database +# +- include: test_privs.yml current_privilege=DROP current_append_privs=yes + +# ============================================================ +# Assert create user with SELECT privileges, attemp to create database and update privileges to create database +# +- include: test_privs.yml current_privilege='UPDATE,ALTER' current_append_privs=no + +# ============================================================ +# Assert creating user with SELECT privileges, attemp to create database and append privileges to create database +# +- include: test_privs.yml current_privilege='INSERT,DELETE' current_append_privs=yes + + + + + + + diff --git a/test/integration/roles/test_mysql_user/tasks/remove_user.yml b/test/integration/roles/test_mysql_user/tasks/remove_user.yml new file mode 100644 index 00000000000..76eca35b877 --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/remove_user.yml @@ -0,0 +1,25 @@ +# test code to remove mysql user +# (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: remove mysql user {{user_name}} + mysql_user: name={{user_name}} password={{user_password}} state=absent + register: result + +- name: assert output message mysql user was removed {{state}} + assert: { that: "result.changed == true" } diff --git a/test/integration/roles/test_mysql_user/tasks/test_privs.yml b/test/integration/roles/test_mysql_user/tasks/test_privs.yml new file mode 100644 index 00000000000..6bfc2d5d165 --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/test_privs.yml @@ -0,0 +1,73 @@ +# test code for privileges for mysql_user 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: create user with basic select privileges + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} priv=*.*:SELECT state=present + when: current_append_privs == "yes" + +- include: assert_user.yml user_name={{user_name_2}} priv='SELECT' + when: current_append_privs == "yes" + +- name: create user with current privileges (expect changed=true) + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} priv=*.*:'{{current_privilege}}' append_privs={{current_append_privs}} state=present + register: result + +- name: assert output message for current privileges + assert: { that: "result.changed == true" } + +- name: run command to show privileges for user (expect privileges in stdout) + command: mysql "-e SHOW GRANTS FOR '{{user_name_2}}'@'localhost';" + register: result + +- name: assert user has correct privileges + assert: { that: "'GRANT {{current_privilege | replace(',', ', ')}} ON *.*' in result.stdout" } + when: current_append_privs == "no" + +- name: assert user has correct privileges + assert: { that: "'GRANT SELECT, {{current_privilege | replace(',', ', ')}} ON *.*' in result.stdout" } + when: current_append_privs == "yes" + +- name: create database using user current privileges + mysql_db: name={{ db_name }} state=present login_user={{ user_name_2 }} login_password={{ user_password_2 }} + ignore_errors: true + +- name: run command to test that database was not created + command: mysql "-e show databases like '{{ db_name }}';" + register: result + +- name: assert database was not created + assert: { that: "'{{ db_name }}' not in result.stdout" } + +- name: update user with all privileges + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} priv=*.*:ALL state=present + +- include: assert_user.yml user_name={{user_name_2}} priv='ALL PRIVILEGES' + +- name: create database using user + mysql_db: name={{ db_name }} state=present login_user={{ user_name_2 }} login_password={{ user_password_2 }} + register: result + +- name: run command to test database was created using user new privileges + command: mysql "-e SHOW CREATE DATABASE {{ db_name }};" + +- name: drop database using using user + mysql_db: name={{ db_name }} state=absent login_user={{ user_name_2 }} login_password={{ user_password_2 }} + +- name: remove username + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} state=absent diff --git a/test/integration/roles/test_mysql_user/tasks/user_password_update_test.yml b/test/integration/roles/test_mysql_user/tasks/user_password_update_test.yml new file mode 100644 index 00000000000..d342d0a4ac7 --- /dev/null +++ b/test/integration/roles/test_mysql_user/tasks/user_password_update_test.yml @@ -0,0 +1,84 @@ +# test code update password for the mysql_user 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 dof 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 . + +# ============================================================ +# Update user password for a user. +# Assert the user password is updated and old password can no longer be used. +# +- name: create user1 state=present with a password + mysql_user: name={{ user_name_1 }} password={{ user_password_1 }} priv=*.*:ALL state=present + +- name: create user2 state=present with a password + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} priv=*.*:ALL state=present + +- name: store user2 grants with old password + command: mysql "-e SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost';" + register: user_password_old + +- name: update user2 state=present with same password (expect changed=false) + mysql_user: name={{ user_name_2 }} password={{ user_password_2 }} priv=*.*:ALL state=present + register: result + +- name: assert output user2 was not updated + assert: { that: "result.changed == false" } + +- include: assert_user.yml user_name={{user_name_2}} priv='ALL PRIVILEGES' + +- name: update user2 state=present with a new password (expect changed=true) + mysql_user: name={{ user_name_2 }} password={{ user_password_1 }} state=present + register: result + +- include: assert_user.yml user_name={{user_name_2}} priv='ALL PRIVILEGES' + +- name: store user2 grants with new password + command: mysql "-e SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost';" + register: user_password_new + +- name: assert output message password was update for user2 + assert: { that: "user_password_old.stdout != user_password_new.stdout" } + +- name: create database using user2 and old password + mysql_db: name={{ db_name }} state=present login_user={{ user_name_2 }} login_password={{ user_password_2 }} + ignore_errors: true + register: result + +- name: assert output message that database not create with old password + assert: + that: + - "result.failed == true" + - "'check login_user and login_password are correct' in result.msg" + +- name: create database using user2 and new password + mysql_db: name={{ db_name }} state=present login_user={{ user_name_2 }} login_password={{ user_password_1 }} + register: result + +- name: assert output message that database is created with new password + assert: { that: "result.changed == true" } + +- name: remove database + mysql_db: name={{ db_name }} state=absent + +- include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }} + +- include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_1 }} + + + + + +