Browse Source

Merge branch 'master' into feature/tunne_bootstrapscrips

feature/tunne_bootstrapscrips
Petr Michalec 6 years ago
parent
commit
d73be0e901
No account linked to committer's email address
34 changed files with 1979 additions and 201 deletions
  1. +28
    -10
      .kitchen.yml
  2. +10
    -3
      .travis.yml
  3. +97
    -5
      README.rst
  4. +1
    -1
      debian/control
  5. +107
    -0
      galera/_ssl.sls
  6. +45
    -0
      galera/clustercheck.sls
  7. +138
    -0
      galera/files/clustercheck.sh
  8. +2
    -2
      galera/files/debian.cnf
  9. +930
    -0
      galera/files/grafana_dashboards/mysql_prometheus.json
  10. +1
    -1
      galera/files/init_bootstrap.sh
  11. +20
    -5
      galera/files/my.cnf
  12. +4
    -4
      galera/files/my.cnf.container
  13. +11
    -4
      galera/files/my.cnf.init
  14. +24
    -0
      galera/files/xinet.d.conf
  15. +3
    -0
      galera/init.sls
  16. +133
    -50
      galera/map.jinja
  17. +33
    -25
      galera/master.sls
  18. +15
    -19
      galera/meta/collectd.yml
  19. +22
    -1
      galera/meta/grafana.yml
  20. +31
    -0
      galera/meta/prometheus.yml
  21. +16
    -0
      galera/meta/telegraf.yml
  22. +86
    -14
      galera/server.sls
  23. +36
    -23
      galera/slave.sls
  24. +4
    -0
      metadata/service/master/cluster.yml
  25. +4
    -0
      metadata/service/master/container.yml
  26. +4
    -0
      metadata/service/slave/cluster.yml
  27. +21
    -0
      metadata/service/ssl.yml
  28. +4
    -0
      metadata/service/support.yml
  29. +10
    -0
      tests/integration/master_cluster/checks_clustercheck_spec.rb
  30. +10
    -0
      tests/integration/slave_cluster/checks_clustercheck_spec.rb
  31. +58
    -27
      tests/pillar/master_cluster.sls
  32. +13
    -1
      tests/pillar/repo_galeracluster.sls
  33. +16
    -2
      tests/pillar/slave_cluster.sls
  34. +42
    -4
      tests/run_tests.sh

+ 28
- 10
.kitchen.yml View File

formula: galera formula: galera
grains: grains:
noservices: True noservices: True
dependencies:
- name: mysql
repo: git
source: https://github.com/salt-formulas/salt-formula-mysql.git
- name: linux
repo: git
source: https://github.com/salt-formulas/salt-formula-linux.git
state_top: state_top:
base: base:
"*": "*":
top.sls: top.sls:
base: base:
"*": "*":
- versions
- repos_base
- repos
- galera - galera
- galeracluster_debian_repo
versions.sls:
galera:
version:
mysql: <%= ENV['MYSQL_VER'] || '5.6' %>
galera: <%= ENV['GALERA_VER'] || '3' %>
# NOTE(vsaienko) There is no guarntee that pillars are loaded before pillars-from-file
# as result we cant assume variables defined via pillars: are available when pillars-from-file
# is loaded. Move 'source' definitions of repos to .kitchen.yml as it used ENV variable
repos_base.sls:
linux:
system:
enabled: true
repo:
galeracluster:
source: deb http://releases.galeracluster.com/galera-<%=ENV['GALERA_VER'] || '3'%>/ubuntu {{ grains.get('oscodename') }} main
mysql-wsrep:
source: deb http://releases.galeracluster.com/mysql-wsrep-<%=ENV['MYSQL_VER'] || '5.6'%>/ubuntu {{ grains.get('oscodename') }} main
pillars-from-files: pillars-from-files:
galeracluster_debian_repo.sls: tests/pillar/repo_galeracluster.sls
dependencies:
- name: mysql
repo: git
source: https://github.com/salt-formulas/salt-formula-mysql.git
dependencies:
- name: linux
repo: git
source: https://github.com/salt-formulas/salt-formula-linux.git
repos.sls: tests/pillar/repo_galeracluster.sls


verifier: verifier:
name: inspec name: inspec

+ 10
- 3
.travis.yml View File

- bundle install - bundle install


env: env:
- PLATFORM=trevorj/salty-whales:trusty
- PLATFORM=trevorj/salty-whales:xenial
- PLATFORM=trevorj/salty-whales:trusty SUITE=master-cluster MYSQL_VER=5.6 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:xenial SUITE=master-cluster MYSQL_VER=5.6 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:trusty SUITE=slave-cluster MYSQL_VER=5.6 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:xenial SUITE=slave-cluster MYSQL_VER=5.6 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:trusty SUITE=master-cluster MYSQL_VER=5.7 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:xenial SUITE=master-cluster MYSQL_VER=5.7 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:trusty SUITE=slave-cluster MYSQL_VER=5.7 GALERA_VER=3
- PLATFORM=trevorj/salty-whales:xenial SUITE=slave-cluster MYSQL_VER=5.7 GALERA_VER=3


before_script: before_script:
- set -o pipefail - set -o pipefail
- make test | tail - make test | tail


script: script:
- test ! -e .kitchen.yml || bundle exec kitchen test -t tests/integration
- test ! -e .kitchen.yml || bundle exec kitchen converge ${SUITE} || true
- test ! -e .kitchen.yml || bundle exec kitchen verify ${SUITE} -t tests/integration


notifications: notifications:
webhooks: webhooks:

+ 97
- 5
README.rst View File

.. code-block:: yaml .. code-block:: yaml


galera: galera:
version:
mysql: 5.6
galera: 3
master: master:
enabled: true enabled: true
name: openstack name: openstack
user: root user: root
password: pass password: pass


Enable TLS support:

.. code-block:: yaml

galera:
slave or master:
ssl:
enabled: True

# path
cert_file: /etc/mysql/ssl/cert.pem
key_file: /etc/mysql/ssl/key.pem
ca_file: /etc/mysql/ssl/ca.pem

# content (not required if files already exists)
key: << body of key >>
cert: << body of cert >>
cacert_chain: << body of ca certs chain >>


Additional mysql users:

.. code-block:: yaml

mysql:
server:
users:
- name: clustercheck
password: clustercheck
database: '*.*'
grants: PROCESS
- name: inspector
host: 127.0.0.1
password: password
databases:
mydb:
- database: mydb
- table: mytable
- grant_option: True
- grants:
- all privileges

Additional mysql SSL grants:

.. code-block:: yaml

mysql:
server:
users:
- name: clustercheck
password: clustercheck
database: '*.*'
grants: PROCESS
ssl_option:
- SSL: True
- X509: True
- SUBJECT: <subject>
- ISSUER: <issuer>
- CIPHER: <cipher>

Additional check params:
========================

.. code-block:: yaml

galera:
clustercheck:
- enabled: True
- user: clustercheck
- password: clustercheck
- available_when_donor: 0
- available_when_readonly: 1
- port 9200

Configurable soft parameters
============================


- **galera_innodb_buffer_pool_size** - the default value is 3138M
- **galera_max_connections** - the default value is 20000

Usage:
.. code-block:: yaml

_param:
galera_innodb_buffer_pool_size: 1024M
galera_max_connections: 200


Usage Usage
===== =====


MySQL Galera check sripts MySQL Galera check sripts


.. code-block:: bash .. code-block:: bash
mysql> SHOW STATUS LIKE 'wsrep%'; mysql> SHOW STATUS LIKE 'wsrep%';


mysql> SHOW STATUS LIKE 'wsrep_cluster_size' ;" mysql> SHOW STATUS LIKE 'wsrep_cluster_size' ;"


.. code-block:: bash .. code-block:: bash


Enter current password for root (enter for none):
Enter current password for root (enter for none):
OK, successfully used password, moving on... OK, successfully used password, moving on...


Setting the root password ensures that nobody can log into the MySQL Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation. root user without the proper authorisation.


Set root password? [Y/n] y Set root password? [Y/n] y
New password:
Re-enter new password:
New password:
Re-enter new password:
Password updated successfully! Password updated successfully!
Reloading privilege tables.. Reloading privilege tables..
... Success! ... Success!
Cleaning up... Cleaning up...


5. service mysql stop 5. service mysql stop
6. uncomment all wsrep* lines except first server, where leave only in my.cnf wsrep_cluster_address='gcomm://';
6. uncomment all wsrep* lines except first server, where leave only in my.cnf wsrep_cluster_address='gcomm://';
7. start first node 7. start first node
8. Start third node which is connected to first one 8. Start third node which is connected to first one
9. Start second node which is connected to third one 9. Start second node which is connected to third one

+ 1
- 1
debian/control View File



Package: salt-formula-galera Package: salt-formula-galera
Architecture: all Architecture: all
Depends: ${misc:Depends}, salt-master, reclass, salt-formula-mysql
Depends: ${misc:Depends}, salt-formula-mysql
Description: galera salt formula Description: galera salt formula
Install and configure galera system. Install and configure galera system.

+ 107
- 0
galera/_ssl.sls View File

{%- from "galera/map.jinja" import master, slave with context %}
{%- if master.get('enabled', False) %}
{%- set service, role = master, 'master' %}
{%- elif slave.get('enabled', False) %}
{%- set service, role = slave, 'slave' %}
{%- endif %}

{%- if service.get('ssl', {}).get('enabled', False) %}

galera_ssl_dir:
file.directory:
- name: /etc/mysql/ssl
- makedirs: true
- mode: 755
- require:
- pkg: galera_packages

{%- if service.ssl.cacert_chain is defined %}
mysql_cacertificate:
file.managed:
- name: {{ service.ssl.ca_file }}
- contents_pillar: galera:{{ role }}:ssl:cacert_chain
- mode: 0444
- makedirs: true
- require_in:
- service: galera_service
- file: galera_config
{%- else %}
mysql_cacertificate_exists:
file.exists:
- name: {{ service.ssl.ca_file }}
mysql_cacertificate:
file.managed:
- name: {{ service.ssl.ca_file }}
- mode: 644
- create: False
- require:
- file: mysql_cacertificate_exists
- file: galera_ssl_dir
- require_in:
- service: galera_service
- file: galera_config
{%- endif %}

{%- if service.ssl.cert is defined %}
mysql_certificate:
file.managed:
- name: {{ service.ssl.cert_file }}
- contents_pillar: galera:{{ role }}:ssl:cert
- mode: 0444
- makedirs: true
- require_in:
- service: galera_service
- file: galera_config
{%- else %}
mysql_certificate_exists:
file.exists:
- name: {{ service.ssl.cert_file }}
mysql_certificate:
file.managed:
- name: {{ service.ssl.cert_file }}
- mode: 644
- create: False
- require:
- file: mysql_certificate_exists
- file: galera_ssl_dir
- require_in:
- service: galera_service
- file: galera_config
{%- endif %}

{%- if service.ssl.key is defined %}
mysql_server_key:
file.managed:
- name: {{ service.ssl.key_file }}
- contents_pillar: galera:{{ role }}:ssl:key
- user: root
- group: mysql
- mode: 0440
- makedirs: true
- require:
- pkg: galera_packages
- file: galera_ssl_dir
- require_in:
- service: galera_service
- file: galera_config
{%- else %}
mysql_server_key_exists:
file.exists:
- name: {{ service.ssl.key_file }}
mysql_server_key:
file.managed:
- name: {{ service.ssl.key_file }}
- user: root
- group: mysql
- mode: 0440
- create: False
- require:
- file: mysql_server_key_exists
- pkg: galera_packages
- file: galera_ssl_dir
- require_in:
- service: galera_service
- file: galera_config
{%- endif %}

{%- endif %}

+ 45
- 0
galera/clustercheck.sls View File

{%- from "galera/map.jinja" import clustercheck with context %}

{%- if clustercheck.get('enabled', False) %}
/usr/local/bin/mysql_clustercheck:
file.managed:
- source: salt://galera/files/clustercheck.sh
- user: root
- group: root
- mode: 755
- dir_mode: 755
- makedirs: True

/etc/xinetd.d/mysql_clustercheck:
file.managed:
- source: salt://galera/files/xinet.d.conf
- template: jinja
- makedirs: True
- defaults:
name: mysqlchk
user: nobody
server: '/usr/local/bin/mysql_clustercheck'
server_args: '{{ clustercheck.get('user', 'clustercheck') }} {{ clustercheck.get('password', 'clustercheck') }} available_when_donor={{ clustercheck.get('available_when_donor', 0) }} /dev/null available_when_readonly={{ clustercheck.get('available_when_readonly', 0) }} {{ clustercheck.config }}'
port: {{ clustercheck.get('port', 9200) }}
flags: REUSE
per_source: UNLIMITED
- require:
- file: /usr/local/bin/mysql_clustercheck
{%- if not grains.get('noservices', False) %}
- watch_in:
- galera_xinetd_service
{%- endif %}

galera_xinetd_package:
pkg.installed:
- name: xinetd

{%- if not grains.get('noservices', False) %}
galera_xinetd_service:
service.running:
- name: xinetd
- require:
- pkg: xinetd
{%- endif %}
{%- endif %}


+ 138
- 0
galera/files/clustercheck.sh View File

#!/bin/bash
#
# Script to make a proxy (ie HAProxy) capable of monitoring MySQL Cluster nodes properly
#
# Author: Olaf van Zandwijk <olaf.vanzandwijk@nedap.com>
# Author: Raghavendra Prabhu <raghavendra.prabhu@percona.com>
# Author: Petr Michalec <pmichalec@mirantis.com>
#
# Documentation and download: https://github.com/epcim/percona-clustercheck
#
# Based on the original script from Unai Rodriguez
#

function httpReply(){
HTTP_STATUS="${1}"
RESPONSE_CONTENT="${2}"

# https://serverfault.com/questions/504756/curl-failure-when-receiving-data-from-peer-using-percona-xtradb-cluster-check
sleep 0.1
if [[ "${HTTP_STATUS}" == "503" ]]
then
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
elif [[ "${HTTP_STATUS}" == "404" ]]
then
echo -en "HTTP/1.1 404 Not Found\r\n"
elif [[ "${HTTP_STATUS}" == "401" ]]
then
echo -en "HTTP/1.1 401 Unauthorized\r\n"
elif [[ "${HTTP_STATUS}" == "200" ]]
then
echo -en "HTTP/1.1 200 OK\r\n"
else
echo -en "HTTP/1.1 ${HTTP_STATUS}\r\n"
fi

echo -en "Content-Type: text/plain\r\n"
echo -en "Connection: close\r\n"
echo -en "Content-Length: ${#RESPONSE_CONTENT}\r\n"
echo -en "\r\n"
echo -en "${RESPONSE_CONTENT}"
echo -en "\r\n"
sleep 0.1
}

if [[ $1 == '-h' || $1 == '--help' ]];then
echo "Usage: $0 <user> <pass> <available_when_donor=0|1> <log_file> <available_when_readonly=0|1> <defaults_extra_file> <timeout>"
exit
fi

# if the disabled file is present, return 503. This allows
# admins to manually remove a node from a cluster easily.
if [ -e "/var/tmp/clustercheck.disabled" ]; then
# Shell return-code is 1
httpReply "503" "MySQL Cluster Node is manually disabled.\r\n"
exit 1
fi

MYSQL_USERNAME="${1-clustercheckuser}"
MYSQL_PASSWORD="${2-clustercheckpassword!}"
AVAILABLE_WHEN_DONOR=${3:-0}
ERR_FILE="${4:-/dev/null}"
AVAILABLE_WHEN_READONLY=${5:-1}
DEFAULTS_EXTRA_FILE=${6:-/etc/my.cnf}
# Timeout exists for instances where mysqld may be hung
# Default value considers the Galera timeouts
TIMEOUT=${7:-18}

EXTRA_ARGS=""
if [[ -n "$MYSQL_USERNAME" ]]; then
EXTRA_ARGS="$EXTRA_ARGS --user=${MYSQL_USERNAME}"
fi
if [[ -n "$MYSQL_PASSWORD" ]]; then
EXTRA_ARGS="$EXTRA_ARGS --password=${MYSQL_PASSWORD}"
fi
if [[ -r $DEFAULTS_EXTRA_FILE ]];then
MYSQL_CMDLINE="mysql --defaults-extra-file=$DEFAULTS_EXTRA_FILE -nNE --connect-timeout=$TIMEOUT \
${EXTRA_ARGS}"
else
MYSQL_CMDLINE="mysql -nNE --connect-timeout=$TIMEOUT ${EXTRA_ARGS}"
fi
#
# Perform the query to check the wsrep_local_state
#
WSREP_STATUS=$($MYSQL_CMDLINE -e "SHOW STATUS LIKE 'wsrep_local_state';" \
2>${ERR_FILE} | tail -1 2>>${ERR_FILE}; exit ${PIPESTATUS[0]})
mysql_ret=$?

if [[ $mysql_ret -eq 1 || $mysql_ret -eq 127 ]]; then
# hash or command can be used here, but command is POSIX
command -v "$MYSQL_CMD"; mysql_ret=$?
if [[ $mysql_ret -eq 1 ]]; then
# mysql program not found
# => return HTTP 404
# Shell return-code is 3
httpReply "404" "Mysql command not found or service is not running.\r\n"
exit 2
fi

# Failed mysql login
# => return HTTP 401
# Shell return-code is 2
httpReply "401" "Access denied to database.\r\n"
exit 2
fi



if [[ "${WSREP_STATUS}" == "4" ]] || [[ "${WSREP_STATUS}" == "2" && ${AVAILABLE_WHEN_DONOR} == 1 ]]
then
# Check only when set to 0 to avoid latency in response.
if [[ $AVAILABLE_WHEN_READONLY -eq 0 ]];then
READ_ONLY=$($MYSQL_CMDLINE -e "SHOW GLOBAL VARIABLES LIKE 'read_only';" \
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})

if [[ "${READ_ONLY}" == "ON" ]];then
# MySQL Cluster node local state is 'Synced', but it is in
# read-only mode. The variable AVAILABLE_WHEN_READONLY is set to 0.
# => return HTTP 503
# Shell return-code is 1
httpReply "503" "MySQL Cluster Node is read-only.\r\n"
exit 1
fi
fi
# MySQL Cluster node local state is 'Synced' => return HTTP 200
# Shell return-code is 0
httpReply "200" "MySQL Cluster Node is synced.\r\n"
exit 0
else
# MySQL Cluster node local state is not 'Synced' => return HTTP 503
# Shell return-code is 1
if [[ -z "${WSREP_STATUS}" ]]
then
httpReply "503" "Received empty reply from MySQL Cluster Node.\r\nMight be a permission issue, check the credentials used by ${0}\r\n"
else
httpReply "503" "MySQL Cluster Node is not synced.\r\n"
fi
exit 1
fi

+ 2
- 2
galera/files/debian.cnf View File

{%- if pillar.galera.master is defined %}
{%- if pillar.galera.get('master',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import master with context %} {%- from "galera/map.jinja" import master with context %}
{%- set service = master %} {%- set service = master %}
{%- endif %} {%- endif %}
{%- if pillar.galera.slave is defined %}
{%- if pillar.galera.get('slave',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import slave with context %} {%- from "galera/map.jinja" import slave with context %}
{%- set service = slave %} {%- set service = slave %}
{%- endif %} {%- endif %}

+ 930
- 0
galera/files/grafana_dashboards/mysql_prometheus.json View File

{
"annotations": {
"enable": false,
"list": []
},
"editable": true,
"gnetId": null,
"graphTooltip": 1,
"hideControls": false,
"id": null,
"links": [],
"refresh": "1m",
"rows": [
{
"collapse": false,
"height": 250,
"panels": [
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": null,
"description": "Displays the number of nodes in the cluster.",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"id": 32,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 2,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "min(mysql_wsrep_cluster_size)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "",
"metric": "mysql_wsrep_cluster_size",
"refId": "A",
"step": 60
}
],
"thresholds": "",
"title": "Cluster size",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "current"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "Displays the average sizes of receive and send queues.",
"fill": 0,
"id": 31,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 5,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "mysql_wsrep_local_recv_queue_avg{host=\"$host\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "receive",
"refId": "A",
"step": 10
},
{
"expr": "mysql_wsrep_local_send_queue_avg{host=\"$host\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "send",
"refId": "B",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Queues",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "Displays the rate of flow control events.",
"fill": 0,
"id": 33,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 5,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(mysql_wsrep_flow_control_recv{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "receive",
"metric": "",
"refId": "A",
"step": 10
},
{
"expr": "irate(mysql_wsrep_flow_control_sent{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "send",
"refId": "B",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Flow control",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true,
"title": "Replication",
"titleSize": "h6"
},
{
"collapse": false,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 0,
"id": 26,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(mysql_bytes_received{host=\"$host\"}[1m])",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"legendFormat": "rx",
"metric": "",
"refId": "A",
"step": 10
},
{
"expr": "irate(mysql_bytes_sent{host=\"$host\"}[1m])",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"legendFormat": "tx",
"metric": "",
"refId": "B",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Network I/O",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "Bps",
"label": "",
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 0,
"id": 27,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(mysql_table_locks_immediate{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "immediate",
"refId": "A",
"step": 10
},
{
"expr": "irate(mysql_table_locks_waited{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "waited",
"refId": "B",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Locks",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 0,
"id": 28,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "mysql_threads_cached{host=\"$host\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "cached",
"refId": "A",
"step": 10
},
{
"expr": "mysql_threads_connected{host=\"$host\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "connected",
"refId": "B",
"step": 10
},
{
"expr": "mysql_threads_running{host=\"$host\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "running",
"refId": "D",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Threads",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 1,
"id": 34,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(mysql_queries{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "queries",
"refId": "A",
"step": 10
},
{
"expr": "irate(mysql_questions{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "questions",
"refId": "B",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Queries",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 0,
"id": 29,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(mysql_commands_commit{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "commit",
"refId": "A",
"step": 10
},
{
"expr": "irate(mysql_commands_delete{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "delete",
"refId": "B",
"step": 10
},
{
"expr": "irate(mysql_commands_insert{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "insert",
"refId": "C",
"step": 10
},
{
"expr": "irate(mysql_commands_select{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "select",
"refId": "D",
"step": 10
},
{
"expr": "irate(mysql_commands_rollback{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "rollback",
"refId": "E",
"step": 10
},
{
"expr": "irate(mysql_commands_update{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "update",
"refId": "F",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Commands",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 0,
"id": 30,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(mysql_handler_commit{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "commit",
"refId": "A",
"step": 10
},
{
"expr": "irate(mysql_handler_delete{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "delete",
"refId": "B",
"step": 10
},
{
"expr": "irate(mysql_handler_write{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "write",
"refId": "C",
"step": 10
},
{
"expr": "irate(mysql_handler_rollback{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "rollback",
"refId": "E",
"step": 10
},
{
"expr": "irate(mysql_handler_update{host=\"$host\"}[1m])",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "update",
"refId": "F",
"step": 10
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Handlers",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true,
"title": "MySQL",
"titleSize": "h6"
}
],
"schemaVersion": 14,
"sharedCrosshair": true,
"style": "dark",
"tags": [],
"templating": {
"enable": true,
"list": [
{
"allFormat": "glob",
"allValue": null,
"current": {},
"datasource": "prometheus",
"hide": 0,
"includeAll": false,
"label": null,
"multi": false,
"name": "host",
"options": [],
"query": "label_values(mysql_connections,host)",
"refresh": 1,
"refresh_on_load": true,
"regex": "",
"sort": 1,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"collapse": false,
"enable": true,
"notice": false,
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"status": "Stable",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"type": "timepicker"
},
"timezone": "browser",
"title": "MySQL",
"version": 33
}

+ 1
- 1
galera/files/init_bootstrap.sh View File



while [ $counter -gt 0 ] while [ $counter -gt 0 ]
do do
if mysql -u root -e"quit"; then
if mysql -u root -e"quit" || mysql -u {{ service.admin.user }} -p{{ service.admin.password }} -e"quit"; then
echo "Sucessfully connected to the MySQL service ($retries retries)." echo "Sucessfully connected to the MySQL service ($retries retries)."
exit 0 exit 0
fi fi

+ 20
- 5
galera/files/my.cnf View File

# All files in this package is subject to the GPL v2 license # All files in this package is subject to the GPL v2 license
# More information is in the COPYING file in the top directory of this package. # More information is in the COPYING file in the top directory of this package.
# Copyright (C) 2011 severalnines.com # Copyright (C) 2011 severalnines.com
{%- if pillar.galera.master is defined %}
{%- if pillar.galera.get('master',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import master with context %} {%- from "galera/map.jinja" import master with context %}
{%- set service = master %} {%- set service = master %}
{%- endif %} {%- endif %}
{%- if pillar.galera.slave is defined %}
{%- if pillar.galera.get('slave',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import slave with context %} {%- from "galera/map.jinja" import slave with context %}
{%- set service = slave %} {%- set service = slave %}
{%- endif %} {%- endif %}

[mysql]
{% if service.get('ssl', {}).get('enabled', False) %}
ssl-ca={{ service.ssl.ca_file }}
ssl-cert={{ service.ssl.cert_file }}
ssl-key={{ service.ssl.key_file }}
{% endif %}

[mysqld_safe] [mysqld_safe]
syslog syslog


datadir=/var/lib/mysql datadir=/var/lib/mysql
bind-address={{ service.bind.address }} bind-address={{ service.bind.address }}
port=3306 port=3306
max_connections={{ service.get('max_connections', 20000) }}
max_connections={{ service.max_connections }}
default-storage-engine=innodb default-storage-engine=innodb
binlog_format=ROW binlog_format=ROW
collation-server=utf8_general_ci collation-server=utf8_general_ci
#log_error=/var/log/mysql/error.log #log_error=/var/log/mysql/error.log
skip-external-locking skip-external-locking
skip-name-resolve skip-name-resolve
socket = /var/run/mysqld/mysqld.sock


myisam_sort_buffer_size=64M myisam_sort_buffer_size=64M
wait_timeout=1800 wait_timeout=1800


innodb_file_format=Barracuda innodb_file_format=Barracuda
innodb_file_per_table=1 innodb_file_per_table=1
innodb_buffer_pool_size=3138M
innodb_buffer_pool_size={{ service.innodb_buffer_pool_size }}
innodb_log_file_size=627M innodb_log_file_size=627M
innodb_read_io_threads=8 innodb_read_io_threads=8
innodb_write_io_threads=8 innodb_write_io_threads=8
innodb_doublewrite=0 innodb_doublewrite=0
innodb_autoinc_lock_mode=2 innodb_autoinc_lock_mode=2
innodb_locks_unsafe_for_binlog=1 innodb_locks_unsafe_for_binlog=1

wsrep_cluster_address="gcomm://{% for member in service.members %}{{ member.host}}:4567{% if not loop.last %},{% endif %}{% endfor %}/?pc.wait_prim=no" wsrep_cluster_address="gcomm://{% for member in service.members %}{{ member.host}}:4567{% if not loop.last %},{% endif %}{% endfor %}/?pc.wait_prim=no"
wsrep_provider={{ service.wsrep_provider }} wsrep_provider={{ service.wsrep_provider }}
wsrep_cluster_name="openstack" wsrep_cluster_name="openstack"
wsrep_provider_options="gcache.size = 256M" wsrep_provider_options="gcache.size = 256M"
wsrep_provider_options="gmcast.listen_addr = tcp://{{ service.bind.address }}:4567" wsrep_provider_options="gmcast.listen_addr = tcp://{{ service.bind.address }}:4567"


{% if service.get('ssl', {}).get('enabled', False) %}
wsrep_provider_options="socket.ssl=yes;socket.ssl_key={{ service.ssl.key_file }};socket.ssl_cert={{ service.ssl.cert_file }};socket.ssl_ca={{ service.ssl.ca_file }}"
ssl-ca={{ service.ssl.ca_file }}
ssl-cert={{ service.ssl.cert_file }}
ssl-key={{ service.ssl.key_file }}
{% endif %}

[xtrabackup] [xtrabackup]
parallel=4 parallel=4



+ 4
- 4
galera/files/my.cnf.container View File

{%- if pillar.galera.master is defined %}
{%- if pillar.galera.get('master',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import master with context %} {%- from "galera/map.jinja" import master with context %}
{%- set service = master %} {%- set service = master %}
{%- endif %} {%- endif %}
pid_file=/var/lib/mysql/mysql.pid pid_file=/var/lib/mysql/mysql.pid
port=3306 port=3306
log_warnings=2 log_warnings=2
innodb_buffer_pool_size=3138M
innodb_buffer_pool_size={{ service.innodb_buffer_pool_size }}
innodb_flush_log_at_trx_commit=2 innodb_flush_log_at_trx_commit=2
innodb_file_per_table=1 innodb_file_per_table=1
innodb_data_file_path = ibdata1:100M:autoextend innodb_data_file_path = ibdata1:100M:autoextend
skip_name_resolve skip_name_resolve
memlock=0 memlock=0
sysdate_is_now=1 sysdate_is_now=1
max_connections={{ service.get('max_connections', 20000) }}
max_connections={{ service.max_connections }}
thread_cache_size=512 thread_cache_size=512
query_cache_type = 0 query_cache_type = 0
query_cache_size = 0 query_cache_size = 0
[xtrabackup] [xtrabackup]
parallel=4 parallel=4
user={{ service.admin.user }} user={{ service.admin.user }}
password={{ service.admin.password }}
password={{ service.admin.password }}

+ 11
- 4
galera/files/my.cnf.init View File

# All files in this package is subject to the GPL v2 license # All files in this package is subject to the GPL v2 license
# More information is in the COPYING file in the top directory of this package. # More information is in the COPYING file in the top directory of this package.
# Copyright (C) 2011 severalnines.com # Copyright (C) 2011 severalnines.com
{%- if pillar.galera.master is defined %}
{%- if pillar.galera.get('master',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import master with context %} {%- from "galera/map.jinja" import master with context %}
{%- set service = master %} {%- set service = master %}
{%- endif %} {%- endif %}
{%- if pillar.galera.slave is defined %}
{%- if pillar.galera.get('slave',{}).get('enabled', False) %}
{%- from "galera/map.jinja" import slave with context %} {%- from "galera/map.jinja" import slave with context %}
{%- set service = slave %} {%- set service = slave %}
{%- endif %} {%- endif %}
datadir=/var/lib/mysql datadir=/var/lib/mysql
bind-address={{ service.bind.address }} bind-address={{ service.bind.address }}
port=3306 port=3306
max_connections={{ service.get('max_connections', 20000) }}
max_connections={{ service.max_connections }}
default-storage-engine=innodb default-storage-engine=innodb
binlog_format=ROW binlog_format=ROW
collation-server=utf8_general_ci collation-server=utf8_general_ci


innodb_file_format=Barracuda innodb_file_format=Barracuda
innodb_file_per_table=1 innodb_file_per_table=1
innodb_buffer_pool_size=3138M
innodb_buffer_pool_size={{ service.innodb_buffer_pool_size }}
innodb_log_file_size=627M innodb_log_file_size=627M
innodb_read_io_threads=8 innodb_read_io_threads=8
innodb_write_io_threads=8 innodb_write_io_threads=8
wsrep_provider_options="gcache.size = 256M" wsrep_provider_options="gcache.size = 256M"
wsrep_provider_options="gmcast.listen_addr = tcp://{{ service.bind.address }}:4567" wsrep_provider_options="gmcast.listen_addr = tcp://{{ service.bind.address }}:4567"


{% if service.get('ssl', {}).get('enabled', False) %}
wsrep_provider_options="socket.ssl=yes;socket.ssl_key={{ service.ssl.key_file }};socket.ssl_cert={{ service.ssl.cert_file }};socket.ssl_ca={{ service.ssl.ca_file }}"
ssl-ca={{ service.ssl.ca_file }}
ssl-cert={{ service.ssl.cert_file }}
ssl-key={{ service.ssl.key_file }}
{% endif %}

[xtrabackup] [xtrabackup]
parallel=4 parallel=4



+ 24
- 0
galera/files/xinet.d.conf View File

# default: {{ default_state|default('on') }}
# description: {{ name }}

service {{ name }}:
{
disable = {{ disable|default('no') }}
{%- if flags is defined %}
flags = {{ flags }}
{%- endif %}
socket_type = {{ socket_type|default('stream') }}
port = {{ port }}
wait = {{ wait|default('no') }}
user = {{ user }}
server = {{ server }}
{%- if server_args is defined %}
server_args = {{ server_args }}
{%- endif %}
log_on_failure += {{ log_on_failure|default('USERID') }}
only_from = {{ only_from|default('0.0.0.0/0') }}
type = {{ type|default('UNLISTED') }}
{%- if per_source is defined %}
per_source = {{ per_source }}
{%- endif %}
}

+ 3
- 0
galera/init.sls View File

{%- if pillar.galera.slave is defined %} {%- if pillar.galera.slave is defined %}
- galera.slave - galera.slave
{%- endif %} {%- endif %}
{%- if pillar.galera.clustercheck is defined %}
- galera.clustercheck
{%- endif %}
{%- if pillar.galera.monitor is defined %} {%- if pillar.galera.monitor is defined %}
- galera.monitor - galera.monitor
{%- endif %} {%- endif %}

+ 133
- 50
galera/map.jinja View File

{% set mysql_version = pillar.galera.get('version', {}).get('mysql', '5.6') %}
{% set galera_version = pillar.galera.get('version', {}).get('galera', '3') %}


{%- set master = salt['grains.filter_by']({
'Debian': {
'pkgs': ['mysql-wsrep-5.6', 'galera-3', 'rsync', 'python-mysqldb', 'psmisc', 'netcat', 'percona-xtrabackup', 'socat', 'libdbd-mysql', 'python-pymysql'],
'service': 'mysql',
'wsrep_provider': '/usr/lib/galera/libgalera_smm.so',
'log_file': '/var/log/mysql.log',
'socket': '/var/run/mysqld/mysqld.sock',
'config': '/etc/mysql/my.cnf',
},
'RedHat': {
'pkgs': ['galera', 'mariadb-galera-server', 'mariadb', 'MySQL-python', 'rsync', 'percona-xtrabackup', 'psmisc', 'socat'],
'xtrabackup_repo': 'http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm',
'service': 'mariadb',
'wsrep_provider': '/usr/lib64/galera/libgalera_smm.so',
'log_file': '/var/log/mariadb/mariadb.log',
'socket': '/var/run/mariadb/mysqld.sock',
'config': '/etc/my.cnf',
},
}, merge=pillar.galera.get('master', {})) %}
{%- load_yaml as master %}
default:
max_connections: 20000
innodb_buffer_pool_size: '3138M'
Debian:
pkgs:
- mysql-wsrep-{{ mysql_version }}
- galera-{{ galera_version }}
- rsync
- python-mysqldb
- psmisc
- netcat
- percona-xtrabackup
- socat
- libdbd-mysql
- python-pymysql
service: mysql
wsrep_provider: /usr/lib/galera/libgalera_smm.so
log_file: /var/log/mysql.log
socket: /var/run/mysqld/mysqld.sock
config: /etc/mysql/my.cnf
RedHat:
pkgs:
- galera
- mariadb-galera-server
- mariadb
- MySQL-python
- rsync
- percona-xtrabackup
- psmisc
- socat
xtrabackup_repo: http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
service: mariadb
wsrep_provider: /usr/lib64/galera/libgalera_smm.so
log_file: /var/log/mariadb/mariadb.log
socket: /var/run/mariadb/mysqld.sock
config: /etc/my.cnf
{%- endload %}
{%- set _pillar = pillar.galera.get('master', {}) %}
{%- if _pillar|length > 1 %}
{%- set master = salt['grains.filter_by'](master, merge=_pillar, base='default') %}
{%- else %}
{%- set master = salt['grains.filter_by'](master, base='default') %}
{%- endif %}


{%- load_yaml as slave %}
default:
max_connections: 20000
innodb_buffer_pool_size: '3138M'
Debian:
pkgs:
- mysql-wsrep-{{ mysql_version }}
- galera-{{ galera_version }}
- rsync
- python-mysqldb
- libmysqlclient18
- psmisc
- netcat
- percona-xtrabackup
- socat
- libdbd-mysql
- python-pymysql
service: mysql
wsrep_provider: /usr/lib/galera/libgalera_smm.so
log_file: /var/log/mysql.log
socket: /var/run/mysqld/mysqld.sock
config: /etc/mysql/my.cnf
RedHat:
pkgs:
- galera
- mariadb-galera-server
- mariadb
- MySQL-python
- rsync
- percona-xtrabackup
- psmisc
- socat
xtrabackup_repo: http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
service: mariadb
wsrep_provider: /usr/lib64/galera/libgalera_smm.so
log_file: /var/log/mariadb/mariadb.log
socket: /var/run/mariadb/mysqld.sock
config: /etc/my.cnf
{%- endload %}
{%- load_yaml as slave_oscodename %}
trusty:
pkgs:
- mysql-wsrep-{{ mysql_version }}
- galera-{{ galera_version }}
- rsync
- python-mysqldb
- libmysqlclient18
- psmisc
- netcat
- percona-xtrabackup
- socat
- libdbd-mysql
- python-pymysql
xenial:
pkgs:
- mysql-wsrep-{{ mysql_version }}
- galera-{{ galera_version }}
- rsync
- python-mysqldb
- libmysqlclient-dev
- psmisc
- netcat
- percona-xtrabackup
- socat
- libdbd-mysql
- python-pymysql
{%- endload %}
{%- set _pillar = pillar.galera.get('slave', {}) %}
{%- if _pillar|length > 1 %}
{%- set _oscodename = salt['grains.filter_by'](slave_oscodename, grain='oscodename', merge=_pillar) %}
{%- else %}
{%- set _oscodename = salt['grains.filter_by'](slave_oscodename, grain='oscodename') %}
{%- endif %}
{%- set slave = salt['grains.filter_by'](slave, merge=_oscodename, base='default') %}


{%- set slave = salt['grains.filter_by']({
{% set clustercheck = salt['grains.filter_by']({
'Debian': { 'Debian': {
'pkgs': ['mysql-wsrep-5.6', 'galera-3', 'rsync', 'python-mysqldb', 'libmysqlclient18', 'psmisc', 'netcat', 'percona-xtrabackup', 'socat', 'libdbd-mysql', 'python-pymysql'],
'service': 'mysql',
'wsrep_provider': '/usr/lib/galera/libgalera_smm.so',
'log_file': '/var/log/mysql.log',
'socket': '/var/run/mysqld/mysqld.sock',
'config': '/etc/mysql/my.cnf', 'config': '/etc/mysql/my.cnf',
},
'enabled': False,
'user': clustercheck,
'password': clustercheck,
'port': '9200'
},
'RedHat': { 'RedHat': {
'pkgs': ['galera', 'mariadb-galera-server', 'mariadb', 'MySQL-python', 'rsync', 'percona-xtrabackup', 'psmisc', 'socat'],
'xtrabackup_repo': 'http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm',
'service': 'mariadb',
'wsrep_provider': '/usr/lib64/galera/libgalera_smm.so',
'log_file': '/var/log/mariadb/mariadb.log',
'socket': '/var/run/mariadb/mysqld.sock',
'config': '/etc/my.cnf', 'config': '/etc/my.cnf',
'enabled': False,
'user': clustercheck,
'password': clustercheck,
'port': '9200'
}, },
}, merge=salt['grains.filter_by']({
'trusty': {
'pkgs': ['mysql-wsrep-5.6', 'galera-3', 'rsync', 'python-mysqldb', 'libmysqlclient18', 'psmisc', 'netcat', 'percona-xtrabackup', 'socat', 'libdbd-mysql', 'python-pymysql'],
'service': 'mysql',
'wsrep_provider': '/usr/lib/galera/libgalera_smm.so',
'log_file': '/var/log/mysql.log',
'socket': '/var/run/mysqld/mysqld.sock',
'config': '/etc/mysql/my.cnf',
},
'xenial': {
'pkgs': ['mysql-wsrep-5.6', 'galera-3', 'rsync', 'python-mysqldb', 'libmysqlclient-dev', 'psmisc', 'netcat', 'percona-xtrabackup', 'socat', 'libdbd-mysql', 'python-pymysql'],
'service': 'mysql',
'wsrep_provider': '/usr/lib/galera/libgalera_smm.so',
'log_file': '/var/log/mysql.log',
'socket': '/var/run/mysqld/mysqld.sock',
'config': '/etc/mysql/my.cnf',
},
}, grain='oscodename', merge=pillar.galera.get('slave', {}))) %}
}, merge=pillar.galera.get('clustercheck', {})) %}

+ 33
- 25
galera/master.sls View File

{%- from "galera/map.jinja" import master with context %} {%- from "galera/map.jinja" import master with context %}
{%- if master.enabled %}
{%- if master.get('enabled', False) %}

{%- if master.get('ssl', {}).get('enabled', False) %}
include:
- galera._ssl
{%- endif %}


{%- if grains.os_family == 'RedHat' %} {%- if grains.os_family == 'RedHat' %}
xtrabackup_repo: xtrabackup_repo:
- refresh: true - refresh: true
- force_yes: True - force_yes: True


galera_log_dir:
galera_dirs:
file.directory: file.directory:
- name: /var/log/mysql
- names: ['/var/log/mysql', '/etc/mysql']
- makedirs: true - makedirs: true
- mode: 755 - mode: 755
- require: - require:
- pkg: galera_packages - pkg: galera_packages


{%- if grains.os_family == 'Debian' %} {%- if grains.os_family == 'Debian' %}

galera_run_dir: galera_run_dir:
file.directory: file.directory:
- name: /var/run/mysqld - name: /var/run/mysqld
file.managed: file.managed:
- name: /etc/systemd/system/mysql.service.d/override.conf - name: /etc/systemd/system/mysql.service.d/override.conf
- contents: | - contents: |
[service]
[Service]
LimitNOFILE=1024000 LimitNOFILE=1024000
- require: - require:
- pkg: galera_packages - pkg: galera_packages
- require: - require:
- pkg: galera_packages - pkg: galera_packages


{%- endif %}
{%- endif %}


galera_init_script: galera_init_script:
file.managed: file.managed:
- defaults: - defaults:
service: {{ master|yaml }} service: {{ master|yaml }}
- template: jinja - template: jinja
- timeout: 1800


galera_bootstrap_script: galera_bootstrap_script:
file.managed: file.managed:
service: {{ master|yaml }} service: {{ master|yaml }}
- template: jinja - template: jinja


{%- if salt['cmd.run']('test -e /var/lib/mysql/.galera_bootstrap; echo $?') != '0' %}
{%- if salt['cmd.shell']('test -e /var/lib/mysql/.galera_bootstrap; echo $?') != '0' %}


# Enforce config before package installation # Enforce config before package installation
galera_pre_config: galera_pre_config:
- require_in: - require_in:
- pkg: galera_packages - pkg: galera_packages


{%- if not grains.get('noservices', False) %}

galera_init_start_service: galera_init_start_service:
cmd.run: cmd.run:
- name: /usr/local/sbin/galera_init.sh - name: /usr/local/sbin/galera_init.sh
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require: - require:
- file: galera_run_dir - file: galera_run_dir
- file: galera_init_script - file: galera_init_script
- timeout: 1800


galera_bootstrap_set_root_password: galera_bootstrap_set_root_password:
cmd.run: cmd.run:
- name: mysqladmin password "{{ master.admin.password }}" - name: mysqladmin password "{{ master.admin.password }}"
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require: - require:
- cmd: galera_init_start_service - cmd: galera_init_start_service


mysql_bootstrap_update_maint_password: mysql_bootstrap_update_maint_password:
cmd.run: cmd.run:
- name: mysql -u root -p{{ master.admin.password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '{{ master.maintenance_password }}';" - name: mysql -u root -p{{ master.admin.password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '{{ master.maintenance_password }}';"
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require: - require:
- cmd: galera_bootstrap_set_root_password - cmd: galera_bootstrap_set_root_password


{%- if not grains.get('noservices', False) %} {%- if not grains.get('noservices', False) %}
- require: - require:
- cmd: mysql_bootstrap_update_maint_password - cmd: mysql_bootstrap_update_maint_password
{%- else %}
- onlyif: /bin/false
{%- endif %} {%- endif %}


{%- endif %}

galera_bootstrap_init_config: galera_bootstrap_init_config:
file.managed: file.managed:
- name: {{ master.config }} - name: {{ master.config }}
- source: salt://galera/files/my.cnf.init - source: salt://galera/files/my.cnf.init
- mode: 644 - mode: 644
- template: jinja - template: jinja
{%- if not grains.get('noservices', False) %}
- require:
- require:
- service: galera_bootstrap_stop_service - service: galera_bootstrap_stop_service
{%- endif %}

{%- if not grains.get('noservices', False) %}


galera_bootstrap_start_service_final: galera_bootstrap_start_service_final:
cmd.run: cmd.run:
- name: /usr/local/sbin/galera_bootstrap.sh - name: /usr/local/sbin/galera_bootstrap.sh
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require: - require:
- file: galera_bootstrap_init_config - file: galera_bootstrap_init_config
- file: galera_bootstrap_script - file: galera_bootstrap_script


{%- endif %}

galera_bootstrap_finish_flag: galera_bootstrap_finish_flag:
file.touch: file.touch:
- name: /var/lib/mysql/.galera_bootstrap - name: /var/lib/mysql/.galera_bootstrap
{%- if not grains.get('noservices', False) %}
- require: - require:
- cmd: galera_bootstrap_start_service_final - cmd: galera_bootstrap_start_service_final
{%- endif %}
- watch_in: - watch_in:
- file: galera_config - file: galera_config


- source: salt://galera/files/my.cnf - source: salt://galera/files/my.cnf
- mode: 644 - mode: 644
- template: jinja - template: jinja
{%- if not grains.get('noservices', False) %}
- require_in:
- require_in:
- service: galera_service - service: galera_service
{%- endif %}

{%- if not grains.get('noservices', False) %}


galera_service: galera_service:
service.running: service.running:
- name: {{ master.service }} - name: {{ master.service }}
- enable: true - enable: true
- reload: true - reload: true
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}


{%- endif %} {%- endif %}
{%- endif %}

+ 15
- 19
galera/meta/collectd.yml View File

{%- if pillar.galera is defined %}
{%- if pillar.galera.master is defined %}
{%- from "galera/map.jinja" import master with context %}
{%- set server = master %}
{%- elif pillar.galera.slave is defined %}
{%- from "galera/map.jinja" import slave with context %}
{%- set server = slave %}
{%- from "galera/map.jinja" import master, slave with context %}
{%- if master.get('enabled', False) %}
{%- set service = master %}
{%- elif slave.get('enabled', False) %}
{%- set service = slave %}
{%- endif %} {%- endif %}
{%- endif %}

{%- if server is defined %}
{%- if service is defined %}
local_plugin: local_plugin:
mysql: mysql:
template: galera/files/collectd_mysql.conf template: galera/files/collectd_mysql.conf
socket: {{ server.socket }}
password: {{ server.admin.password }}
username: {{ server.admin.user }}
socket: {{ service.socket }}
password: {{ service.admin.password }}
username: {{ service.admin.user }}
mysql_status: mysql_status:
template: galera/files/collectd_mysql_status.conf template: galera/files/collectd_mysql_status.conf
socket: {{ server.socket }}
password: {{ server.admin.password }}
username: {{ server.admin.user }}
socket: {{ service.socket }}
password: {{ service.admin.password }}
username: {{ service.admin.user }}
mysql_check: mysql_check:
plugin: python plugin: python
template: galera/files/collectd_mysql_check.conf template: galera/files/collectd_mysql_check.conf
socket: {{ server.socket }}
password: {{ server.admin.password }}
username: {{ server.admin.user }}
socket: {{ service.socket }}
password: {{ service.admin.password }}
username: {{ service.admin.user }}
{%- endif %} {%- endif %}

+ 22
- 1
galera/meta/grafana.yml View File

dashboard: dashboard:
galera:
galera_prometheus:
datasource: prometheus
format: json
template: galera/files/grafana_dashboards/mysql_prometheus.json
galera_influxdb:
datasource: influxdb
format: json format: json
template: galera/files/grafana_dashboards/mysql_influxdb.json template: galera/files/grafana_dashboards/mysql_influxdb.json
main: main:
datasource: influxdb
row: row:
ost-middleware: ost-middleware:
title: Middleware title: Middleware
cluster_status: cluster_status:
rawQuery: true rawQuery: true
query: SELECT last(value) FROM cluster_status WHERE cluster_name = 'mysql' AND environment_label = '$environment' AND $timeFilter GROUP BY time($interval) fill(null) query: SELECT last(value) FROM cluster_status WHERE cluster_name = 'mysql' AND environment_label = '$environment' AND $timeFilter GROUP BY time($interval) fill(null)
main_prometheus:
datasource: prometheus
row:
ost-middleware:
title: Middleware
panel:
nova:
title: MySQL
links:
- dashboard: MySQL
title: MySQL
type: dashboard
target:
cluster_status:
expr: avg(mysql_up) by (name)

+ 31
- 0
galera/meta/prometheus.yml View File

{% raw %}
server:
alert:
GaleraServiceDown:
if: >-
mysql_up != 1
labels:
severity: warning
service: mysql
annotations:
summary: 'Galera service down'
description: 'Galera service is down on node {{ $labels.host }}'
GaleraNodeNotReady:
if: 'mysql_wsrep_ready != 1'
for: 1m
labels:
severity: warning
service: mysql
annotations:
summary: 'Galera on {{ $labels.host }} not ready'
description: 'The Galera service on {{ $labels.host }} is not ready to serve queries.'
GaleraNodeNotConnected:
if: 'mysql_wsrep_connected != 1'
for: 1m
labels:
severity: warning
service: mysql
annotations:
summary: 'Galera on {{ $labels.host }} not connected'
description: 'The Galera service on {{ $labels.host }} is not connected to the cluster.'
{% endraw %}

+ 16
- 0
galera/meta/telegraf.yml View File

{%- from "galera/map.jinja" import master, slave with context %}
{%- if master.get('enabled', False) %}
{%- set service = master %}
{%- elif slave.get('enabled', False) %}
{%- set service = slave %}
{%- endif %}

{%- if service is defined %}
agent:
input:
mysql:
address: {{ service.socket }}
username: {{ service.admin.user }}
password: {{ service.admin.password }}
tagexclude: [service]
{%- endif %}

+ 86
- 14
galera/server.sls View File

{%- if pillar.get('mysql', {}).server is defined %} {%- if pillar.get('mysql', {}).server is defined %}
{%- from "mysql/map.jinja" import mysql_connection_args as connection with context %}
{%- set server = pillar.mysql.server %} {%- set server = pillar.mysql.server %}


{%- for database_name, database in server.get('database', {}).iteritems() %} {%- for database_name, database in server.get('database', {}).iteritems() %}
mysql_database_{{ database_name }}: mysql_database_{{ database_name }}:
mysql_database.present: mysql_database.present:
- name: {{ database_name }} - name: {{ database_name }}
- character_set: {{ database.get('encoding', 'utf8') }}
#- connection_user: {{ connection.user }}
#- connection_pass: {{ connection.password }}
#- connection_charset: {{ connection.charset }}
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}


{%- for user in database.users %}

{%- for user in database.get('users', {}) %}
mysql_user_{{ user.name }}_{{ database_name }}_{{ user.host }}: mysql_user_{{ user.name }}_{{ database_name }}_{{ user.host }}:
mysql_user.present: mysql_user.present:
- host: '{{ user.host }}' - host: '{{ user.host }}'
- name: '{{ user.name }}' - name: '{{ user.name }}'
{%- if user.password is defined %}
- password: {{ user.password }} - password: {{ user.password }}
{%- else %}
- allow_passwordless: true
{%- endif %}
#- connection_user: {{ connection.user }}
#- connection_pass: {{ connection.password }}
#- connection_charset: {{ connection.charset }}
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}


mysql_grants_{{ user.name }}_{{ database_name }}_{{ user.host }}: mysql_grants_{{ user.name }}_{{ database_name }}_{{ user.host }}:
mysql_grants.present: mysql_grants.present:
- database: '{{ database_name }}.*' - database: '{{ database_name }}.*'
- user: '{{ user.name }}' - user: '{{ user.name }}'
- host: '{{ user.host }}' - host: '{{ user.host }}'
- ssl_option: {{ user.get('ssl_option', False) }}
#- connection_user: {{ connection.user }}
#- connection_pass: {{ connection.password }}
#- connection_charset: {{ connection.charset }}
- require: - require:
- mysql_user: mysql_user_{{ user.name }}_{{ database_name }}_{{ user.host }} - mysql_user: mysql_user_{{ user.name }}_{{ database_name }}_{{ user.host }}
- mysql_database: mysql_database_{{ database_name }} - mysql_database: mysql_database_{{ database_name }}

{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
{%- endfor %} {%- endfor %}


{%- if database.initial_data is defined %} {%- if database.initial_data is defined %}

/root/mysql/scripts/restore_{{ database_name }}.sh: /root/mysql/scripts/restore_{{ database_name }}.sh:
file.managed: file.managed:
- source: salt://mysql/conf/restore.sh - source: salt://mysql/conf/restore.sh
- defaults: - defaults:
database_name: {{ database_name }} database_name: {{ database_name }}
database: {{ database }} database: {{ database }}
- require:
- require:
- file: mysql_dirs - file: mysql_dirs
- mysql_database: mysql_database_{{ database_name }} - mysql_database: mysql_database_{{ database_name }}


- cwd: /root - cwd: /root
- require: - require:
- file: /root/mysql/scripts/restore_{{ database_name }}.sh - file: /root/mysql/scripts/restore_{{ database_name }}.sh

{%- endif %} {%- endif %}


{%- endfor %} {%- endfor %}


{%- if not grains.get('noservices', False) %}
{%- for user in server.get('users', []) %} {%- for user in server.get('users', []) %}
mysql_user_{{ user.name }}_{{ user.host }}:
{%- for host in user.get('hosts', user.get('host', 'localhost'))|sequence %}
mysql_user_{{ user.name }}_{{ host }}:
mysql_user.present: mysql_user.present:
- host: '{{ user.host }}'
- host: '{{ host }}'
- name: '{{ user.name }}' - name: '{{ user.name }}'
{%- if user.password is defined %}
- password: {{ user.password }}
{%- if user['password_hash'] is defined %}
- password_hash: '{{ user.password_hash }}'
{%- elif user['password'] is defined and user['password'] != None %}
- password: '{{ user.password }}'
{%- else %} {%- else %}
- allow_passwordless: True - allow_passwordless: True
{%- endif %} {%- endif %}
#- connection_user: {{ connection.user }}
#- connection_pass: {{ connection.password }}
#- connection_charset: {{ connection.charset }}
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}

{%- if 'grants' in user %}
mysql_user_{{ user.name }}_{{ host }}_grants:
mysql_grants.present:
- name: {{ user.name }}
- grant: {{ user['grants']|sequence|join(",") }}
- database: '{{ user.get('database','*.*') }}'
- grant_option: {{ user['grant_option'] | default(False) }}
- user: {{ user.name }}
- host: '{{ host }}'
- ssl_option: {{ user.get('ssl_option', False) }}
#- connection_user: {{ connection.user }}
#- connection_pass: {{ connection.password }}
#- connection_charset: {{ connection.charset }}
- require:
- mysql_user_{{ user.name }}_{{ host }}
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
{%- endif %}


{%- if 'databases' in user %}
{%- for db in user['databases'] %}
mysql_user_{{ user.name }}_{{ host }}_grants_db_{{ db.database }}_{{ loop.index0 }}:
mysql_grants.present:
- name: {{ user.name ~ '_' ~ db['database'] ~ '_' ~ db['table'] | default('all') }}
- grant: {{ db['grants']|sequence|join(",") }}
- database: '{{ db['database'] }}.{{ db['table'] | default('*') }}'
- grant_option: {{ db['grant_option'] | default(False) }}
- user: {{ user.name }}
- host: '{{ host }}'
- ssl_option: {{ db.get('ssl_option', False) }}
#- connection_user: {{ connection.user }}
#- connection_pass: {{ connection.password }}
#- connection_charset: {{ connection.charset }}
- require:
- mysql_user_{{ user.name }}_{{ host }}
# the following line is not mandatory as database might not be managed by salt formula
#- mysql_database_{{ db.database }}
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
{%- endfor %}
{%- endif %}

{%- endfor %}
{%- endfor %} {%- endfor %}

{%- endif %} {%- endif %}
{%- endif %}

+ 36
- 23
galera/slave.sls View File

{%- from "galera/map.jinja" import slave with context %} {%- from "galera/map.jinja" import slave with context %}
{%- if slave.enabled %}
{%- if slave.get('enabled', False) %}

{%- if slave.get('ssl', {}).get('enabled', False) %}
include:
- galera._ssl
{%- endif %}


{%- if grains.os_family == 'RedHat' %} {%- if grains.os_family == 'RedHat' %}
xtrabackup_repo: xtrabackup_repo:
- refresh: true - refresh: true
- force_yes: True - force_yes: True


galera_log_dir:
galera_dirs:
file.directory: file.directory:
- name: /var/log/mysql
- names: ['/var/log/mysql', '/etc/mysql']
- makedirs: true - makedirs: true
- mode: 755 - mode: 755
- require: - require:
file.managed: file.managed:
- name: /etc/systemd/system/mysql.service.d/override.conf - name: /etc/systemd/system/mysql.service.d/override.conf
- contents: | - contents: |
[service]
[Service]
LimitNOFILE=1024000 LimitNOFILE=1024000
- require: - require:
- pkg: galera_packages - pkg: galera_packages
- source: salt://galera/files/bootstrap.sh - source: salt://galera/files/bootstrap.sh
- template: jinja - template: jinja


{%- if salt['cmd.run']('test -e /var/lib/mysql/.galera_bootstrap; echo $?') != '0' %}
{%- if salt['cmd.shell']('test -e /var/lib/mysql/.galera_bootstrap; echo $?') != '0' %}


# Enforce config before package installation # Enforce config before package installation
galera_pre_config: galera_pre_config:
- require_in: - require_in:
- pkg: galera_packages - pkg: galera_packages


{%- if not grains.get('noservices', False) %}

galera_init_start_service: galera_init_start_service:
cmd.run: cmd.run:
- name: /usr/local/sbin/galera_init.sh - name: /usr/local/sbin/galera_init.sh
- require:
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require:
- file: galera_run_dir - file: galera_run_dir
- file: galera_init_script - file: galera_init_script
- timeout: 1800


galera_bootstrap_set_root_password: galera_bootstrap_set_root_password:
cmd.run: cmd.run:
- name: mysqladmin password "{{ slave.admin.password }}" - name: mysqladmin password "{{ slave.admin.password }}"
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require: - require:
- cmd: galera_init_start_service - cmd: galera_init_start_service


mysql_bootstrap_update_maint_password: mysql_bootstrap_update_maint_password:
cmd.run: cmd.run:
- name: mysql -u root -p{{ slave.admin.password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '{{ slave.maintenance_password }}';" - name: mysql -u root -p{{ slave.admin.password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '{{ slave.maintenance_password }}';"
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require: - require:
- cmd: galera_bootstrap_set_root_password - cmd: galera_bootstrap_set_root_password


galera_bootstrap_stop_service: galera_bootstrap_stop_service:
service.dead: service.dead:
- name: {{ slave.service }} - name: {{ slave.service }}
{%- if not grains.get('noservices', False) %}
- require: - require:
- cmd: mysql_bootstrap_update_maint_password - cmd: mysql_bootstrap_update_maint_password

{%- endif %}
{%- else %}
- onlyif: /bin/false
{%- endif %}


galera_bootstrap_init_config: galera_bootstrap_init_config:
file.managed: file.managed:
- source: salt://galera/files/my.cnf - source: salt://galera/files/my.cnf
- mode: 644 - mode: 644
- template: jinja - template: jinja
{%- if not grains.get('noservices', False) %}
- require:
- require:
- service: galera_bootstrap_stop_service - service: galera_bootstrap_stop_service
{%- endif %}

{%- if not grains.get('noservices', False) %}


galera_bootstrap_start_service_final: galera_bootstrap_start_service_final:
cmd.run: cmd.run:
- name: /usr/local/sbin/galera_bootstrap.sh - name: /usr/local/sbin/galera_bootstrap.sh
- require:
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}
- require:
- file: galera_bootstrap_init_config - file: galera_bootstrap_init_config
- file: galera_bootstrap_script - file: galera_bootstrap_script
- timeout: 1800


galera_bootstrap_finish_flag: galera_bootstrap_finish_flag:
file.touch: file.touch:
- file: galera_config - file: galera_config


{%- endif %} {%- endif %}
{%- endif %}


galera_config: galera_config:
file.managed: file.managed:
- source: salt://galera/files/my.cnf - source: salt://galera/files/my.cnf
- mode: 644 - mode: 644
- template: jinja - template: jinja
{%- if not grains.get('noservices', False) %}
- require_in:
- require_in:
- service: galera_service - service: galera_service
{%- endif %}

{%- if not grains.get('noservices', False) %}


galera_service: galera_service:
service.running: service.running:
- name: {{ slave.service }} - name: {{ slave.service }}
- enable: true - enable: true
- reload: true - reload: true
{%- if grains.get('noservices') %}
- onlyif: /bin/false
{%- endif %}


{%- endif %} {%- endif %}
{%- endif %}

+ 4
- 0
metadata/service/master/cluster.yml View File

galera_server_bind_address: ${_param:cluster_local_address} galera_server_bind_address: ${_param:cluster_local_address}
galera_server_bind_port: 3306 galera_server_bind_port: 3306
galera_server_admin_user: root galera_server_admin_user: root
galera_max_connections: 20000
galera_innodb_buffer_pool_size: 3138M
galera: galera:
master: master:
enabled: true enabled: true
port: 4567 port: 4567
- host: ${_param:cluster_node03_address} - host: ${_param:cluster_node03_address}
port: 4567 port: 4567
max_connections: ${_param:galera_max_connections}
innodb_buffer_pool_size: ${_param:galera_innodb_buffer_pool_size}
mysql: mysql:
server: server:
users: users:

+ 4
- 0
metadata/service/master/container.yml View File

galera_server_cluster_name: galeracluster galera_server_cluster_name: galeracluster
galera_server_bind_port: 3306 galera_server_bind_port: 3306
galera_server_admin_user: root galera_server_admin_user: root
galera_max_connections: 20000
galera_innodb_buffer_pool_size: 3138M
kubernetes: kubernetes:
control: control:
configmap: configmap:
port: 4567 port: 4567
- host: ${_param:mysql_service_host03} - host: ${_param:mysql_service_host03}
port: 4567 port: 4567
max_connections: ${_param:galera_max_connections}
innodb_buffer_pool_size: ${_param:galera_innodb_buffer_pool_size}
mysql: mysql:
server: server:
users: users:

+ 4
- 0
metadata/service/slave/cluster.yml View File

galera_server_bind_address: ${_param:cluster_local_address} galera_server_bind_address: ${_param:cluster_local_address}
galera_server_bind_port: 3306 galera_server_bind_port: 3306
galera_server_admin_user: root galera_server_admin_user: root
galera_max_connections: 20000
galera_innodb_buffer_pool_size: 3138M
galera: galera:
slave: slave:
enabled: true enabled: true
port: 4567 port: 4567
- host: ${_param:cluster_node03_address} - host: ${_param:cluster_node03_address}
port: 4567 port: 4567
max_connections: ${_param:galera_max_connections}
innodb_buffer_pool_size: ${_param:galera_innodb_buffer_pool_size}
mysql: mysql:
server: server:
users: users:

+ 21
- 0
metadata/service/ssl.yml View File

# class to enable tls for galera.master and galera.slave

parameters:
_param:
mysql_ssl_key_file: /etc/mysql/ssl/key.pem
mysql_ssl_cert_file: /etc/mysql/ssl/cert.pem
mysql_ssl_ca_file: /etc/mysql/ssl/ca.pem

galera:
master:
ssl:
enabled: True
key_file: ${_param:mysql_ssl_key_file}
cert_file: ${_param:mysql_ssl_cert_file}
ca_file: ${_param:mysql_ssl_ca_file}
slave:
ssl:
enabled: True
key_file: ${_param:mysql_ssl_key_file}
cert_file: ${_param:mysql_ssl_cert_file}
ca_file: ${_param:mysql_ssl_ca_file}

+ 4
- 0
metadata/service/support.yml View File

enabled: true enabled: true
grafana: grafana:
enabled: true enabled: true
prometheus:
enabled: true
telegraf:
enabled: true

+ 10
- 0
tests/integration/master_cluster/checks_clustercheck_spec.rb View File

describe file('/etc/xinetd.d/mysql_clustercheck') do
it('should exist')
its('content') { should match /server.*\/usr\/local\/bin\/mysql_clustercheck/ }
its('content') { should match /server_args.*clustercheck password available_when_donor=1 \/dev\/null available_when_readonly=1/ }
end

describe file('/usr/local/bin/mysql_clustercheck') do
it('should exist')
it('should be_executable')
end

+ 10
- 0
tests/integration/slave_cluster/checks_clustercheck_spec.rb View File

describe file('/etc/xinetd.d/mysql_clustercheck') do
it('should exist')
its('content') { should match /server.*\/usr\/local\/bin\/mysql_clustercheck/ }
its('content') { should match /server_args.*clustercheck password available_when_donor=1 \/dev\/null available_when_readonly=1/ }
end

describe file('/usr/local/bin/mysql_clustercheck') do
it('should exist')
it('should be_executable')
end

+ 58
- 27
tests/pillar/master_cluster.sls View File

galera:
master:
enabled: true
name: galeracluster
bind:
address: 127.0.0.1
port: 3306
maintenance_password: password
admin:
user: user
password: password
members:
- host: 127.0.0.1
port: 4567
- host: 127.0.0.1
port: 4567
- host: 127.0.0.1
port: 4567
mysql:
server:
users:
- name: haproxy
host: localhost
- name: haproxy
host: '%'
- name: haproxy
host: 127.0.0.1
galera:
master:
enabled: true
name: galeracluster
bind:
address: 127.0.0.1
port: 3306
maintenance_password: password
admin:
user: root
password: password
members:
- host: 127.0.0.1
port: 4567
- host: 127.0.0.1
port: 4567
- host: 127.0.0.1
port: 4567
clustercheck:
enabled: True
user: clustercheck
password: password
available_when_donor: 1
available_when_readonly: 1
port: 9200
max_connections: 20000
innodb_buffer_pool_size: 3138M
mysql:
server:
enabled: true
bind:
address: 0.0.0.0
port: 3306
protocol: tcp
database:
mydb:
encoding: 'utf8'
users:
- name: haproxy
host: localhost
- name: haproxy
host: '%'
- name: haproxy
host: 127.0.0.1
- name: clustercheck
#host: localhost
password: password
database: '*.*'
grants: PROCESS
- name: inspector
host: 127.0.0.1
password: password
databases:
- database: mydb
table: mytable
grant_option: True
grants:
- all privileges

+ 13
- 1
tests/pillar/repo_galeracluster.sls View File

enabled: true enabled: true
repo: repo:
galeracluster: galeracluster:
source: 'deb http://releases.galeracluster.com/ubuntu {{ grains.get('oscodename') }} main'
key_id: BC19DDBA key_id: BC19DDBA
key_server: hkp://p80.pool.sks-keyservers.net:80 key_server: hkp://p80.pool.sks-keyservers.net:80
pin:
- pin: 'release o=Galera Cluster'
priority: 1001
package: '*'
mysql-wsrep:
key_id: BC19DDBA
key_server: hkp://p80.pool.sks-keyservers.net:80
pin:
- pin: 'release o=Galera Cluster'
priority: 1001
package: '*'
mitaka-staging_PPA: mitaka-staging_PPA:
source: "deb http://ppa.launchpad.net/ubuntu-cloud-archive/mitaka-staging/ubuntu trusty main" source: "deb http://ppa.launchpad.net/ubuntu-cloud-archive/mitaka-staging/ubuntu trusty main"
key_id: 8A6844A29F68104E
key_server: hkp://p80.pool.sks-keyservers.net:80

+ 16
- 2
tests/pillar/slave_cluster.sls View File

port: 3306 port: 3306
maintenance_password: password maintenance_password: password
admin: admin:
user: user
user: root
password: password password: password
members: members:
- host: 127.0.0.1 - host: 127.0.0.1
port: 4567 port: 4567
- host: 127.0.0.1 - host: 127.0.0.1
port: 4567 port: 4567
clustercheck:
enabled: True
user: clustercheck
password: password
available_when_donor: 1
available_when_readonly: 1
port: 9200
max_connections: 20000
innodb_buffer_pool_size: 3138M
mysql: mysql:
server: server:
users: users:
- name: haproxy - name: haproxy
host: '%' host: '%'
- name: haproxy - name: haproxy
host: 127.0.0.1
host: 127.0.0.1
- name: clustercheck
#host: localhost
password: password
database: '*.*'
grants: PROCESS

+ 42
- 4
tests/run_tests.sh View File

CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
METADATA=${CURDIR}/../metadata.yml METADATA=${CURDIR}/../metadata.yml
FORMULA_NAME=$(cat $METADATA | python -c "import sys,yaml; print yaml.load(sys.stdin)['name']") FORMULA_NAME=$(cat $METADATA | python -c "import sys,yaml; print yaml.load(sys.stdin)['name']")
FORMULA_META_DIR=${CURDIR}/../${FORMULA_NAME}/meta


## Overrideable parameters ## Overrideable parameters
PILLARDIR=${PILLARDIR:-${CURDIR}/pillar} PILLARDIR=${PILLARDIR:-${CURDIR}/pillar}
BUILDDIR=${BUILDDIR:-${CURDIR}/build} BUILDDIR=${BUILDDIR:-${CURDIR}/build}
VENV_DIR=${VENV_DIR:-${BUILDDIR}/virtualenv} VENV_DIR=${VENV_DIR:-${BUILDDIR}/virtualenv}
MOCK_BIN_DIR=${MOCK_BIN_DIR:-${CURDIR}/mock_bin}
DEPSDIR=${BUILDDIR}/deps DEPSDIR=${BUILDDIR}/deps


SALT_FILE_DIR=${SALT_FILE_DIR:-${BUILDDIR}/file_root} SALT_FILE_DIR=${SALT_FILE_DIR:-${BUILDDIR}/file_root}
SALT_CONFIG_DIR=${SALT_CONFIG_DIR:-${BUILDDIR}/salt} SALT_CONFIG_DIR=${SALT_CONFIG_DIR:-${BUILDDIR}/salt}
SALT_CACHE_DIR=${SALT_CACHE_DIR:-${SALT_CONFIG_DIR}/cache} SALT_CACHE_DIR=${SALT_CACHE_DIR:-${SALT_CONFIG_DIR}/cache}


SALT_OPTS="${SALT_OPTS} --retcode-passthrough --local -c ${SALT_CONFIG_DIR}"
SALT_OPTS="${SALT_OPTS} --retcode-passthrough --local -c ${SALT_CONFIG_DIR} --log-file=/dev/null"


if [ "x${SALT_VERSION}" != "x" ]; then if [ "x${SALT_VERSION}" != "x" ]; then
PIP_SALT_VERSION="==${SALT_VERSION}" PIP_SALT_VERSION="==${SALT_VERSION}"
log_info "Setting up Python virtualenv" log_info "Setting up Python virtualenv"
virtualenv $VENV_DIR virtualenv $VENV_DIR
source ${VENV_DIR}/bin/activate source ${VENV_DIR}/bin/activate
pip install salt${PIP_SALT_VERSION}
python -m pip install salt${PIP_SALT_VERSION}
}

setup_mock_bin() {
# If some state requires a binary, a lightweight replacement for
# such binary can be put into MOCK_BIN_DIR for test purposes
if [ -d "${MOCK_BIN_DIR}" ]; then
PATH="${MOCK_BIN_DIR}:$PATH"
export PATH
fi
} }


setup_pillar() { setup_pillar() {
[ ! -d ${SALT_PILLAR_DIR} ] && mkdir -p ${SALT_PILLAR_DIR} [ ! -d ${SALT_PILLAR_DIR} ] && mkdir -p ${SALT_PILLAR_DIR}
echo "base:" > ${SALT_PILLAR_DIR}/top.sls echo "base:" > ${SALT_PILLAR_DIR}/top.sls
for pillar in ${PILLARDIR}/*; do for pillar in ${PILLARDIR}/*; do
grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue
state_name=$(basename ${pillar%.sls}) state_name=$(basename ${pillar%.sls})
echo -e " ${state_name}:\n - ${state_name}" >> ${SALT_PILLAR_DIR}/top.sls echo -e " ${state_name}:\n - ${state_name}" >> ${SALT_PILLAR_DIR}/top.sls
done done


echo "base:" > ${SALT_FILE_DIR}/top.sls echo "base:" > ${SALT_FILE_DIR}/top.sls
for pillar in ${PILLARDIR}/*.sls; do for pillar in ${PILLARDIR}/*.sls; do
grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue
state_name=$(basename ${pillar%.sls}) state_name=$(basename ${pillar%.sls})
echo -e " ${state_name}:\n - ${FORMULA_NAME}" >> ${SALT_FILE_DIR}/top.sls echo -e " ${state_name}:\n - ${FORMULA_NAME}" >> ${SALT_FILE_DIR}/top.sls
done done
file_client: local file_client: local
cachedir: ${SALT_CACHE_DIR} cachedir: ${SALT_CACHE_DIR}
verify_env: False verify_env: False
minion_id_caching: False


file_roots: file_roots:
base: base:
} }


salt_run() { salt_run() {
[ -e ${VEN_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate
salt-call ${SALT_OPTS} $*
[ -e ${VENV_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate
python $(which salt-call) ${SALT_OPTS} $*
} }


prepare() { prepare() {
[ -d ${BUILDDIR} ] && mkdir -p ${BUILDDIR} [ -d ${BUILDDIR} ] && mkdir -p ${BUILDDIR}


which salt-call || setup_virtualenv which salt-call || setup_virtualenv
setup_mock_bin
setup_pillar setup_pillar
setup_salt setup_salt
install_dependencies install_dependencies


run() { run() {
for pillar in ${PILLARDIR}/*.sls; do for pillar in ${PILLARDIR}/*.sls; do
grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue
state_name=$(basename ${pillar%.sls}) state_name=$(basename ${pillar%.sls})
salt_run grains.set 'noservices' False force=True

echo "Checking state ${FORMULA_NAME}.${state_name} ..."
salt_run --id=${state_name} state.show_sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1) salt_run --id=${state_name} state.show_sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1)

# Check that all files in 'meta' folder can be rendered using any valid pillar
for meta in `find ${FORMULA_META_DIR} -type f`; do
meta_name=$(basename ${meta})
echo "Checking meta ${meta_name} ..."
salt_run --out=quiet --id=${state_name} cp.get_template ${meta} ${SALT_CACHE_DIR}/${meta_name} \
|| (log_err "Failed to render meta ${meta} using pillar ${FORMULA_NAME}.${state_name}"; exit 1)
cat ${SALT_CACHE_DIR}/${meta_name}
done
done
}

real_run() {
for pillar in ${PILLARDIR}/*.sls; do
state_name=$(basename ${pillar%.sls})
salt_run --id=${state_name} state.sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1)
done done
} }


run) run)
run run
;; ;;
real-run)
real_run
;;
*) *)
prepare prepare
run run

Loading…
Cancel
Save