summaryrefslogtreecommitdiffstats
path: root/collections-debian-merged/ansible_collections/community/proxysql/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'collections-debian-merged/ansible_collections/community/proxysql/plugins')
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/README.md31
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/doc_fragments/proxysql.py61
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/module_utils/mysql.py110
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_backend_servers.py518
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_global_variables.py269
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_manage_config.py218
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_mysql_users.py516
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_query_rules.py632
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_replication_hostgroups.py381
-rw-r--r--collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_scheduler.py424
10 files changed, 3160 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/README.md b/collections-debian-merged/ansible_collections/community/proxysql/plugins/README.md
new file mode 100644
index 00000000..6541cf7c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/README.md
@@ -0,0 +1,31 @@
+# Collections Plugins Directory
+
+This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that
+is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that
+would contain module utils and modules respectively.
+
+Here is an example directory of the majority of plugins currently supported by Ansible:
+
+```
+└── plugins
+ ├── action
+ ├── become
+ ├── cache
+ ├── callback
+ ├── cliconf
+ ├── connection
+ ├── filter
+ ├── httpapi
+ ├── inventory
+ ├── lookup
+ ├── module_utils
+ ├── modules
+ ├── netconf
+ ├── shell
+ ├── strategy
+ ├── terminal
+ ├── test
+ └── vars
+```
+
+A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible/2.9/plugins/plugins.html). \ No newline at end of file
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/doc_fragments/proxysql.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/doc_fragments/proxysql.py
new file mode 100644
index 00000000..ae38b94c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/doc_fragments/proxysql.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ # Documentation fragment for ProxySQL connectivity
+ CONNECTIVITY = r'''
+options:
+ login_user:
+ description:
+ - The username used to authenticate to ProxySQL admin interface.
+ type: str
+ login_password:
+ description:
+ - The password used to authenticate to ProxySQL admin interface.
+ type: str
+ login_host:
+ description:
+ - The host used to connect to ProxySQL admin interface.
+ type: str
+ default: '127.0.0.1'
+ login_unix_socket:
+ description:
+ - The socket used to connect to ProxySQL admin interface.
+ type: str
+ login_port:
+ description:
+ - The port used to connect to ProxySQL admin interface.
+ type: int
+ default: 6032
+ config_file:
+ description:
+ - Specify a config file from which I(login_user) and I(login_password)
+ are to be read.
+ type: path
+ default: ''
+requirements:
+ - PyMySQL (Python 2.7 and Python 3.X), or
+ - MySQLdb (Python 2.x)
+'''
+
+ # Documentation fragment for managing ProxySQL configuration
+ MANAGING_CONFIG = r'''
+options:
+ save_to_disk:
+ description:
+ - Save config to sqlite db on disk to persist the configuration.
+ type: bool
+ default: 'yes'
+ load_to_runtime:
+ description:
+ - Dynamically load config to runtime memory.
+ type: bool
+ default: 'yes'
+'''
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/module_utils/mysql.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/module_utils/mysql.py
new file mode 100644
index 00000000..b5beb027
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/module_utils/mysql.py
@@ -0,0 +1,110 @@
+# This code is part of Ansible, but is an independent component.
+# This particular file snippet, and this file snippet only, is BSD licensed.
+# Modules you write using this snippet, which is embedded dynamically by Ansible
+# still belong to the author of the module, and may assign their own license
+# to the complete work.
+#
+# Copyright (c), Jonathan Mainguy <jon@soh.re>, 2015
+# Most of this was originally added by Sven Schliesing @muffl0n in the mysql_user.py module
+#
+# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+
+from ansible.module_utils.six.moves import configparser
+
+try:
+ import pymysql as mysql_driver
+ _mysql_cursor_param = 'cursor'
+except ImportError:
+ try:
+ import MySQLdb as mysql_driver
+ import MySQLdb.cursors
+ _mysql_cursor_param = 'cursorclass'
+ except ImportError:
+ mysql_driver = None
+
+mysql_driver_fail_msg = 'The PyMySQL (Python 2.7 and Python 3.X) or MySQL-python (Python 2.X) module is required.'
+
+
+def parse_from_mysql_config_file(cnf):
+ cp = configparser.ConfigParser()
+ cp.read(cnf)
+ return cp
+
+
+def mysql_connect(module, login_user=None, login_password=None, config_file='', ssl_cert=None,
+ ssl_key=None, ssl_ca=None, db=None, cursor_class=None,
+ connect_timeout=30, autocommit=False, config_overrides_defaults=False):
+ config = {}
+
+ if config_file and os.path.exists(config_file):
+ config['read_default_file'] = config_file
+ cp = parse_from_mysql_config_file(config_file)
+ # Override some commond defaults with values from config file if needed
+ if cp and cp.has_section('client') and config_overrides_defaults:
+ try:
+ module.params['login_host'] = cp.get('client', 'host', fallback=module.params['login_host'])
+ module.params['login_port'] = cp.getint('client', 'port', fallback=module.params['login_port'])
+ except Exception as e:
+ if "got an unexpected keyword argument 'fallback'" in e.message:
+ module.fail_json('To use config_overrides_defaults, '
+ 'it needs Python 3.5+ as the default interpreter on a target host')
+
+ if ssl_ca is not None or ssl_key is not None or ssl_cert is not None:
+ config['ssl'] = {}
+
+ if module.params['login_unix_socket']:
+ config['unix_socket'] = module.params['login_unix_socket']
+ else:
+ config['host'] = module.params['login_host']
+ config['port'] = module.params['login_port']
+
+ # If login_user or login_password are given, they should override the
+ # config file
+ if login_user is not None:
+ config['user'] = login_user
+ if login_password is not None:
+ config['passwd'] = login_password
+ if ssl_cert is not None:
+ config['ssl']['cert'] = ssl_cert
+ if ssl_key is not None:
+ config['ssl']['key'] = ssl_key
+ if ssl_ca is not None:
+ config['ssl']['ca'] = ssl_ca
+ if db is not None:
+ config['db'] = db
+ if connect_timeout is not None:
+ config['connect_timeout'] = connect_timeout
+
+ if _mysql_cursor_param == 'cursor':
+ # In case of PyMySQL driver:
+ db_connection = mysql_driver.connect(autocommit=autocommit, **config)
+ else:
+ # In case of MySQLdb driver
+ db_connection = mysql_driver.connect(**config)
+ if autocommit:
+ db_connection.autocommit(True)
+
+ if cursor_class == 'DictCursor':
+ return db_connection.cursor(**{_mysql_cursor_param: mysql_driver.cursors.DictCursor}), db_connection
+ else:
+ return db_connection.cursor(), db_connection
+
+
+def mysql_common_argument_spec():
+ return dict(
+ login_user=dict(type='str', default=None),
+ login_password=dict(type='str', no_log=True),
+ login_host=dict(type='str', default='localhost'),
+ login_port=dict(type='int', default=3306),
+ login_unix_socket=dict(type='str'),
+ config_file=dict(type='path', default='~/.my.cnf'),
+ connect_timeout=dict(type='int', default=30),
+ client_cert=dict(type='path', aliases=['ssl_cert']),
+ client_key=dict(type='path', aliases=['ssl_key']),
+ ca_cert=dict(type='path', aliases=['ssl_ca']),
+ )
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_backend_servers.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_backend_servers.py
new file mode 100644
index 00000000..fe4c7954
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_backend_servers.py
@@ -0,0 +1,518 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_backend_servers
+author: "Ben Mildren (@bmildren)"
+short_description: Adds or removes mysql hosts from proxysql admin interface.
+description:
+ - The M(community.proxysql.proxysql_backend_servers) module adds or removes mysql hosts using
+ the proxysql admin interface.
+options:
+ hostgroup_id:
+ description:
+ - The hostgroup in which this mysqld instance is included. An instance
+ can be part of one or more hostgroups.
+ type: int
+ default: 0
+ hostname:
+ description:
+ - The ip address at which the mysqld instance can be contacted.
+ type: str
+ required: True
+ port:
+ description:
+ - The port at which the mysqld instance can be contacted.
+ type: int
+ default: 3306
+ status:
+ description:
+ - ONLINE - Backend server is fully operational.
+ OFFLINE_SOFT - When a server is put into C(OFFLINE_SOFT) mode,
+ connections are kept in use until the current
+ transaction is completed. This allows to gracefully
+ detach a backend.
+ OFFLINE_HARD - When a server is put into C(OFFLINE_HARD) mode, the
+ existing connections are dropped, while new incoming
+ connections aren't accepted either.
+
+ If omitted the proxysql database default for I(status) is C(ONLINE).
+ type: str
+ choices: [ "ONLINE", "OFFLINE_SOFT", "OFFLINE_HARD"]
+ weight:
+ description:
+ - The bigger the weight of a server relative to other weights, the higher
+ the probability of the server being chosen from the hostgroup. If
+ omitted the proxysql database default for I(weight) is 1.
+ type: int
+ compression:
+ description:
+ - If the value of I(compression) is greater than 0, new connections to
+ that server will use compression. If omitted the proxysql database
+ default for I(compression) is 0.
+ type: int
+ max_connections:
+ description:
+ - The maximum number of connections ProxySQL will open to this backend
+ server. If omitted the proxysql database default for I(max_connections)
+ is 1000.
+ type: int
+ max_replication_lag:
+ description:
+ - If greater than 0, ProxySQL will regularly monitor replication lag. If
+ replication lag goes above I(max_replication_lag), proxysql will
+ temporarily shun the server until replication catches up. If omitted
+ the proxysql database default for I(max_replication_lag) is 0.
+ type: int
+ use_ssl:
+ description:
+ - If I(use_ssl) is set to C(True), connections to this server will be
+ made using SSL connections. If omitted the proxysql database default
+ for I(use_ssl) is C(False).
+ type: bool
+ max_latency_ms:
+ description:
+ - Ping time is monitored regularly. If a host has a ping time greater
+ than I(max_latency_ms) it is excluded from the connection pool
+ (although the server stays ONLINE). If omitted the proxysql database
+ default for I(max_latency_ms) is 0.
+ type: int
+ comment:
+ description:
+ - Text field that can be used for any purposed defined by the user.
+ Could be a description of what the host stores, a reminder of when the
+ host was added or disabled, or a JSON processed by some checker script.
+ type: str
+ default: ''
+ state:
+ description:
+ - When C(present) - adds the host, when C(absent) - removes the host.
+ type: str
+ choices: [ "present", "absent" ]
+ default: present
+extends_documentation_fragment:
+- community.proxysql.proxysql.managing_config
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example adds a server, it saves the mysql server config to disk, but
+# avoids loading the mysql server config to runtime (this might be because
+# several servers are being added and the user wants to push the config to
+# runtime in a single batch using the community.general.proxysql_manage_config
+# module). It uses supplied credentials to connect to the proxysql admin
+# interface.
+
+- name: Add a server
+ community.proxysql.proxysql_backend_servers:
+ login_user: 'admin'
+ login_password: 'admin'
+ hostname: 'mysql01'
+ state: present
+ load_to_runtime: False
+
+# This example removes a server, saves the mysql server config to disk, and
+# dynamically loads the mysql server config to runtime. It uses credentials
+# in a supplied config file to connect to the proxysql admin interface.
+
+- name: Remove a server
+ community.proxysql.proxysql_backend_servers:
+ config_file: '~/proxysql.cnf'
+ hostname: 'mysql02'
+ state: absent
+'''
+
+RETURN = '''
+stdout:
+ description: The mysql host modified or removed from proxysql
+ returned: On create/update will return the newly modified host, on delete
+ it will return the deleted record.
+ type: dict
+ "sample": {
+ "changed": true,
+ "hostname": "192.168.52.1",
+ "msg": "Added server to mysql_hosts",
+ "server": {
+ "comment": "",
+ "compression": "0",
+ "hostgroup_id": "1",
+ "hostname": "192.168.52.1",
+ "max_connections": "1000",
+ "max_latency_ms": "0",
+ "max_replication_lag": "0",
+ "port": "3306",
+ "status": "ONLINE",
+ "use_ssl": "0",
+ "weight": "1"
+ },
+ "state": "present"
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils.six import iteritems
+from ansible.module_utils._text import to_native
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if module.params["port"] < 0 \
+ or module.params["port"] > 65535:
+ module.fail_json(
+ msg="port must be a valid unix port number (0-65535)"
+ )
+
+ if module.params["compression"]:
+ if module.params["compression"] < 0 \
+ or module.params["compression"] > 102400:
+ module.fail_json(
+ msg="compression must be set between 0 and 102400"
+ )
+
+ if module.params["max_replication_lag"]:
+ if module.params["max_replication_lag"] < 0 \
+ or module.params["max_replication_lag"] > 126144000:
+ module.fail_json(
+ msg="max_replication_lag must be set between 0 and 102400"
+ )
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def save_config_to_disk(cursor):
+ cursor.execute("SAVE MYSQL SERVERS TO DISK")
+ return True
+
+
+def load_config_to_runtime(cursor):
+ cursor.execute("LOAD MYSQL SERVERS TO RUNTIME")
+ return True
+
+
+class ProxySQLServer(object):
+
+ def __init__(self, module):
+ self.state = module.params["state"]
+ self.save_to_disk = module.params["save_to_disk"]
+ self.load_to_runtime = module.params["load_to_runtime"]
+
+ self.hostgroup_id = module.params["hostgroup_id"]
+ self.hostname = module.params["hostname"]
+ self.port = module.params["port"]
+
+ config_data_keys = ["status",
+ "weight",
+ "compression",
+ "max_connections",
+ "max_replication_lag",
+ "use_ssl",
+ "max_latency_ms",
+ "comment"]
+
+ self.config_data = dict((k, module.params[k])
+ for k in config_data_keys)
+
+ def check_server_config_exists(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `host_count`
+ FROM mysql_servers
+ WHERE hostgroup_id = %s
+ AND hostname = %s
+ AND port = %s"""
+
+ query_data = \
+ [self.hostgroup_id,
+ self.hostname,
+ self.port]
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+ return (int(check_count['host_count']) > 0)
+
+ def check_server_config(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `host_count`
+ FROM mysql_servers
+ WHERE hostgroup_id = %s
+ AND hostname = %s
+ AND port = %s"""
+
+ query_data = \
+ [self.hostgroup_id,
+ self.hostname,
+ self.port]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ query_data.append(val)
+ query_string += "\n AND " + col + " = %s"
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+
+ if isinstance(check_count, tuple):
+ return int(check_count[0]) > 0
+
+ return (int(check_count['host_count']) > 0)
+
+ def get_server_config(self, cursor):
+ query_string = \
+ """SELECT *
+ FROM mysql_servers
+ WHERE hostgroup_id = %s
+ AND hostname = %s
+ AND port = %s"""
+
+ query_data = \
+ [self.hostgroup_id,
+ self.hostname,
+ self.port]
+
+ cursor.execute(query_string, query_data)
+ server = cursor.fetchone()
+ return server
+
+ def create_server_config(self, cursor):
+ query_string = \
+ """INSERT INTO mysql_servers (
+ hostgroup_id,
+ hostname,
+ port"""
+
+ cols = 3
+ query_data = \
+ [self.hostgroup_id,
+ self.hostname,
+ self.port]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ query_string += ",\n" + col
+
+ query_string += \
+ (")\n" +
+ "VALUES (" +
+ "%s ," * cols)
+
+ query_string = query_string[:-2]
+ query_string += ")"
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def update_server_config(self, cursor):
+ query_string = """UPDATE mysql_servers"""
+
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ if cols == 1:
+ query_string += "\nSET " + col + "= %s,"
+ else:
+ query_string += "\n " + col + " = %s,"
+
+ query_string = query_string[:-1]
+ query_string += ("\nWHERE hostgroup_id = %s\n AND hostname = %s" +
+ "\n AND port = %s")
+
+ query_data.append(self.hostgroup_id)
+ query_data.append(self.hostname)
+ query_data.append(self.port)
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def delete_server_config(self, cursor):
+ query_string = \
+ """DELETE FROM mysql_servers
+ WHERE hostgroup_id = %s
+ AND hostname = %s
+ AND port = %s"""
+
+ query_data = \
+ [self.hostgroup_id,
+ self.hostname,
+ self.port]
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def manage_config(self, cursor, state):
+ if state:
+ if self.save_to_disk:
+ save_config_to_disk(cursor)
+ if self.load_to_runtime:
+ load_config_to_runtime(cursor)
+
+ def create_server(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.create_server_config(cursor)
+ result['msg'] = "Added server to mysql_hosts"
+ result['server'] = \
+ self.get_server_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Server would have been added to" +
+ " mysql_hosts, however check_mode" +
+ " is enabled.")
+
+ def update_server(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.update_server_config(cursor)
+ result['msg'] = "Updated server in mysql_hosts"
+ result['server'] = \
+ self.get_server_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Server would have been updated in" +
+ " mysql_hosts, however check_mode" +
+ " is enabled.")
+
+ def delete_server(self, check_mode, result, cursor):
+ if not check_mode:
+ result['server'] = \
+ self.get_server_config(cursor)
+ result['changed'] = \
+ self.delete_server_config(cursor)
+ result['msg'] = "Deleted server from mysql_hosts"
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Server would have been deleted from" +
+ " mysql_hosts, however check_mode is" +
+ " enabled.")
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default='127.0.0.1'),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default='', type='path'),
+ hostgroup_id=dict(default=0, type='int'),
+ hostname=dict(required=True, type='str'),
+ port=dict(default=3306, type='int'),
+ status=dict(choices=['ONLINE',
+ 'OFFLINE_SOFT',
+ 'OFFLINE_HARD']),
+ weight=dict(type='int'),
+ compression=dict(type='int'),
+ max_connections=dict(type='int'),
+ max_replication_lag=dict(type='int'),
+ use_ssl=dict(type='bool'),
+ max_latency_ms=dict(type='int'),
+ comment=dict(default='', type='str'),
+ state=dict(default='present', choices=['present',
+ 'absent']),
+ save_to_disk=dict(default=True, type='bool'),
+ load_to_runtime=dict(default=True, type='bool')
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file,
+ cursor_class='DictCursor')
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ proxysql_server = ProxySQLServer(module)
+ result = {}
+
+ result['state'] = proxysql_server.state
+ if proxysql_server.hostname:
+ result['hostname'] = proxysql_server.hostname
+
+ if proxysql_server.state == "present":
+ try:
+ if not proxysql_server.check_server_config(cursor):
+ if not proxysql_server.check_server_config_exists(cursor):
+ proxysql_server.create_server(module.check_mode,
+ result,
+ cursor)
+ else:
+ proxysql_server.update_server(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The server already exists in mysql_hosts" +
+ " and doesn't need to be updated.")
+ result['server'] = \
+ proxysql_server.get_server_config(cursor)
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to modify server.. %s" % to_native(e)
+ )
+
+ elif proxysql_server.state == "absent":
+ try:
+ if proxysql_server.check_server_config_exists(cursor):
+ proxysql_server.delete_server(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The server is already absent from the" +
+ " mysql_hosts memory configuration")
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to remove server.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_global_variables.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_global_variables.py
new file mode 100644
index 00000000..1e65bc82
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_global_variables.py
@@ -0,0 +1,269 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_global_variables
+author: "Ben Mildren (@bmildren)"
+short_description: Gets or sets the proxysql global variables.
+description:
+ - The M(community.proxysql.proxysql_global_variables) module gets or sets the proxysql global
+ variables.
+options:
+ variable:
+ description:
+ - Defines which variable should be returned, or if I(value) is specified
+ which variable should be updated.
+ type: str
+ required: True
+ value:
+ description:
+ - Defines a value the variable specified using I(variable) should be set
+ to.
+ type: str
+extends_documentation_fragment:
+- community.proxysql.proxysql.managing_config
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example sets the value of a variable, saves the mysql admin variables
+# config to disk, and dynamically loads the mysql admin variables config to
+# runtime. It uses supplied credentials to connect to the proxysql admin
+# interface.
+
+- name: Set the value of a variable
+ community.proxysql.proxysql_global_variables:
+ login_user: 'admin'
+ login_password: 'admin'
+ variable: 'mysql-max_connections'
+ value: 4096
+
+# This example gets the value of a variable. It uses credentials in a
+# supplied config file to connect to the proxysql admin interface.
+
+- name: Get the value of a variable
+ community.proxysql.proxysql_global_variables:
+ config_file: '~/proxysql.cnf'
+ variable: 'mysql-default_query_delay'
+'''
+
+RETURN = '''
+stdout:
+ description: Returns the mysql variable supplied with it's associated value.
+ returned: Returns the current variable and value, or the newly set value
+ for the variable supplied..
+ type: dict
+ "sample": {
+ "changed": false,
+ "msg": "The variable is already been set to the supplied value",
+ "var": {
+ "variable_name": "mysql-poll_timeout",
+ "variable_value": "3000"
+ }
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils._text import to_native
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def save_config_to_disk(variable, cursor):
+ if variable.startswith("admin"):
+ cursor.execute("SAVE ADMIN VARIABLES TO DISK")
+ else:
+ cursor.execute("SAVE MYSQL VARIABLES TO DISK")
+ return True
+
+
+def load_config_to_runtime(variable, cursor):
+ if variable.startswith("admin"):
+ cursor.execute("LOAD ADMIN VARIABLES TO RUNTIME")
+ else:
+ cursor.execute("LOAD MYSQL VARIABLES TO RUNTIME")
+ return True
+
+
+def check_config(variable, value, cursor):
+ query_string = \
+ """SELECT count(*) AS `variable_count`
+ FROM global_variables
+ WHERE variable_name = %s and variable_value = %s"""
+
+ query_data = \
+ [variable, value]
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+
+ if isinstance(check_count, tuple):
+ return int(check_count[0]) > 0
+
+ return (int(check_count['variable_count']) > 0)
+
+
+def get_config(variable, cursor):
+
+ query_string = \
+ """SELECT *
+ FROM global_variables
+ WHERE variable_name = %s"""
+
+ query_data = \
+ [variable, ]
+
+ cursor.execute(query_string, query_data)
+ row_count = cursor.rowcount
+ resultset = cursor.fetchone()
+
+ if row_count > 0:
+ return resultset
+ else:
+ return False
+
+
+def set_config(variable, value, cursor):
+
+ query_string = \
+ """UPDATE global_variables
+ SET variable_value = %s
+ WHERE variable_name = %s"""
+
+ query_data = \
+ [value, variable]
+
+ cursor.execute(query_string, query_data)
+ return True
+
+
+def manage_config(variable, save_to_disk, load_to_runtime, cursor, state):
+ if state:
+ if save_to_disk:
+ save_config_to_disk(variable, cursor)
+ if load_to_runtime:
+ load_config_to_runtime(variable, cursor)
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default="127.0.0.1"),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default="", type='path'),
+ variable=dict(required=True, type='str'),
+ value=dict(),
+ save_to_disk=dict(default=True, type='bool'),
+ load_to_runtime=dict(default=True, type='bool')
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+ variable = module.params["variable"]
+ value = module.params["value"]
+ save_to_disk = module.params["save_to_disk"]
+ load_to_runtime = module.params["load_to_runtime"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file,
+ cursor_class='DictCursor')
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ result = {}
+
+ if not value:
+ try:
+ if get_config(variable, cursor):
+ result['changed'] = False
+ result['msg'] = \
+ "Returned the variable and it's current value"
+ result['var'] = get_config(variable, cursor)
+ else:
+ module.fail_json(
+ msg="The variable \"%s\" was not found" % variable
+ )
+
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to get config.. %s" % to_native(e)
+ )
+ else:
+ try:
+ if get_config(variable, cursor):
+ if not check_config(variable, value, cursor):
+ if not module.check_mode:
+ result['changed'] = set_config(variable, value, cursor)
+ result['msg'] = \
+ "Set the variable to the supplied value"
+ result['var'] = get_config(variable, cursor)
+ manage_config(variable,
+ save_to_disk,
+ load_to_runtime,
+ cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Variable would have been set to" +
+ " the supplied value, however" +
+ " check_mode is enabled.")
+ else:
+ result['changed'] = False
+ result['msg'] = ("The variable is already been set to" +
+ " the supplied value")
+ result['var'] = get_config(variable, cursor)
+ else:
+ module.fail_json(
+ msg="The variable \"%s\" was not found" % variable
+ )
+
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to set config.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_manage_config.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_manage_config.py
new file mode 100644
index 00000000..0ca99b3d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_manage_config.py
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_manage_config
+
+author: "Ben Mildren (@bmildren)"
+short_description: Writes the proxysql configuration settings between layers.
+description:
+ - The M(community.proxysql.proxysql_global_variables) module writes the proxysql configuration
+ settings between layers. Currently this module will always report a
+ changed state, so should typically be used with WHEN however this will
+ change in a future version when the CHECKSUM table commands are available
+ for all tables in proxysql.
+options:
+ action:
+ description:
+ - The supplied I(action) combines with the supplied I(direction) to
+ provide the semantics of how we want to move the I(config_settings)
+ between the I(config_layers).
+ type: str
+ choices: [ "LOAD", "SAVE" ]
+ required: True
+ config_settings:
+ description:
+ - The I(config_settings) specifies which configuration we're writing.
+ type: str
+ choices: [ "MYSQL USERS", "MYSQL SERVERS", "MYSQL QUERY RULES",
+ "MYSQL VARIABLES", "ADMIN VARIABLES", "SCHEDULER" ]
+ required: True
+ direction:
+ description:
+ - FROM - denotes we're reading values FROM the supplied I(config_layer)
+ and writing to the next layer.
+ TO - denotes we're reading from the previous layer and writing TO the
+ supplied I(config_layer)."
+ type: str
+ choices: [ "FROM", "TO" ]
+ required: True
+ config_layer:
+ description:
+ - RUNTIME - represents the in-memory data structures of ProxySQL used by
+ the threads that are handling the requests.
+ MEMORY - (sometimes also referred as main) represents the in-memory
+ SQLite3 database.
+ DISK - represents the on-disk SQLite3 database.
+ CONFIG - is the classical config file. You can only LOAD FROM the
+ config file.
+ type: str
+ choices: [ "MEMORY", "DISK", "RUNTIME", "CONFIG" ]
+ required: True
+extends_documentation_fragment:
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example saves the mysql users config from memory to disk. It uses
+# supplied credentials to connect to the proxysql admin interface.
+
+- name: Save the mysql users config from memory to disk
+ community.proxysql.proxysql_manage_config:
+ login_user: 'admin'
+ login_password: 'admin'
+ action: "SAVE"
+ config_settings: "MYSQL USERS"
+ direction: "FROM"
+ config_layer: "MEMORY"
+
+# This example loads the mysql query rules config from memory to runtime. It
+# uses supplied credentials to connect to the proxysql admin interface.
+
+- name: Load the mysql query rules config from memory to runtime
+ community.proxysql.proxysql_manage_config:
+ config_file: '~/proxysql.cnf'
+ action: "LOAD"
+ config_settings: "MYSQL QUERY RULES"
+ direction: "TO"
+ config_layer: "RUNTIME"
+'''
+
+RETURN = '''
+stdout:
+ description: Simply reports whether the action reported a change.
+ returned: Currently the returned value with always be changed=True.
+ type: dict
+ "sample": {
+ "changed": true
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils._text import to_native
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if module.params["config_layer"] == 'CONFIG' and \
+ (module.params["action"] != 'LOAD' or
+ module.params["direction"] != 'FROM'):
+
+ if (module.params["action"] != 'LOAD' and
+ module.params["direction"] != 'FROM'):
+ msg_string = ("Neither the action \"%s\" nor the direction" +
+ " \"%s\" are valid combination with the CONFIG" +
+ " config_layer")
+ module.fail_json(msg=msg_string % (module.params["action"],
+ module.params["direction"]))
+
+ elif module.params["action"] != 'LOAD':
+ msg_string = ("The action \"%s\" is not a valid combination" +
+ " with the CONFIG config_layer")
+ module.fail_json(msg=msg_string % module.params["action"])
+
+ else:
+ msg_string = ("The direction \"%s\" is not a valid combination" +
+ " with the CONFIG config_layer")
+ module.fail_json(msg=msg_string % module.params["direction"])
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def manage_config(manage_config_settings, cursor):
+
+ query_string = "%s" % ' '.join(manage_config_settings)
+
+ cursor.execute(query_string)
+ return True
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default="127.0.0.1"),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default="", type='path'),
+ action=dict(required=True, choices=['LOAD',
+ 'SAVE']),
+ config_settings=dict(required=True, choices=['MYSQL USERS',
+ 'MYSQL SERVERS',
+ 'MYSQL QUERY RULES',
+ 'MYSQL VARIABLES',
+ 'ADMIN VARIABLES',
+ 'SCHEDULER']),
+ direction=dict(required=True, choices=['FROM',
+ 'TO']),
+ config_layer=dict(required=True, choices=['MEMORY',
+ 'DISK',
+ 'RUNTIME',
+ 'CONFIG'])
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+ action = module.params["action"]
+ config_settings = module.params["config_settings"]
+ direction = module.params["direction"]
+ config_layer = module.params["config_layer"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file)
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ result = {}
+
+ manage_config_settings = \
+ [action, config_settings, direction, config_layer]
+
+ try:
+ result['changed'] = manage_config(manage_config_settings,
+ cursor)
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to manage config.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_mysql_users.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_mysql_users.py
new file mode 100644
index 00000000..aa60ed10
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_mysql_users.py
@@ -0,0 +1,516 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_mysql_users
+author: "Ben Mildren (@bmildren)"
+short_description: Adds or removes mysql users from proxysql admin interface.
+description:
+ - The M(community.proxysql.proxysql_mysql_users) module adds or removes mysql users using the
+ proxysql admin interface.
+options:
+ username:
+ description:
+ - Name of the user connecting to the mysqld or ProxySQL instance.
+ type: str
+ required: True
+ password:
+ description:
+ - Password of the user connecting to the mysqld or ProxySQL instance.
+ type: str
+ encrypt_password:
+ description:
+ - Encrypt a cleartext password passed in the I(password) option, using
+ the method defined in I(encryption_method).
+ default: False
+ type: bool
+ encryption_method:
+ description:
+ - Encryption method used when I(encrypt_password) is set to C(True).
+ type: str
+ choices: [ "mysql_native_password" ]
+ default: mysql_native_password
+ active:
+ description:
+ - A user with I(active) set to C(False) will be tracked in the database,
+ but will be never loaded in the in-memory data structures. If omitted
+ the proxysql database default for I(active) is C(True).
+ type: bool
+ use_ssl:
+ description:
+ - If I(use_ssl) is set to C(True), connections by this user will be made
+ using SSL connections. If omitted the proxysql database default for
+ I(use_ssl) is C(False).
+ type: bool
+ default_hostgroup:
+ description:
+ - If there is no matching rule for the queries sent by this user, the
+ traffic it generates is sent to the specified hostgroup.
+ If omitted the proxysql database default for I(use_ssl) is 0.
+ type: int
+ default_schema:
+ description:
+ - The schema to which the connection should change to by default.
+ type: str
+ transaction_persistent:
+ description:
+ - If this is set for the user with which the MySQL client is connecting
+ to ProxySQL (thus a "frontend" user), transactions started within a
+ hostgroup will remain within that hostgroup regardless of any other
+ rules.
+ If omitted the proxysql database default for I(transaction_persistent)
+ is C(False).
+ type: bool
+ fast_forward:
+ description:
+ - If I(fast_forward) is set to C(True), I(fast_forward) will bypass the
+ query processing layer (rewriting, caching) and pass through the query
+ directly as is to the backend server. If omitted the proxysql database
+ default for I(fast_forward) is C(False).
+ type: bool
+ backend:
+ description:
+ - If I(backend) is set to C(True), this (username, password) pair is
+ used for authenticating to the ProxySQL instance.
+ default: True
+ type: bool
+ frontend:
+ description:
+ - If I(frontend) is set to C(True), this (username, password) pair is
+ used for authenticating to the mysqld servers against any hostgroup.
+ default: True
+ type: bool
+ max_connections:
+ description:
+ - The maximum number of connections ProxySQL will open to the backend for
+ this user. If omitted the proxysql database default for
+ I(max_connections) is 10000.
+ type: int
+ state:
+ description:
+ - When C(present) - adds the user, when C(absent) - removes the user.
+ type: str
+ choices: [ "present", "absent" ]
+ default: present
+extends_documentation_fragment:
+- community.proxysql.proxysql.managing_config
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example adds a user, it saves the mysql user config to disk, but
+# avoids loading the mysql user config to runtime (this might be because
+# several users are being added and the user wants to push the config to
+# runtime in a single batch using the community.general.proxysql_manage_config
+# module). It uses supplied credentials to connect to the proxysql admin
+# interface.
+
+- name: Add a user
+ community.proxysql.proxysql_mysql_users:
+ login_user: 'admin'
+ login_password: 'admin'
+ username: 'productiondba'
+ state: present
+ load_to_runtime: False
+
+# This example removes a user, saves the mysql user config to disk, and
+# dynamically loads the mysql user config to runtime. It uses credentials
+# in a supplied config file to connect to the proxysql admin interface.
+
+- name: Remove a user
+ community.proxysql.proxysql_mysql_users:
+ config_file: '~/proxysql.cnf'
+ username: 'mysqlboy'
+ state: absent
+'''
+
+RETURN = '''
+stdout:
+ description: The mysql user modified or removed from proxysql
+ returned: On create/update will return the newly modified user, on delete
+ it will return the deleted record.
+ type: dict
+ sample:
+ changed: true
+ msg: Added user to mysql_users
+ state: present
+ user:
+ active: 1
+ backend: 1
+ default_hostgroup: 1
+ default_schema: null
+ fast_forward: 0
+ frontend: 1
+ max_connections: 10000
+ password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
+ schema_locked: 0
+ transaction_persistent: 0
+ use_ssl: 0
+ username: guest_ro
+ username: guest_ro
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils.six import iteritems
+from ansible.module_utils._text import to_native, to_bytes
+from hashlib import sha1
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def save_config_to_disk(cursor):
+ cursor.execute("SAVE MYSQL USERS TO DISK")
+ return True
+
+
+def load_config_to_runtime(cursor):
+ cursor.execute("LOAD MYSQL USERS TO RUNTIME")
+ return True
+
+
+def _mysql_native_password(cleartext_password):
+ mysql_native_encrypted_password = "*" + sha1(sha1(to_bytes(cleartext_password)).digest()).hexdigest().upper()
+ return mysql_native_encrypted_password
+
+
+def encrypt_cleartext_password(password_to_encrypt, encryption_method):
+ encrypted_password = encryption_method(password_to_encrypt)
+ return encrypted_password
+
+
+encryption_method_map = {
+ 'mysql_native_password': _mysql_native_password
+}
+
+
+class ProxySQLUser(object):
+
+ def __init__(self, module):
+ self.state = module.params["state"]
+ self.save_to_disk = module.params["save_to_disk"]
+ self.load_to_runtime = module.params["load_to_runtime"]
+
+ self.username = module.params["username"]
+ self.backend = module.params["backend"]
+ self.frontend = module.params["frontend"]
+
+ config_data_keys = ["password",
+ "active",
+ "use_ssl",
+ "default_hostgroup",
+ "default_schema",
+ "transaction_persistent",
+ "fast_forward",
+ "max_connections"]
+
+ self.config_data = dict((k, module.params[k])
+ for k in config_data_keys)
+
+ if module.params["password"] is not None and module.params["encrypt_password"]:
+ encryption_method = encryption_method_map[module.params["encryption_method"]]
+ encrypted_password = encrypt_cleartext_password(module.params["password"], encryption_method)
+ self.config_data["password"] = encrypted_password
+
+ def check_user_config_exists(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `user_count`
+ FROM mysql_users
+ WHERE username = %s
+ AND backend = %s
+ AND frontend = %s"""
+
+ query_data = \
+ [self.username,
+ self.backend,
+ self.frontend]
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+ return (int(check_count['user_count']) > 0)
+
+ def check_user_privs(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `user_count`
+ FROM mysql_users
+ WHERE username = %s
+ AND backend = %s
+ AND frontend = %s"""
+
+ query_data = \
+ [self.username,
+ self.backend,
+ self.frontend]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ query_data.append(val)
+ query_string += "\n AND " + col + " = %s"
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+ return (int(check_count['user_count']) > 0)
+
+ def get_user_config(self, cursor):
+ query_string = \
+ """SELECT *
+ FROM mysql_users
+ WHERE username = %s
+ AND backend = %s
+ AND frontend = %s"""
+
+ query_data = \
+ [self.username,
+ self.backend,
+ self.frontend]
+
+ cursor.execute(query_string, query_data)
+ user = cursor.fetchone()
+ return user
+
+ def create_user_config(self, cursor):
+ query_string = \
+ """INSERT INTO mysql_users (
+ username,
+ backend,
+ frontend"""
+
+ cols = 3
+ query_data = \
+ [self.username,
+ self.backend,
+ self.frontend]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ query_string += ",\n" + col
+
+ query_string += \
+ (")\n" +
+ "VALUES (" +
+ "%s ," * cols)
+
+ query_string = query_string[:-2]
+ query_string += ")"
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def update_user_config(self, cursor):
+ query_string = """UPDATE mysql_users"""
+
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ if cols == 1:
+ query_string += "\nSET " + col + "= %s,"
+ else:
+ query_string += "\n " + col + " = %s,"
+
+ query_string = query_string[:-1]
+ query_string += ("\nWHERE username = %s\n AND backend = %s" +
+ "\n AND frontend = %s")
+
+ query_data.append(self.username)
+ query_data.append(self.backend)
+ query_data.append(self.frontend)
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def delete_user_config(self, cursor):
+ query_string = \
+ """DELETE FROM mysql_users
+ WHERE username = %s
+ AND backend = %s
+ AND frontend = %s"""
+
+ query_data = \
+ [self.username,
+ self.backend,
+ self.frontend]
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def manage_config(self, cursor, state):
+ if state:
+ if self.save_to_disk:
+ save_config_to_disk(cursor)
+ if self.load_to_runtime:
+ load_config_to_runtime(cursor)
+
+ def create_user(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.create_user_config(cursor)
+ result['msg'] = "Added user to mysql_users"
+ result['user'] = \
+ self.get_user_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("User would have been added to" +
+ " mysql_users, however check_mode" +
+ " is enabled.")
+
+ def update_user(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.update_user_config(cursor)
+ result['msg'] = "Updated user in mysql_users"
+ result['user'] = \
+ self.get_user_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("User would have been updated in" +
+ " mysql_users, however check_mode" +
+ " is enabled.")
+
+ def delete_user(self, check_mode, result, cursor):
+ if not check_mode:
+ result['user'] = \
+ self.get_user_config(cursor)
+ result['changed'] = \
+ self.delete_user_config(cursor)
+ result['msg'] = "Deleted user from mysql_users"
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("User would have been deleted from" +
+ " mysql_users, however check_mode is" +
+ " enabled.")
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default="127.0.0.1"),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default='', type='path'),
+ username=dict(required=True, type='str'),
+ password=dict(no_log=True, type='str'),
+ encrypt_password=dict(default=False, type='bool'),
+ encryption_method=dict(default='mysql_native_password', choices=list(encryption_method_map.keys())),
+ active=dict(type='bool'),
+ use_ssl=dict(type='bool'),
+ default_hostgroup=dict(type='int'),
+ default_schema=dict(type='str'),
+ transaction_persistent=dict(type='bool'),
+ fast_forward=dict(type='bool'),
+ backend=dict(default=True, type='bool'),
+ frontend=dict(default=True, type='bool'),
+ max_connections=dict(type='int'),
+ state=dict(default='present', choices=['present',
+ 'absent']),
+ save_to_disk=dict(default=True, type='bool'),
+ load_to_runtime=dict(default=True, type='bool')
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file,
+ cursor_class='DictCursor')
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ proxysql_user = ProxySQLUser(module)
+ result = {}
+
+ result['state'] = proxysql_user.state
+ if proxysql_user.username:
+ result['username'] = proxysql_user.username
+
+ if proxysql_user.state == "present":
+ try:
+ if not proxysql_user.check_user_privs(cursor):
+ if not proxysql_user.check_user_config_exists(cursor):
+ proxysql_user.create_user(module.check_mode,
+ result,
+ cursor)
+ else:
+ proxysql_user.update_user(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The user already exists in mysql_users" +
+ " and doesn't need to be updated.")
+ result['user'] = \
+ proxysql_user.get_user_config(cursor)
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to modify user.. %s" % to_native(e)
+ )
+
+ elif proxysql_user.state == "absent":
+ try:
+ if proxysql_user.check_user_config_exists(cursor):
+ proxysql_user.delete_user(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The user is already absent from the" +
+ " mysql_users memory configuration")
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to remove user.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_query_rules.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_query_rules.py
new file mode 100644
index 00000000..3088a034
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_query_rules.py
@@ -0,0 +1,632 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_query_rules
+author: "Ben Mildren (@bmildren)"
+short_description: Modifies query rules using the proxysql admin interface.
+description:
+ - The M(community.proxysql.proxysql_query_rules) module modifies query rules using the
+ proxysql admin interface.
+options:
+ rule_id:
+ description:
+ - The unique id of the rule. Rules are processed in rule_id order.
+ type: int
+ active:
+ description:
+ - A rule with I(active) set to C(False) will be tracked in the database,
+ but will be never loaded in the in-memory data structures.
+ type: bool
+ username:
+ description:
+ - Filtering criteria matching username. If I(username) is non-NULL, a
+ query will match only if the connection is made with the correct
+ username.
+ type: str
+ schemaname:
+ description:
+ - Filtering criteria matching schemaname. If I(schemaname) is non-NULL, a
+ query will match only if the connection uses schemaname as its default
+ schema.
+ type: str
+ flagIN:
+ description:
+ - Used in combination with I(flagOUT) and I(apply) to create chains of
+ rules.
+ type: int
+ client_addr:
+ description:
+ - Match traffic from a specific source.
+ type: str
+ proxy_addr:
+ description:
+ - Match incoming traffic on a specific local IP.
+ type: str
+ proxy_port:
+ description:
+ - Match incoming traffic on a specific local port.
+ type: int
+ digest:
+ description:
+ - Match queries with a specific digest, as returned by
+ stats_mysql_query_digest.digest.
+ type: str
+ match_digest:
+ description:
+ - Regular expression that matches the query digest. The dialect of
+ regular expressions used is that of re2 - https://github.com/google/re2
+ type: str
+ match_pattern:
+ description:
+ - Regular expression that matches the query text. The dialect of regular
+ expressions used is that of re2 - https://github.com/google/re2
+ type: str
+ negate_match_pattern:
+ description:
+ - If I(negate_match_pattern) is set to C(True), only queries not matching
+ the query text will be considered as a match. This acts as a NOT
+ operator in front of the regular expression matching against
+ match_pattern.
+ type: bool
+ flagOUT:
+ description:
+ - Used in combination with I(flagIN) and apply to create chains of rules.
+ When set, I(flagOUT) signifies the I(flagIN) to be used in the next
+ chain of rules.
+ type: int
+ replace_pattern:
+ description:
+ - This is the pattern with which to replace the matched pattern. Note
+ that this is optional, and when omitted, the query processor will only
+ cache, route, or set other parameters without rewriting.
+ type: str
+ destination_hostgroup:
+ description:
+ - Route matched queries to this hostgroup. This happens unless there is a
+ started transaction and the logged in user has
+ I(transaction_persistent) set to C(True) (see M(community.proxysql.proxysql_mysql_users)).
+ type: int
+ cache_ttl:
+ description:
+ - The number of milliseconds for which to cache the result of the query.
+ Note in ProxySQL 1.1 I(cache_ttl) was in seconds.
+ type: int
+ timeout:
+ description:
+ - The maximum timeout in milliseconds with which the matched or rewritten
+ query should be executed. If a query run for longer than the specific
+ threshold, the query is automatically killed. If timeout is not
+ specified, the global variable mysql-default_query_timeout applies.
+ type: int
+ retries:
+ description:
+ - The maximum number of times a query needs to be re-executed in case of
+ detected failure during the execution of the query. If retries is not
+ specified, the global variable mysql-query_retries_on_failure applies.
+ type: int
+ delay:
+ description:
+ - Number of milliseconds to delay the execution of the query. This is
+ essentially a throttling mechanism and QoS, and allows a way to give
+ priority to queries over others. This value is added to the
+ mysql-default_query_delay global variable that applies to all queries.
+ type: int
+ mirror_flagOUT:
+ description:
+ - Enables query mirroring. If set I(mirror_flagOUT) can be used to
+ evaluates the mirrored query against the specified chain of rules.
+ type: int
+ mirror_hostgroup:
+ description:
+ - Enables query mirroring. If set I(mirror_hostgroup) can be used to
+ mirror queries to the same or different hostgroup.
+ type: int
+ error_msg:
+ description:
+ - Query will be blocked, and the specified error_msg will be returned to
+ the client.
+ type: str
+ log:
+ description:
+ - Query will be logged.
+ type: bool
+ apply:
+ description:
+ - Used in combination with I(flagIN) and I(flagOUT) to create chains of
+ rules. Setting apply to True signifies the last rule to be applied.
+ type: bool
+ comment:
+ description:
+ - Free form text field, usable for a descriptive comment of the query
+ rule.
+ type: str
+ state:
+ description:
+ - When C(present) - adds the rule, when C(absent) - removes the rule.
+ type: str
+ choices: [ "present", "absent" ]
+ default: present
+ force_delete:
+ description:
+ - By default we avoid deleting more than one schedule in a single batch,
+ however if you need this behaviour and you're not concerned about the
+ schedules deleted, you can set I(force_delete) to C(True).
+ type: bool
+ default: False
+extends_documentation_fragment:
+- community.proxysql.proxysql.managing_config
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example adds a rule to redirect queries from a specific user to another
+# hostgroup, it saves the mysql query rule config to disk, but avoids loading
+# the mysql query config config to runtime (this might be because several
+# rules are being added and the user wants to push the config to runtime in a
+# single batch using the community.general.proxysql_manage_config module). It
+# uses supplied credentials to connect to the proxysql admin interface.
+
+- name: Add a rule
+ community.proxysql.proxysql_query_rules:
+ login_user: admin
+ login_password: admin
+ username: 'guest_ro'
+ match_pattern: "^SELECT.*"
+ destination_hostgroup: 1
+ active: 1
+ retries: 3
+ state: present
+ load_to_runtime: False
+
+# This example removes all rules that use the username 'guest_ro', saves the
+# mysql query rule config to disk, and dynamically loads the mysql query rule
+# config to runtime. It uses credentials in a supplied config file to connect
+# to the proxysql admin interface.
+
+- name: Remove rules
+ community.proxysql.proxysql_query_rules:
+ config_file: '~/proxysql.cnf'
+ username: 'guest_ro'
+ state: absent
+ force_delete: true
+'''
+
+RETURN = '''
+stdout:
+ description: The mysql user modified or removed from proxysql
+ returned: On create/update will return the newly modified rule, in all
+ other cases will return a list of rules that match the supplied
+ criteria.
+ type: dict
+ "sample": {
+ "changed": true,
+ "msg": "Added rule to mysql_query_rules",
+ "rules": [
+ {
+ "active": "0",
+ "apply": "0",
+ "cache_ttl": null,
+ "client_addr": null,
+ "comment": null,
+ "delay": null,
+ "destination_hostgroup": 1,
+ "digest": null,
+ "error_msg": null,
+ "flagIN": "0",
+ "flagOUT": null,
+ "log": null,
+ "match_digest": null,
+ "match_pattern": null,
+ "mirror_flagOUT": null,
+ "mirror_hostgroup": null,
+ "negate_match_pattern": "0",
+ "proxy_addr": null,
+ "proxy_port": null,
+ "reconnect": null,
+ "replace_pattern": null,
+ "retries": null,
+ "rule_id": "1",
+ "schemaname": null,
+ "timeout": null,
+ "username": "guest_ro"
+ }
+ ],
+ "state": "present"
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils.six import iteritems
+from ansible.module_utils._text import to_native
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def save_config_to_disk(cursor):
+ cursor.execute("SAVE MYSQL QUERY RULES TO DISK")
+ return True
+
+
+def load_config_to_runtime(cursor):
+ cursor.execute("LOAD MYSQL QUERY RULES TO RUNTIME")
+ return True
+
+
+class ProxyQueryRule(object):
+
+ def __init__(self, module):
+ self.state = module.params["state"]
+ self.force_delete = module.params["force_delete"]
+ self.save_to_disk = module.params["save_to_disk"]
+ self.load_to_runtime = module.params["load_to_runtime"]
+
+ config_data_keys = ["rule_id",
+ "active",
+ "username",
+ "schemaname",
+ "flagIN",
+ "client_addr",
+ "proxy_addr",
+ "proxy_port",
+ "digest",
+ "match_digest",
+ "match_pattern",
+ "negate_match_pattern",
+ "flagOUT",
+ "replace_pattern",
+ "destination_hostgroup",
+ "cache_ttl",
+ "timeout",
+ "retries",
+ "delay",
+ "mirror_flagOUT",
+ "mirror_hostgroup",
+ "error_msg",
+ "log",
+ "apply",
+ "comment"]
+
+ self.config_data = dict((k, module.params[k])
+ for k in config_data_keys)
+
+ def check_rule_pk_exists(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `rule_count`
+ FROM mysql_query_rules
+ WHERE rule_id = %s"""
+
+ query_data = \
+ [self.config_data["rule_id"]]
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+ return (int(check_count['rule_count']) > 0)
+
+ def check_rule_cfg_exists(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `rule_count`
+ FROM mysql_query_rules"""
+
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ if cols == 1:
+ query_string += "\n WHERE " + col + " = %s"
+ else:
+ query_string += "\n AND " + col + " = %s"
+
+ if cols > 0:
+ cursor.execute(query_string, query_data)
+ else:
+ cursor.execute(query_string)
+ check_count = cursor.fetchone()
+ return int(check_count['rule_count'])
+
+ def get_rule_config(self, cursor, created_rule_id=None):
+ query_string = \
+ """SELECT *
+ FROM mysql_query_rules"""
+
+ if created_rule_id:
+ query_data = [created_rule_id, ]
+ query_string += "\nWHERE rule_id = %s"
+
+ cursor.execute(query_string, query_data)
+ rule = cursor.fetchone()
+ else:
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ if cols == 1:
+ query_string += "\n WHERE " + col + " = %s"
+ else:
+ query_string += "\n AND " + col + " = %s"
+
+ if cols > 0:
+ cursor.execute(query_string, query_data)
+ else:
+ cursor.execute(query_string)
+ rule = cursor.fetchall()
+
+ return rule
+
+ def create_rule_config(self, cursor):
+ query_string = \
+ """INSERT INTO mysql_query_rules ("""
+
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ query_string += "\n" + col + ","
+
+ query_string = query_string[:-1]
+
+ query_string += \
+ (")\n" +
+ "VALUES (" +
+ "%s ," * cols)
+
+ query_string = query_string[:-2]
+ query_string += ")"
+
+ cursor.execute(query_string, query_data)
+ new_rule_id = cursor.lastrowid
+ return True, new_rule_id
+
+ def update_rule_config(self, cursor):
+ query_string = """UPDATE mysql_query_rules"""
+
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None and col != "rule_id":
+ cols += 1
+ query_data.append(val)
+ if cols == 1:
+ query_string += "\nSET " + col + "= %s,"
+ else:
+ query_string += "\n " + col + " = %s,"
+
+ query_string = query_string[:-1]
+ query_string += "\nWHERE rule_id = %s"
+
+ query_data.append(self.config_data["rule_id"])
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def delete_rule_config(self, cursor):
+ query_string = \
+ """DELETE FROM mysql_query_rules"""
+
+ cols = 0
+ query_data = []
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ if cols == 1:
+ query_string += "\n WHERE " + col + " = %s"
+ else:
+ query_string += "\n AND " + col + " = %s"
+
+ if cols > 0:
+ cursor.execute(query_string, query_data)
+ else:
+ cursor.execute(query_string)
+ check_count = cursor.rowcount
+ return True, int(check_count)
+
+ def manage_config(self, cursor, state):
+ if state:
+ if self.save_to_disk:
+ save_config_to_disk(cursor)
+ if self.load_to_runtime:
+ load_config_to_runtime(cursor)
+
+ def create_rule(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'], new_rule_id = \
+ self.create_rule_config(cursor)
+ result['msg'] = "Added rule to mysql_query_rules"
+ self.manage_config(cursor,
+ result['changed'])
+ result['rules'] = \
+ self.get_rule_config(cursor, new_rule_id)
+ else:
+ result['changed'] = True
+ result['msg'] = ("Rule would have been added to" +
+ " mysql_query_rules, however" +
+ " check_mode is enabled.")
+
+ def update_rule(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.update_rule_config(cursor)
+ result['msg'] = "Updated rule in mysql_query_rules"
+ self.manage_config(cursor,
+ result['changed'])
+ result['rules'] = \
+ self.get_rule_config(cursor)
+ else:
+ result['changed'] = True
+ result['msg'] = ("Rule would have been updated in" +
+ " mysql_query_rules, however" +
+ " check_mode is enabled.")
+
+ def delete_rule(self, check_mode, result, cursor):
+ if not check_mode:
+ result['rules'] = \
+ self.get_rule_config(cursor)
+ result['changed'], result['rows_affected'] = \
+ self.delete_rule_config(cursor)
+ result['msg'] = "Deleted rule from mysql_query_rules"
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Rule would have been deleted from" +
+ " mysql_query_rules, however" +
+ " check_mode is enabled.")
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default="127.0.0.1"),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default="", type='path'),
+ rule_id=dict(type='int'),
+ active=dict(type='bool'),
+ username=dict(type='str'),
+ schemaname=dict(type='str'),
+ flagIN=dict(type='int'),
+ client_addr=dict(type='str'),
+ proxy_addr=dict(type='str'),
+ proxy_port=dict(type='int'),
+ digest=dict(type='str'),
+ match_digest=dict(type='str'),
+ match_pattern=dict(type='str'),
+ negate_match_pattern=dict(type='bool'),
+ flagOUT=dict(type='int'),
+ replace_pattern=dict(type='str'),
+ destination_hostgroup=dict(type='int'),
+ cache_ttl=dict(type='int'),
+ timeout=dict(type='int'),
+ retries=dict(type='int'),
+ delay=dict(type='int'),
+ mirror_flagOUT=dict(type='int'),
+ mirror_hostgroup=dict(type='int'),
+ error_msg=dict(type='str'),
+ log=dict(type='bool'),
+ apply=dict(type='bool'),
+ comment=dict(type='str'),
+ state=dict(default='present', choices=['present',
+ 'absent']),
+ force_delete=dict(default=False, type='bool'),
+ save_to_disk=dict(default=True, type='bool'),
+ load_to_runtime=dict(default=True, type='bool')
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file,
+ cursor_class='DictCursor')
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ proxysql_query_rule = ProxyQueryRule(module)
+ result = {}
+
+ result['state'] = proxysql_query_rule.state
+
+ if proxysql_query_rule.state == "present":
+ try:
+ if not proxysql_query_rule.check_rule_cfg_exists(cursor):
+ if proxysql_query_rule.config_data["rule_id"] and \
+ proxysql_query_rule.check_rule_pk_exists(cursor):
+ proxysql_query_rule.update_rule(module.check_mode,
+ result,
+ cursor)
+ else:
+ proxysql_query_rule.create_rule(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The rule already exists in" +
+ " mysql_query_rules and doesn't need to be" +
+ " updated.")
+ result['rules'] = \
+ proxysql_query_rule.get_rule_config(cursor)
+
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to modify rule.. %s" % to_native(e)
+ )
+
+ elif proxysql_query_rule.state == "absent":
+ try:
+ existing_rules = proxysql_query_rule.check_rule_cfg_exists(cursor)
+ if existing_rules > 0:
+ if existing_rules == 1 or \
+ proxysql_query_rule.force_delete:
+ proxysql_query_rule.delete_rule(module.check_mode,
+ result,
+ cursor)
+ else:
+ module.fail_json(
+ msg=("Operation would delete multiple rules" +
+ " use force_delete to override this")
+ )
+ else:
+ result['changed'] = False
+ result['msg'] = ("The rule is already absent from the" +
+ " mysql_query_rules memory configuration")
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to remove rule.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_replication_hostgroups.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_replication_hostgroups.py
new file mode 100644
index 00000000..d8f5ee72
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_replication_hostgroups.py
@@ -0,0 +1,381 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_replication_hostgroups
+author: "Ben Mildren (@bmildren)"
+short_description: Manages replication hostgroups using the proxysql admin
+ interface.
+description:
+ - Each row in mysql_replication_hostgroups represent a pair of
+ writer_hostgroup and reader_hostgroup. ProxySQL will monitor the value of
+ read_only for all the servers in specified hostgroups, and based on the
+ value of read_only will assign the server to the writer or reader
+ hostgroups.
+options:
+ writer_hostgroup:
+ description:
+ - Id of the writer hostgroup.
+ type: int
+ required: True
+ reader_hostgroup:
+ description:
+ - Id of the reader hostgroup.
+ type: int
+ required: True
+ comment:
+ description:
+ - Text field that can be used for any purposes defined by the user.
+ type: str
+ state:
+ description:
+ - When C(present) - adds the replication hostgroup, when C(absent) -
+ removes the replication hostgroup.
+ type: str
+ choices: [ "present", "absent" ]
+ default: present
+extends_documentation_fragment:
+- community.proxysql.proxysql.managing_config
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example adds a replication hostgroup, it saves the mysql server config
+# to disk, but avoids loading the mysql server config to runtime (this might be
+# because several replication hostgroup are being added and the user wants to
+# push the config to runtime in a single batch using the
+# community.general.proxysql_manage_config module). It uses supplied credentials
+# to connect to the proxysql admin interface.
+
+- name: Add a replication hostgroup
+ community.proxysql.proxysql_replication_hostgroups:
+ login_user: 'admin'
+ login_password: 'admin'
+ writer_hostgroup: 1
+ reader_hostgroup: 2
+ state: present
+ load_to_runtime: False
+
+# This example removes a replication hostgroup, saves the mysql server config
+# to disk, and dynamically loads the mysql server config to runtime. It uses
+# credentials in a supplied config file to connect to the proxysql admin
+# interface.
+
+- name: Remove a replication hostgroup
+ community.proxysql.proxysql_replication_hostgroups:
+ config_file: '~/proxysql.cnf'
+ writer_hostgroup: 3
+ reader_hostgroup: 4
+ state: absent
+'''
+
+RETURN = '''
+stdout:
+ description: The replication hostgroup modified or removed from proxysql
+ returned: On create/update will return the newly modified group, on delete
+ it will return the deleted record.
+ type: dict
+ "sample": {
+ "changed": true,
+ "msg": "Added server to mysql_hosts",
+ "repl_group": {
+ "comment": "",
+ "reader_hostgroup": "1",
+ "writer_hostgroup": "2"
+ },
+ "state": "present"
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils._text import to_native
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if not module.params["writer_hostgroup"] >= 0:
+ module.fail_json(
+ msg="writer_hostgroup must be a integer greater than or equal to 0"
+ )
+
+ if not module.params["reader_hostgroup"] == \
+ module.params["writer_hostgroup"]:
+ if not module.params["reader_hostgroup"] > 0:
+ module.fail_json(
+ msg=("writer_hostgroup must be a integer greater than" +
+ " or equal to 0")
+ )
+ else:
+ module.fail_json(
+ msg="reader_hostgroup cannot equal writer_hostgroup"
+ )
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def save_config_to_disk(cursor):
+ cursor.execute("SAVE MYSQL SERVERS TO DISK")
+ return True
+
+
+def load_config_to_runtime(cursor):
+ cursor.execute("LOAD MYSQL SERVERS TO RUNTIME")
+ return True
+
+
+class ProxySQLReplicationHostgroup(object):
+
+ def __init__(self, module):
+ self.state = module.params["state"]
+ self.save_to_disk = module.params["save_to_disk"]
+ self.load_to_runtime = module.params["load_to_runtime"]
+ self.writer_hostgroup = module.params["writer_hostgroup"]
+ self.reader_hostgroup = module.params["reader_hostgroup"]
+ self.comment = module.params["comment"]
+
+ def check_repl_group_config(self, cursor, keys):
+ query_string = \
+ """SELECT count(*) AS `repl_groups`
+ FROM mysql_replication_hostgroups
+ WHERE writer_hostgroup = %s
+ AND reader_hostgroup = %s"""
+
+ query_data = \
+ [self.writer_hostgroup,
+ self.reader_hostgroup]
+
+ if self.comment and not keys:
+ query_string += "\n AND comment = %s"
+ query_data.append(self.comment)
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+ return (int(check_count['repl_groups']) > 0)
+
+ def get_repl_group_config(self, cursor):
+ query_string = \
+ """SELECT *
+ FROM mysql_replication_hostgroups
+ WHERE writer_hostgroup = %s
+ AND reader_hostgroup = %s"""
+
+ query_data = \
+ [self.writer_hostgroup,
+ self.reader_hostgroup]
+
+ cursor.execute(query_string, query_data)
+ repl_group = cursor.fetchone()
+ return repl_group
+
+ def create_repl_group_config(self, cursor):
+ query_string = \
+ """INSERT INTO mysql_replication_hostgroups (
+ writer_hostgroup,
+ reader_hostgroup,
+ comment)
+ VALUES (%s, %s, %s)"""
+
+ query_data = \
+ [self.writer_hostgroup,
+ self.reader_hostgroup,
+ self.comment or '']
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def update_repl_group_config(self, cursor):
+ query_string = \
+ """UPDATE mysql_replication_hostgroups
+ SET comment = %s
+ WHERE writer_hostgroup = %s
+ AND reader_hostgroup = %s"""
+
+ query_data = \
+ [self.comment,
+ self.writer_hostgroup,
+ self.reader_hostgroup]
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def delete_repl_group_config(self, cursor):
+ query_string = \
+ """DELETE FROM mysql_replication_hostgroups
+ WHERE writer_hostgroup = %s
+ AND reader_hostgroup = %s"""
+
+ query_data = \
+ [self.writer_hostgroup,
+ self.reader_hostgroup]
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def manage_config(self, cursor, state):
+ if state:
+ if self.save_to_disk:
+ save_config_to_disk(cursor)
+ if self.load_to_runtime:
+ load_config_to_runtime(cursor)
+
+ def create_repl_group(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.create_repl_group_config(cursor)
+ result['msg'] = "Added server to mysql_hosts"
+ result['repl_group'] = \
+ self.get_repl_group_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Repl group would have been added to" +
+ " mysql_replication_hostgroups, however" +
+ " check_mode is enabled.")
+
+ def update_repl_group(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.update_repl_group_config(cursor)
+ result['msg'] = "Updated server in mysql_hosts"
+ result['repl_group'] = \
+ self.get_repl_group_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Repl group would have been updated in" +
+ " mysql_replication_hostgroups, however" +
+ " check_mode is enabled.")
+
+ def delete_repl_group(self, check_mode, result, cursor):
+ if not check_mode:
+ result['repl_group'] = \
+ self.get_repl_group_config(cursor)
+ result['changed'] = \
+ self.delete_repl_group_config(cursor)
+ result['msg'] = "Deleted server from mysql_hosts"
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Repl group would have been deleted from" +
+ " mysql_replication_hostgroups, however" +
+ " check_mode is enabled.")
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default="127.0.0.1"),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default="", type='path'),
+ writer_hostgroup=dict(required=True, type='int'),
+ reader_hostgroup=dict(required=True, type='int'),
+ comment=dict(type='str'),
+ state=dict(default='present', choices=['present',
+ 'absent']),
+ save_to_disk=dict(default=True, type='bool'),
+ load_to_runtime=dict(default=True, type='bool')
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file,
+ cursor_class='DictCursor')
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ proxysql_repl_group = ProxySQLReplicationHostgroup(module)
+ result = {}
+
+ result['state'] = proxysql_repl_group.state
+
+ if proxysql_repl_group.state == "present":
+ try:
+ if not proxysql_repl_group.check_repl_group_config(cursor,
+ keys=True):
+ proxysql_repl_group.create_repl_group(module.check_mode,
+ result,
+ cursor)
+ else:
+ if not proxysql_repl_group.check_repl_group_config(cursor,
+ keys=False):
+ proxysql_repl_group.update_repl_group(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The repl group already exists in" +
+ " mysql_replication_hostgroups and" +
+ " doesn't need to be updated.")
+ result['repl_group'] = \
+ proxysql_repl_group.get_repl_group_config(cursor)
+
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to modify replication hostgroup.. %s" % to_native(e)
+ )
+
+ elif proxysql_repl_group.state == "absent":
+ try:
+ if proxysql_repl_group.check_repl_group_config(cursor,
+ keys=True):
+ proxysql_repl_group.delete_repl_group(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The repl group is already absent from the" +
+ " mysql_replication_hostgroups memory" +
+ " configuration")
+
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to delete replication hostgroup.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_scheduler.py b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_scheduler.py
new file mode 100644
index 00000000..136b3283
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/community/proxysql/plugins/modules/proxysql_scheduler.py
@@ -0,0 +1,424 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: proxysql_scheduler
+author: "Ben Mildren (@bmildren)"
+short_description: Adds or removes schedules from proxysql admin interface.
+description:
+ - The M(community.proxysql.proxysql_scheduler) module adds or removes schedules using the
+ proxysql admin interface.
+options:
+ active:
+ description:
+ - A schedule with I(active) set to C(False) will be tracked in the
+ database, but will be never loaded in the in-memory data structures.
+ type: bool
+ default: True
+ interval_ms:
+ description:
+ - How often (in millisecond) the job will be started. The minimum value
+ for I(interval_ms) is 100 milliseconds.
+ type: int
+ default: 10000
+ filename:
+ description:
+ - Full path of the executable to be executed.
+ type: str
+ required: True
+ arg1:
+ description:
+ - Argument that can be passed to the job.
+ type: str
+ arg2:
+ description:
+ - Argument that can be passed to the job.
+ type: str
+ arg3:
+ description:
+ - Argument that can be passed to the job.
+ type: str
+ arg4:
+ description:
+ - Argument that can be passed to the job.
+ type: str
+ arg5:
+ description:
+ - Argument that can be passed to the job.
+ type: str
+ comment:
+ description:
+ - Text field that can be used for any purposed defined by the user.
+ type: str
+ state:
+ description:
+ - When C(present) - adds the schedule, when C(absent) - removes the
+ schedule.
+ type: str
+ choices: [ "present", "absent" ]
+ default: present
+ force_delete:
+ description:
+ - By default we avoid deleting more than one schedule in a single batch,
+ however if you need this behaviour and you're not concerned about the
+ schedules deleted, you can set I(force_delete) to C(True).
+ type: bool
+ default: False
+extends_documentation_fragment:
+- community.proxysql.proxysql.managing_config
+- community.proxysql.proxysql.connectivity
+
+'''
+
+EXAMPLES = '''
+---
+# This example adds a schedule, it saves the scheduler config to disk, but
+# avoids loading the scheduler config to runtime (this might be because
+# several servers are being added and the user wants to push the config to
+# runtime in a single batch using the community.general.proxysql_manage_config
+# module). It uses supplied credentials to connect to the proxysql admin
+# interface.
+
+- name: Add a schedule
+ community.proxysql.proxysql_scheduler:
+ login_user: 'admin'
+ login_password: 'admin'
+ interval_ms: 1000
+ filename: "/opt/maintenance.py"
+ state: present
+ load_to_runtime: False
+
+# This example removes a schedule, saves the scheduler config to disk, and
+# dynamically loads the scheduler config to runtime. It uses credentials
+# in a supplied config file to connect to the proxysql admin interface.
+
+- name: Remove a schedule
+ community.proxysql.proxysql_scheduler:
+ config_file: '~/proxysql.cnf'
+ filename: "/opt/old_script.py"
+ state: absent
+'''
+
+RETURN = '''
+stdout:
+ description: The schedule modified or removed from proxysql
+ returned: On create/update will return the newly modified schedule, on
+ delete it will return the deleted record.
+ type: dict
+ "sample": {
+ "changed": true,
+ "filename": "/opt/test.py",
+ "msg": "Added schedule to scheduler",
+ "schedules": [
+ {
+ "active": "1",
+ "arg1": null,
+ "arg2": null,
+ "arg3": null,
+ "arg4": null,
+ "arg5": null,
+ "comment": "",
+ "filename": "/opt/test.py",
+ "id": "1",
+ "interval_ms": "10000"
+ }
+ ],
+ "state": "present"
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.proxysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg
+from ansible.module_utils.six import iteritems
+from ansible.module_utils._text import to_native
+
+# ===========================================
+# proxysql module specific support methods.
+#
+
+
+def perform_checks(module):
+ if module.params["login_port"] < 0 \
+ or module.params["login_port"] > 65535:
+ module.fail_json(
+ msg="login_port must be a valid unix port number (0-65535)"
+ )
+
+ if module.params["interval_ms"] < 100 \
+ or module.params["interval_ms"] > 100000000:
+ module.fail_json(
+ msg="interval_ms must between 100ms & 100000000ms"
+ )
+
+ if mysql_driver is None:
+ module.fail_json(msg=mysql_driver_fail_msg)
+
+
+def save_config_to_disk(cursor):
+ cursor.execute("SAVE SCHEDULER TO DISK")
+ return True
+
+
+def load_config_to_runtime(cursor):
+ cursor.execute("LOAD SCHEDULER TO RUNTIME")
+ return True
+
+
+class ProxySQLSchedule(object):
+
+ def __init__(self, module):
+ self.state = module.params["state"]
+ self.force_delete = module.params["force_delete"]
+ self.save_to_disk = module.params["save_to_disk"]
+ self.load_to_runtime = module.params["load_to_runtime"]
+ self.active = module.params["active"]
+ self.interval_ms = module.params["interval_ms"]
+ self.filename = module.params["filename"]
+
+ config_data_keys = ["arg1",
+ "arg2",
+ "arg3",
+ "arg4",
+ "arg5",
+ "comment"]
+
+ self.config_data = dict((k, module.params[k])
+ for k in config_data_keys)
+
+ def check_schedule_config(self, cursor):
+ query_string = \
+ """SELECT count(*) AS `schedule_count`
+ FROM scheduler
+ WHERE active = %s
+ AND interval_ms = %s
+ AND filename = %s"""
+
+ query_data = \
+ [self.active,
+ self.interval_ms,
+ self.filename]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ query_data.append(val)
+ query_string += "\n AND " + col + " = %s"
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.fetchone()
+ return int(check_count['schedule_count'])
+
+ def get_schedule_config(self, cursor):
+ query_string = \
+ """SELECT *
+ FROM scheduler
+ WHERE active = %s
+ AND interval_ms = %s
+ AND filename = %s"""
+
+ query_data = \
+ [self.active,
+ self.interval_ms,
+ self.filename]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ query_data.append(val)
+ query_string += "\n AND " + col + " = %s"
+
+ cursor.execute(query_string, query_data)
+ schedule = cursor.fetchall()
+ return schedule
+
+ def create_schedule_config(self, cursor):
+ query_string = \
+ """INSERT INTO scheduler (
+ active,
+ interval_ms,
+ filename"""
+
+ cols = 0
+ query_data = \
+ [self.active,
+ self.interval_ms,
+ self.filename]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ cols += 1
+ query_data.append(val)
+ query_string += ",\n" + col
+
+ query_string += \
+ (")\n" +
+ "VALUES (%s, %s, %s" +
+ ", %s" * cols +
+ ")")
+
+ cursor.execute(query_string, query_data)
+ return True
+
+ def delete_schedule_config(self, cursor):
+ query_string = \
+ """DELETE FROM scheduler
+ WHERE active = %s
+ AND interval_ms = %s
+ AND filename = %s"""
+
+ query_data = \
+ [self.active,
+ self.interval_ms,
+ self.filename]
+
+ for col, val in iteritems(self.config_data):
+ if val is not None:
+ query_data.append(val)
+ query_string += "\n AND " + col + " = %s"
+
+ cursor.execute(query_string, query_data)
+ check_count = cursor.rowcount
+ return True, int(check_count)
+
+ def manage_config(self, cursor, state):
+ if state:
+ if self.save_to_disk:
+ save_config_to_disk(cursor)
+ if self.load_to_runtime:
+ load_config_to_runtime(cursor)
+
+ def create_schedule(self, check_mode, result, cursor):
+ if not check_mode:
+ result['changed'] = \
+ self.create_schedule_config(cursor)
+ result['msg'] = "Added schedule to scheduler"
+ result['schedules'] = \
+ self.get_schedule_config(cursor)
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Schedule would have been added to" +
+ " scheduler, however check_mode" +
+ " is enabled.")
+
+ def delete_schedule(self, check_mode, result, cursor):
+ if not check_mode:
+ result['schedules'] = \
+ self.get_schedule_config(cursor)
+ result['changed'] = \
+ self.delete_schedule_config(cursor)
+ result['msg'] = "Deleted schedule from scheduler"
+ self.manage_config(cursor,
+ result['changed'])
+ else:
+ result['changed'] = True
+ result['msg'] = ("Schedule would have been deleted from" +
+ " scheduler, however check_mode is" +
+ " enabled.")
+
+# ===========================================
+# Module execution.
+#
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ login_user=dict(default=None, type='str'),
+ login_password=dict(default=None, no_log=True, type='str'),
+ login_host=dict(default="127.0.0.1"),
+ login_unix_socket=dict(default=None),
+ login_port=dict(default=6032, type='int'),
+ config_file=dict(default="", type='path'),
+ active=dict(default=True, type='bool'),
+ interval_ms=dict(default=10000, type='int'),
+ filename=dict(required=True, type='str'),
+ arg1=dict(type='str'),
+ arg2=dict(type='str'),
+ arg3=dict(type='str'),
+ arg4=dict(type='str'),
+ arg5=dict(type='str'),
+ comment=dict(type='str'),
+ state=dict(default='present', choices=['present',
+ 'absent']),
+ force_delete=dict(default=False, type='bool'),
+ save_to_disk=dict(default=True, type='bool'),
+ load_to_runtime=dict(default=True, type='bool')
+ ),
+ supports_check_mode=True
+ )
+
+ perform_checks(module)
+
+ login_user = module.params["login_user"]
+ login_password = module.params["login_password"]
+ config_file = module.params["config_file"]
+
+ cursor = None
+ try:
+ cursor, db_conn = mysql_connect(module,
+ login_user,
+ login_password,
+ config_file,
+ cursor_class='DictCursor')
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to connect to ProxySQL Admin Module.. %s" % to_native(e)
+ )
+
+ proxysql_schedule = ProxySQLSchedule(module)
+ result = {}
+
+ result['state'] = proxysql_schedule.state
+ result['filename'] = proxysql_schedule.filename
+
+ if proxysql_schedule.state == "present":
+ try:
+ if proxysql_schedule.check_schedule_config(cursor) <= 0:
+ proxysql_schedule.create_schedule(module.check_mode,
+ result,
+ cursor)
+ else:
+ result['changed'] = False
+ result['msg'] = ("The schedule already exists and doesn't" +
+ " need to be updated.")
+ result['schedules'] = \
+ proxysql_schedule.get_schedule_config(cursor)
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to modify schedule.. %s" % to_native(e)
+ )
+
+ elif proxysql_schedule.state == "absent":
+ try:
+ existing_schedules = \
+ proxysql_schedule.check_schedule_config(cursor)
+ if existing_schedules > 0:
+ if existing_schedules == 1 or proxysql_schedule.force_delete:
+ proxysql_schedule.delete_schedule(module.check_mode,
+ result,
+ cursor)
+ else:
+ module.fail_json(
+ msg=("Operation would delete multiple records" +
+ " use force_delete to override this")
+ )
+ else:
+ result['changed'] = False
+ result['msg'] = ("The schedule is already absent from the" +
+ " memory configuration")
+ except mysql_driver.Error as e:
+ module.fail_json(
+ msg="unable to remove schedule.. %s" % to_native(e)
+ )
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()