salt/tests/pytests/functional/modules/test_mysql.py
Pedro Algarvio 066afb90f0 Skip tests which can't run, or even pass on FIPS enabled platforms
Signed-off-by: Pedro Algarvio <palgarvio@vmware.com>
2023-11-14 20:42:57 +00:00

918 lines
21 KiB
Python

"""
Test Salt MySQL module across various MySQL variants
"""
import logging
import time
import pytest
from pytestshellutils.utils import format_callback_to_string
import salt.modules.mysql as mysqlmod
from salt.utils.versions import version_cmp
from tests.support.pytest.mysql import * # pylint: disable=wildcard-import,unused-wildcard-import
log = logging.getLogger(__name__)
pytestmark = [
pytest.mark.slow_test,
pytest.mark.skip_if_binaries_missing("dockerd"),
pytest.mark.skipif(
mysqlmod.MySQLdb is None, reason="No python mysql client installed."
),
pytest.mark.skip_on_fips_enabled_platform,
]
def _get_mysql_error(context):
return context.pop("mysql.error", None)
class CallWrapper:
def __init__(self, func, container, ctx):
self.func = func
self.container = container
self.ctx = ctx
def __call__(self, *args, **kwargs):
kwargs.update(self.container.get_credentials(**kwargs))
retry = 1
retries = 3
ret = None
while True:
ret = self.func(*list(args), **kwargs.copy())
mysql_error = _get_mysql_error(self.ctx)
if mysql_error is None:
break
retry += 1
if retry > retries:
break
time.sleep(0.5)
log.debug(
"Retrying(%s out of %s) %s because of the following error: %s",
retry,
retries,
format_callback_to_string(self.func, args, kwargs),
mysql_error,
)
return ret
@pytest.fixture(scope="module")
def mysql(modules, mysql_container, loaders):
for name in list(modules):
if not name.startswith("mysql."):
continue
modules._dict[name] = CallWrapper(
modules._dict[name],
mysql_container,
loaders.context,
)
return modules.mysql
def test_query(mysql):
ret = mysql.query("mysql", "SELECT 1")
assert ret
assert ret["results"] == (("1",),)
def test_version(mysql, mysql_container):
ret = mysql.version()
assert ret
assert mysql_container.mysql_version in ret
def test_status(mysql):
ret = mysql.status()
assert ret
def test_db_list(mysql):
ret = mysql.db_list()
assert ret
assert "mysql" in ret
def test_db_create_alter_remove(mysql):
ret = mysql.db_create("salt")
assert ret
ret = mysql.alter_db(
name="salt",
character_set="latin1",
collate="latin1_general_ci",
)
assert ret
ret = mysql.db_remove(name="salt")
assert ret
def test_user_list(mysql, mysql_combo):
ret = mysql.user_list()
assert ret
assert {
"User": mysql_combo.mysql_root_user,
"Host": mysql_combo.mysql_host,
} in ret
def test_user_exists(mysql, mysql_combo):
ret = mysql.user_exists(
mysql_combo.mysql_root_user,
host=mysql_combo.mysql_host,
password=mysql_combo.mysql_passwd,
)
assert ret
ret = mysql.user_exists(
"george",
"hostname",
"badpassword",
)
assert not ret
def test_user_info(mysql, mysql_combo):
ret = mysql.user_info(mysql_combo.mysql_root_user, host=mysql_combo.mysql_host)
assert ret
# Check that a subset of the information
# is available in the returned user information.
expected = {
"Host": mysql_combo.mysql_host,
"User": mysql_combo.mysql_root_user,
"Select_priv": "Y",
"Insert_priv": "Y",
"Update_priv": "Y",
"Delete_priv": "Y",
"Create_priv": "Y",
"Drop_priv": "Y",
"Reload_priv": "Y",
"Shutdown_priv": "Y",
"Process_priv": "Y",
"File_priv": "Y",
"Grant_priv": "Y",
"References_priv": "Y",
"Index_priv": "Y",
"Alter_priv": "Y",
"Show_db_priv": "Y",
"Super_priv": "Y",
"Create_tmp_table_priv": "Y",
"Lock_tables_priv": "Y",
"Execute_priv": "Y",
"Repl_slave_priv": "Y",
"Repl_client_priv": "Y",
"Create_view_priv": "Y",
"Show_view_priv": "Y",
"Create_routine_priv": "Y",
"Alter_routine_priv": "Y",
"Create_user_priv": "Y",
"Event_priv": "Y",
"Trigger_priv": "Y",
"Create_tablespace_priv": "Y",
}
data = ret.copy()
for key in list(data):
if key not in expected:
data.pop(key)
assert data == expected
def test_user_create_chpass_delete(mysql):
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
ret = mysql.user_chpass(
"george",
host="localhost",
password="different_password",
)
assert ret
ret = mysql.user_remove("george", host="localhost")
assert ret
def test_user_grants(mysql, mysql_combo):
ret = mysql.user_grants(mysql_combo.mysql_root_user, host=mysql_combo.mysql_host)
assert ret
def test_grant_add_revoke(mysql):
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="localhost",
)
assert ret
# Revoke the grant
ret = mysql.grant_revoke(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="localhost",
)
assert not ret
# Grant privileges to user globally
ret = mysql.grant_add(
grant="ALL PRIVILEGES",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the global exists
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="ALL PRIVILEGES",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_grant_replication_replica_add_revoke(mysql, mysql_container):
# The REPLICATION REPLICA grant is only available for mariadb
if "mariadb" not in mysql_container.mysql_name:
pytest.skip(
"The REPLICATION REPLICA grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# The REPLICATION REPLICA grant was added in mariadb 10.5.1
if version_cmp(mysql_container.mysql_version, "10.5.1") < 0:
pytest.skip(
"The REPLICATION REPLICA grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="REPLICATION REPLICA",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="REPLICATION REPLICA",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="REPLICATION REPLICA",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="REPLICATION REPLICA",
database="*.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_grant_replication_slave_add_revoke(mysql, mysql_container):
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="REPLICATION SLAVE",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="REPLICATION SLAVE",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="REPLICATION SLAVE",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="REPLICATION SLAVE",
database="*.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_grant_replication_client_add_revoke(mysql, mysql_container):
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="REPLICATION CLIENT",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="REPLICATION CLIENT",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="REPLICATION CLIENT",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="REPLICATION CLIENT",
database="*.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_grant_binlog_monitor_add_revoke(mysql, mysql_container):
# The BINLOG MONITOR grant is only available for mariadb
if "mariadb" not in mysql_container.mysql_name:
pytest.skip(
"The BINLOG MONITOR grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# The BINLOG MONITOR grant was added in mariadb 10.5.2
if version_cmp(mysql_container.mysql_version, "10.5.2") < 0:
pytest.skip(
"The BINLOG_MONITOR grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="BINLOG MONITOR",
database="salt.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="BINLOG MONITOR",
database="salt.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="BINLOG MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="BINLOG MONITOR",
database="salt.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_grant_replica_monitor_add_revoke(mysql, mysql_container):
# The REPLICA MONITOR grant is only available for mariadb
if "mariadb" not in mysql_container.mysql_name:
pytest.skip(
"The REPLICA MONITOR grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# The REPLICA MONITOR grant was added in mariadb 10.5.9
if version_cmp(mysql_container.mysql_version, "10.5.9") < 0:
pytest.skip(
"The REPLICA MONITOR grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="REPLICA MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="REPLICA MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="REPLICA MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="REPLICA MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_grant_slave_monitor_add_revoke(mysql, mysql_container):
# The SLAVE MONITOR grant is only available for mariadb
if "mariadb" not in mysql_container.mysql_name:
pytest.skip(
"The SLAVE MONITOR grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# The SLAVE MONITOR grant was added in mariadb 10.5.9
if version_cmp(mysql_container.mysql_version, "10.5.9") < 0:
pytest.skip(
"The SLAVE MONITOR grant is unavailable "
"for the {}:{} docker image.".format(
mysql_container.mysql_name, mysql_container.mysql_version
)
)
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="localhost",
password="badpassword",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="SLAVE MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="SLAVE MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Revoke the global grant
ret = mysql.grant_revoke(
grant="SLAVE MONITOR",
database="*.*",
user="george",
host="localhost",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="SLAVE MONITOR",
database="salt.*",
user="george",
host="localhost",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="localhost")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_plugin_add_status_remove(mysql, mysql_combo):
if "mariadb" in mysql_combo.mysql_name:
plugin = "simple_password_check"
else:
plugin = "auth_socket"
ret = mysql.plugin_status(plugin, host=mysql_combo.mysql_host)
assert not ret
ret = mysql.plugin_add(plugin)
assert ret
ret = mysql.plugin_status(plugin, host=mysql_combo.mysql_host)
assert ret
assert ret == "ACTIVE"
ret = mysql.plugin_remove(plugin)
assert ret
ret = mysql.plugin_status(plugin, host=mysql_combo.mysql_host)
assert not ret
def test_plugin_list(mysql, mysql_container):
if "mariadb" in mysql_container.mysql_name:
plugin = "simple_password_check"
else:
plugin = "auth_socket"
ret = mysql.plugins_list()
assert {"name": plugin, "status": "ACTIVE"} not in ret
assert ret
ret = mysql.plugin_add(plugin)
assert ret
ret = mysql.plugins_list()
assert ret
assert {"name": plugin, "status": "ACTIVE"} in ret
ret = mysql.plugin_remove(plugin)
assert ret
def test_grant_add_revoke_password_hash(mysql):
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="%",
password_hash="*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert ret
# Check the grant exists via a query
ret = mysql.query(
database="salt",
query="SELECT 1",
connection_user="george",
connection_pass="password",
connection_db="salt",
)
assert ret
# Revoke the grant
ret = mysql.grant_revoke(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="%")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret
def test_create_alter_password_hash(mysql):
# Create the database
ret = mysql.db_create("salt")
assert ret
# Create a user
ret = mysql.user_create(
"george",
host="%",
password_hash="*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19",
)
assert ret
# Grant privileges to user to specific table
ret = mysql.grant_add(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert ret
# Check the grant exists
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert ret
# Check we can query as the new user
ret = mysql.query(
database="salt",
query="SELECT 1",
connection_user="george",
connection_pass="password",
connection_db="salt",
)
assert ret
# Change the user password
ret = mysql.user_chpass(
"george",
host="%",
password_hash="*F4A5147613F01DEC0C5226BF24CD1D5762E6AAF2",
)
assert ret
# Check we can query with the new password
ret = mysql.query(
database="salt",
query="SELECT 1",
connection_user="george",
connection_pass="badpassword",
connection_db="salt",
)
assert ret
# Revoke the grant
ret = mysql.grant_revoke(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert ret
# Check the grant does not exist
ret = mysql.grant_exists(
grant="ALL PRIVILEGES",
database="salt.*",
user="george",
host="%",
)
assert not ret
# Remove the user
ret = mysql.user_remove("george", host="%")
assert ret
# Remove the database
ret = mysql.db_remove("salt")
assert ret