Unify all 3 mysql modules.
Use same connection method, use config_file, and add ssl support
This commit is contained in:
parent
8d293651df
commit
0cdb2719e5
3 changed files with 85 additions and 301 deletions
|
@ -35,31 +35,6 @@ options:
|
||||||
required: true
|
required: true
|
||||||
default: null
|
default: null
|
||||||
aliases: [ db ]
|
aliases: [ db ]
|
||||||
login_user:
|
|
||||||
description:
|
|
||||||
- The username used to authenticate with
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
login_password:
|
|
||||||
description:
|
|
||||||
- The password used to authenticate with
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
login_host:
|
|
||||||
description:
|
|
||||||
- Host running the database
|
|
||||||
required: false
|
|
||||||
default: localhost
|
|
||||||
login_port:
|
|
||||||
description:
|
|
||||||
- Port of the MySQL server. Requires login_host be defined as other then localhost if login_port is used
|
|
||||||
required: false
|
|
||||||
default: 3306
|
|
||||||
login_unix_socket:
|
|
||||||
description:
|
|
||||||
- The path to a Unix domain socket for local connections
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- The database state
|
- The database state
|
||||||
|
@ -81,19 +56,8 @@ options:
|
||||||
- Location, on the remote host, of the dump file to read from or write to. Uncompressed SQL
|
- Location, on the remote host, of the dump file to read from or write to. Uncompressed SQL
|
||||||
files (C(.sql)) as well as bzip2 (C(.bz2)), gzip (C(.gz)) and xz (Added in 2.0) compressed files are supported.
|
files (C(.sql)) as well as bzip2 (C(.bz2)), gzip (C(.gz)) and xz (Added in 2.0) compressed files are supported.
|
||||||
required: false
|
required: false
|
||||||
notes:
|
|
||||||
- Requires the MySQLdb Python package on the remote host. For Ubuntu, this
|
|
||||||
is as easy as apt-get install python-mysqldb. (See M(apt).) For CentOS/Fedora, this
|
|
||||||
is as easy as yum install MySQL-python. (See M(yum).)
|
|
||||||
- Requires the mysql command line client. For Centos/Fedora, this is as easy as
|
|
||||||
yum install mariadb (See M(yum).). For Debian/Ubuntu this is as easy as
|
|
||||||
apt-get install mariadb-client. (See M(apt).)
|
|
||||||
- Both I(login_password) and I(login_user) are required when you are
|
|
||||||
passing credentials. If none are present, the module will attempt to read
|
|
||||||
the credentials from C(~/.my.cnf), and finally fall back to using the MySQL
|
|
||||||
default login of C(root) with no password.
|
|
||||||
requirements: [ ConfigParser ]
|
|
||||||
author: "Ansible Core Team"
|
author: "Ansible Core Team"
|
||||||
|
extends_documentation_fragment: mysql
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -111,11 +75,11 @@ EXAMPLES = '''
|
||||||
- mysql_db: state=import name=all target=/tmp/{{ inventory_hostname }}.sql
|
- mysql_db: state=import name=all target=/tmp/{{ inventory_hostname }}.sql
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import ConfigParser
|
|
||||||
import os
|
import os
|
||||||
import pipes
|
import pipes
|
||||||
import stat
|
import stat
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import MySQLdb
|
import MySQLdb
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -136,9 +100,20 @@ def db_delete(cursor, db):
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def db_dump(module, host, user, password, db_name, target, all_databases, port, socket=None):
|
def db_dump(module, host, user, password, db_name, target, all_databases, port, config_file, socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None):
|
||||||
cmd = module.get_bin_path('mysqldump', True)
|
cmd = module.get_bin_path('mysqldump', True)
|
||||||
cmd += " --quick --user=%s --password=%s" % (pipes.quote(user), pipes.quote(password))
|
# If defined, mysqldump demands --defaults-extra-file be the first option
|
||||||
|
cmd += " --defaults-extra-file=%s --quick" % pipes.quote(config_file)
|
||||||
|
if user is not None:
|
||||||
|
cmd += " --user=%s" % pipes.quote(user)
|
||||||
|
if password is not None:
|
||||||
|
cmd += " --password=%s" % pipes.quote(password)
|
||||||
|
if ssl_cert is not None:
|
||||||
|
cmd += " --ssl-cert=%s" % pipes.quote(ssl_cert)
|
||||||
|
if ssl_key is not None:
|
||||||
|
cmd += " --ssl-key=%s" % pipes.quote(ssl_key)
|
||||||
|
if ssl_cert is not None:
|
||||||
|
cmd += " --ssl-ca=%s" % pipes.quote(ssl_ca)
|
||||||
if socket is not None:
|
if socket is not None:
|
||||||
cmd += " --socket=%s" % pipes.quote(socket)
|
cmd += " --socket=%s" % pipes.quote(socket)
|
||||||
else:
|
else:
|
||||||
|
@ -164,17 +139,25 @@ def db_dump(module, host, user, password, db_name, target, all_databases, port,
|
||||||
rc, stdout, stderr = module.run_command(cmd, use_unsafe_shell=True)
|
rc, stdout, stderr = module.run_command(cmd, use_unsafe_shell=True)
|
||||||
return rc, stdout, stderr
|
return rc, stdout, stderr
|
||||||
|
|
||||||
def db_import(module, host, user, password, db_name, target, all_databases, port, socket=None):
|
def db_import(module, host, user, password, db_name, target, all_databases, port, config_file, socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None):
|
||||||
if not os.path.exists(target):
|
if not os.path.exists(target):
|
||||||
return module.fail_json(msg="target %s does not exist on the host" % target)
|
return module.fail_json(msg="target %s does not exist on the host" % target)
|
||||||
|
|
||||||
cmd = [module.get_bin_path('mysql', True)]
|
cmd = [module.get_bin_path('mysql', True)]
|
||||||
|
# --defaults-file must go first, or errors out
|
||||||
|
cmd.append("--defaults-extra-file=%s" % pipes.quote(config_file))
|
||||||
if user:
|
if user:
|
||||||
cmd.append("--user=%s" % pipes.quote(user))
|
cmd.append("--user=%s" % pipes.quote(user))
|
||||||
if password:
|
if password:
|
||||||
cmd.append("--password=%s" % pipes.quote(password))
|
cmd.append("--password=%s" % pipes.quote(password))
|
||||||
if socket is not None:
|
if socket is not None:
|
||||||
cmd.append("--socket=%s" % pipes.quote(socket))
|
cmd.append("--socket=%s" % pipes.quote(socket))
|
||||||
|
if ssl_cert is not None:
|
||||||
|
cmd.append("--ssl-cert=%s" % pipes.quote(ssl_cert))
|
||||||
|
if ssl_key is not None:
|
||||||
|
cmd.append("--ssl-key=%s" % pipes.quote(ssl_key))
|
||||||
|
if ssl_cert is not None:
|
||||||
|
cmd.append("--ssl-ca=%s" % pipes.quote(ssl_ca))
|
||||||
else:
|
else:
|
||||||
cmd.append("--host=%s" % pipes.quote(host))
|
cmd.append("--host=%s" % pipes.quote(host))
|
||||||
cmd.append("--port=%i" % port)
|
cmd.append("--port=%i" % port)
|
||||||
|
@ -218,61 +201,6 @@ def db_create(cursor, db, encoding, collation):
|
||||||
res = cursor.execute(query, query_params)
|
res = cursor.execute(query, query_params)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def strip_quotes(s):
|
|
||||||
""" Remove surrounding single or double quotes
|
|
||||||
|
|
||||||
>>> print strip_quotes('hello')
|
|
||||||
hello
|
|
||||||
>>> print strip_quotes('"hello"')
|
|
||||||
hello
|
|
||||||
>>> print strip_quotes("'hello'")
|
|
||||||
hello
|
|
||||||
>>> print strip_quotes("'hello")
|
|
||||||
'hello
|
|
||||||
|
|
||||||
"""
|
|
||||||
single_quote = "'"
|
|
||||||
double_quote = '"'
|
|
||||||
|
|
||||||
if s.startswith(single_quote) and s.endswith(single_quote):
|
|
||||||
s = s.strip(single_quote)
|
|
||||||
elif s.startswith(double_quote) and s.endswith(double_quote):
|
|
||||||
s = s.strip(double_quote)
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def config_get(config, section, option):
|
|
||||||
""" Calls ConfigParser.get and strips quotes
|
|
||||||
|
|
||||||
See: http://dev.mysql.com/doc/refman/5.0/en/option-files.html
|
|
||||||
"""
|
|
||||||
return strip_quotes(config.get(section, option))
|
|
||||||
|
|
||||||
|
|
||||||
def load_mycnf():
|
|
||||||
config = ConfigParser.RawConfigParser()
|
|
||||||
mycnf = os.path.expanduser('~/.my.cnf')
|
|
||||||
if not os.path.exists(mycnf):
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
config.readfp(open(mycnf))
|
|
||||||
except (IOError):
|
|
||||||
return False
|
|
||||||
# We support two forms of passwords in .my.cnf, both pass= and password=,
|
|
||||||
# as these are both supported by MySQL.
|
|
||||||
try:
|
|
||||||
passwd = config_get(config, 'client', 'password')
|
|
||||||
except (ConfigParser.NoOptionError):
|
|
||||||
try:
|
|
||||||
passwd = config_get(config, 'client', 'pass')
|
|
||||||
except (ConfigParser.NoOptionError):
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
creds = dict(user=config_get(config, 'client', 'user'),passwd=passwd)
|
|
||||||
except (ConfigParser.NoOptionError):
|
|
||||||
return False
|
|
||||||
return creds
|
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# Module execution.
|
# Module execution.
|
||||||
#
|
#
|
||||||
|
@ -290,6 +218,10 @@ def main():
|
||||||
collation=dict(default=""),
|
collation=dict(default=""),
|
||||||
target=dict(default=None),
|
target=dict(default=None),
|
||||||
state=dict(default="present", choices=["absent", "present","dump", "import"]),
|
state=dict(default="present", choices=["absent", "present","dump", "import"]),
|
||||||
|
ssl_cert=dict(default=None),
|
||||||
|
ssl_key=dict(default=None),
|
||||||
|
ssl_ca=dict(default=None),
|
||||||
|
config_file=dict(default="~/.my.cnf"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -305,62 +237,37 @@ def main():
|
||||||
login_port = module.params["login_port"]
|
login_port = module.params["login_port"]
|
||||||
if login_port < 0 or login_port > 65535:
|
if login_port < 0 or login_port > 65535:
|
||||||
module.fail_json(msg="login_port must be a valid unix port number (0-65535)")
|
module.fail_json(msg="login_port must be a valid unix port number (0-65535)")
|
||||||
|
ssl_cert = module.params["ssl_cert"]
|
||||||
|
ssl_key = module.params["ssl_key"]
|
||||||
|
ssl_ca = module.params["ssl_ca"]
|
||||||
|
config_file = module.params['config_file']
|
||||||
|
config_file = os.path.expanduser(os.path.expandvars(config_file))
|
||||||
|
login_password = module.params["login_password"]
|
||||||
|
login_user = module.params["login_user"]
|
||||||
|
login_host = module.params["login_host"]
|
||||||
|
|
||||||
# make sure the target path is expanded for ~ and $HOME
|
# make sure the target path is expanded for ~ and $HOME
|
||||||
if target is not None:
|
if target is not None:
|
||||||
target = os.path.expandvars(os.path.expanduser(target))
|
target = os.path.expandvars(os.path.expanduser(target))
|
||||||
|
|
||||||
# Either the caller passes both a username and password with which to connect to
|
|
||||||
# mysql, or they pass neither and allow this module to read the credentials from
|
|
||||||
# ~/.my.cnf.
|
|
||||||
login_password = module.params["login_password"]
|
|
||||||
login_user = module.params["login_user"]
|
|
||||||
if login_user is None and login_password is None:
|
|
||||||
mycnf_creds = load_mycnf()
|
|
||||||
if mycnf_creds is False:
|
|
||||||
login_user = "root"
|
|
||||||
login_password = ""
|
|
||||||
else:
|
|
||||||
login_user = mycnf_creds["user"]
|
|
||||||
login_password = mycnf_creds["passwd"]
|
|
||||||
elif login_password is None or login_user is None:
|
|
||||||
module.fail_json(msg="when supplying login arguments, both login_user and login_password must be provided")
|
|
||||||
login_host = module.params["login_host"]
|
|
||||||
|
|
||||||
if state in ['dump','import']:
|
if state in ['dump','import']:
|
||||||
if target is None:
|
if target is None:
|
||||||
module.fail_json(msg="with state=%s target is required" % (state))
|
module.fail_json(msg="with state=%s target is required" % (state))
|
||||||
if db == 'all':
|
if db == 'all':
|
||||||
connect_to_db = 'mysql'
|
|
||||||
db = 'mysql'
|
db = 'mysql'
|
||||||
all_databases = True
|
all_databases = True
|
||||||
else:
|
else:
|
||||||
connect_to_db = db
|
|
||||||
all_databases = False
|
all_databases = False
|
||||||
else:
|
else:
|
||||||
if db == 'all':
|
if db == 'all':
|
||||||
module.fail_json(msg="name is not allowed to equal 'all' unless state equals import, or dump.")
|
module.fail_json(msg="name is not allowed to equal 'all' unless state equals import, or dump.")
|
||||||
connect_to_db = ''
|
|
||||||
try:
|
try:
|
||||||
if socket:
|
cursor = mysql_connect(module, login_user, login_password, config_file, ssl_cert, ssl_key, ssl_ca)
|
||||||
try:
|
|
||||||
socketmode = os.stat(socket).st_mode
|
|
||||||
if not stat.S_ISSOCK(socketmode):
|
|
||||||
module.fail_json(msg="%s, is not a socket, unable to connect" % socket)
|
|
||||||
except OSError:
|
|
||||||
module.fail_json(msg="%s, does not exist, unable to connect" % socket)
|
|
||||||
db_connection = MySQLdb.connect(host=module.params["login_host"], unix_socket=socket, user=login_user, passwd=login_password, db=connect_to_db)
|
|
||||||
elif login_port != 3306 and module.params["login_host"] == "localhost":
|
|
||||||
module.fail_json(msg="login_host is required when login_port is defined, login_host cannot be localhost when login_port is defined")
|
|
||||||
else:
|
|
||||||
db_connection = MySQLdb.connect(host=module.params["login_host"], port=login_port, user=login_user, passwd=login_password, db=connect_to_db)
|
|
||||||
cursor = db_connection.cursor()
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
errno, errstr = e.args
|
if os.path.exists(config_file):
|
||||||
if "Unknown database" in str(e):
|
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. Exception message: %s" % (config_file, e))
|
||||||
module.fail_json(msg="ERROR: %s %s" % (errno, errstr))
|
|
||||||
else:
|
else:
|
||||||
module.fail_json(msg="unable to connect, check login credentials (login_user, and login_password, which can be defined in ~/.my.cnf), check that mysql socket exists and mysql server is running (ERROR: %s %s)" % (errno, errstr))
|
module.fail_json(msg="unable to find %s. Exception message: %s" % (config_file, e))
|
||||||
|
|
||||||
changed = False
|
changed = False
|
||||||
if db_exists(cursor, db):
|
if db_exists(cursor, db):
|
||||||
|
@ -372,8 +279,7 @@ def main():
|
||||||
elif state == "dump":
|
elif state == "dump":
|
||||||
rc, stdout, stderr = db_dump(module, login_host, login_user,
|
rc, stdout, stderr = db_dump(module, login_host, login_user,
|
||||||
login_password, db, target, all_databases,
|
login_password, db, target, all_databases,
|
||||||
port=login_port,
|
login_port, config_file, socket, ssl_cert, ssl_key, ssl_ca)
|
||||||
socket=module.params['login_unix_socket'])
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(msg="%s" % stderr)
|
module.fail_json(msg="%s" % stderr)
|
||||||
else:
|
else:
|
||||||
|
@ -381,8 +287,7 @@ def main():
|
||||||
elif state == "import":
|
elif state == "import":
|
||||||
rc, stdout, stderr = db_import(module, login_host, login_user,
|
rc, stdout, stderr = db_import(module, login_host, login_user,
|
||||||
login_password, db, target, all_databases,
|
login_password, db, target, all_databases,
|
||||||
port=login_port,
|
login_port, config_file, socket, ssl_cert, ssl_key, ssl_ca)
|
||||||
socket=module.params['login_unix_socket'])
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(msg="%s" % stderr)
|
module.fail_json(msg="%s" % stderr)
|
||||||
else:
|
else:
|
||||||
|
@ -399,5 +304,6 @@ def main():
|
||||||
# import module snippets
|
# import module snippets
|
||||||
from ansible.module_utils.basic import *
|
from ansible.module_utils.basic import *
|
||||||
from ansible.module_utils.database import *
|
from ansible.module_utils.database import *
|
||||||
|
from ansible.module_utils.mysql import *
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -56,32 +56,6 @@ options:
|
||||||
choices: [ "yes", "no" ]
|
choices: [ "yes", "no" ]
|
||||||
default: "no"
|
default: "no"
|
||||||
version_added: "2.1"
|
version_added: "2.1"
|
||||||
login_user:
|
|
||||||
description:
|
|
||||||
- The username used to authenticate with
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
login_password:
|
|
||||||
description:
|
|
||||||
- The password used to authenticate with
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
login_host:
|
|
||||||
description:
|
|
||||||
- Host running the database
|
|
||||||
required: false
|
|
||||||
default: localhost
|
|
||||||
login_port:
|
|
||||||
description:
|
|
||||||
- Port of the MySQL server
|
|
||||||
required: false
|
|
||||||
default: 3306
|
|
||||||
version_added: '1.4'
|
|
||||||
login_unix_socket:
|
|
||||||
description:
|
|
||||||
- The path to a Unix domain socket for local connections
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
priv:
|
priv:
|
||||||
description:
|
description:
|
||||||
- "MySQL privileges string in the format: C(db.table:priv1,priv2)"
|
- "MySQL privileges string in the format: C(db.table:priv1,priv2)"
|
||||||
|
@ -116,19 +90,7 @@ options:
|
||||||
version_added: "1.9"
|
version_added: "1.9"
|
||||||
description:
|
description:
|
||||||
- C(always) will update passwords if they differ. C(on_create) will only set the password for newly created users.
|
- C(always) will update passwords if they differ. C(on_create) will only set the password for newly created users.
|
||||||
config_file:
|
|
||||||
description:
|
|
||||||
- Specify a config file from which user and password are to be read
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
version_added: "1.8"
|
|
||||||
notes:
|
notes:
|
||||||
- Requires the MySQLdb Python package on the remote host. For Ubuntu, this
|
|
||||||
is as easy as apt-get install python-mysqldb.
|
|
||||||
- Both C(login_password) and C(login_user) are required when you are
|
|
||||||
passing credentials. If none are present, the module will attempt to read
|
|
||||||
the credentials from C(~/.my.cnf), and finally fall back to using the MySQL
|
|
||||||
default login of 'root' with no password.
|
|
||||||
- "MySQL server installs with default login_user of 'root' and no password. To secure this user
|
- "MySQL server installs with default login_user of 'root' and no password. To secure this user
|
||||||
as part of an idempotent playbook, you must create at least two tasks: the first must change the root user's password,
|
as part of an idempotent playbook, you must create at least two tasks: the first must change the root user's password,
|
||||||
without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing
|
without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing
|
||||||
|
@ -136,8 +98,8 @@ notes:
|
||||||
the file."
|
the file."
|
||||||
- Currently, there is only support for the `mysql_native_password` encryted password hash module.
|
- Currently, there is only support for the `mysql_native_password` encryted password hash module.
|
||||||
|
|
||||||
requirements: [ "MySQLdb" ]
|
|
||||||
author: "Jonathan Mainguy (@Jmainguy)"
|
author: "Jonathan Mainguy (@Jmainguy)"
|
||||||
|
extends_documentation_fragment: mysql
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
|
@ -212,25 +174,18 @@ class InvalidPrivsError(Exception):
|
||||||
# MySQL module specific support methods.
|
# MySQL module specific support methods.
|
||||||
#
|
#
|
||||||
|
|
||||||
def connect(module, login_user=None, login_password=None, config_file=''):
|
# User Authentication Management was change in MySQL 5.7
|
||||||
config = {
|
# This is a generic check for if the server version is less than version 5.7
|
||||||
'host': module.params['login_host'],
|
def server_version_check(cursor):
|
||||||
'db': 'mysql'
|
cursor.execute("SELECT VERSION()");
|
||||||
}
|
result = cursor.fetchone()
|
||||||
|
version_str = result[0]
|
||||||
|
version = version_str.split('.')
|
||||||
|
|
||||||
if module.params['login_unix_socket']:
|
if (int(version[0]) <= 5 and int(version[1]) < 7):
|
||||||
config['unix_socket'] = module.params['login_unix_socket']
|
return True
|
||||||
else:
|
else:
|
||||||
config['port'] = module.params['login_port']
|
return False
|
||||||
|
|
||||||
if os.path.exists(config_file):
|
|
||||||
config['read_default_file'] = config_file
|
|
||||||
else:
|
|
||||||
config['user'] = login_user
|
|
||||||
config['passwd'] = login_password
|
|
||||||
|
|
||||||
db_connection = MySQLdb.connect(**config)
|
|
||||||
return db_connection.cursor()
|
|
||||||
|
|
||||||
def user_exists(cursor, user, host, host_all):
|
def user_exists(cursor, user, host, host_all):
|
||||||
if host_all:
|
if host_all:
|
||||||
|
@ -480,6 +435,9 @@ def main():
|
||||||
check_implicit_admin=dict(default=False, type='bool'),
|
check_implicit_admin=dict(default=False, type='bool'),
|
||||||
update_password=dict(default="always", choices=["always", "on_create"]),
|
update_password=dict(default="always", choices=["always", "on_create"]),
|
||||||
config_file=dict(default="~/.my.cnf"),
|
config_file=dict(default="~/.my.cnf"),
|
||||||
|
ssl_cert=dict(default=None),
|
||||||
|
ssl_key=dict(default=None),
|
||||||
|
ssl_ca=dict(default=None),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
login_user = module.params["login_user"]
|
login_user = module.params["login_user"]
|
||||||
|
@ -495,6 +453,10 @@ def main():
|
||||||
config_file = module.params['config_file']
|
config_file = module.params['config_file']
|
||||||
append_privs = module.boolean(module.params["append_privs"])
|
append_privs = module.boolean(module.params["append_privs"])
|
||||||
update_password = module.params['update_password']
|
update_password = module.params['update_password']
|
||||||
|
ssl_cert = module.params["ssl_cert"]
|
||||||
|
ssl_key = module.params["ssl_key"]
|
||||||
|
ssl_ca = module.params["ssl_ca"]
|
||||||
|
db = 'mysql'
|
||||||
|
|
||||||
config_file = os.path.expanduser(os.path.expandvars(config_file))
|
config_file = os.path.expanduser(os.path.expandvars(config_file))
|
||||||
if not mysqldb_found:
|
if not mysqldb_found:
|
||||||
|
@ -510,14 +472,14 @@ def main():
|
||||||
try:
|
try:
|
||||||
if check_implicit_admin:
|
if check_implicit_admin:
|
||||||
try:
|
try:
|
||||||
cursor = connect(module, 'root', '', config_file)
|
cursor = mysql_connect(module, 'root', '', config_file, ssl_cert, ssl_key, ssl_ca, db)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not cursor:
|
if not cursor:
|
||||||
cursor = connect(module, login_user, login_password, config_file)
|
cursor = mysql_connect(module, login_user, login_password, config_file, ssl_cert, ssl_key, ssl_ca, db)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials")
|
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. Exception message: %s" % (config_file, e))
|
||||||
|
|
||||||
if state == "present":
|
if state == "present":
|
||||||
if user_exists(cursor, user, host):
|
if user_exists(cursor, user, host):
|
||||||
|
@ -548,5 +510,6 @@ def main():
|
||||||
# import module snippets
|
# import module snippets
|
||||||
from ansible.module_utils.basic import *
|
from ansible.module_utils.basic import *
|
||||||
from ansible.module_utils.database import *
|
from ansible.module_utils.database import *
|
||||||
|
from ansible.module_utils.mysql import *
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -40,26 +40,7 @@ options:
|
||||||
description:
|
description:
|
||||||
- If set, then sets variable value to this
|
- If set, then sets variable value to this
|
||||||
required: False
|
required: False
|
||||||
login_user:
|
extends_documentation_fragment: mysql
|
||||||
description:
|
|
||||||
- username to connect mysql host, if defined login_password also needed.
|
|
||||||
required: False
|
|
||||||
login_password:
|
|
||||||
description:
|
|
||||||
- password to connect mysql host, if defined login_user also needed.
|
|
||||||
required: False
|
|
||||||
login_host:
|
|
||||||
description:
|
|
||||||
- mysql host to connect
|
|
||||||
required: False
|
|
||||||
login_port:
|
|
||||||
version_added: "1.9"
|
|
||||||
description:
|
|
||||||
- mysql port to connect
|
|
||||||
required: False
|
|
||||||
login_unix_socket:
|
|
||||||
description:
|
|
||||||
- unix socket to connect mysql server
|
|
||||||
'''
|
'''
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
# Check for sync_binlog setting
|
# Check for sync_binlog setting
|
||||||
|
@ -70,7 +51,6 @@ EXAMPLES = '''
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
import ConfigParser
|
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
from re import match
|
from re import match
|
||||||
|
@ -134,66 +114,6 @@ def setvariable(cursor, mysqlvar, value):
|
||||||
result = str(e)
|
result = str(e)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def strip_quotes(s):
|
|
||||||
""" Remove surrounding single or double quotes
|
|
||||||
|
|
||||||
>>> print strip_quotes('hello')
|
|
||||||
hello
|
|
||||||
>>> print strip_quotes('"hello"')
|
|
||||||
hello
|
|
||||||
>>> print strip_quotes("'hello'")
|
|
||||||
hello
|
|
||||||
>>> print strip_quotes("'hello")
|
|
||||||
'hello
|
|
||||||
|
|
||||||
"""
|
|
||||||
single_quote = "'"
|
|
||||||
double_quote = '"'
|
|
||||||
|
|
||||||
if s.startswith(single_quote) and s.endswith(single_quote):
|
|
||||||
s = s.strip(single_quote)
|
|
||||||
elif s.startswith(double_quote) and s.endswith(double_quote):
|
|
||||||
s = s.strip(double_quote)
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def config_get(config, section, option):
|
|
||||||
""" Calls ConfigParser.get and strips quotes
|
|
||||||
|
|
||||||
See: http://dev.mysql.com/doc/refman/5.0/en/option-files.html
|
|
||||||
"""
|
|
||||||
return strip_quotes(config.get(section, option))
|
|
||||||
|
|
||||||
|
|
||||||
def load_mycnf():
|
|
||||||
config = ConfigParser.RawConfigParser()
|
|
||||||
mycnf = os.path.expanduser('~/.my.cnf')
|
|
||||||
if not os.path.exists(mycnf):
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
config.readfp(open(mycnf))
|
|
||||||
except (IOError):
|
|
||||||
return False
|
|
||||||
# We support two forms of passwords in .my.cnf, both pass= and password=,
|
|
||||||
# as these are both supported by MySQL.
|
|
||||||
try:
|
|
||||||
passwd = config_get(config, 'client', 'password')
|
|
||||||
except (ConfigParser.NoOptionError):
|
|
||||||
try:
|
|
||||||
passwd = config_get(config, 'client', 'pass')
|
|
||||||
except (ConfigParser.NoOptionError):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# If .my.cnf doesn't specify a user, default to user login name
|
|
||||||
try:
|
|
||||||
user = config_get(config, 'client', 'user')
|
|
||||||
except (ConfigParser.NoOptionError):
|
|
||||||
user = getpass.getuser()
|
|
||||||
creds = dict(user=user, passwd=passwd)
|
|
||||||
return creds
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec = dict(
|
argument_spec = dict(
|
||||||
|
@ -203,14 +123,24 @@ def main():
|
||||||
login_port=dict(default="3306", type='int'),
|
login_port=dict(default="3306", type='int'),
|
||||||
login_unix_socket=dict(default=None),
|
login_unix_socket=dict(default=None),
|
||||||
variable=dict(default=None),
|
variable=dict(default=None),
|
||||||
value=dict(default=None)
|
value=dict(default=None),
|
||||||
|
ssl_cert=dict(default=None),
|
||||||
|
ssl_key=dict(default=None),
|
||||||
|
ssl_ca=dict(default=None),
|
||||||
|
config_file=dict(default="~/.my.cnf")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
user = module.params["login_user"]
|
user = module.params["login_user"]
|
||||||
password = module.params["login_password"]
|
password = module.params["login_password"]
|
||||||
host = module.params["login_host"]
|
host = module.params["login_host"]
|
||||||
port = module.params["login_port"]
|
port = module.params["login_port"]
|
||||||
|
ssl_cert = module.params["ssl_cert"]
|
||||||
|
ssl_key = module.params["ssl_key"]
|
||||||
|
ssl_ca = module.params["ssl_ca"]
|
||||||
|
config_file = module.params['config_file']
|
||||||
|
config_file = os.path.expanduser(os.path.expandvars(config_file))
|
||||||
|
db = 'mysql'
|
||||||
|
|
||||||
mysqlvar = module.params["variable"]
|
mysqlvar = module.params["variable"]
|
||||||
value = module.params["value"]
|
value = module.params["value"]
|
||||||
if mysqlvar is None:
|
if mysqlvar is None:
|
||||||
|
@ -222,30 +152,14 @@ def main():
|
||||||
else:
|
else:
|
||||||
warnings.filterwarnings('error', category=MySQLdb.Warning)
|
warnings.filterwarnings('error', category=MySQLdb.Warning)
|
||||||
|
|
||||||
# Either the caller passes both a username and password with which to connect to
|
|
||||||
# mysql, or they pass neither and allow this module to read the credentials from
|
|
||||||
# ~/.my.cnf.
|
|
||||||
login_password = module.params["login_password"]
|
|
||||||
login_user = module.params["login_user"]
|
|
||||||
if login_user is None and login_password is None:
|
|
||||||
mycnf_creds = load_mycnf()
|
|
||||||
if mycnf_creds is False:
|
|
||||||
login_user = "root"
|
|
||||||
login_password = ""
|
|
||||||
else:
|
|
||||||
login_user = mycnf_creds["user"]
|
|
||||||
login_password = mycnf_creds["passwd"]
|
|
||||||
elif login_password is None or login_user is None:
|
|
||||||
module.fail_json(msg="when supplying login arguments, both login_user and login_password must be provided")
|
|
||||||
try:
|
try:
|
||||||
if module.params["login_unix_socket"]:
|
cursor = mysql_connect(module, user, password, config_file, ssl_cert, ssl_key, ssl_ca, db)
|
||||||
db_connection = MySQLdb.connect(host=module.params["login_host"], port=module.params["login_port"], unix_socket=module.params["login_unix_socket"], user=login_user, passwd=login_password, db="mysql")
|
|
||||||
else:
|
|
||||||
db_connection = MySQLdb.connect(host=module.params["login_host"], port=module.params["login_port"], user=login_user, passwd=login_password, db="mysql")
|
|
||||||
cursor = db_connection.cursor()
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
errno, errstr = e.args
|
if os.path.exists(config_file):
|
||||||
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials (ERROR: %s %s)" % (errno, errstr))
|
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. Exception message: %s" % (config_file, e))
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="unable to find %s. Exception message: %s" % (config_file, e))
|
||||||
|
|
||||||
mysqlvar_val = getvariable(cursor, mysqlvar)
|
mysqlvar_val = getvariable(cursor, mysqlvar)
|
||||||
if mysqlvar_val is None:
|
if mysqlvar_val is None:
|
||||||
module.fail_json(msg="Variable not available \"%s\"" % mysqlvar, changed=False)
|
module.fail_json(msg="Variable not available \"%s\"" % mysqlvar, changed=False)
|
||||||
|
@ -269,4 +183,5 @@ def main():
|
||||||
# import module snippets
|
# import module snippets
|
||||||
from ansible.module_utils.basic import *
|
from ansible.module_utils.basic import *
|
||||||
from ansible.module_utils.database import *
|
from ansible.module_utils.database import *
|
||||||
|
from ansible.module_utils.mysql import *
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in a new issue