@ -100,7 +100,12 @@ options:
version_added : " 2.0 "
description :
- 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 :
- Requires the MySQLdb Python package on the remote host . For Ubuntu , this
is as easy as apt - get install python - mysqldb .
@ -114,7 +119,7 @@ notes:
the new root credentials . Subsequent runs of the playbook will then succeed by reading the new credentials from
the file . "
requirements : [ " ConfigParser" , " MySQLdb" ]
requirements : [ " MySQLdb" ]
author : Mark Theunissen
'''
@ -152,7 +157,6 @@ user=root
password = n < _665 { vS43y
"""
import ConfigParser
import getpass
import tempfile
try :
@ -179,6 +183,26 @@ class InvalidPrivsError(Exception):
# MySQL module specific support methods.
#
def connect ( module , login_user , login_password , config_file = ' ~/.my.cnf ' ) :
config = {
' host ' : module . params [ ' login_host ' ] ,
' db ' : ' mysql '
}
if module . params [ ' login_unix_socket ' ] :
config [ ' unix_socket ' ] = module . params [ ' login_unix_socket ' ]
else :
config [ ' port ' ] = module . params [ ' login_port ' ]
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 ) :
cursor . execute ( " SELECT count(*) FROM user WHERE user = %s AND host = %s " , ( user , host ) )
count = cursor . fetchone ( )
@ -341,100 +365,6 @@ def privileges_grant(cursor, user,host,db_table,priv):
query = ' ' . join ( query )
cursor . execute ( query , ( user , host ) )
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 _safe_cnf_load ( config , path ) :
data = { ' user ' : ' ' , ' password ' : ' ' }
# read in user/pass
f = open ( path , ' r ' )
for line in f . readlines ( ) :
line = line . strip ( )
if line . startswith ( ' user= ' ) :
data [ ' user ' ] = line . split ( ' = ' , 1 ) [ 1 ] . strip ( )
if line . startswith ( ' password= ' ) or line . startswith ( ' pass= ' ) :
data [ ' password ' ] = line . split ( ' = ' , 1 ) [ 1 ] . strip ( )
f . close ( )
# write out a new cnf file with only user/pass
fh , newpath = tempfile . mkstemp ( prefix = path + ' . ' )
f = open ( newpath , ' wb ' )
f . write ( ' [client] \n ' )
f . write ( ' user= %s \n ' % data [ ' user ' ] )
f . write ( ' password= %s \n ' % data [ ' password ' ] )
f . close ( )
config . readfp ( open ( newpath ) )
os . remove ( newpath )
return config
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
except :
config = _safe_cnf_load ( config , mycnf )
# 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 connect ( module , login_user , login_password ) :
if module . params [ " login_unix_socket " ] :
db_connection = MySQLdb . connect ( host = module . params [ " login_host " ] , 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 " )
return db_connection . cursor ( )
# ===========================================
# Module execution.
#
@ -455,14 +385,18 @@ def main():
append_privs = dict ( type = " bool " , default = " no " ) ,
check_implicit_admin = dict ( default = False ) ,
update_password = dict ( default = " always " , choices = [ " always " , " on_create " ] ) ,
config_file = dict ( default = None ) ,
)
)
login_user = module . params [ " login_user " ]
login_password = module . params [ " login_password " ]
user = module . params [ " user " ]
password = module . params [ " password " ]
host = module . params [ " host " ]
state = module . params [ " state " ]
priv = module . params [ " priv " ]
check_implicit_admin = module . params [ ' check_implicit_admin ' ]
config_file = module . params [ ' config_file ' ]
append_privs = module . boolean ( module . params [ " append_privs " ] )
update_password = module . params [ ' update_password ' ]
@ -475,32 +409,16 @@ def main():
except Exception , e :
module . fail_json ( msg = " invalid privileges string: %s " % str ( e ) )
# 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 " )
cursor = None
try :
if check_implicit_admin :
try :
cursor = connect ( module , ' root ' , ' ' )
cursor = connect ( module , ' root ' , ' ' , config_file )
except :
pass
if not cursor :
cursor = connect ( module , login_user , login_password )
cursor = connect ( module , login_user , login_password , config_file )
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 " )