febbb5b40b
Replacement for MySQL balancing solution provided by haproxy. Needed-By: https://review.opendev.org/c/openstack/kolla-ansible/+/770215 Change-Id: I85ebe3b20294cd9dc847a3582053d3e21f6a2216
153 lines
5.4 KiB
Python
153 lines
5.4 KiB
Python
#!/usr/bin/python3
|
|
|
|
# Copyright 2021 Michal Arbet
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import logging
|
|
import os
|
|
import yaml
|
|
|
|
# Default paths
|
|
PROXYSQL_CONFIG_DIR = "/etc/proxysql"
|
|
PROXYSQL_CONFIG = "/etc/proxysql.cnf"
|
|
|
|
# Logging
|
|
log_format = '%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s'
|
|
logging.basicConfig(format=log_format,
|
|
datefmt='%H:%M:%S',
|
|
level=logging.DEBUG)
|
|
LOG = logging.getLogger("proxysql_config_sync")
|
|
|
|
|
|
class ProxySQLConfig:
|
|
|
|
def __init__(self, conf_dir, conf_file):
|
|
self.configs = dict()
|
|
self.config = dict()
|
|
self.configs['global'] = "{}/proxysql.yaml".format(conf_dir)
|
|
self.configs['users'] = "{}/users".format(conf_dir)
|
|
self.configs['rules'] = "{}/rules".format(conf_dir)
|
|
self.conf_file = conf_file
|
|
self._load_config()
|
|
|
|
def _load_config(self):
|
|
users = dict()
|
|
rules = dict()
|
|
|
|
for cfg, path in self.configs.items():
|
|
if not os.path.isdir(path):
|
|
with open(path) as config_file:
|
|
self.config.update(
|
|
yaml.safe_load(config_file))
|
|
else:
|
|
users['mysql_users'] = list()
|
|
rules['mysql_query_rules'] = list()
|
|
user_paths = [os.path.join(self.configs['users'], f)
|
|
for f in os.listdir(self.configs['users'])]
|
|
rule_paths = [os.path.join(self.configs['rules'], f)
|
|
for f in os.listdir(self.configs['rules'])]
|
|
|
|
for user_conf in user_paths:
|
|
with open(user_conf) as config_file:
|
|
tmp_users = yaml.safe_load(config_file)
|
|
for i in tmp_users['mysql_users']:
|
|
users['mysql_users'].append(i)
|
|
self.config.update(users)
|
|
for rule_conf in rule_paths:
|
|
with open(rule_conf) as config_file:
|
|
tmp_rules = yaml.safe_load(config_file)
|
|
for i in tmp_rules['mysql_query_rules']:
|
|
rules['mysql_query_rules'].append(i)
|
|
self.config.update(rules)
|
|
self._sanity()
|
|
|
|
def _sanity(self):
|
|
self._users_sanity()
|
|
self._rules_sanity()
|
|
|
|
def _users_sanity(self):
|
|
users_added = list()
|
|
users = list()
|
|
for user in self.config['mysql_users']:
|
|
if user['username'] not in users_added:
|
|
users_added.append(user['username'])
|
|
users.append(user)
|
|
else:
|
|
LOG.warning("User {} already exist, ignoring."
|
|
.format(user['username']))
|
|
self.config['mysql_users'] = users
|
|
|
|
def _rules_sanity(self):
|
|
rules_added = list()
|
|
rules = list()
|
|
rule_id = 1
|
|
for rule in self.config['mysql_query_rules']:
|
|
if rule['schemaname'] not in rules_added:
|
|
rules_added.append(rule['schemaname'])
|
|
rule['rule_id'] = rule_id
|
|
rules.append(rule)
|
|
rule_id += 1
|
|
else:
|
|
LOG.warning("Rule witch schemaname {} already exist, ignoring."
|
|
.format(rule['schemaname']))
|
|
self.config['mysql_query_rules'] = rules
|
|
|
|
def _write_dict(self, key, value):
|
|
if not isinstance(value, list):
|
|
value = [value]
|
|
with open(self.conf_file, "a+") as f:
|
|
if key:
|
|
f.write("{} =\n".format(key))
|
|
for i in range(len(value)):
|
|
f.write(" {\n")
|
|
for k, v in value[i].items():
|
|
if isinstance(v, str):
|
|
v = '"{}"'.format(v)
|
|
f.write(" {} = {}\n".format(k, v))
|
|
if i == len(value)-1:
|
|
f.write(" }\n")
|
|
else:
|
|
f.write(" },\n")
|
|
|
|
def _write_list(self, key, values):
|
|
with open(self.conf_file, "a+") as f:
|
|
f.write("{} =\n".format(key))
|
|
f.write("(\n")
|
|
self._write_dict(key=None, value=values)
|
|
with open(self.conf_file, "a+") as f:
|
|
f.write(")\n")
|
|
|
|
def _write(self, key, value):
|
|
with open(self.conf_file, "a+") as f:
|
|
if isinstance(value, str):
|
|
value = '"{}"'.format(value)
|
|
f.write("{} = {}\n".format(key, value))
|
|
|
|
def write_config(self):
|
|
LOG.info("Writing config to {}".format(self.conf_file))
|
|
if os.path.exists(self.conf_file):
|
|
os.remove(self.conf_file)
|
|
for k, v in self.config.items():
|
|
if isinstance(v, dict):
|
|
self._write_dict(k, v)
|
|
elif isinstance(v, list):
|
|
self._write_list(k, v)
|
|
else:
|
|
self._write(k, v)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
config = ProxySQLConfig(PROXYSQL_CONFIG_DIR, PROXYSQL_CONFIG)
|
|
config.write_config()
|