Mini Shell
"""
Management of MySQL users
=========================
:depends: - MySQLdb Python module
:configuration: See :py:mod:`salt.modules.mysql` for setup instructions.
.. code-block:: yaml
frank:
mysql_user.present:
- host: localhost
- password: bobcat
.. versionadded:: 0.16.2
Authentication overrides have been added.
The MySQL authentication information specified in the minion config file can be
overridden in states using the following arguments: ``connection_host``,
``connection_port``, ``connection_user``, ``connection_pass``,
``connection_db``, ``connection_unix_socket``, ``connection_default_file`` and
``connection_charset``.
.. code-block:: yaml
frank:
mysql_user.present:
- host: localhost
- password: "bob@cat"
- connection_user: someuser
- connection_pass: somepass
- connection_charset: utf8
- saltenv:
- LC_ALL: "en_US.utf8"
This state is not able to grant permissions for the user. See
:py:mod:`salt.states.mysql_grants` for further instructions.
"""
import sys
import salt.utils.data
def __virtual__():
"""
Only load if the mysql module is in __salt__
"""
if "mysql.user_create" in __salt__:
return True
return (False, "mysql module could not be loaded")
def _get_mysql_error():
"""
Look in module context for a MySQL error. Eventually we should make a less
ugly way of doing this.
"""
return sys.modules[__salt__["test.ping"].__module__].__context__.pop(
"mysql.error", None
)
def present(
name,
host="localhost",
password=None,
password_hash=None,
allow_passwordless=False,
unix_socket=False,
password_column=None,
auth_plugin="mysql_native_password",
**connection_args,
):
"""
Ensure that the named user is present with the specified properties. A
passwordless user can be configured by omitting ``password`` and
``password_hash``, and setting ``allow_passwordless`` to ``True``.
name
The name of the user to manage
host
Host for which this user/password combo applies
password
The password to use for this user. Will take precedence over the
``password_hash`` option if both are specified.
password_hash
The password in hashed form. Be sure to quote the password because YAML
doesn't like the ``*``. A password hash can be obtained from the mysql
command-line client like so::
mysql> SELECT PASSWORD('mypass');
+-------------------------------------------+
| PASSWORD('mypass') |
+-------------------------------------------+
| *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
+-------------------------------------------+
1 row in set (0.00 sec)
allow_passwordless
If ``True``, then ``password`` and ``password_hash`` can be omitted to
permit a passwordless login.
.. versionadded:: 0.16.2
unix_socket
If ``True`` and allow_passwordless is ``True``, the unix_socket auth
plugin will be used.
"""
ret = {
"name": name,
"changes": {},
"result": True,
"comment": f"User {name}@{host} is already present",
}
passwordless = not any((password, password_hash))
# check if user exists with the same password (or passwordless login)
if passwordless:
if not salt.utils.data.is_true(allow_passwordless) and not unix_socket:
ret["comment"] = (
"Either password or password_hash must be "
"specified, unless allow_passwordless is True"
)
ret["result"] = False
return ret
else:
if __salt__["mysql.user_exists"](
name,
host,
passwordless=True,
unix_socket=unix_socket,
password_column=password_column,
**connection_args,
):
if allow_passwordless:
ret["comment"] += " with passwordless login"
return ret
else:
err = _get_mysql_error()
if err is not None:
ret["comment"] = err
ret["result"] = False
return ret
else:
if __salt__["mysql.user_exists"](
name,
host,
password,
password_hash,
unix_socket=unix_socket,
password_column=password_column,
**connection_args,
):
if auth_plugin == "mysql_native_password":
ret["comment"] += " with the desired password"
if password_hash and not password:
ret["comment"] += " hash"
else:
ret["comment"] += ". Unable to verify password."
return ret
else:
err = _get_mysql_error()
if err is not None:
ret["comment"] = err
ret["result"] = False
return ret
# check if user exists with a different password
if __salt__["mysql.user_exists"](
name, host, unix_socket=unix_socket, **connection_args
):
# The user is present, change the password
if __opts__["test"]:
ret["comment"] = f"Password for user {name}@{host} is set to be "
ret["result"] = None
if passwordless:
ret["comment"] += "cleared"
if not salt.utils.data.is_true(allow_passwordless):
ret["comment"] += ", but allow_passwordless != True"
ret["result"] = False
else:
ret["comment"] += "changed"
return ret
if __salt__["mysql.user_chpass"](
name,
host,
password,
password_hash,
allow_passwordless,
unix_socket,
**connection_args,
):
ret["comment"] = "Password for user {}@{} has been {}".format(
name, host, "cleared" if passwordless else "changed"
)
ret["changes"][name] = "Updated"
else:
ret["comment"] = "Failed to {} password for user {}@{}".format(
"clear" if passwordless else "change", name, host
)
err = _get_mysql_error()
if err is not None:
ret["comment"] += f" ({err})"
if passwordless and not salt.utils.data.is_true(allow_passwordless):
ret["comment"] += (
". Note: allow_passwordless must be True "
"to permit passwordless login."
)
ret["result"] = False
else:
err = _get_mysql_error()
if err is not None:
ret["comment"] = err
ret["result"] = False
return ret
# The user is not present, make it!
if __opts__["test"]:
ret["comment"] = f"User {name}@{host} is set to be added"
ret["result"] = None
if allow_passwordless:
ret["comment"] += " with passwordless login"
if not salt.utils.data.is_true(allow_passwordless):
ret["comment"] += ", but allow_passwordless != True"
ret["result"] = False
if unix_socket:
ret["comment"] += " using unix_socket"
return ret
if __salt__["mysql.user_create"](
name,
host,
password,
password_hash,
allow_passwordless,
unix_socket=unix_socket,
password_column=password_column,
auth_plugin=auth_plugin,
**connection_args,
):
ret["comment"] = f"The user {name}@{host} has been added"
if allow_passwordless:
ret["comment"] += " with passwordless login"
if unix_socket:
ret["comment"] += " using unix_socket"
ret["changes"][name] = "Present"
else:
ret["comment"] = f"Failed to create user {name}@{host}"
err = _get_mysql_error()
if err is not None:
ret["comment"] += f" ({err})"
ret["result"] = False
return ret
def absent(name, host="localhost", **connection_args):
"""
Ensure that the named user is absent
name
The name of the user to remove
"""
ret = {"name": name, "changes": {}, "result": True, "comment": ""}
# Check if user exists, and if so, remove it
if __salt__["mysql.user_exists"](name, host, **connection_args):
if __opts__["test"]:
ret["result"] = None
ret["comment"] = f"User {name}@{host} is set to be removed"
return ret
if __salt__["mysql.user_remove"](name, host, **connection_args):
ret["comment"] = f"User {name}@{host} has been removed"
ret["changes"][name] = "Absent"
return ret
else:
err = _get_mysql_error()
if err is not None:
ret["comment"] = err
ret["result"] = False
return ret
else:
err = _get_mysql_error()
if err is not None:
ret["comment"] = err
ret["result"] = False
return ret
# fallback
ret["comment"] = "User {}@{} is not present, so it cannot be removed".format(
name, host
)
return ret
Zerion Mini Shell 1.0