2
# -*- mode: python; indent-tabs-mode: nil; -*-
3
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5
# Copyright (C) 2010,2011 Patrick Crews
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
""" mysqld.py: code to allow a serverManager
23
to provision and start up a mysqld server object
34
from lib.server_mgmt.server import Server
36
class mysqlServer(Server):
37
""" represents a mysql server, its possessions
38
(datadir, ports, etc), and methods for controlling
41
TODO: create a base server class that contains
42
standard methods from which we can inherit
43
Currently there are definitely methods / attr
48
def __init__( self, name, server_manager, code_tree, default_storage_engine
49
, server_options, requester, workdir_root):
50
super(mysqlServer, self).__init__( name
53
, default_storage_engine
57
self.preferred_base_port = 9306
60
self.mysqldump = self.code_tree.mysqldump
61
self.mysqladmin = self.code_tree.mysqladmin
62
self.mysql_client = self.code_tree.mysql_client
63
self.mysqlimport = self.code_tree.mysqlimport
64
self.mysqlslap = self.code_tree.mysqlslap
65
self.server_path = self.code_tree.mysql_server
66
self.mysql_client_path = self.code_tree.mysql_client
69
self.langdir = self.code_tree.langdir
70
self.charsetdir = self.code_tree.charsetdir
71
self.bootstrap_file = self.code_tree.bootstrap_path
72
self.bootstrap_cmd = None
75
self.port_block = self.system_manager.port_manager.get_port_block( self.name
76
, self.preferred_base_port
78
self.master_port = self.port_block[0]
80
# Generate our working directories
81
self.dirset = { self.name : { 'var': {'std_data_ln':( os.path.join(self.code_tree.testdir,'std_data'))
85
,'master-data': {'local': { 'test':None
92
self.workdir = self.system_manager.create_dirset( workdir_root
94
self.vardir = os.path.join(self.workdir,'var')
95
self.tmpdir = os.path.join(self.vardir,'tmp')
96
self.rundir = os.path.join(self.vardir,'run')
97
self.logdir = os.path.join(self.vardir,'log')
98
self.datadir = os.path.join(self.vardir,'master-data')
100
self.error_log = os.path.join(self.logdir,('%s.err' %(self.name)))
101
self.bootstrap_log = os.path.join(self.logdir,('bootstrap.log'))
102
self.pid_file = os.path.join(self.rundir,('%s.pid' %(self.name)))
103
self.socket_file = os.path.join(self.vardir, ('%s.sock' %(self.name)))
104
self.timer_file = os.path.join(self.logdir,('timer'))
106
self.snapshot_path = os.path.join(self.tmpdir,('snapshot_%s' %(self.master_port)))
107
# We want to use --secure-file-priv = $vardir by default
108
# but there are times / tools when we need to shut this off
109
if self.no_secure_file_priv:
110
self.secure_file_string = ''
112
self.secure_file_string = "--secure-file-priv='%s'" %(self.vardir)
113
self.user_string = '--user=root'
115
self.initialize_databases()
116
self.take_db_snapshot()
118
self.logging.debug_class(self)
121
""" We print out some general useful info """
122
report_values = [ 'name'
128
self.logging.info("%s server:" %(self.owner))
129
for key in report_values:
130
value = vars(self)[key]
131
self.logging.info("%s: %s" %(key.upper(), value))
133
def initialize_databases(self):
134
""" Do the voodoo required to have a working database setup.
135
For MySQL, this is calling the server with the
136
--bootstrap argument. We generate the bootstrap
137
file during codeTree intialization as the file is standard for
138
all MySQL servers that are spawned from a single codeTree
142
# generate the bootstrap startup command
143
if not self.bootstrap_cmd:
144
mysqld_args = [ "--no-defaults"
146
, "--basedir=%s" %(self.code_tree.basedir)
147
, "--datadir=%s" %(self.datadir)
148
, "--loose-skip-falcon"
149
, "--loose-skip-ndbcluster"
150
, "--tmpdir=%s" %(self.tmpdir)
152
, "--lc-messages-dir=%s" %(self.langdir)
153
, "--character-sets-dir=%s" %(self.charsetdir)
155
# We add server_path into the mix this way as we
156
# may alter how we store / handle server args later
157
mysqld_args = [self.server_path].append(mysqld_args)
158
self.bootstrap_cmd = " ".join(mysqld_args)
159
# execute our command
160
bootstrap_subproc = subprocess.Popen( self.bootstrap_cmd
162
, stdout=self.bootstrap_log
163
, stderr=self.bootstrap_log
165
bootstrap_subproc.wait()
166
bootstrap_retcode = bootstrap_subproc.returncode
167
if bootstrap_retcode:
168
self.logging.error("Received retcode: %s executing command: %s"
169
%(bootstrap_retcode, self.bootstrap_cmd))
170
self.logging.error("Check the bootstrap log: %s" %(self.bootstrap_log))
174
def get_start_cmd(self):
175
""" Return the command string that will start up the server
176
as desired / intended
180
server_args = [ self.process_server_options()
181
, "--mysql-protocol.port=%d" %(self.master_port)
182
, "--mysql-protocol.connect-timeout=60"
183
, "--innodb.data-file-path=ibdata1:20M:autoextend"
184
, "--sort-buffer-size=256K"
185
, "--max-heap-table-size=1M"
186
, "--mysql-unix-socket-protocol.path=%s" %(self.socket_file)
187
, "--pid-file=%s" %(self.pid_file)
188
, "--mysql-protocol.port=%d" %(self.mysql_tcp_port)
189
, "--default-storage-engine=%s" %(self.default_storage_engine)
190
, "--datadir=%s" %(self.datadir)
191
, "--tmpdir=%s" %(self.tmpdir)
192
, self.secure_file_string
197
server_args.append('--gdb')
198
return self.system_manager.handle_gdb_reqs(self, server_args)
200
return "%s %s %s & " % ( self.cmd_prefix
202
, " ".join(server_args)
206
def get_stop_cmd(self):
207
""" Return the command that will shut us down """
209
return "%s --user=root --port=%d --connect-timeout=5 --silent --password= --shutdown " %(self.mysql_client_path, self.master_port)
212
def get_ping_cmd(self):
213
"""Return the command string that will
214
ping / check if the server is alive
218
return "%s --ping --port=%d --user=root" % (self.mysql_client_path, self.master_port)
220
def is_started(self):
221
""" Determine if the server is up and running -
222
this may vary from server type to server type
226
# We experiment with waiting for a pid file to be created vs. pinging
227
# This is what test-run.pl does and it helps us pass logging_stats tests
228
# while not self.ping_server(server, quiet=True) and timer != timeout:
230
return self.system_manager.find_path( [self.pid_file]