Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
ansible
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ansible
Commits
d7529196
Commit
d7529196
authored
Jul 30, 2013
by
Balazs Pocze
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mysql_replication module added
parent
8cc13590
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
399 additions
and
0 deletions
+399
-0
library/database/mysql_replication
+399
-0
No files found.
library/database/mysql_replication
0 → 100644
View file @
d7529196
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Ansible module to manage mysql replication
(c) 2013, Balazs Pocze <banyek@gawker.com>
Certain parts are taken from Mark Theunissen's mysqldb 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: mysql_replication
short_description: Manage MySQL replication
description:
- Manages MySQL server replication, slave, master status get and change master host.
options:
mode:
description:
- module operating mode. Could be getslave (SHOW SLAVE STATUS), getmaster (SHOW MASTER STATUS), changemaster (CHANGE MASTER TO), startslave (START SLAVE), stopslave (STOP SLAVE)
required: False
choices:
- getslave
- getmaster
- changemaster
- stopslave
- startslave
default: getslave
login_user:
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_unix_socket:
description:
- unix socket to connect mysql server
master_host:
description:
- same as mysql variable
master_user:
description:
- same as mysql variable
master_password:
description:
- same as mysql variable
master_port:
description:
- same as mysql variable
master_connect_retry:
description:
- same as mysql variable
master_log_file:
description:
- same as mysql variable
master_log_pos:
description:
- same as mysql variable
relay_log_file:
description:
- same as mysql variable
relay_log_pos:
description:
- same as mysql variable
master_ssl:
description:
- same as mysql variable
possible values: 0,1
master_ssl_ca:
description:
- same as mysql variable
master_ssl_capath:
description:
- same as mysql variable
master_ssl_cert:
description:
- same as mysql variable
master_ssl_key:
description:
- same as mysql variable
master_ssl_cipher:
description:
- same as mysql variable
'''
import
ConfigParser
import
os
import
warnings
try
:
import
MySQLdb
except
ImportError
:
mysqldb_found
=
False
else
:
mysqldb_found
=
True
def
get_master_status
(
cursor
):
cursor
.
execute
(
"SHOW MASTER STATUS"
)
masterstatus
=
cursor
.
fetchone
()
return
masterstatus
def
get_slave_status
(
cursor
):
cursor
.
execute
(
"SHOW SLAVE STATUS"
)
slavestatus
=
cursor
.
fetchone
()
return
slavestatus
def
stop_slave
(
cursor
):
try
:
cursor
.
execute
(
"STOP SLAVE"
)
stopped
=
True
except
:
stopped
=
False
return
stopped
def
start_slave
(
cursor
):
try
:
cursor
.
execute
(
"START SLAVE"
)
started
=
True
except
:
started
=
False
return
started
def
changemaster
(
cursor
,
chm
):
SQLPARAM
=
","
.
join
(
chm
)
cursor
.
execute
(
"CHANGE MASTER TO "
+
SQLPARAM
)
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
():
module
=
AnsibleModule
(
argument_spec
=
dict
(
login_user
=
dict
(
default
=
None
),
login_password
=
dict
(
default
=
None
),
login_host
=
dict
(
default
=
"localhost"
),
login_unix_socket
=
dict
(
default
=
None
),
mode
=
dict
(
default
=
"getslave"
,
choices
=
[
"getmaster"
,
"getslave"
,
"changemaster"
,
"stopslave"
,
"startslave"
]),
master_host
=
dict
(
default
=
None
),
master_user
=
dict
(
default
=
None
),
master_password
=
dict
(
default
=
None
),
master_port
=
dict
(
default
=
None
),
master_connect_retry
=
dict
(
default
=
None
),
master_log_file
=
dict
(
default
=
None
),
master_log_pos
=
dict
(
default
=
None
),
relay_log_file
=
dict
(
default
=
None
),
relay_log_pos
=
dict
(
default
=
None
),
master_ssl
=
dict
(
default
=
None
,
choices
=
[
0
,
1
]),
master_ssl_ca
=
dict
(
default
=
None
),
master_ssl_capath
=
dict
(
default
=
None
),
master_ssl_cert
=
dict
(
default
=
None
),
master_ssl_key
=
dict
(
default
=
None
),
master_ssl_cipher
=
dict
(
default
=
None
),
)
)
user
=
module
.
params
[
"login_user"
]
password
=
module
.
params
[
"login_password"
]
host
=
module
.
params
[
"login_host"
]
mode
=
module
.
params
[
"mode"
]
master_host
=
module
.
params
[
"master_host"
]
master_user
=
module
.
params
[
"master_user"
]
master_password
=
module
.
params
[
"master_password"
]
master_port
=
module
.
params
[
"master_port"
]
master_connect_retry
=
module
.
params
[
"master_connect_retry"
]
master_log_file
=
module
.
params
[
"master_log_file"
]
master_log_pos
=
module
.
params
[
"master_log_pos"
]
relay_log_file
=
module
.
params
[
"relay_log_file"
]
relay_log_pos
=
module
.
params
[
"relay_log_pos"
]
master_ssl
=
module
.
params
[
"master_ssl"
]
master_ssl_ca
=
module
.
params
[
"master_ssl_ca"
]
master_ssl_capath
=
module
.
params
[
"master_ssl_capath"
]
master_ssl_cert
=
module
.
params
[
"master_ssl_cert"
]
master_ssl_key
=
module
.
params
[
"master_ssl_key"
]
master_ssl_cipher
=
module
.
params
[
"master_ssl_cipher"
]
if
not
mysqldb_found
:
module
.
fail_json
(
msg
=
"the python mysqldb module is required"
)
else
:
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
:
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"
],
user
=
login_user
,
passwd
=
login_password
,
db
=
"mysql"
)
cursor
=
db_connection
.
cursor
()
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"
)
if
mode
in
"getmaster"
:
masterstatus
=
get_master_status
(
cursor
)
try
:
module
.
exit_json
(
File
=
masterstatus
[
0
],
Position
=
masterstatus
[
1
],
Binlog_Do_DB
=
masterstatus
[
2
],
Binlog_Ignore_DB
=
masterstatus
[
3
]
)
except
TypeError
:
module
.
fail_json
(
msg
=
"Server is not configured as mysql master"
)
elif
mode
in
"getslave"
:
slavestatus
=
get_slave_status
(
cursor
)
try
:
module
.
exit_json
(
Slave_IO_State
=
slavestatus
[
0
],
Master_Host
=
slavestatus
[
1
],
Master_User
=
slavestatus
[
2
],
Master_Port
=
slavestatus
[
3
],
Connect_Retry
=
slavestatus
[
4
],
Master_Log_File
=
slavestatus
[
5
],
Read_Master_Log_Pos
=
slavestatus
[
6
],
Relay_Log_File
=
slavestatus
[
7
],
Relay_Log_Pos
=
slavestatus
[
8
],
Relay_Master_Log_File
=
slavestatus
[
9
],
Slave_IO_Running
=
slavestatus
[
10
],
Slave_SQL_Running
=
slavestatus
[
11
],
Replicate_Do_DB
=
slavestatus
[
12
],
Replicate_Ignore_DB
=
slavestatus
[
13
],
Replicate_Do_Table
=
slavestatus
[
14
],
Replicate_Ignore_Table
=
slavestatus
[
15
],
Replicate_Wild_Do_Table
=
slavestatus
[
16
],
Replicate_Wild_Ignore_Table
=
slavestatus
[
17
],
Last_Errno
=
slavestatus
[
18
],
Last_Error
=
slavestatus
[
19
],
Skip_Counter
=
slavestatus
[
20
],
Exec_Master_Log_Pos
=
slavestatus
[
21
],
Relay_Log_Space
=
slavestatus
[
22
],
Until_Condition
=
slavestatus
[
23
],
Until_Log_File
=
slavestatus
[
24
],
Until_Log_Pos
=
slavestatus
[
25
],
Master_SSL_Allowed
=
slavestatus
[
26
],
Master_SSL_CA_File
=
slavestatus
[
27
],
Master_SSL_CA_Path
=
slavestatus
[
28
],
Master_SSL_Cert
=
slavestatus
[
29
],
Master_SSL_Cipher
=
slavestatus
[
30
],
Master_SSL_Key
=
slavestatus
[
31
],
Seconds_Behind_Master
=
slavestatus
[
32
],
Master_SSL_Verify_Server_Cert
=
slavestatus
[
33
],
Last_IO_Errno
=
slavestatus
[
34
],
Last_IO_Error
=
slavestatus
[
35
],
Last_SQL_Errno
=
slavestatus
[
36
],
Last_SQL_Error
=
slavestatus
[
37
],
Replicate_Ignore_Server_Ids
=
slavestatus
[
38
],
Master_Server_Id
=
slavestatus
[
39
]
)
except
TypeError
:
module
.
fail_json
(
msg
=
"Server is not configured as mysql slave"
)
elif
mode
in
"changemaster"
:
print
"Change master"
chm
=
[]
if
master_host
:
chm
.
append
(
"MASTER_HOST='"
+
master_host
+
"'"
)
if
master_user
:
chm
.
append
(
"MASTER_USER='"
+
master_user
+
"'"
)
if
master_password
:
chm
.
append
(
"MASTER_PASSWORD='"
+
master_password
+
"'"
)
if
master_port
:
chm
.
append
(
"MASTER_PORT='"
+
master_port
+
"'"
)
if
master_connect_retry
:
chm
.
append
(
"MASTER_CONNECT_RETRY='"
+
master_connect_retry
+
"'"
)
if
master_log_file
:
chm
.
append
(
"MASTER_LOG_FILE='"
+
master_log_file
+
"'"
)
if
master_log_pos
:
chm
.
append
(
"MASTER_LOG_POS="
+
master_log_pos
)
if
relay_log_file
:
chm
.
append
(
"RELAY_LOG_FILE='"
+
relay_log_file
+
"'"
)
if
relay_log_pos
:
chm
.
append
(
"RELAY_LOG_POS="
+
relay_log_pos
)
if
master_ssl
:
chm
.
append
(
"MASTER_SSL="
+
master_ssl
)
if
master_ssl_ca
:
chm
.
append
(
"MASTER_SSL_CA='"
+
master_ssl_ca
+
"'"
)
if
master_ssl_capath
:
chm
.
append
(
"MASTER_SSL_CAPATH='"
+
master_ssl_capath
+
"'"
)
if
master_ssl_cert
:
chm
.
append
(
"MASTER_SSL_CERT='"
+
master_ssl_cert
+
"'"
)
if
master_ssl_key
:
chm
.
append
(
"MASTER_SSL_KEY='"
+
master_ssl_key
+
"'"
)
if
master_ssl_cipher
:
chm
.
append
(
"MASTER_SSL_CIPTHER='"
+
master_ssl_cipher
+
"'"
)
changemaster
(
cursor
,
chm
)
module
.
exit_json
(
changed
=
True
)
elif
mode
in
"startslave"
:
started
=
start_slave
(
cursor
)
if
started
is
True
:
module
.
exit_json
(
msg
=
"Slave started "
,
changed
=
True
)
else
:
module
.
exit_json
(
msg
=
"Slave already started (Or cannot be started)"
,
changed
=
False
)
elif
mode
in
"stopslave"
:
stopped
=
stop_slave
(
cursor
)
if
stopped
is
True
:
module
.
exit_json
(
msg
=
"Slave stopped"
,
changed
=
True
)
else
:
module
.
exit_json
(
msg
=
"Slave already stopped"
,
changed
=
False
)
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment