The mysql-proxy administration interface can be accessed using any MySQL client using the standard protocols. You can use the administration interface to gain information about the proxy server as a whole - standard connections to the proxy are isolated to operate as if you were connected directly to the backend MySQL server.
In mysql-proxy 0.8.0 and earlier, a rudimentary interface was built into the proxy. In later versions this was replaced so that you must specify an administration script to be used when users connect to the administration interface.
To use the administration interface, you should specify the
username and password required to connect to the admin point
(using the --admin-username
and
--admin-password
options). You must also
specify the Lua script to be used as the interface to the
administration service by using the
admin-lua-script
script option to point to a
Lua script.
For example, you can create a basic interface to the internal components of the mysql-proxy system using the following script, written by Diego Medina:
--[[ Copyright (C) 2009 MySQL AB, 2008 Sun Microsystems, Inc This program 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; version 2 of the License. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --]] -- admin.lua --[[ See http://forge.mysql.com/tools/tool.php?id=78 (Thanks to Jan Kneschke) See http://www.chriscalender.com/?p=41 (Thanks to Chris Calender) See http://datacharmer.blogspot.com/2009/01/mysql-proxy-is-back.html (Thanks Giuseppe Maxia) --]] function set_error(errmsg) proxy.response = { type = proxy.MYSQLD_PACKET_ERR, errmsg = errmsg or "error" } end function read_query(packet) if packet:byte() ~= proxy.COM_QUERY then set_error("[admin] we only handle text-based queries (COM_QUERY)") return proxy.PROXY_SEND_RESULT end local query = packet:sub(2) local rows = { } local fields = { } -- try to match the string up to the first non-alphanum local f_s, f_e, command = string.find(packet, "^%s*(%w+)", 2) local option if f_e then -- if that match, take the next sub-string as option f_s, f_e, option = string.find(packet, "^%s+(%w+)", f_e + 1) end -- we got our commands, execute it if command == "show" and option == "querycounter" then --- -- proxy.PROXY_SEND_RESULT requires -- -- proxy.response.type to be either -- * proxy.MYSQLD_PACKET_OK or -- * proxy.MYSQLD_PACKET_ERR -- -- for proxy.MYSQLD_PACKET_OK you need a resultset -- * fields -- * rows -- -- for proxy.MYSQLD_PACKET_ERR -- * errmsg proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { { type = proxy.MYSQL_TYPE_LONG, name = "query_counter", }, }, rows = { { proxy.global.query_counter } } } -- we have our result, send it back return proxy.PROXY_SEND_RESULT elseif command == "show" and option == "myerror" then proxy.response.type = proxy.MYSQLD_PACKET_ERR proxy.response.errmsg = "my first error" return proxy.PROXY_SEND_RESULT elseif string.sub(packet, 2):lower() == 'select help' then return show_process_help() elseif string.sub(packet, 2):lower() == 'show proxy processlist' then return show_process_table() elseif query == "SELECT * FROM backends" then fields = { { name = "backend_ndx", type = proxy.MYSQL_TYPE_LONG }, { name = "address", type = proxy.MYSQL_TYPE_STRING }, { name = "state", type = proxy.MYSQL_TYPE_STRING }, { name = "type", type = proxy.MYSQL_TYPE_STRING }, } for i = 1, #proxy.global.backends do local b = proxy.global.backends[i] rows[#rows + 1] = { i, b.dst.name, b.state, b.type } end else set_error() return proxy.PROXY_SEND_RESULT end proxy.response = { type = proxy.MYSQLD_PACKET_OK, resultset = { fields = fields, rows = rows } } return proxy.PROXY_SEND_RESULT end function make_dataset (header, dataset) proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = {}, rows = {} } for i,v in pairs (header) do table.insert(proxy.response.resultset.fields, {type = proxy.MYSQL_TYPE_STRING, name = v}) end for i,v in pairs (dataset) do table.insert(proxy.response.resultset.rows, v ) end return proxy.PROXY_SEND_RESULT end function show_process_table() local dataset = {} local header = { 'Id', 'IP Address', 'Time' } local rows = {} for t_i, t_v in pairs (proxy.global.process) do for s_i, s_v in pairs ( t_v ) do table.insert(rows, { t_i, s_v.ip, os.date('%c',s_v.ts) }) end end return make_dataset(header,rows) end function show_process_help() local dataset = {} local header = { 'command', 'description' } local rows = { {'SELECT HELP', 'This command.'}, {'SHOW PROXY PROCESSLIST', 'Show all connections and their true IP Address.'}, } return make_dataset(header,rows) end function dump_process_table() proxy.global.initialize_process_table() print('current contents of process table') for t_i, t_v in pairs (proxy.global.process) do print ('session id: ', t_i) for s_i, s_v in pairs ( t_v ) do print ( '\t', s_i, s_v.ip, s_v.ts ) end end print ('---END PROCESS TABLE---') end --[[ Help we use a simple string-match to split commands are word-boundaries mysql> show querycounter is split into command = "show" option = "querycounter" spaces are ignored, the case has to be as is. mysql> show myerror returns a error-packet --]]
The script works in combination with a main proxy script,
reporter.lua
:
--[[ Copyright (C) 2009 MySQL AB, 2008 Sun Microsystems, Inc This program 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; version 2 of the License. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --]] -- reporter.lua --[[ See http://forge.mysql.com/tools/tool.php?id=78 (Thanks to Jan Kneschke) See http://www.chriscalender.com/?p=41 (Thanks to Chris Calender) See http://datacharmer.blogspot.com/2009/01/mysql-proxy-is-back.html (Thanks Giuseppe Maxia) --]] proxy.global.query_counter = proxy.global.query_counter or 0 function proxy.global.initialize_process_table() if proxy.global.process == nil then proxy.global.process = {} end if proxy.global.process[proxy.connection.server.thread_id] == nil then proxy.global.process[proxy.connection.server.thread_id] = {} end end function read_auth_result( auth ) local state = auth.packet:byte() if state == proxy.MYSQLD_PACKET_OK then proxy.global.initialize_process_table() table.insert( proxy.global.process[proxy.connection.server.thread_id], { ip = proxy.connection.client.src.name, ts = os.time() } ) end end function disconnect_client() local connection_id = proxy.connection.server.thread_id if connection_id then -- client has disconnected, set this to nil proxy.global.process[connection_id] = nil end end --- -- read_query() can return a resultset -- -- You can use read_query() to return a result-set. -- -- @param packet the mysql-packet sent by the client -- -- @return -- * nothing to pass on the packet as is, -- * proxy.PROXY_SEND_QUERY to send the queries from the proxy.queries queue -- * proxy.PROXY_SEND_RESULT to send your own result-set -- function read_query( packet ) -- a new query came in in this connection -- using proxy.global.* to make it available to the admin plugin proxy.global.query_counter = proxy.global.query_counter + 1 end
To use the script, save the first script to a file
(admin.lua
in the example below) and the
other to reporter.lua
, and then run
mysql-proxy specifying the admin script and a
backend MySQL server:
shell> mysql-proxy --admin-lua-script=admin.lua --admin-password=password \ » --admin-username=root --backend-addresses=127.0.0.1:3306 -proxy-lua-script=reporter.lua
In a separate window, connect to the MySQL server through the proxy:
shell> mysql --user=root --password=password --port=4040 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1798669 Server version: 5.0.70-log Gentoo Linux mysql-5.0.70-r1 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>
In another different window, connect to the mysql-proxy admin service using the specified username and password:
shell> mysql --user=root --password=password --port=4041 --host=localhost Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.0.99-agent-admin Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>
You can monitor the status of the proxy by asking for a list of the current active processes:
mysql> show proxy processlist; +---------+---------------------+--------------------------+ | Id | IP Address | Time | +---------+---------------------+--------------------------+ | 1798669 | 192.168.0.112:52592 | Wed Jan 20 16:58:00 2010 | +---------+---------------------+--------------------------+ 1 row in set (0.00 sec) mysql>
For more information on the example, see MySQL Proxy Admin Example.