MXS-591 Add filter for injecting comments
Comments specified in the cnf file will be injected as a comment before every sql statement.
This commit is contained in:
70
Documentation/Filters/Comment.md
Normal file
70
Documentation/Filters/Comment.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
# Comment Filter
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
With the _comment_ filter it is possible to define comments that are
|
||||||
|
injected before the actual statements. These comments appear as sql
|
||||||
|
comments when they are received by the server.
|
||||||
|
|
||||||
|
```
|
||||||
|
[MyComment]
|
||||||
|
type=filter
|
||||||
|
module=comment
|
||||||
|
inject=Comment to be injected
|
||||||
|
|
||||||
|
[MyService]
|
||||||
|
type=service
|
||||||
|
router=readwritesplit
|
||||||
|
servers=server1
|
||||||
|
user=myuser
|
||||||
|
passwd=mypasswd
|
||||||
|
filters=MyComment
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Filter Parameters
|
||||||
|
|
||||||
|
The Comment filter requires one mandatory parameter to be defined.
|
||||||
|
|
||||||
|
### `inject`
|
||||||
|
|
||||||
|
A parameter that contains the comment injected before the statements.
|
||||||
|
There is also defined variable $IP that can be used to comment the
|
||||||
|
IP address of the client in the injected comment.
|
||||||
|
Variables must be written in all caps.
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Example 1 - Inject IP address of the connected client into statements
|
||||||
|
as comment.
|
||||||
|
|
||||||
|
You want to see the IP addresses of the clients with the server so you
|
||||||
|
define filter to comment the into the statements they send.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
[IPComment]
|
||||||
|
type=filter
|
||||||
|
module=comment
|
||||||
|
inject=IP=$IP
|
||||||
|
|
||||||
|
[MyService]
|
||||||
|
type=service
|
||||||
|
router=readwritesplit
|
||||||
|
servers=server1
|
||||||
|
user=myuser
|
||||||
|
passwd=mypasswd
|
||||||
|
filters=IPComment
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example when MaxScale receives statement like:
|
||||||
|
```
|
||||||
|
SELECT user FROM people;
|
||||||
|
```
|
||||||
|
It would look like
|
||||||
|
```
|
||||||
|
/* IP=::ffff:127.0.0.1 */SELECT user FROM people;
|
||||||
|
```
|
||||||
|
when received by server.
|
||||||
@ -16,3 +16,4 @@ add_subdirectory(tee)
|
|||||||
add_subdirectory(throttlefilter)
|
add_subdirectory(throttlefilter)
|
||||||
add_subdirectory(topfilter)
|
add_subdirectory(topfilter)
|
||||||
add_subdirectory(tpmfilter)
|
add_subdirectory(tpmfilter)
|
||||||
|
add_subdirectory(comment)
|
||||||
|
|||||||
4
server/modules/filter/comment/CMakeLists.txt
Normal file
4
server/modules/filter/comment/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
add_library(comment SHARED commentfilter.cc commentfiltersession.cc)
|
||||||
|
set_target_properties(comment PROPERTIES VERSION "1.0.0")
|
||||||
|
install_module(comment core)
|
||||||
|
|
||||||
91
server/modules/filter/comment/commentfilter.cc
Normal file
91
server/modules/filter/comment/commentfilter.cc
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||||
|
*
|
||||||
|
* Change Date: 2020-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// All log messages from this module are prefixed with this
|
||||||
|
#define MXS_MODULE_NAME "commentfilter"
|
||||||
|
|
||||||
|
#include "commentfilter.hh"
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const char CN_INJECT[] = "inject";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// This declares a module in MaxScale
|
||||||
|
extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||||
|
{
|
||||||
|
static MXS_MODULE info =
|
||||||
|
{
|
||||||
|
MXS_MODULE_API_FILTER,
|
||||||
|
MXS_MODULE_IN_DEVELOPMENT,
|
||||||
|
MXS_FILTER_VERSION,
|
||||||
|
"A comment filter that can inject comments in sql queries",
|
||||||
|
"V1.0.0",
|
||||||
|
RCAP_TYPE_NONE,
|
||||||
|
&CommentFilter::s_object, // This is defined in the MaxScale filter template
|
||||||
|
NULL, /* Process init. */
|
||||||
|
NULL, /* Process finish. */
|
||||||
|
NULL, /* Thread init. */
|
||||||
|
NULL, /* Thread finish. */
|
||||||
|
{
|
||||||
|
{ CN_INJECT, MXS_MODULE_PARAM_STRING, NULL, MXS_MODULE_OPT_REQUIRED },
|
||||||
|
{ MXS_END_MODULE_PARAMS }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return &info;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentFilter::CommentFilter(std::string comment) : m_comment(comment)
|
||||||
|
{
|
||||||
|
MXS_INFO("Comment filter with comment [%s] created.", m_comment.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentFilter::~CommentFilter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
CommentFilter* CommentFilter::create(const char* zName, char** pzOptions, MXS_CONFIG_PARAMETER* pParams)
|
||||||
|
{
|
||||||
|
return new CommentFilter(config_get_string(pParams, CN_INJECT));
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentFilterSession* CommentFilter::newSession(MXS_SESSION* pSession)
|
||||||
|
{
|
||||||
|
return CommentFilterSession::create(pSession, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void CommentFilter::diagnostics(DCB* pDcb) const
|
||||||
|
{
|
||||||
|
dcb_printf(pDcb, "Comment filter with comment: %s", m_comment.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
json_t* CommentFilter::diagnostics_json() const
|
||||||
|
{
|
||||||
|
json_t* rval = json_object();
|
||||||
|
json_object_set_new(rval, "Comment", json_string(m_comment.c_str()));
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
uint64_t CommentFilter::getCapabilities()
|
||||||
|
{
|
||||||
|
return RCAP_TYPE_NONE;
|
||||||
|
}
|
||||||
53
server/modules/filter/comment/commentfilter.hh
Normal file
53
server/modules/filter/comment/commentfilter.hh
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||||
|
*
|
||||||
|
* Change Date: 2020-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <maxscale/cppdefs.hh>
|
||||||
|
#include <maxscale/filter.hh>
|
||||||
|
#include "commentfiltersession.hh"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CommentFilter : public maxscale::Filter<CommentFilter, CommentFilterSession>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Prevent copy-constructor and assignment operator usage
|
||||||
|
CommentFilter(const CommentFilter&) = delete;
|
||||||
|
CommentFilter& operator = (const CommentFilter&) = delete;
|
||||||
|
|
||||||
|
~CommentFilter();
|
||||||
|
|
||||||
|
// Creates a new filter instance
|
||||||
|
static CommentFilter* create(const char* zName, char** pzOptions, MXS_CONFIG_PARAMETER* ppParams);
|
||||||
|
|
||||||
|
// Creates a new session for this filter
|
||||||
|
CommentFilterSession* newSession(MXS_SESSION* pSession);
|
||||||
|
|
||||||
|
// Print diagnostics to a DCB
|
||||||
|
void diagnostics(DCB* pDcb) const;
|
||||||
|
|
||||||
|
|
||||||
|
// Returns JSON form diagnostic data
|
||||||
|
json_t* diagnostics_json() const;
|
||||||
|
|
||||||
|
// Get filter capabilities
|
||||||
|
uint64_t getCapabilities();
|
||||||
|
std::string comment() const
|
||||||
|
{
|
||||||
|
return m_comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_comment;
|
||||||
|
// Used in the create function
|
||||||
|
CommentFilter(std::string comment);
|
||||||
|
};
|
||||||
80
server/modules/filter/comment/commentfiltersession.cc
Normal file
80
server/modules/filter/comment/commentfiltersession.cc
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||||
|
*
|
||||||
|
* Change Date: 2020-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// All log messages from this module are prefixed with this
|
||||||
|
#define MXS_MODULE_NAME "commentfilter"
|
||||||
|
|
||||||
|
#include "commentfiltersession.hh"
|
||||||
|
#include "commentfilter.hh"
|
||||||
|
#include <maxscale/modutil.hh>
|
||||||
|
#include <string>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
CommentFilterSession::CommentFilterSession(MXS_SESSION* pSession, const CommentFilter* pFilter)
|
||||||
|
: maxscale::FilterSession(pSession),
|
||||||
|
m_filter(*pFilter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentFilterSession::~CommentFilterSession()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
CommentFilterSession* CommentFilterSession::create(MXS_SESSION* pSession, const CommentFilter* pFilter)
|
||||||
|
{
|
||||||
|
return new CommentFilterSession(pSession, pFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommentFilterSession::close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CommentFilterSession::routeQuery(GWBUF* pPacket)
|
||||||
|
{
|
||||||
|
if (modutil_is_SQL(pPacket))
|
||||||
|
{
|
||||||
|
string sql = mxs::extract_sql(pPacket);
|
||||||
|
string comment = parseComment(m_filter.comment());
|
||||||
|
string newsql = string("/* ").append(comment).append(" */").append(sql);
|
||||||
|
pPacket = modutil_replace_SQL(pPacket, (char*)newsql.c_str());
|
||||||
|
//maxscale expects contiguous memory to arrive from client so we must make the buffer contiguous
|
||||||
|
//after using modutil_replace_SQL.
|
||||||
|
GWBUF* pModified_packet = gwbuf_make_contiguous(pPacket);
|
||||||
|
if (pModified_packet)
|
||||||
|
{
|
||||||
|
pPacket = pModified_packet;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gwbuf_free(pPacket);
|
||||||
|
pPacket = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pPacket ? mxs::FilterSession::routeQuery(pPacket) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CommentFilterSession::clientReply(GWBUF* pPacket)
|
||||||
|
{
|
||||||
|
return mxs::FilterSession::clientReply(pPacket);
|
||||||
|
}
|
||||||
|
//TODO this probably should be refactored in some way in case we add more variables
|
||||||
|
string CommentFilterSession::parseComment(string comment)
|
||||||
|
{
|
||||||
|
string ip = m_pSession->client_dcb->remote;
|
||||||
|
string parsedComment = std::regex_replace(comment, std::regex("\\$IP"), ip);
|
||||||
|
return parsedComment;
|
||||||
|
}
|
||||||
48
server/modules/filter/comment/commentfiltersession.hh
Normal file
48
server/modules/filter/comment/commentfiltersession.hh
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||||
|
*
|
||||||
|
* Change Date: 2020-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <maxscale/cppdefs.hh>
|
||||||
|
#include <maxscale/filter.hh>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CommentFilter;
|
||||||
|
|
||||||
|
class CommentFilterSession : public maxscale::FilterSession
|
||||||
|
{
|
||||||
|
// Prevent copy-constructor and assignment operator usage
|
||||||
|
CommentFilterSession(const CommentFilterSession&);
|
||||||
|
CommentFilterSession& operator = (const CommentFilterSession&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~CommentFilterSession();
|
||||||
|
|
||||||
|
// Called when a client session has been closed
|
||||||
|
void close();
|
||||||
|
|
||||||
|
// Create a new filter session
|
||||||
|
static CommentFilterSession* create(MXS_SESSION* pSession, const CommentFilter* pFilter);
|
||||||
|
|
||||||
|
// Handle a query from the client
|
||||||
|
int routeQuery(GWBUF* pPacket);
|
||||||
|
|
||||||
|
// Handle a reply from server
|
||||||
|
int clientReply(GWBUF* pPacket);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Used in the create function
|
||||||
|
CommentFilterSession(MXS_SESSION* pSession, const CommentFilter* pFilter);
|
||||||
|
const CommentFilter& m_filter;
|
||||||
|
std::string parseComment(std::string comment);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user