mirror of
https://github.com/saltstack-formulas/mysql-formula.git
synced 2025-04-17 10:10:30 +00:00
Add scripted parsing of all mysql options
This commit is contained in:
parent
b697e58c73
commit
a7494c9490
4 changed files with 1229 additions and 115 deletions
39
README.rst
39
README.rst
|
@ -6,8 +6,8 @@ Install the MySQL client and/or server.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
See the full `Salt Formulas installation and usage instructions
|
See the full `Salt Formulas installation and usage instructions
|
||||||
<http://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html>`_.
|
<http://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html>`_.
|
||||||
|
|
||||||
Available states
|
Available states
|
||||||
================
|
================
|
||||||
|
@ -53,14 +53,41 @@ Create and manage MySQL databases.
|
||||||
Install mysql python bindings.
|
Install mysql python bindings.
|
||||||
|
|
||||||
``mysql.user``
|
``mysql.user``
|
||||||
----------------
|
--------------
|
||||||
|
|
||||||
Create and manage MySQL database users with definable GRANT privileges.
|
Create and manage MySQL database users with definable GRANT privileges.
|
||||||
|
|
||||||
The state accepts MySQL hashed passwords or clear text. Hashed password have priority.
|
The state accepts MySQL hashed passwords or clear text. Hashed password have
|
||||||
|
priority.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
See the `salt.states.mysql_user <http://docs.saltstack.com/en/latest/ref/states/all/salt.states.mysql_user.html#module-salt.states.mysql_user>`_ docs for additional information on configuring hashed passwords.
|
See the `salt.states.mysql_user
|
||||||
|
<http://docs.saltstack.com/en/latest/ref/states/all/salt.states.mysql_user.html#module-salt.states.mysql_user>`_
|
||||||
|
docs for additional information on configuring hashed passwords.
|
||||||
|
|
||||||
Make sure to **quote the passwords** in the pillar so YAML doesn't throw an exception.
|
Make sure to **quote the passwords** in the pillar so YAML doesn't throw an exception.
|
||||||
|
|
||||||
|
|
||||||
|
Updating the supported parameters
|
||||||
|
=================================
|
||||||
|
|
||||||
|
The ``supported_params.yaml`` file contains the full listing of options that
|
||||||
|
are acceptable in the MySQL options file. On occassion, especially on new
|
||||||
|
releases of MySQL, this file may need to be updated. To update, run the
|
||||||
|
supplied script (requires Python 3.x)::
|
||||||
|
|
||||||
|
./scripts/parse_supported_params.py -o ./mysql/supported_params.yaml
|
||||||
|
|
||||||
|
This script will scrape the options from the official MySQL documentation
|
||||||
|
online, and thus requires web access. Scraping is inherently brittle, though
|
||||||
|
this script has been defensively coded, where possible.
|
||||||
|
|
||||||
|
Once the ``supported_params.yaml`` file has been updated, commit the result to
|
||||||
|
the repository.
|
||||||
|
|
||||||
|
Support for new applications
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
To add support for configuration of other MySQL applications, add the URL and
|
||||||
|
section identifier into the relevant section of the script. Consult the
|
||||||
|
comments in the code to determine where your section should be added.
|
||||||
|
|
File diff suppressed because it is too large
Load diff
61
scripts/html_table_parser.py
Normal file
61
scripts/html_table_parser.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Name: html_table_parser
|
||||||
|
# Purpose: Simple class for parsing an (x)html string to extract tables.
|
||||||
|
# Written in python3
|
||||||
|
#
|
||||||
|
# Author: Josua Schmid
|
||||||
|
#
|
||||||
|
# Created: 05.03.2014
|
||||||
|
# Copyright: (c) Josua Schmid 2014
|
||||||
|
# Licence: GPLv3
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
|
class HTMLTableParser(HTMLParser):
|
||||||
|
""" This class serves as a html table parser. It is able to parse multiple
|
||||||
|
tables which you feed in. You can access the result per .tables field.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
HTMLParser.__init__(self)
|
||||||
|
self.__in_td = False
|
||||||
|
self.__in_th = False
|
||||||
|
self.__current_table = []
|
||||||
|
self.__current_row = []
|
||||||
|
self.__current_cell = []
|
||||||
|
self.tables = []
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
""" We need to remember the opening point for the content of interest.
|
||||||
|
The other tags (<table>, <tr>) are only handled at the closing point.
|
||||||
|
"""
|
||||||
|
if tag == 'td':
|
||||||
|
self.__in_td = True
|
||||||
|
if tag == 'th':
|
||||||
|
self.__in_th = True
|
||||||
|
|
||||||
|
def handle_data(self, data):
|
||||||
|
""" This is where we save content to a cell """
|
||||||
|
if self.__in_td ^ self.__in_th:
|
||||||
|
self.__current_cell.append(data.strip())
|
||||||
|
|
||||||
|
def handle_endtag(self, tag):
|
||||||
|
""" Here we exit the tags. If the closing tag is </tr>, we know that we
|
||||||
|
can save our currently parsed cells to the current table as a row and
|
||||||
|
prepare for a new row. If the closing tag is </table>, we save the
|
||||||
|
current table and prepare for a new one.
|
||||||
|
"""
|
||||||
|
if tag == 'td':
|
||||||
|
self.__in_td = False
|
||||||
|
if tag == 'th':
|
||||||
|
self.__in_th = False
|
||||||
|
|
||||||
|
if (tag == 'td') ^ (tag == 'th'):
|
||||||
|
final_cell = " ".join(self.__current_cell).strip()
|
||||||
|
self.__current_row.append(final_cell)
|
||||||
|
self.__current_cell = []
|
||||||
|
if tag == 'tr':
|
||||||
|
self.__current_table.append(self.__current_row)
|
||||||
|
self.__current_row = []
|
||||||
|
if tag == 'table':
|
||||||
|
self.tables.append(self.__current_table)
|
||||||
|
self.__current_table = []
|
167
scripts/parse_supported_params.py
Executable file
167
scripts/parse_supported_params.py
Executable file
|
@ -0,0 +1,167 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# coding: utf-8
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
from html_table_parser import HTMLTableParser
|
||||||
|
|
||||||
|
# Regex for parsing options on MySQL documentation pages
|
||||||
|
# Options are (normally) specified as command-line options
|
||||||
|
# as anchor tags on the page. Certain documentation pages only
|
||||||
|
# show options in table listings, however.
|
||||||
|
OPTION_REGEX = '<a name="option_%s_(.*?)"></a>'
|
||||||
|
OPTION_TABLE_REGEX = '^(--)?([A-Za-z_-]+).*$'
|
||||||
|
|
||||||
|
# File heading, as per the original supported_params file
|
||||||
|
FILE_HEADER = """# vim
|
||||||
|
{#- Do not edit this YAML file by hand. See README.rst for how to update -#}
|
||||||
|
{% load_yaml as supported_params %}
|
||||||
|
"""
|
||||||
|
FILE_FOOTER = """{% endload %}"""
|
||||||
|
|
||||||
|
# Standard YAML template for options for a section
|
||||||
|
YAML_TEMPLATE = """# From %(url)s
|
||||||
|
%(section)s:
|
||||||
|
- %(options)s
|
||||||
|
"""
|
||||||
|
|
||||||
|
# For rendering Jinja that handles multiple sections
|
||||||
|
# Several MySQL utilities use exactly the same options
|
||||||
|
# Note this variable is string formatted twice, hence the double-double % signs
|
||||||
|
YAML_TEMPLATE_MULTI = """# From %%(url)s
|
||||||
|
{%%%% for section in %(sections)r %%%%}
|
||||||
|
{{ section }}:
|
||||||
|
- %%(options)s
|
||||||
|
{%%%% endfor %%%%}
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Options specified in HTML documentation as command-line options
|
||||||
|
# like so <a name="option_mysql_help"></a>.
|
||||||
|
# Structure is (section_id, documentation_url, yaml_template_str)
|
||||||
|
SECTIONS = (
|
||||||
|
('mysql',
|
||||||
|
'https://dev.mysql.com/doc/refman/5.7/en/mysql-command-options.html',
|
||||||
|
YAML_TEMPLATE_MULTI % {'sections': ['client', 'mysql']}),
|
||||||
|
('mysqldump',
|
||||||
|
'https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
('mysqld_safe',
|
||||||
|
'https://dev.mysql.com/doc/refman/5.7/en/mysqld-safe.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
# Removed in MySQL 5.7
|
||||||
|
('mysqlhotcopy',
|
||||||
|
'http://dev.mysql.com/doc/refman/5.6/en/mysqlhotcopy.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
('mysqladmin',
|
||||||
|
'http://dev.mysql.com/doc/refman/5.7/en/mysqladmin.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
('mysqlcheck',
|
||||||
|
'http://dev.mysql.com/doc/refman/5.7/en/mysqlcheck.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
('mysqlimport',
|
||||||
|
'http://dev.mysql.com/doc/refman/5.7/en/mysqlimport.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
('mysqlshow',
|
||||||
|
'http://dev.mysql.com/doc/refman/5.7/en/mysqlshow.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
('myisampack',
|
||||||
|
'http://dev.mysql.com/doc/refman/5.7/en/myisampack.html',
|
||||||
|
YAML_TEMPLATE),
|
||||||
|
)
|
||||||
|
# Options specified in documentation as command-line and
|
||||||
|
# option file values in a table only.
|
||||||
|
SECTIONS_VIA_TABLE = (
|
||||||
|
('myisamchk',
|
||||||
|
'https://dev.mysql.com/doc/refman/5.7/en/myisamchk.html',
|
||||||
|
YAML_TEMPLATE_MULTI % {'sections': ['myisamchk', 'isamchk']}),
|
||||||
|
)
|
||||||
|
# Server options specified in documentation
|
||||||
|
SERVER_OPTIONS = (
|
||||||
|
'mysqld',
|
||||||
|
'https://dev.mysql.com/doc/refman/5.7/en/mysqld-option-tables.html',
|
||||||
|
YAML_TEMPLATE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def read_url(url):
|
||||||
|
""" Read the given URL and decode the response as UTF-8.
|
||||||
|
"""
|
||||||
|
request = urllib.request.Request(url)
|
||||||
|
response = urllib.request.urlopen(request)
|
||||||
|
return response.read().decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def read_first_table(url):
|
||||||
|
""" Read the given URL, parse the result, and return the first table.
|
||||||
|
"""
|
||||||
|
xhtml = read_url(url)
|
||||||
|
parser = HTMLTableParser()
|
||||||
|
parser.feed(xhtml)
|
||||||
|
return parser.tables[0] # Use first table on the page
|
||||||
|
|
||||||
|
|
||||||
|
def parse_anchors(url, section):
|
||||||
|
""" Return parsed options from option anchors at the given URL.
|
||||||
|
"""
|
||||||
|
return re.findall(OPTION_REGEX % section, read_url(url))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_tables(url, section):
|
||||||
|
""" Return arsed options from HTML tables at the given URL.
|
||||||
|
|
||||||
|
This matches the given option regex, and ensures that the
|
||||||
|
first row of the table is ignored; it contains headings only.
|
||||||
|
"""
|
||||||
|
table = read_first_table(url)
|
||||||
|
return [re.match(OPTION_TABLE_REGEX, row[0]).groups()[1]
|
||||||
|
for row in table[1:]]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_mysqld(url, section):
|
||||||
|
""" Return the parsed options from the huge mysqld table.
|
||||||
|
|
||||||
|
The massive options table shows variables and options and
|
||||||
|
highlights where they can be used. The following code only
|
||||||
|
pulls out those that are marked as 'Yes' for use in an option file.
|
||||||
|
"""
|
||||||
|
table = read_first_table(url)
|
||||||
|
# Find which column holds the option file data
|
||||||
|
option_index = table[0].index('Option File')
|
||||||
|
# Only pull out options able to be used in an options file
|
||||||
|
return [re.match(OPTION_TABLE_REGEX, row[0]).groups()[1]
|
||||||
|
for row in table[1:]
|
||||||
|
if len(row) >= option_index + 1 and
|
||||||
|
row[option_index].strip().lower() == 'yes']
|
||||||
|
|
||||||
|
|
||||||
|
def print_yaml_options(sections, parser, file=sys.stdout):
|
||||||
|
""" Perform really basic templating for output.
|
||||||
|
|
||||||
|
A YAML library could be used, but we avoid extra dependencies by
|
||||||
|
just using string formatting.
|
||||||
|
"""
|
||||||
|
for section, url, yaml in sections:
|
||||||
|
options = parser(url, section)
|
||||||
|
print(yaml % {'section': section,
|
||||||
|
'options': '\n - '.join(options),
|
||||||
|
'url': url}, end='', file=file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Scrape the MySQL documentation to obtain'
|
||||||
|
' all the supported parameters for different utilities.')
|
||||||
|
parser.add_argument('--output',
|
||||||
|
'-o',
|
||||||
|
help='File output location',
|
||||||
|
default=sys.stdout)
|
||||||
|
config = parser.parse_args()
|
||||||
|
output = open(config.output, 'w') if isinstance(config.output, str) \
|
||||||
|
else config.output
|
||||||
|
|
||||||
|
print(FILE_HEADER, end='', file=output)
|
||||||
|
print_yaml_options(SECTIONS, parse_anchors, file=output)
|
||||||
|
print_yaml_options(SECTIONS_VIA_TABLE, parse_tables, file=output)
|
||||||
|
print_yaml_options((SERVER_OPTIONS,), parse_mysqld, file=output)
|
||||||
|
print(FILE_FOOTER, end='', file=output)
|
Loading…
Add table
Reference in a new issue