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

15.7.5.1. Используя Интерфейс Администрирования

К интерфейсу администрирования mysql-прокси можно получить доступ, используя любой клиент MySQL, использующий стандартные протоколы. Можно использовать интерфейс администрирования, чтобы получить информацию о прокси-сервере в целом - стандартные соединения с прокси изолируются, чтобы работать, как будто Вы были соединены непосредственно с сервером MySQL бэкэнда.

В mysql-прокси 0.8.0 и ранее, элементарный интерфейс был встроен в прокси. В более поздних версиях это было заменено так, чтобы Вы определили сценарий администрирования, который будет использоваться, когда пользователи соединяются с интерфейсом администрирования.

Чтобы использовать интерфейс администрирования, определите имя пользователя и пароль, требуемый соединяться с администраторской службой, используя --admin-username и --admin-password опции. Следует также определить сценарий Lua, который будет использоваться в качестве интерфейса к службе администрирования при использовании admin-lua-script опция сценария, чтобы указать на сценарий Lua.

Например, можно создать основной интерфейс к внутренним компонентам системы mysql-прокси, используя следующий сценарий, записанный Диего Мединой:

--[[   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--]]

Сценарий работает в комбинации с основным сценарием прокси, 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

Чтобы использовать сценарий, сохраните первый сценарий к файлу (admin.lua в следующем примере) и другой к reporter.lua, тогда выполненный mysql-прокси, определяющий администраторский сценарий и сервер MySQL бэкэнда:

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

В различном окне соединитесь с сервером MySQL через прокси:

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> 

В другом различном окне соединитесь с администраторской службой mysql-прокси, используя указанное имя пользователя и пароль:

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>

Чтобы контролировать состояние прокси, попросите список текущих активных процессов:

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>

Для получения дополнительной информации по примеру см. MySQL Proxy Admin Example.