mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
Add support for MariaDB 10.5's new grants and grant aliases (#59280)
* Add support for MariaDB 10.5's new grants and grant aliases * Add support for MariaDB 10.5.9's REPLICA/SLAVE MONITOR grant * Add tests for MariaDB grant aliases * Update test_mysql.py * Update test_mysql.py Co-authored-by: Gareth J. Greenaway <gareth@saltstack.com>
This commit is contained in:
parent
17401db607
commit
8b53054b5e
2 changed files with 499 additions and 0 deletions
|
@ -82,7 +82,11 @@ __grants__ = [
|
|||
"ALTER ROUTINE",
|
||||
"BACKUP_ADMIN",
|
||||
"BINLOG_ADMIN",
|
||||
"BINLOG ADMIN",
|
||||
"BINLOG MONITOR",
|
||||
"BINLOG REPLAY",
|
||||
"CONNECTION_ADMIN",
|
||||
"CONNECTION ADMIN",
|
||||
"CREATE",
|
||||
"CREATE ROLE",
|
||||
"CREATE ROUTINE",
|
||||
|
@ -96,6 +100,7 @@ __grants__ = [
|
|||
"ENCRYPTION_KEY_ADMIN",
|
||||
"EVENT",
|
||||
"EXECUTE",
|
||||
"FEDERATED ADMIN",
|
||||
"FILE",
|
||||
"GRANT OPTION",
|
||||
"GROUP_REPLICATION_ADMIN",
|
||||
|
@ -104,15 +109,21 @@ __grants__ = [
|
|||
"LOCK TABLES",
|
||||
"PERSIST_RO_VARIABLES_ADMIN",
|
||||
"PROCESS",
|
||||
"READ_ONLY ADMIN",
|
||||
"REFERENCES",
|
||||
"RELOAD",
|
||||
"REPLICA MONITOR",
|
||||
"REPLICATION CLIENT",
|
||||
"REPLICATION MASTER ADMIN",
|
||||
"REPLICATION REPLICA",
|
||||
"REPLICATION SLAVE",
|
||||
"REPLICATION_SLAVE_ADMIN",
|
||||
"REPLICATION SLAVE ADMIN",
|
||||
"RESOURCE_GROUP_ADMIN",
|
||||
"RESOURCE_GROUP_USER",
|
||||
"ROLE_ADMIN",
|
||||
"SELECT",
|
||||
"SET USER",
|
||||
"SET_USER_ID",
|
||||
"SHOW DATABASES",
|
||||
"SHOW VIEW",
|
||||
|
@ -620,6 +631,67 @@ def _grant_to_tokens(grant):
|
|||
return dict(user=user, host=host, grant=grant_tokens, database=database)
|
||||
|
||||
|
||||
def _resolve_grant_aliases(grants, server_version):
|
||||
"""
|
||||
|
||||
There can be a situation where the database supports grants "A" and "B", where
|
||||
"B" is an alias for "A". In that case, when you want to grant "B" to a user,
|
||||
the database will actually report it added "A". We need to resolve those
|
||||
aliases to not report (wrong) errors.
|
||||
|
||||
:param grants: the tokenized grants
|
||||
|
||||
:param server_version: version string of the connected database
|
||||
|
||||
"""
|
||||
if "MariaDB" not in server_version:
|
||||
return grants
|
||||
|
||||
mariadb_version_compare_replication_replica = "10.5.1"
|
||||
mariadb_version_compare_binlog_monitor = "10.5.2"
|
||||
mariadb_version_compare_slave_monitor = "10.5.9"
|
||||
|
||||
resolved_tokens = []
|
||||
|
||||
for token in grants:
|
||||
if (
|
||||
salt.utils.versions.version_cmp(
|
||||
server_version, mariadb_version_compare_replication_replica
|
||||
)
|
||||
>= 0
|
||||
):
|
||||
if token == "REPLICATION REPLICA":
|
||||
# https://mariadb.com/kb/en/grant/#replication-replica
|
||||
resolved_tokens.append("REPLICATION SLAVE")
|
||||
continue
|
||||
|
||||
if (
|
||||
salt.utils.versions.version_cmp(
|
||||
server_version, mariadb_version_compare_binlog_monitor
|
||||
)
|
||||
>= 0
|
||||
):
|
||||
if token == "REPLICATION CLIENT":
|
||||
# https://mariadb.com/kb/en/grant/#replication-client
|
||||
resolved_tokens.append("BINLOG MONITOR")
|
||||
continue
|
||||
|
||||
if (
|
||||
salt.utils.versions.version_cmp(
|
||||
server_version, mariadb_version_compare_slave_monitor
|
||||
)
|
||||
>= 0
|
||||
):
|
||||
if token == "REPLICA MONITOR":
|
||||
# https://mariadb.com/kb/en/grant/#replica-monitor
|
||||
resolved_tokens.append("SLAVE MONITOR")
|
||||
continue
|
||||
|
||||
resolved_tokens.append(token)
|
||||
|
||||
return resolved_tokens
|
||||
|
||||
|
||||
def quote_identifier(identifier, for_grants=False):
|
||||
r"""
|
||||
Return an identifier name (column, table, database, etc) escaped for MySQL
|
||||
|
@ -2439,6 +2511,9 @@ def grant_exists(
|
|||
_grants = {}
|
||||
for grant in grants:
|
||||
grant_token = _grant_to_tokens(grant)
|
||||
grant_token["grant"] = _resolve_grant_aliases(
|
||||
grant_token["grant"], server_version
|
||||
)
|
||||
if grant_token["database"] not in _grants:
|
||||
_grants[grant_token["database"]] = {
|
||||
"user": grant_token["user"],
|
||||
|
@ -2450,6 +2525,9 @@ def grant_exists(
|
|||
_grants[grant_token["database"]]["grant"].extend(grant_token["grant"])
|
||||
|
||||
target_tokens = _grant_to_tokens(target)
|
||||
target_tokens["grant"] = _resolve_grant_aliases(
|
||||
target_tokens["grant"], server_version
|
||||
)
|
||||
for database, grant_tokens in _grants.items():
|
||||
try:
|
||||
_grant_tokens = {}
|
||||
|
|
|
@ -8,6 +8,7 @@ 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__)
|
||||
|
@ -297,6 +298,426 @@ def test_grant_add_revoke(mysql):
|
|||
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:
|
||||
|
|
Loading…
Add table
Reference in a new issue