2015-01-08 12:58:31 +01:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Ansible module to manage mssql databases
# (c) 2014, Vedit Firat Arig <firatarig@gmail.com>
# Outline and parts are reused from Mark Theunissen's mysql_db module
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
DOCUMENTATION = '''
- - -
module : mssql_db
short_description : Add or remove MSSQL databases from a remote host .
description :
- Add or remove MSSQL databases from a remote host .
2016-02-19 09:14:52 +01:00
version_added : " 2.2 "
2015-01-08 12:58:31 +01:00
options :
name :
description :
- name of the database to add or remove
required : true
default : null
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
login_port :
description :
- Port of the MSSQL server . Requires login_host be defined as other then localhost if login_port is used
required : false
default : 1433
state :
description :
- The database state
required : false
default : present
choices : [ " present " , " absent " , " import " ]
target :
description :
- Location , on the remote host , of the dump file to read from or write to . Uncompressed SQL
files ( C ( . sql ) ) files are supported .
required : false
2016-02-19 09:14:52 +01:00
autocommit :
description :
- Automatically commit the change only if the import succeed . Sometimes it is necessary to use autocommit = true , since some content can ' t be changed within a transaction.
required : false
default : false
choices : [ " false " , " true " ]
2015-01-08 12:58:31 +01:00
notes :
- Requires the pymssql Python package on the remote host . For Ubuntu , this
is as easy as pip install pymssql ( See M ( pip ) . )
2016-05-25 21:09:49 +02:00
requirements :
- python > = 2.7
- pymssql
2015-01-08 12:58:31 +01:00
author : Vedit Firat Arig
'''
EXAMPLES = '''
# Create a new database with name 'jackdata'
- mssql_db : name = jackdata state = present
# Copy database dump file to remote host and restore it to database 'my_db'
- copy : src = dump . sql dest = / tmp
- mssql_db : name = my_db state = import target = / tmp / dump . sql
'''
2016-02-19 09:14:52 +01:00
RETURN = '''
#
'''
2015-01-08 12:58:31 +01:00
import os
try :
import pymssql
except ImportError :
mssql_found = False
else :
mssql_found = True
def db_exists ( conn , cursor , db ) :
2016-02-19 09:14:52 +01:00
cursor . execute ( " SELECT name FROM master.sys.databases WHERE name = %s " , db )
2015-01-08 12:58:31 +01:00
conn . commit ( )
return bool ( cursor . rowcount )
def db_create ( conn , cursor , db ) :
2016-02-19 09:14:52 +01:00
cursor . execute ( " CREATE DATABASE [ %s ] " % db )
2015-01-08 12:58:31 +01:00
return db_exists ( conn , cursor , db )
def db_delete ( conn , cursor , db ) :
try :
2016-02-19 09:14:52 +01:00
cursor . execute ( " ALTER DATABASE [ %s ] SET single_user WITH ROLLBACK IMMEDIATE " % db )
2015-01-08 12:58:31 +01:00
except :
pass
2016-02-19 09:14:52 +01:00
cursor . execute ( " DROP DATABASE [ %s ] " % db )
2015-01-08 12:58:31 +01:00
return not db_exists ( conn , cursor , db )
def db_import ( conn , cursor , module , db , target ) :
if os . path . isfile ( target ) :
2016-02-19 09:14:52 +01:00
backup = open ( target , ' r ' )
try :
sqlQuery = " USE [ %s ] \n " % db
2015-01-08 12:58:31 +01:00
for line in backup :
if line is None :
break
elif line . startswith ( ' GO ' ) :
2016-02-19 09:14:52 +01:00
cursor . execute ( sqlQuery )
sqlQuery = " USE [ %s ] \n " % db
2015-01-08 12:58:31 +01:00
else :
sqlQuery + = line
2016-02-19 09:14:52 +01:00
cursor . execute ( sqlQuery )
2015-01-08 12:58:31 +01:00
conn . commit ( )
2016-02-19 09:14:52 +01:00
finally :
backup . close ( )
2015-01-08 12:58:31 +01:00
return 0 , " import successful " , " "
else :
return 1 , " cannot find target file " , " cannot find target file "
def main ( ) :
module = AnsibleModule (
argument_spec = dict (
name = dict ( required = True , aliases = [ ' db ' ] ) ,
2016-02-19 09:14:52 +01:00
login_user = dict ( default = ' ' ) ,
login_password = dict ( default = ' ' ) ,
2015-01-08 12:58:31 +01:00
login_host = dict ( required = True ) ,
2016-02-19 09:14:52 +01:00
login_port = dict ( default = ' 1433 ' ) ,
2015-01-08 12:58:31 +01:00
target = dict ( default = None ) ,
2016-02-19 09:14:52 +01:00
autocommit = dict ( type = ' bool ' , default = False ) ,
2015-01-08 12:58:31 +01:00
state = dict (
default = ' present ' , choices = [ ' present ' , ' absent ' , ' import ' ] )
)
)
if not mssql_found :
module . fail_json ( msg = " pymssql python module is required " )
db = module . params [ ' name ' ]
state = module . params [ ' state ' ]
2016-02-19 09:14:52 +01:00
autocommit = module . params [ ' autocommit ' ]
2015-01-08 12:58:31 +01:00
target = module . params [ " target " ]
login_user = module . params [ ' login_user ' ]
login_password = module . params [ ' login_password ' ]
login_host = module . params [ ' login_host ' ]
login_port = module . params [ ' login_port ' ]
2016-02-19 09:14:52 +01:00
login_querystring = login_host
if login_port != " 1433 " :
login_querystring = " %s : %s " % ( login_host , login_port )
2015-01-08 12:58:31 +01:00
2016-02-19 09:14:52 +01:00
if login_user != " " and login_password == " " :
module . fail_json ( msg = " when supplying login_user arguments login_password must be provided " )
2015-01-08 12:58:31 +01:00
try :
conn = pymssql . connect ( user = login_user , password = login_password , host = login_querystring , database = ' master ' )
cursor = conn . cursor ( )
2016-05-25 21:09:49 +02:00
except Exception as e :
2015-01-08 12:58:31 +01:00
if " Unknown database " in str ( e ) :
errno , errstr = e . args
module . fail_json ( msg = " ERROR: %s %s " % ( errno , errstr ) )
else :
2016-02-19 09:14:52 +01:00
module . fail_json ( msg = " unable to connect, check login_user and login_password are correct, or alternatively check your @sysconfdir@/freetds.conf / $ {HOME} /.freetds.conf " )
2015-01-08 12:58:31 +01:00
2016-02-19 09:14:52 +01:00
conn . autocommit ( True )
2015-01-08 12:58:31 +01:00
changed = False
2016-02-19 09:14:52 +01:00
2015-01-08 12:58:31 +01:00
if db_exists ( conn , cursor , db ) :
if state == " absent " :
try :
changed = db_delete ( conn , cursor , db )
2016-05-25 21:09:49 +02:00
except Exception as e :
2015-01-08 12:58:31 +01:00
module . fail_json ( msg = " error deleting database: " + str ( e ) )
elif state == " import " :
2016-02-19 09:14:52 +01:00
conn . autocommit ( autocommit )
2015-01-08 12:58:31 +01:00
rc , stdout , stderr = db_import ( conn , cursor , module , db , target )
2016-02-19 09:14:52 +01:00
2015-01-08 12:58:31 +01:00
if rc != 0 :
module . fail_json ( msg = " %s " % stderr )
else :
module . exit_json ( changed = True , db = db , msg = stdout )
else :
if state == " present " :
try :
changed = db_create ( conn , cursor , db )
2016-05-25 21:09:49 +02:00
except Exception as e :
2015-01-08 12:58:31 +01:00
module . fail_json ( msg = " error creating database: " + str ( e ) )
elif state == " import " :
try :
changed = db_create ( conn , cursor , db )
2016-05-25 21:09:49 +02:00
except Exception as e :
2015-01-08 12:58:31 +01:00
module . fail_json ( msg = " error creating database: " + str ( e ) )
2016-02-19 09:14:52 +01:00
conn . autocommit ( autocommit )
2015-01-08 12:58:31 +01:00
rc , stdout , stderr = db_import ( conn , cursor , module , db , target )
2016-02-19 09:14:52 +01:00
2015-01-08 12:58:31 +01:00
if rc != 0 :
module . fail_json ( msg = " %s " % stderr )
else :
module . exit_json ( changed = True , db = db , msg = stdout )
module . exit_json ( changed = changed , db = db )
# import module snippets
from ansible . module_utils . basic import *
if __name__ == ' __main__ ' :
main ( )