"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "salt/modules/mysql.py" between
salt-3002.1.tar.gz and salt-3002.2.tar.gz

About: SaltStack is a systems management software for data center automation, cloud orchestration, server provisioning, configuration management and more. Community version.

mysql.py  (salt-3002.1):mysql.py  (salt-3002.2)
# -*- coding: utf-8 -*-
""" """
Module to provide MySQL compatibility to salt. Module to provide MySQL compatibility to salt.
:depends: - MySQLdb Python module :depends: - MySQLdb Python module
.. note:: .. note::
On CentOS 5 (and possibly RHEL 5) both MySQL-python and python26-mysqldb On CentOS 5 (and possibly RHEL 5) both MySQL-python and python26-mysqldb
need to be installed. need to be installed.
skipping to change at line 36 skipping to change at line 35
mysql.default_file: '/etc/mysql/debian.cnf' mysql.default_file: '/etc/mysql/debian.cnf'
.. versionchanged:: 2014.1.0 .. versionchanged:: 2014.1.0
\'charset\' connection argument added. This is a MySQL charset, not a python one. \'charset\' connection argument added. This is a MySQL charset, not a python one.
.. versionchanged:: 0.16.2 .. versionchanged:: 0.16.2
Connection arguments from the minion config file can be overridden on the Connection arguments from the minion config file can be overridden on the
CLI by using the arguments defined :mod:`here <salt.states.mysql_user>`. CLI by using the arguments defined :mod:`here <salt.states.mysql_user>`.
Additionally, it is now possible to setup a user with no password. Additionally, it is now possible to setup a user with no password.
""" """
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import copy import copy
import hashlib import hashlib
import logging import logging
import os import os
import re import re
import shlex import shlex
import sys import sys
import time import time
# Import salt libs
import salt.utils.data import salt.utils.data
import salt.utils.files import salt.utils.files
import salt.utils.stringutils import salt.utils.stringutils
# Import third party libs
from salt.ext import six
# pylint: disable=import-error # pylint: disable=import-error
from salt.ext.six.moves import range, zip from salt.ext.six.moves import range, zip
try: try:
# Trying to import MySQLdb # Trying to import MySQLdb
import MySQLdb import MySQLdb
import MySQLdb.cursors import MySQLdb.cursors
import MySQLdb.converters import MySQLdb.converters
from MySQLdb.constants import FIELD_TYPE, FLAG from MySQLdb.constants import FIELD_TYPE, FLAG
from MySQLdb import OperationalError from MySQLdb import OperationalError
skipping to change at line 262 skipping to change at line 254
''' '''
def __virtual__(): def __virtual__():
""" """
Confirm that a python mysql client is installed. Confirm that a python mysql client is installed.
""" """
return bool(MySQLdb), "No python mysql client installed." if MySQLdb is None else "" return bool(MySQLdb), "No python mysql client installed." if MySQLdb is None else ""
def __mysql_hash_password(password): def __mysql_hash_password(password):
_password = hashlib.sha1(password.encode()).digest() _password = hashlib.sha1(password.encode()).digest()
_password = "*{0}".format(hashlib.sha1(_password).hexdigest().upper()) _password = "*{}".format(hashlib.sha1(_password).hexdigest().upper())
return _password return _password
def __check_table(name, table, **connection_args): def __check_table(name, table, **connection_args):
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return {} return {}
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
s_name = quote_identifier(name) s_name = quote_identifier(name)
s_table = quote_identifier(table) s_table = quote_identifier(table)
# identifiers cannot be used as values # identifiers cannot be used as values
qry = "CHECK TABLE {0}.{1}".format(s_name, s_table) qry = "CHECK TABLE {}.{}".format(s_name, s_table)
_execute(cur, qry) _execute(cur, qry)
results = cur.fetchall() results = cur.fetchall()
log.debug(results) log.debug(results)
return results return results
def __repair_table(name, table, **connection_args): def __repair_table(name, table, **connection_args):
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return {} return {}
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
s_name = quote_identifier(name) s_name = quote_identifier(name)
s_table = quote_identifier(table) s_table = quote_identifier(table)
# identifiers cannot be used as values # identifiers cannot be used as values
qry = "REPAIR TABLE {0}.{1}".format(s_name, s_table) qry = "REPAIR TABLE {}.{}".format(s_name, s_table)
_execute(cur, qry) _execute(cur, qry)
results = cur.fetchall() results = cur.fetchall()
log.debug(results) log.debug(results)
return results return results
def __optimize_table(name, table, **connection_args): def __optimize_table(name, table, **connection_args):
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return {} return {}
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
s_name = quote_identifier(name) s_name = quote_identifier(name)
s_table = quote_identifier(table) s_table = quote_identifier(table)
# identifiers cannot be used as values # identifiers cannot be used as values
qry = "OPTIMIZE TABLE {0}.{1}".format(s_name, s_table) qry = "OPTIMIZE TABLE {}.{}".format(s_name, s_table)
_execute(cur, qry) _execute(cur, qry)
results = cur.fetchall() results = cur.fetchall()
log.debug(results) log.debug(results)
return results return results
def __password_column(**connection_args): def __password_column(**connection_args):
if "mysql.password_column" in __context__: if "mysql.password_column" in __context__:
return __context__["mysql.password_column"] return __context__["mysql.password_column"]
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
skipping to change at line 339 skipping to change at line 331
def __get_auth_plugin(user, host, **connection_args): def __get_auth_plugin(user, host, **connection_args):
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return [] return []
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
try: try:
qry = "SELECT plugin FROM mysql.user WHERE User=%(user)s and Host=%(host )s" qry = "SELECT plugin FROM mysql.user WHERE User=%(user)s and Host=%(host )s"
args = {"user": user, "host": host} args = {"user": user, "host": host}
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return "mysql_native_password" return "mysql_native_password"
results = cur.fetchall() results = cur.fetchall()
log.debug(results) log.debug(results)
if results: if results:
return results[0].get("plugin", "mysql_native_password") return results[0].get("plugin", "mysql_native_password")
else: else:
return "mysql_native_password" return "mysql_native_password"
skipping to change at line 379 skipping to change at line 371
if name in kwargs: if name in kwargs:
connargs[key] = kwargs[name] connargs[key] = kwargs[name]
elif get_opts: elif get_opts:
prefix = "connection_" prefix = "connection_"
if name.startswith(prefix): if name.startswith(prefix):
try: try:
name = name[len(prefix) :] name = name[len(prefix) :]
except IndexError: except IndexError:
return return
val = __salt__["config.option"]("mysql.{0}".format(name), None) val = __salt__["config.option"]("mysql.{}".format(name), None)
if val is not None: if val is not None:
connargs[key] = val connargs[key] = val
# If a default file is explicitly passed to kwargs, don't grab the # If a default file is explicitly passed to kwargs, don't grab the
# opts/pillar settings, as it can override info in the defaults file # opts/pillar settings, as it can override info in the defaults file
if "connection_default_file" in kwargs: if "connection_default_file" in kwargs:
get_opts = False get_opts = False
else: else:
get_opts = True get_opts = True
skipping to change at line 422 skipping to change at line 414
del connargs[key] del connargs[key]
if ( if (
connargs.get("passwd", True) is None connargs.get("passwd", True) is None
): # If present but set to None. (Extreme edge case.) ): # If present but set to None. (Extreme edge case.)
log.warning("MySQL password of None found. Attempting passwordless login .") log.warning("MySQL password of None found. Attempting passwordless login .")
connargs.pop("passwd") connargs.pop("passwd")
try: try:
dbc = MySQLdb.connect(**connargs) dbc = MySQLdb.connect(**connargs)
except OperationalError as exc: except OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return None return None
except MySQLdb.err.InternalError as exc: except MySQLdb.err.InternalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return None return None
dbc.autocommit(True) dbc.autocommit(True)
return dbc return dbc
def _grant_to_tokens(grant): def _grant_to_tokens(grant):
""" """
skipping to change at line 560 skipping to change at line 552
): ):
# End of token detected # End of token detected
if multiword_statement: if multiword_statement:
multiword_statement.append(token) multiword_statement.append(token)
grant_tokens.append(" ".join(multiword_statement)) grant_tokens.append(" ".join(multiword_statement))
multiword_statement = [] multiword_statement = []
else: else:
if not column: if not column:
current_grant = token current_grant = token
else: else:
token = "{0}.{1}".format(current_grant, token) token = "{}.{}".format(current_grant, token)
grant_tokens.append(token) grant_tokens.append(token)
else: # This is a multi-word, ala LOCK TABLES else: # This is a multi-word, ala LOCK TABLES
multiword_statement.append(token) multiword_statement.append(token)
elif phrase == "db": elif phrase == "db":
# the shlex splitter may have split on special database characters ` # the shlex splitter may have split on special database characters `
database += token database += token
# Read-ahead # Read-ahead
try: try:
if exploded_grant[position_tracker + 1] == ".": if exploded_grant[position_tracker + 1] == ".":
skipping to change at line 776 skipping to change at line 768
connection_args.update({"connection_db": database, "connection_conv": conv}) connection_args.update({"connection_db": database, "connection_conv": conv})
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return {} return {}
cur = dbc.cursor() cur = dbc.cursor()
start = time.time() start = time.time()
log.debug("Using db: %s to run query %s", database, query) log.debug("Using db: %s to run query %s", database, query)
try: try:
affected = _execute(cur, query) affected = _execute(cur, query)
except OperationalError as exc: except OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
results = cur.fetchall() results = cur.fetchall()
elapsed = time.time() - start elapsed = time.time() - start
if elapsed < 0.200: if elapsed < 0.200:
elapsed_h = str(round(elapsed * 1000, 1)) + "ms" elapsed_h = str(round(elapsed * 1000, 1)) + "ms"
else: else:
elapsed_h = str(round(elapsed, 2)) + "s" elapsed_h = str(round(elapsed, 2)) + "s"
skipping to change at line 885 skipping to change at line 877
ret["query time"]["raw"] += float(query_result["query time"]["ra w"]) ret["query time"]["raw"] += float(query_result["query time"]["ra w"])
if "rows returned" in query_result: if "rows returned" in query_result:
ret["rows returned"] += query_result["rows returned"] ret["rows returned"] += query_result["rows returned"]
if "columns" in query_result: if "columns" in query_result:
ret["columns"].append(query_result["columns"]) ret["columns"].append(query_result["columns"])
if "results" in query_result: if "results" in query_result:
ret["results"].append(query_result["results"]) ret["results"].append(query_result["results"])
if "rows affected" in query_result: if "rows affected" in query_result:
ret["rows affected"] += query_result["rows affected"] ret["rows affected"] += query_result["rows affected"]
ret["query time"]["human"] = ( ret["query time"]["human"] = str(round(float(ret["query time"]["raw"]), 2))
six.text_type(round(float(ret["query time"]["raw"]), 2)) + "s" + "s"
)
ret["query time"]["raw"] = round(float(ret["query time"]["raw"]), 5) ret["query time"]["raw"] = round(float(ret["query time"]["raw"]), 5)
"s"
# Remove empty keys in ret # Remove empty keys in ret
ret = {k: v for k, v in six.iteritems(ret) if v} ret = {k: v for k, v in ret.items() if v}
return ret return ret
def status(**connection_args): def status(**connection_args):
""" """
Return the status of a MySQL server using the output from the ``SHOW Return the status of a MySQL server using the output from the ``SHOW
STATUS`` query. STATUS`` query.
CLI Example: CLI Example:
skipping to change at line 914 skipping to change at line 904
salt '*' mysql.status salt '*' mysql.status
""" """
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return {} return {}
cur = dbc.cursor() cur = dbc.cursor()
qry = "SHOW STATUS" qry = "SHOW STATUS"
try: try:
_execute(cur, qry) _execute(cur, qry)
except OperationalError as exc: except OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return {} return {}
ret = {} ret = {}
for _ in range(cur.rowcount): for _ in range(cur.rowcount):
row = cur.fetchone() row = cur.fetchone()
ret[row[0]] = row[1] ret[row[0]] = row[1]
return ret return ret
skipping to change at line 947 skipping to change at line 937
return __context__["mysql.version"] return __context__["mysql.version"]
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return "" return ""
cur = dbc.cursor() cur = dbc.cursor()
qry = "SELECT VERSION()" qry = "SELECT VERSION()"
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return "" return ""
try: try:
__context__["mysql.version"] = salt.utils.data.decode(cur.fetchone()[0]) __context__["mysql.version"] = salt.utils.data.decode(cur.fetchone()[0])
return __context__["mysql.version"] return __context__["mysql.version"]
except IndexError: except IndexError:
return "" return ""
skipping to change at line 980 skipping to change at line 970
salt '*' mysql.slave_lag salt '*' mysql.slave_lag
""" """
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return -3 return -3
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
qry = "show slave status" qry = "show slave status"
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return -3 return -3
results = cur.fetchone() results = cur.fetchone()
if cur.rowcount == 0: if cur.rowcount == 0:
# Server is not a slave if master is not defined. Return empty tuple # Server is not a slave if master is not defined. Return empty tuple
# in this case. Could probably check to see if Slave_IO_Running and # in this case. Could probably check to see if Slave_IO_Running and
# Slave_SQL_Running are both set to 'Yes' as well to be really really # Slave_SQL_Running are both set to 'Yes' as well to be really really
# sure that it is a slave. # sure that it is a slave.
skipping to change at line 1063 skipping to change at line 1053
salt '*' mysql.db_list salt '*' mysql.db_list
""" """
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return [] return []
cur = dbc.cursor() cur = dbc.cursor()
qry = "SHOW DATABASES" qry = "SHOW DATABASES"
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return [] return []
ret = [] ret = []
results = cur.fetchall() results = cur.fetchall()
for dbs in results: for dbs in results:
ret.append(dbs[0]) ret.append(dbs[0])
log.debug(ret) log.debug(ret)
skipping to change at line 1092 skipping to change at line 1082
.. code-block:: bash .. code-block:: bash
salt '*' mysql.alter_db testdb charset='latin1' salt '*' mysql.alter_db testdb charset='latin1'
""" """
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return [] return []
cur = dbc.cursor() cur = dbc.cursor()
existing = db_get(name, **connection_args) existing = db_get(name, **connection_args)
qry = "ALTER DATABASE `{0}` CHARACTER SET {1} COLLATE {2};".format( qry = "ALTER DATABASE `{}` CHARACTER SET {} COLLATE {};".format(
name.replace("%", r"\%").replace("_", r"\_"), name.replace("%", r"\%").replace("_", r"\_"),
character_set or existing.get("character_set"), character_set or existing.get("character_set"),
collate or existing.get("collate"), collate or existing.get("collate"),
) )
args = {} args = {}
_execute(cur, qry, args) _execute(cur, qry, args)
def db_get(name, **connection_args): def db_get(name, **connection_args):
""" """
Return a list of databases of a MySQL server using the output Return a list of databases of a MySQL server using the output
skipping to change at line 1147 skipping to change at line 1137
if not db_exists(name, **connection_args): if not db_exists(name, **connection_args):
log.info("Database '%s' does not exist", name) log.info("Database '%s' does not exist", name)
return False return False
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return [] return []
cur = dbc.cursor() cur = dbc.cursor()
s_name = quote_identifier(name) s_name = quote_identifier(name)
# identifiers cannot be used as values # identifiers cannot be used as values
qry = "SHOW TABLES IN {0}".format(s_name) qry = "SHOW TABLES IN {}".format(s_name)
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return [] return []
ret = [] ret = []
results = cur.fetchall() results = cur.fetchall()
for table in results: for table in results:
ret.append(table[0]) ret.append(table[0])
log.debug(ret) log.debug(ret)
return ret return ret
skipping to change at line 1185 skipping to change at line 1175
return False return False
cur = dbc.cursor() cur = dbc.cursor()
# Warn: here db identifier is not backtyped but should be # Warn: here db identifier is not backtyped but should be
# escaped as a string value. Note also that LIKE special characters # escaped as a string value. Note also that LIKE special characters
# '_' and '%' should also be escaped. # '_' and '%' should also be escaped.
args = {"dbname": name} args = {"dbname": name}
qry = "SHOW DATABASES LIKE %(dbname)s;" qry = "SHOW DATABASES LIKE %(dbname)s;"
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
cur.fetchall() cur.fetchall()
return cur.rowcount == 1 return cur.rowcount == 1
def db_create(name, character_set=None, collate=None, **connection_args): def db_create(name, character_set=None, collate=None, **connection_args):
""" """
Adds a databases to the MySQL server. Adds a databases to the MySQL server.
skipping to change at line 1224 skipping to change at line 1214
log.info("DB '%s' already exists", name) log.info("DB '%s' already exists", name)
return False return False
# db doesn't exist, proceed # db doesn't exist, proceed
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
cur = dbc.cursor() cur = dbc.cursor()
s_name = quote_identifier(name) s_name = quote_identifier(name)
# identifiers cannot be used as values # identifiers cannot be used as values
qry = "CREATE DATABASE IF NOT EXISTS {0}".format(s_name) qry = "CREATE DATABASE IF NOT EXISTS {}".format(s_name)
args = {} args = {}
if character_set is not None: if character_set is not None:
qry += " CHARACTER SET %(character_set)s" qry += " CHARACTER SET %(character_set)s"
args["character_set"] = character_set args["character_set"] = character_set
if collate is not None: if collate is not None:
qry += " COLLATE %(collate)s" qry += " COLLATE %(collate)s"
args["collate"] = collate args["collate"] = collate
qry += ";" qry += ";"
try: try:
if _execute(cur, qry, args): if _execute(cur, qry, args):
log.info("DB '%s' created", name) log.info("DB '%s' created", name)
return True return True
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
def db_remove(name, **connection_args): def db_remove(name, **connection_args):
""" """
Removes a databases from the MySQL server. Removes a databases from the MySQL server.
CLI Example: CLI Example:
skipping to change at line 1270 skipping to change at line 1260
log.info("DB '%s' may not be removed", name) log.info("DB '%s' may not be removed", name)
return False return False
# db does exists, proceed # db does exists, proceed
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
cur = dbc.cursor() cur = dbc.cursor()
s_name = quote_identifier(name) s_name = quote_identifier(name)
# identifiers cannot be used as values # identifiers cannot be used as values
qry = "DROP DATABASE {0};".format(s_name) qry = "DROP DATABASE {};".format(s_name)
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
if not db_exists(name, **connection_args): if not db_exists(name, **connection_args):
log.info("Database '%s' has been removed", name) log.info("Database '%s' has been removed", name)
return True return True
log.info("Database '%s' has not been removed", name) log.info("Database '%s' has not been removed", name)
return False return False
skipping to change at line 1305 skipping to change at line 1295
salt '*' mysql.user_list salt '*' mysql.user_list
""" """
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return [] return []
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
try: try:
qry = "SELECT User,Host FROM mysql.user" qry = "SELECT User,Host FROM mysql.user"
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return [] return []
results = cur.fetchall() results = cur.fetchall()
log.debug(results) log.debug(results)
return results return results
def _mysql_user_exists( def _mysql_user_exists(
user, user,
host="localhost", host="localhost",
skipping to change at line 1343 skipping to change at line 1333
if salt.utils.data.is_true(passwordless): if salt.utils.data.is_true(passwordless):
if salt.utils.data.is_true(unix_socket): if salt.utils.data.is_true(unix_socket):
qry += " AND plugin=%(unix_socket)s" qry += " AND plugin=%(unix_socket)s"
args["unix_socket"] = "auth_socket" args["unix_socket"] = "auth_socket"
else: else:
qry += " AND " + password_column + " = ''" qry += " AND " + password_column + " = ''"
elif password: elif password:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0 : if salt.utils.versions.version_cmp(server_version, compare_version) >= 0 :
if auth_plugin == "mysql_native_password": if auth_plugin == "mysql_native_password":
_password = __mysql_hash_password(six.text_type(password)) _password = __mysql_hash_password(str(password))
qry += " AND " + password_column + " = %(password)s" qry += " AND " + password_column + " = %(password)s"
args["password"] = six.text_type(_password) args["password"] = str(_password)
else: else:
err = "Unable to verify password." err = "Unable to verify password."
log.error(err) log.error(err)
__context__["mysql.error"] = err __context__["mysql.error"] = err
else: else:
qry += " AND " + password_column + " = PASSWORD(%(password)s)" qry += " AND " + password_column + " = PASSWORD(%(password)s)"
args["password"] = six.text_type(password) args["password"] = str(password)
elif password_hash: elif password_hash:
qry += " AND " + password_column + " = %(password)s" qry += " AND " + password_column + " = %(password)s"
args["password"] = password_hash args["password"] = password_hash
return qry, args return qry, args
def _mariadb_user_exists( def _mariadb_user_exists(
user, user,
host="localhost", host="localhost",
password=None, password=None,
skipping to change at line 1386 skipping to change at line 1376
args["host"] = host args["host"] = host
if salt.utils.data.is_true(passwordless): if salt.utils.data.is_true(passwordless):
if salt.utils.data.is_true(unix_socket): if salt.utils.data.is_true(unix_socket):
qry += " AND plugin=%(unix_socket)s" qry += " AND plugin=%(unix_socket)s"
args["unix_socket"] = "unix_socket" args["unix_socket"] = "unix_socket"
else: else:
qry += " AND " + password_column + " = ''" qry += " AND " + password_column + " = ''"
elif password: elif password:
qry += " AND " + password_column + " = PASSWORD(%(password)s)" qry += " AND " + password_column + " = PASSWORD(%(password)s)"
args["password"] = six.text_type(password) args["password"] = str(password)
elif password_hash: elif password_hash:
qry += " AND " + password_column + " = %(password)s" qry += " AND " + password_column + " = %(password)s"
args["password"] = password_hash args["password"] = password_hash
return qry, args return qry, args
def user_exists( def user_exists(
user, user,
host="localhost", host="localhost",
password=None, password=None,
skipping to change at line 1422 skipping to change at line 1412
.. code-block:: bash .. code-block:: bash
salt '*' mysql.user_exists 'username' 'hostname' 'password' salt '*' mysql.user_exists 'username' 'hostname' 'password'
salt '*' mysql.user_exists 'username' 'hostname' password_hash='hash' salt '*' mysql.user_exists 'username' 'hostname' password_hash='hash'
salt '*' mysql.user_exists 'username' passwordless=True salt '*' mysql.user_exists 'username' passwordless=True
salt '*' mysql.user_exists 'username' password_column='authentication_st ring' salt '*' mysql.user_exists 'username' password_column='authentication_st ring'
""" """
run_verify = False run_verify = False
server_version = salt.utils.data.decode(version(**connection_args)) server_version = salt.utils.data.decode(version(**connection_args))
if not server_version: if not server_version and password:
last_err = __context__["mysql.error"] # Did we fail to connect with the user we are checking
err = 'MySQL Error: Unable to fetch current server version. Last error w # Its password might have previously change with the same command/state
as: "{}"'.format(
last_err # Clear the previous error
) __context__["mysql.error"] = None
log.error(err) connection_args["connection_pass"] = password
return False
server_version = salt.utils.data.decode(version(**connection_args))
if not server_version:
last_err = __context__["mysql.error"]
err = 'MySQL Error: Unable to fetch current server version. Last err
or was: "{}"'.format(
last_err
)
log.error(err)
return False
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
# Did we fail to connect with the user we are checking # Did we fail to connect with the user we are checking
# Its password might have previously change with the same command/state # Its password might have previously change with the same command/state
if ( if (
dbc is None dbc is None
and __context__["mysql.error"].startswith( and __context__["mysql.error"].startswith(
"MySQL Error 1045: Access denied for user '{0}'@".format(user) "MySQL Error 1045: Access denied for user '{}'@".format(user)
) )
and password and password
): ):
# Clear the previous error # Clear the previous error
__context__["mysql.error"] = None __context__["mysql.error"] = None
connection_args["connection_pass"] = password connection_args["connection_pass"] = password
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
skipping to change at line 1480 skipping to change at line 1480
passwordless, passwordless,
unix_socket, unix_socket,
password_column=password_column, password_column=password_column,
auth_plugin=auth_plugin, auth_plugin=auth_plugin,
**connection_args **connection_args
) )
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
return cur.rowcount == 1 return cur.rowcount == 1
def user_info(user, host="localhost", **connection_args): def user_info(user, host="localhost", **connection_args):
""" """
Get full info on a MySQL user Get full info on a MySQL user
skipping to change at line 1510 skipping to change at line 1510
cur = dbc.cursor(MySQLdb.cursors.DictCursor) cur = dbc.cursor(MySQLdb.cursors.DictCursor)
qry = "SELECT * FROM mysql.user WHERE User = %(user)s AND " "Host = %(host)s " qry = "SELECT * FROM mysql.user WHERE User = %(user)s AND " "Host = %(host)s "
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
result = cur.fetchone() result = cur.fetchone()
log.debug(result) log.debug(result)
return result return result
def _mysql_user_create( def _mysql_user_create(
user, user,
host="localhost", host="localhost",
skipping to change at line 1543 skipping to change at line 1543
qry = "CREATE USER %(user)s@%(host)s" qry = "CREATE USER %(user)s@%(host)s"
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
if password is not None: if password is not None:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0 : if salt.utils.versions.version_cmp(server_version, compare_version) >= 0 :
args["auth_plugin"] = auth_plugin args["auth_plugin"] = auth_plugin
qry += " IDENTIFIED WITH %(auth_plugin)s BY %(password)s" qry += " IDENTIFIED WITH %(auth_plugin)s BY %(password)s"
else: else:
qry += " IDENTIFIED BY %(password)s" qry += " IDENTIFIED BY %(password)s"
args["password"] = six.text_type(password) args["password"] = str(password)
elif password_hash is not None: elif password_hash is not None:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0 : if salt.utils.versions.version_cmp(server_version, compare_version) >= 0 :
qry += " IDENTIFIED BY %(password)s" qry += " IDENTIFIED BY %(password)s"
else: else:
qry += " IDENTIFIED BY PASSWORD %(password)s" qry += " IDENTIFIED BY PASSWORD %(password)s"
args["password"] = password_hash args["password"] = password_hash
elif salt.utils.data.is_true(allow_passwordless): elif salt.utils.data.is_true(allow_passwordless):
if not plugin_status("auth_socket", **connection_args): if not plugin_status("auth_socket", **connection_args):
err = "The auth_socket plugin is not enabled." err = "The auth_socket plugin is not enabled."
log.error(err) log.error(err)
skipping to change at line 1589 skipping to change at line 1589
auth_plugin="mysql_native_password", auth_plugin="mysql_native_password",
**connection_args **connection_args
): ):
qry = "CREATE USER %(user)s@%(host)s" qry = "CREATE USER %(user)s@%(host)s"
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
if password is not None: if password is not None:
qry += " IDENTIFIED BY %(password)s" qry += " IDENTIFIED BY %(password)s"
args["password"] = six.text_type(password) args["password"] = str(password)
elif password_hash is not None: elif password_hash is not None:
qry += " IDENTIFIED BY PASSWORD %(password)s" qry += " IDENTIFIED BY PASSWORD %(password)s"
args["password"] = password_hash args["password"] = password_hash
elif salt.utils.data.is_true(allow_passwordless): elif salt.utils.data.is_true(allow_passwordless):
if not plugin_status("unix_socket", **connection_args): if not plugin_status("unix_socket", **connection_args):
err = "The unix_socket plugin is not enabled." err = "The unix_socket plugin is not enabled."
log.error(err) log.error(err)
__context__["mysql.error"] = err __context__["mysql.error"] = err
qry = False qry = False
else: else:
skipping to change at line 1673 skipping to change at line 1673
CLI Examples: CLI Examples:
.. code-block:: bash .. code-block:: bash
salt '*' mysql.user_create 'username' 'hostname' 'password' salt '*' mysql.user_create 'username' 'hostname' 'password'
salt '*' mysql.user_create 'username' 'hostname' password_hash='hash' salt '*' mysql.user_create 'username' 'hostname' password_hash='hash'
salt '*' mysql.user_create 'username' 'hostname' allow_passwordless=True salt '*' mysql.user_create 'username' 'hostname' allow_passwordless=True
""" """
server_version = salt.utils.data.decode(version(**connection_args)) server_version = salt.utils.data.decode(version(**connection_args))
if not server_version: if not server_version and password:
last_err = __context__["mysql.error"] # Did we fail to connect with the user we are checking
err = 'MySQL Error: Unable to fetch current server version. Last error w # Its password might have previously change with the same command/state
as: "{}"'.format(
last_err # Clear the previous error
) __context__["mysql.error"] = None
log.error(err) connection_args["connection_pass"] = password
return False
server_version = salt.utils.data.decode(version(**connection_args))
if not server_version:
last_err = __context__["mysql.error"]
err = 'MySQL Error: Unable to fetch current server version. Last err
or was: "{}"'.format(
last_err
)
log.error(err)
return False
if user_exists(user, host, **connection_args): if user_exists(user, host, **connection_args):
log.info("User '%s'@'%s' already exists", user, host) log.info("User '%s'@'%s' already exists", user, host)
return False return False
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
if not password_column: if not password_column:
skipping to change at line 1724 skipping to change at line 1733
auth_plugin=auth_plugin, auth_plugin=auth_plugin,
**connection_args **connection_args
) )
if isinstance(qry, bool): if isinstance(qry, bool):
return qry return qry
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
if user_exists( if user_exists(
user, user,
host, host,
password, password,
password_hash, password_hash,
password_column=password_column, password_column=password_column,
**connection_args **connection_args
): ):
msg = "User '{0}'@'{1}' has been created".format(user, host) msg = "User '{}'@'{}' has been created".format(user, host)
if not any((password, password_hash)): if not any((password, password_hash)):
msg += " with passwordless login" msg += " with passwordless login"
log.info(msg) log.info(msg)
return True return True
log.info("User '%s'@'%s' was not created", user, host) log.info("User '%s'@'%s' was not created", user, host)
return False return False
def _mysql_user_chpass( def _mysql_user_chpass(
user, user,
skipping to change at line 1941 skipping to change at line 1950
CLI Examples: CLI Examples:
.. code-block:: bash .. code-block:: bash
salt '*' mysql.user_chpass frank localhost newpassword salt '*' mysql.user_chpass frank localhost newpassword
salt '*' mysql.user_chpass frank localhost password_hash='hash' salt '*' mysql.user_chpass frank localhost password_hash='hash'
salt '*' mysql.user_chpass frank localhost allow_passwordless=True salt '*' mysql.user_chpass frank localhost allow_passwordless=True
""" """
server_version = salt.utils.data.decode(version(**connection_args)) server_version = salt.utils.data.decode(version(**connection_args))
if not server_version: if not server_version and password:
last_err = __context__["mysql.error"] # Did we fail to connect with the user we are checking
err = 'MySQL Error: Unable to fetch current server version. Last error w # Its password might have previously change with the same command/state
as: "{}"'.format(
last_err # Clear the previous error
) __context__["mysql.error"] = None
log.error(err) connection_args["connection_pass"] = password
return False
server_version = salt.utils.data.decode(version(**connection_args))
if not server_version:
last_err = __context__["mysql.error"]
err = 'MySQL Error: Unable to fetch current server version. Last err
or was: "{}"'.format(
last_err
)
log.error(err)
return False
if not user_exists(user, host, **connection_args): if not user_exists(user, host, **connection_args):
log.info("User '%s'@'%s' does not exists", user, host) log.info("User '%s'@'%s' does not exists", user, host)
return False return False
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
skipping to change at line 1993 skipping to change at line 2011
allow_passwordless, allow_passwordless,
unix_socket, unix_socket,
password_column=password_column, password_column=password_column,
auth_plugin=auth_plugin, auth_plugin=auth_plugin,
**connection_args **connection_args
) )
try: try:
result = _execute(cur, qry, args) result = _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
compare_version = "10.4.0" if "MariaDB" in server_version else "8.0.11" compare_version = "10.4.0" if "MariaDB" in server_version else "8.0.11"
res = False res = False
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0: if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
_execute(cur, "FLUSH PRIVILEGES;") _execute(cur, "FLUSH PRIVILEGES;")
res = True res = True
else: else:
skipping to change at line 2053 skipping to change at line 2071
return False return False
cur = dbc.cursor() cur = dbc.cursor()
qry = "DROP USER %(user)s@%(host)s" qry = "DROP USER %(user)s@%(host)s"
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
if not user_exists(user, host, **connection_args): if not user_exists(user, host, **connection_args):
log.info("User '%s'@'%s' has been removed", user, host) log.info("User '%s'@'%s' has been removed", user, host)
return True return True
log.info("User '%s'@'%s' has NOT been removed", user, host) log.info("User '%s'@'%s' has NOT been removed", user, host)
return False return False
skipping to change at line 2159 skipping to change at line 2177
def __grant_normalize(grant): def __grant_normalize(grant):
# MySQL normalizes ALL to ALL PRIVILEGES, we do the same so that # MySQL normalizes ALL to ALL PRIVILEGES, we do the same so that
# grant_exists and grant_add ALL work correctly # grant_exists and grant_add ALL work correctly
if grant.strip().upper() == "ALL": if grant.strip().upper() == "ALL":
grant = "ALL PRIVILEGES" grant = "ALL PRIVILEGES"
# Grants are paste directly in SQL, must filter it # Grants are paste directly in SQL, must filter it
exploded_grants = __grant_split(grant) exploded_grants = __grant_split(grant)
for chkgrant, _ in exploded_grants: for chkgrant, _ in exploded_grants:
if chkgrant.strip().upper() not in __grants__: if chkgrant.strip().upper() not in __grants__:
raise Exception("Invalid grant : '{0}'".format(chkgrant)) raise Exception("Invalid grant : '{}'".format(chkgrant))
return grant return grant
def __grant_split(grant): def __grant_split(grant):
pattern = re.compile(r"([\w\s]+)(\([^)(]*\))?\s*,?") pattern = re.compile(r"([\w\s]+)(\([^)(]*\))?\s*,?")
return pattern.findall(grant) return pattern.findall(grant)
def __ssl_option_sanitize(ssl_option): def __ssl_option_sanitize(ssl_option):
new_ssl_option = [] new_ssl_option = []
# Like most other "salt dsl" YAML structures, ssl_option is a list of single -element dicts # Like most other "salt dsl" YAML structures, ssl_option is a list of single -element dicts
for opt in ssl_option: for opt in ssl_option:
key = next(six.iterkeys(opt)) key = next(iter(opt.keys()))
normal_key = key.strip().upper() normal_key = key.strip().upper()
if normal_key not in __ssl_options__: if normal_key not in __ssl_options__:
raise Exception("Invalid SSL option : '{0}'".format(key)) raise Exception("Invalid SSL option : '{}'".format(key))
if normal_key in __ssl_options_parameterized__: if normal_key in __ssl_options_parameterized__:
# SSL option parameters (cipher, issuer, subject) are pasted directl y to SQL so # SSL option parameters (cipher, issuer, subject) are pasted directl y to SQL so
# we need to sanitize for single quotes... # we need to sanitize for single quotes...
new_ssl_option.append( new_ssl_option.append(
"{0} '{1}'".format(normal_key, opt[key].replace("'", "")) "{} '{}'".format(normal_key, opt[key].replace("'", ""))
) )
# omit if falsey # omit if falsey
elif opt[key]: elif opt[key]:
new_ssl_option.append(normal_key) new_ssl_option.append(normal_key)
return " REQUIRE " + " AND ".join(new_ssl_option) return " REQUIRE " + " AND ".join(new_ssl_option)
def __grant_generate( def __grant_generate(
grant, grant,
database, database,
skipping to change at line 2224 skipping to change at line 2242
table = db_part[2] table = db_part[2]
if escape: if escape:
if dbc != "*": if dbc != "*":
# _ and % are authorized on GRANT queries and should get escaped # _ and % are authorized on GRANT queries and should get escaped
# on the db name, but only if not requesting a table level grant # on the db name, but only if not requesting a table level grant
dbc = quote_identifier(dbc, for_grants=(table == "*")) dbc = quote_identifier(dbc, for_grants=(table == "*"))
if table != "*": if table != "*":
table = quote_identifier(table) table = quote_identifier(table)
# identifiers cannot be used as values, and same thing for grants # identifiers cannot be used as values, and same thing for grants
qry = "GRANT {0} ON {1}.{2} TO %(user)s@%(host)s".format(grant, dbc, table) qry = "GRANT {} ON {}.{} TO %(user)s@%(host)s".format(grant, dbc, table)
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
if ssl_option and isinstance(ssl_option, list): if ssl_option and isinstance(ssl_option, list):
qry += __ssl_option_sanitize(ssl_option) qry += __ssl_option_sanitize(ssl_option)
if salt.utils.data.is_true(grant_option): if salt.utils.data.is_true(grant_option):
qry += " WITH GRANT OPTION" qry += " WITH GRANT OPTION"
log.debug("Grant Query generated: %s args %s", qry, repr(args)) log.debug("Grant Query generated: %s args %s", qry, repr(args))
return {"qry": qry, "args": args} return {"qry": qry, "args": args}
skipping to change at line 2260 skipping to change at line 2278
if dbc is None: if dbc is None:
return False return False
cur = dbc.cursor() cur = dbc.cursor()
qry = "SHOW GRANTS FOR %(user)s@%(host)s" qry = "SHOW GRANTS FOR %(user)s@%(host)s"
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
ret = [] ret = []
results = salt.utils.data.decode(cur.fetchall()) results = salt.utils.data.decode(cur.fetchall())
for grant in results: for grant in results:
tmp = grant[0].split(" IDENTIFIED BY")[0] tmp = grant[0].split(" IDENTIFIED BY")[0]
if "WITH GRANT OPTION" in grant[0] and "WITH GRANT OPTION" not in tmp: if "WITH GRANT OPTION" in grant[0] and "WITH GRANT OPTION" not in tmp:
tmp = "{0} WITH GRANT OPTION".format(tmp) tmp = "{} WITH GRANT OPTION".format(tmp)
ret.append(tmp) ret.append(tmp)
log.debug(ret) log.debug(ret)
return ret return ret
def grant_exists( def grant_exists(
grant, grant,
database, database,
user, user,
host="localhost", host="localhost",
grant_option=False, grant_option=False,
skipping to change at line 2425 skipping to change at line 2443
try: try:
qry = __grant_generate( qry = __grant_generate(
grant, database, user, host, grant_option, escape, ssl_option grant, database, user, host, grant_option, escape, ssl_option
) )
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
log.error("Error during grant generation") log.error("Error during grant generation")
return False return False
try: try:
_execute(cur, qry["qry"], qry["args"]) _execute(cur, qry["qry"], qry["args"])
except (MySQLdb.OperationalError, MySQLdb.ProgrammingError) as exc: except (MySQLdb.OperationalError, MySQLdb.ProgrammingError) as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
if grant_exists( if grant_exists(
grant, database, user, host, grant_option, escape, **connection_args grant, database, user, host, grant_option, escape, **connection_args
): ):
log.info( log.info(
"Grant '%s' on '%s' for user '%s' has been added", grant, database, user "Grant '%s' on '%s' for user '%s' has been added", grant, database, user
) )
return True return True
skipping to change at line 2486 skipping to change at line 2504
# on the db name, but only if not requesting a table level grant # on the db name, but only if not requesting a table level grant
s_database = quote_identifier(dbc, for_grants=(table == "*")) s_database = quote_identifier(dbc, for_grants=(table == "*"))
if dbc == "*": if dbc == "*":
# add revoke for *.* # add revoke for *.*
# before the modification query send to mysql will looks like # before the modification query send to mysql will looks like
# REVOKE SELECT ON `*`.* FROM %(user)s@%(host)s # REVOKE SELECT ON `*`.* FROM %(user)s@%(host)s
s_database = dbc s_database = dbc
if table != "*": if table != "*":
table = quote_identifier(table) table = quote_identifier(table)
# identifiers cannot be used as values, same thing for grants # identifiers cannot be used as values, same thing for grants
qry = "REVOKE {0} ON {1}.{2} FROM %(user)s@%(host)s;".format( qry = "REVOKE {} ON {}.{} FROM %(user)s@%(host)s;".format(grant, s_database,
grant, s_database, table table)
)
args = {} args = {}
args["user"] = user args["user"] = user
args["host"] = host args["host"] = host
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
if not grant_exists( if not grant_exists(
grant, database, user, host, grant_option, escape, **connection_args grant, database, user, host, grant_option, escape, **connection_args
): ):
log.info( log.info(
"Grant '%s' on '%s' for user '%s' has been " "revoked", "Grant '%s' on '%s' for user '%s' has been " "revoked",
grant, grant,
skipping to change at line 2809 skipping to change at line 2825
salt '*' mysql.plugins_list salt '*' mysql.plugins_list
""" """
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return [] return []
cur = dbc.cursor() cur = dbc.cursor()
qry = "SHOW PLUGINS" qry = "SHOW PLUGINS"
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return [] return []
ret = [] ret = []
results = cur.fetchall() results = cur.fetchall()
for dbs in results: for dbs in results:
ret.append({"name": dbs[0], "status": dbs[1]}) ret.append({"name": dbs[0], "status": dbs[1]})
log.debug(ret) log.debug(ret)
skipping to change at line 2844 skipping to change at line 2860
return False return False
if plugin_status(name, **connection_args): if plugin_status(name, **connection_args):
log.error("Plugin %s is already installed.", name) log.error("Plugin %s is already installed.", name)
return True return True
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
cur = dbc.cursor() cur = dbc.cursor()
qry = "INSTALL PLUGIN {0}".format(name) qry = "INSTALL PLUGIN {}".format(name)
if soname: if soname:
qry += ' SONAME "{0}"'.format(soname) qry += ' SONAME "{}"'.format(soname)
else: else:
qry += ' SONAME "{0}.so"'.format(name) qry += ' SONAME "{}.so"'.format(name)
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
return True return True
def plugin_remove(name, **connection_args): def plugin_remove(name, **connection_args):
""" """
Remove a plugin. Remove a plugin.
skipping to change at line 2883 skipping to change at line 2899
return False return False
if not plugin_status(name, **connection_args): if not plugin_status(name, **connection_args):
log.error("Plugin %s is not installed.", name) log.error("Plugin %s is not installed.", name)
return True return True
dbc = _connect(**connection_args) dbc = _connect(**connection_args)
if dbc is None: if dbc is None:
return False return False
cur = dbc.cursor() cur = dbc.cursor()
qry = "UNINSTALL PLUGIN {0}".format(name) qry = "UNINSTALL PLUGIN {}".format(name)
args = {} args = {}
args["name"] = name args["name"] = name
try: try:
_execute(cur, qry) _execute(cur, qry)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return False return False
return True return True
def plugin_status(name, **connection_args): def plugin_status(name, **connection_args):
""" """
Return the status of a plugin. Return the status of a plugin.
skipping to change at line 2922 skipping to change at line 2938
if dbc is None: if dbc is None:
return "" return ""
cur = dbc.cursor() cur = dbc.cursor()
qry = "SELECT PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAM E = %(name)s" qry = "SELECT PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAM E = %(name)s"
args = {} args = {}
args["name"] = name args["name"] = name
try: try:
_execute(cur, qry, args) _execute(cur, qry, args)
except MySQLdb.OperationalError as exc: except MySQLdb.OperationalError as exc:
err = "MySQL Error {0}: {1}".format(*exc.args) err = "MySQL Error {}: {}".format(*exc.args)
__context__["mysql.error"] = err __context__["mysql.error"] = err
log.error(err) log.error(err)
return "" return ""
try: try:
status = cur.fetchone() status = cur.fetchone()
if status is None: if status is None:
return "" return ""
else: else:
return status[0] return status[0]
 End of changes. 64 change blocks. 
92 lines changed or deleted 111 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)