mirror of https://github.com/sysown/proxysql
Conflicts: include/proxysql.h lib/MySQL_Session.cpppull/739/head
commit
cbfc9bfcfd
@ -0,0 +1,47 @@
|
||||
301,338d300
|
||||
< static int my_verify_callback(int ok, X509_STORE_CTX *ctx)
|
||||
< {
|
||||
< X509 *check_cert;
|
||||
< SSL *ssl;
|
||||
< MYSQL *mysql;
|
||||
< DBUG_ENTER("my_verify_callback");
|
||||
<
|
||||
< ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
< DBUG_ASSERT(ssl != NULL);
|
||||
< mysql= (MYSQL *)SSL_get_app_data(ssl);
|
||||
< DBUG_ASSERT(mysql != NULL);
|
||||
<
|
||||
< /* skip verification if no ca_file/path was specified */
|
||||
< if (!mysql->options.ssl_ca && !mysql->options.ssl_capath)
|
||||
< {
|
||||
< ok= 1;
|
||||
< DBUG_RETURN(1);
|
||||
< }
|
||||
<
|
||||
< if (!ok)
|
||||
< {
|
||||
< uint depth;
|
||||
< if (!(check_cert= X509_STORE_CTX_get_current_cert(ctx)))
|
||||
< DBUG_RETURN(0);
|
||||
< depth= X509_STORE_CTX_get_error_depth(ctx);
|
||||
< if (depth == 0)
|
||||
< ok= 1;
|
||||
< }
|
||||
<
|
||||
< /*
|
||||
< my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||
< ER(CR_SSL_CONNECTION_ERROR),
|
||||
< X509_verify_cert_error_string(ctx->error));
|
||||
< */
|
||||
< DBUG_RETURN(ok);
|
||||
< }
|
||||
<
|
||||
<
|
||||
352d313
|
||||
< int verify;
|
||||
372,376d332
|
||||
< verify= (!mysql->options.ssl_ca && !mysql->options.ssl_capath) ?
|
||||
< SSL_VERIFY_NONE : SSL_VERIFY_PEER;
|
||||
<
|
||||
< SSL_CTX_set_verify(SSL_context, verify, my_verify_callback);
|
||||
< SSL_CTX_set_verify_depth(SSL_context, 1);
|
||||
@ -0,0 +1,7 @@
|
||||
enabled=True
|
||||
db = None
|
||||
host = 127.0.0.1
|
||||
passwd = stats
|
||||
port = 6032
|
||||
user = stats
|
||||
|
||||
@ -0,0 +1,191 @@
|
||||
# coding=utf-8
|
||||
|
||||
import diamond.collector
|
||||
from diamond.collector import str_to_bool
|
||||
import re
|
||||
import time
|
||||
|
||||
try:
|
||||
import MySQLdb
|
||||
from MySQLdb import MySQLError
|
||||
except ImportError:
|
||||
MySQLdb = None
|
||||
MySQLError = ValueError
|
||||
|
||||
|
||||
class ProxySQLCollector(diamond.collector.Collector):
|
||||
|
||||
_GAUGE_KEYS = [
|
||||
'Active_Transactions',
|
||||
'Client_Connections_connected',
|
||||
'ConnPool_memory_bytes',
|
||||
'MySQL_Monitor_Workers',
|
||||
'MySQL_Thread_Workers',
|
||||
'Query_Cache_Entries',
|
||||
'Query_Cache_Memory_bytes',
|
||||
'SQLite3_memory_bytes',
|
||||
'Server_Connections_connected',
|
||||
'mysql_backend_buffers_bytes',
|
||||
'mysql_frontend_buffers_bytes',
|
||||
'mysql_session_internal_bytes',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProxySQLCollector, self).__init__(*args, **kwargs)
|
||||
|
||||
def process_config(self):
|
||||
super(ProxySQLCollector, self).process_config()
|
||||
if self.config['hosts'].__class__.__name__ != 'list':
|
||||
self.config['hosts'] = [self.config['hosts']]
|
||||
|
||||
# Move legacy config format to new format
|
||||
if 'host' in self.config:
|
||||
hoststr = "%s:%s@%s:%s/%s" % (
|
||||
self.config['user'],
|
||||
self.config['passwd'],
|
||||
self.config['host'],
|
||||
self.config['port'],
|
||||
self.config['db'],
|
||||
)
|
||||
self.config['hosts'].append(hoststr)
|
||||
|
||||
self.db = None
|
||||
|
||||
def get_default_config_help(self):
|
||||
config_help = super(ProxySQLCollector, self).get_default_config_help()
|
||||
config_help.update({
|
||||
'publish':
|
||||
"Which rows of 'SHOW MYSQL STATUS' you would " +
|
||||
"like to publish. Leave unset to publish all",
|
||||
'hosts': 'List of hosts to collect from. Format is ' +
|
||||
'yourusername:yourpassword@host:port/db[/nickname]' +
|
||||
'use db "None" to avoid connecting to a particular db'
|
||||
})
|
||||
return config_help
|
||||
|
||||
def get_default_config(self):
|
||||
"""
|
||||
Returns the default collector settings
|
||||
"""
|
||||
config = super(ProxySQLCollector, self).get_default_config()
|
||||
config.update({
|
||||
'path': 'proxysql',
|
||||
# Connection settings
|
||||
'hosts': [],
|
||||
|
||||
})
|
||||
return config
|
||||
|
||||
def get_db_stats(self, query):
|
||||
cursor = self.db.cursor(cursorclass=MySQLdb.cursors.DictCursor)
|
||||
|
||||
try:
|
||||
cursor.execute(query)
|
||||
return cursor.fetchall()
|
||||
except MySQLError, e:
|
||||
self.log.error('ProxySQLCollector could not get db stats', e)
|
||||
return ()
|
||||
|
||||
def connect(self, params):
|
||||
try:
|
||||
self.db = MySQLdb.connect(**params)
|
||||
self.log.debug('ProxySQLCollector: Connected to database.')
|
||||
except MySQLError, e:
|
||||
self.log.error('ProxySQLCollector couldnt connect to database %s', e)
|
||||
return False
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
self.db.close()
|
||||
|
||||
def get_db_global_status(self):
|
||||
return self.get_db_stats('SHOW MYSQL STATUS')
|
||||
|
||||
def get_stats(self, params):
|
||||
metrics = {'status': {}}
|
||||
|
||||
if not self.connect(params):
|
||||
return metrics
|
||||
|
||||
rows = self.get_db_global_status()
|
||||
for row in rows:
|
||||
try:
|
||||
metrics['status'][row['Variable_name']] = float(row['Value'])
|
||||
except:
|
||||
pass
|
||||
|
||||
self.disconnect()
|
||||
|
||||
return metrics
|
||||
|
||||
def _publish_stats(self, nickname, metrics):
|
||||
|
||||
for key in metrics:
|
||||
for metric_name in metrics[key]:
|
||||
metric_value = metrics[key][metric_name]
|
||||
|
||||
if type(metric_value) is not float:
|
||||
continue
|
||||
|
||||
if metric_name not in self._GAUGE_KEYS:
|
||||
metric_value = self.derivative(nickname + metric_name,
|
||||
metric_value)
|
||||
if key == 'status':
|
||||
if (('publish' not in self.config or
|
||||
metric_name in self.config['publish'])):
|
||||
self.publish(nickname + metric_name, metric_value)
|
||||
else:
|
||||
self.publish(nickname + metric_name, metric_value)
|
||||
|
||||
def collect(self):
|
||||
|
||||
if MySQLdb is None:
|
||||
self.log.error('Unable to import MySQLdb')
|
||||
return False
|
||||
|
||||
for host in self.config['hosts']:
|
||||
matches = re.search(
|
||||
'^([^:]*):([^@]*)@([^:]*):?([^/]*)/([^/]*)/?(.*)', host)
|
||||
|
||||
if not matches:
|
||||
self.log.error(
|
||||
'Connection string not in required format, skipping: %s',
|
||||
host)
|
||||
continue
|
||||
|
||||
params = {}
|
||||
|
||||
params['host'] = matches.group(3)
|
||||
try:
|
||||
params['port'] = int(matches.group(4))
|
||||
except ValueError:
|
||||
params['port'] = 3306
|
||||
params['db'] = matches.group(5)
|
||||
params['user'] = matches.group(1)
|
||||
params['passwd'] = matches.group(2)
|
||||
|
||||
nickname = matches.group(6)
|
||||
if len(nickname):
|
||||
nickname += '.'
|
||||
|
||||
if params['db'] == 'None':
|
||||
del params['db']
|
||||
|
||||
try:
|
||||
metrics = self.get_stats(params=params)
|
||||
except Exception, e:
|
||||
try:
|
||||
self.disconnect()
|
||||
except MySQLdb.ProgrammingError:
|
||||
pass
|
||||
self.log.error('Collection failed for %s %s', nickname, e)
|
||||
continue
|
||||
|
||||
# Warn if publish contains an unknown variable
|
||||
if 'publish' in self.config and metrics['status']:
|
||||
for k in self.config['publish'].split():
|
||||
if k not in metrics['status']:
|
||||
self.log.error("No such key '%s' available, issue " +
|
||||
"'show global status' for a full " +
|
||||
"list", k)
|
||||
self._publish_stats(nickname, metrics)
|
||||
@ -0,0 +1,37 @@
|
||||
# ProxySQL v1.2.3
|
||||
|
||||
Release date: 2016-09-20
|
||||
|
||||
## Performance improvement
|
||||
|
||||
None
|
||||
|
||||
|
||||
## Usability improvement
|
||||
|
||||
* Admin: introduced new table `runtime_mysql_users` [#691](../../../../issues/691)
|
||||
* Compile: new packages avaiable for Fedora24
|
||||
* Compile: new packages avaiable for Ubuntu16
|
||||
* Doc: updated documentation on passwords
|
||||
* General: added suppot for systemd (yet not included in binaries)
|
||||
|
||||
|
||||
## New features
|
||||
|
||||
* Admin: introduced new variable `admin-hash_passwords` to automatically hash mysql passwords [#676](../../../../issues/676)
|
||||
* Query Cache: aggressive memory purging when 90% of memory limit is reached [#690](../../../../issues/690)
|
||||
* Query Processor: added parsing for several SQL commands
|
||||
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Mirroring: fixes several bugs related to errors handling
|
||||
* Mirroring: fixes crashing bug
|
||||
* Query Cache: memory used was computed incorrectly
|
||||
* Connection Pool: a failed `CHANGE_USER` could cause a crash [#682](../../../../issues/682)
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
Thanks to contributors, in alphabetical order:
|
||||
* @dveeden
|
||||
@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=High Performance Advanced Proxy for MySQL
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
LimitNOFILE=102400
|
||||
LimitCORE=1073741824
|
||||
ExecStart=/usr/local/bin/proxysql -f
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
Loading…
Reference in new issue