Spec-Zone .ru
спецификации, руководства, описания, API

15.7.5.1. Using the Administration Interface

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, specify the user name and password required to connect to the admin service, 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 2008, 2010, Oracle and/or its affiliates. All rights reserved.      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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA--]]-- admin.lua--[[    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"    }endfunction 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_RESULTendfunction 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_RESULTendfunction 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)endfunction 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)endfunction 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--[[    Helpwe use a simple string-match to split commands are word-boundariesmysql> show querycounteris split intocommand = "show"option  = "querycounter"spaces are ignored, the case has to be as is.mysql> show myerrorreturns a error-packet--]]

The script works in combination with a main proxy script, reporter.lua:

--[[   Copyright 2008, 2010, Oracle and/or its affiliates. All rights reserved.      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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA--]]-- reporter.lua--[[    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 0function 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] = {}    endendfunction 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() } )    endendfunction 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    endend----- 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 + 1end

To use the script, save the first script to a file (admin.lua in the following example) and the other to reporter.lua, 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
        --proxy-backend-addresses=127.0.0.1:3306 -proxy-lua-script=reporter.lua

In a different window, connect to the MySQL server through the proxy:

shell> mysql --user=root --password=password
        --port=4040Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 1798669Server version: 5.0.70-log Gentoo Linux mysql-5.0.70-r1Type '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 user name and password:

shell> mysql --user=root --password=password
        --port=4041 --host=localhostWelcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 1Server version: 5.0.99-agent-adminType 'help;' or '\h' for help. Type '\c' to clear the buffer.mysql>

To monitor the status of the proxy, ask 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.