@ -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 ( )