From ca054bd8f74ac9f7e4d2a41589faf12806863553 Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Thu, 16 Nov 2017 16:35:54 -0600 Subject: [PATCH] Tune-up the galera role for efficiency The galera server role has quite a bit going on within it and because of recent improvements in Ansible we can make better use of tasks, blocks, facts, local facts, and organization. This change tunes the role up following some of our better/more modern patterns allowing the role to not only be more efficient but also easier to understand and improves the roles idempotency. Change-Id: If189a8192f22aafb168587361ca8e6903c918697 Signed-off-by: Kevin Carter --- defaults/main.yml | 32 +++--- files/galera_new_cluster | 72 ++++++++++++++ handlers/main.yml | 137 ++++++++++++-------------- library/mysql_status_facts | 74 -------------- tasks/galera_bootstrap.yml | 100 ------------------- tasks/galera_cluster_state.yml | 97 ++++++------------ tasks/galera_install.yml | 67 +++++++++++-- tasks/galera_install_apt.yml | 22 +---- tasks/galera_install_yum.yml | 52 ---------- tasks/galera_install_zypper.yml | 12 --- tasks/galera_post_install.yml | 87 ++++++++-------- tasks/galera_pre_install.yml | 74 -------------- tasks/galera_running_check.yml | 55 ----------- tasks/galera_secure_mysql.yml | 44 --------- tasks/galera_setup.yml | 31 +++++- tasks/galera_ssl.yml | 53 ++++++---- tasks/galera_ssl_key_create.yml | 73 +++++++++----- tasks/galera_upgrade.yml | 51 ++++++++++ tasks/galera_upgrade_check.yml | 25 ----- tasks/galera_upgrade_check_apt.yml | 51 ---------- tasks/galera_upgrade_check_dnf.yml | 1 - tasks/galera_upgrade_check_yum.yml | 59 ----------- tasks/galera_upgrade_check_zypper.yml | 1 - tasks/galera_upgrade_post.yml | 43 -------- tasks/galera_upgrade_pre.yml | 86 ++++++---------- tasks/main.yml | 82 +++++++++------ templates/galera_secure_node.j2 | 44 +++++++++ tox.ini | 3 +- vars/redhat-7.yml | 6 ++ vars/suse-42.yml | 3 + vars/ubuntu-16.04.yml | 3 + 31 files changed, 580 insertions(+), 960 deletions(-) create mode 100644 files/galera_new_cluster delete mode 100644 library/mysql_status_facts delete mode 100644 tasks/galera_bootstrap.yml delete mode 100644 tasks/galera_pre_install.yml delete mode 100644 tasks/galera_running_check.yml delete mode 100644 tasks/galera_secure_mysql.yml create mode 100644 tasks/galera_upgrade.yml delete mode 100644 tasks/galera_upgrade_check.yml delete mode 100644 tasks/galera_upgrade_check_apt.yml delete mode 120000 tasks/galera_upgrade_check_dnf.yml delete mode 100644 tasks/galera_upgrade_check_yum.yml delete mode 120000 tasks/galera_upgrade_check_zypper.yml delete mode 100644 tasks/galera_upgrade_post.yml create mode 100644 templates/galera_secure_node.j2 diff --git a/defaults/main.yml b/defaults/main.yml index cbfded02..c5d1bb8c 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -21,14 +21,11 @@ galera_cluster_members: "{{ groups['galera_all'] }}" galera_server_bootstrap_node: "{{ galera_cluster_members[0] }}" galera_ignore_cluster_state: false galera_upgrade: false +galera_force_bootstrap: false galera_wsrep_node_name: "{{ inventory_hostname }}" galera_cluster_name: openstack_galera_cluster -# This variable will prevent the galera_cluster_name from changing unintentionally on a running cluster. -# To intentionally change the galera_cluster_name set this variable to True -galera_force_change_cluster_name: False - # The galera server-id should be set on all cluster nodes to ensure # that replication is handled correctly and the error # "Warning: You should set server-id to a non-0 value if master_host is @@ -64,9 +61,6 @@ galera_percona_xtrabackup_repo: "{{ _galera_percona_xtrabackup_repo | default({} # Enable the use of the upstream percona repo use_percona_upstream: "{{ _use_percona_upstream }}" -galera_existing_cluster: true -galera_running_and_bootstrapped: false - galera_monitoring_user: monitoring galera_monitoring_user_password: "" # NOTE(cloudnull): Set an interface or CIDR to limit the traffic source when @@ -98,6 +92,7 @@ galera_innodb_log_buffer_size: 128M ## wsrep configuration galera_wsrep_address: "{{ ansible_host }}" +galera_wsrep_address_port: "{{ galera_wsrep_address }}:3306" galera_wsrep_cluster_address: >- {% set _var = [] -%} {% for cluster_host in galera_cluster_members -%} @@ -181,11 +176,12 @@ galera_use_ssl: false galera_ssl_cert: /etc/mysql/ssl/galera.pem galera_ssl_key: /etc/mysql/ssl/galera.key galera_ssl_ca_cert: /etc/mysql/ssl/galera-ca.pem -# These options should be specified in user_variables if necessary, otherwise self-signed certs are used. -galera_user_ssl_cert: /etc/openstack_deploy/self_signed_certs/galera.pem -galera_user_ssl_key: /etc/openstack_deploy/self_signed_certs/galera.key -galera_user_ssl_ca_cert: /etc/openstack_deploy/self_signed_certs/galera-ca.pem -# Set galera_ssl_self_signed_regen to true if you want to generate a new +## These options should be specified in user_variables if necessary, otherwise self-signed certs are used. +# galera_user_ssl_cert: /etc/openstack_deploy/self_signed_certs/galera.pem +# galera_user_ssl_key: /etc/openstack_deploy/self_signed_certs/galera.key +# galera_user_ssl_ca_cert: /etc/openstack_deploy/self_signed_certs/galera-ca.pem + +## Set galera_ssl_self_signed_regen to true if you want to generate a new # SSL certificate for Galera when this playbook runs. You can also change # the subject of the self-signed certificate here if you prefer. galera_ssl_self_signed_regen: false @@ -196,11 +192,10 @@ galera_ssl_ca_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT" galera_ssl_address: "{{ ansible_host }}" # MariaDB 10.1+ ships with 'PrivateDevices=True' in the systemd unit file. This -# provides some additional security, but it causes problems with creating -# mount namespaces on CentOS 7 with systemd 219. While the security -# enhancements are helpful on bare metal hosts with multiple services running, -# they are not as helpful when MariaDB is running in a container with its own -# isolated namespaces. +# provides some additional security, but it causes problems with systemd 219. +# While the security enhancements are helpful on bare metal hosts with multiple +# services running, they are not as helpful when MariaDB is running in a +# container with its own isolated namespaces. # # Related bugs: # https://bugs.launchpad.net/openstack-ansible/+bug/1697531 @@ -208,8 +203,7 @@ galera_ssl_address: "{{ ansible_host }}" # https://github.com/systemd/systemd/issues/6121 # # Setting the following variable to 'yes' will disable the PrivateDevices -# setting in the systemd unit file for MariaDB on CentOS 7 hosts. -galera_disable_privatedevices: no +galera_disable_privatedevices: "{{ _galera_disable_privatedevices }}" ## Set default mirror for openSUSE repositories # NOTE(hwoarang): Ensure that the full path to the 'opensuse' directory is used. diff --git a/files/galera_new_cluster b/files/galera_new_cluster new file mode 100644 index 00000000..1e2ea7fe --- /dev/null +++ b/files/galera_new_cluster @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Copyright 2017, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +## Shell Opts ---------------------------------------------------------------- +set -e + +## Functions ----------------------------------------------------------------- +function cleanup { + echo "Running Cleanup." + systemctl unset-environment _WSREP_NEW_CLUSTER || systemctl set-environment _WSREP_NEW_CLUSTER='' + if [[ -f "/etc/my.cnf.d/99_bootstrap.cnf" ]]; then + rm /etc/my.cnf.d/99_bootstrap.cnf + fi +} + +function wait_operational { + WAITCMD="while ! mysql --silent --skip-column-names -e 'SHOW STATUS LIKE \"wsrep_evs_state\"' | grep -wq \"OPERATIONAL\"; do sleep 5; done" + if ! timeout 180 sh -c "${WAITCMD}"; then + echo "Cluster failed to return an \"OPERATIONAL\" state" + return 1 + else + echo "Cluster is now OPERATIONAL" + return 0 + fi +} + +function bootstrap_opts { + cat > /etc/my.cnf.d/99_bootstrap.cnf < /dev/null; then + systemctl set-environment _WSREP_NEW_CLUSTER='--wsrep-new-cluster' + if grep -rniq -e suse -e opensuse /etc/os-release; then + bootstrap_opts + fi + if systemctl start mysql; then + EXIT_CODE=3 + else + echo "Cluster bootstrap failed." + systemctl status mysql + exit 99 + fi +fi + +wait_operational + +cat < + mysql --silent --skip-column-names --connect-timeout=10 -e 'SHOW STATUS LIKE "wsrep_local_state";' + failed_when: false + changed_when: true + register: node_status + listen: Restart all mysql + notify: + - Bootstrap cluster + - Restart mysql (All) + +- name: Check if node is in the cluster + command: > + mysql --silent --skip-column-names --connect-timeout=10 -e 'SHOW STATUS LIKE "wsrep_incoming_addresses";' + failed_when: false + changed_when: false + register: incoming_addresses + listen: Bootstrap cluster + +- name: Set incoming addresses fact (primary) + set_fact: + galera_incoming_addresses: "{{ (incoming_addresses.stdout.split()[-1] | default('')).split(',') }}" + listen: Bootstrap cluster + +- name: Set node status fact + set_fact: + galera_cluster_ready: "{{ (galera_wsrep_address_port in galera_incoming_addresses) or ((node_status.stdout.split()[-1] | default(false)) in ['2', '4']) }}" + listen: Bootstrap cluster + +- name: Stop mysql service: name: mysql - state: restarted - sleep: 2 - arguments: "{{ (not galera_existing_cluster | bool and inventory_hostname == galera_server_bootstrap_node) | ternary('--wsrep-new-cluster', '') }}" + state: stopped + changed_when: true + listen: Bootstrap cluster + when: + - not galera_cluster_ready | bool + +- name: Start new cluster + command: /usr/local/bin/galera_new_cluster + failed_when: not start_new_cluster.rc in [0, 3] + changed_when: start_new_cluster.rc == 3 + register: start_new_cluster + delegate_to: "{{ galera_server_bootstrap_node }}" + run_once: true + when: + - not galera_cluster_ready | bool + listen: Bootstrap cluster + +- name: Restart mysql (All) + service: + name: mysql + state: "{{ (not hostvars[item]['galera_cluster_ready'] | bool) | ternary('started', 'restarted') }}" environment: MYSQLD_STARTUP_TIMEOUT: 180 - when: - - not galera_running_and_bootstrapped | bool - - ansible_pkg_mgr != "zypper" register: galera_restart until: galera_restart | success - retries: 3 + retries: 6 delay: 5 - # notifies are only fired when status is "changed" - changed_when: galera_restart | failed - failed_when: false - notify: - - "Remove stale .sst" - - "Restart mysql fall back" - listen: "Restart all mysql" - -- name: Remove stale .sst - file: - path: "/var/lib/mysql/.sst" - state: absent - -- name: Restart mysql fall back - service: - name: mysql - state: restarted - sleep: 2 - arguments: "{{ (not galera_existing_cluster | bool and inventory_hostname == galera_server_bootstrap_node) | ternary('--wsrep-new-cluster', '') }}" - environment: - MYSQLD_STARTUP_TIMEOUT: 180 - register: galera_restart_fall_back - until: galera_restart_fall_back | success - retries: 3 - delay: 5 - -- name: "Set wsrep-new-cluster" - lineinfile: - line: 'wsrep-new-cluster' - insertafter: 'wsrep_cluster_name' - state: present - dest: "{{ galera_etc_include_dir }}/cluster.cnf" - listen: "Restart all mysql" + delegate_to: "{{ item }}" when: - - not galera_running_and_bootstrapped | bool - - not galera_existing_cluster | bool and inventory_hostname == galera_server_bootstrap_node - - ansible_pkg_mgr == "zypper" - -- name: "Ensure node is not in bootstrap mode" - lineinfile: - line: 'wsrep-new-cluster' - state: absent - dest: "{{ galera_etc_include_dir }}/cluster.cnf" - listen: "Restart all mysql" - when: - - not galera_running_and_bootstrapped | bool - - (not galera_existing_cluster | bool) or (not inventory_hostname == galera_server_bootstrap_node) - - ansible_pkg_mgr == "zypper" - -- name: Restart mysql on SUSE - service: - name: mysql - state: restarted - when: - - not galera_running_and_bootstrapped | bool - - ansible_pkg_mgr == "zypper" - register: galera_restart - until: galera_restart | success - retries: 3 - delay: 5 - # notifies are only fired when status is "changed" - changed_when: galera_restart | failed - failed_when: false - notify: - - "Remove stale .sst" - listen: "Restart all mysql" + - hostvars[item]['galera_cluster_ready'] is defined + with_items: + - "{{ ansible_play_hosts }}" + run_once: true - meta: noop listen: Manage LB diff --git a/library/mysql_status_facts b/library/mysql_status_facts deleted file mode 100644 index 2c8d18b7..00000000 --- a/library/mysql_status_facts +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python -# Copyright 2015, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import subprocess - -# import module snippets -from ansible.module_utils.basic import * - - -DOCUMENTATION = """ ---- -module: mysql_status_facts -short_description: - - A module for gathering mysql status and global variable facts. -description: - - A module for gathering mysql status and global variable facts. -author: Rcbops -""" - -EXAMPLES = """ -- name: Gather mysql status facts - mysql_status_facts: -""" - - -class MysqlStatusFacts(object): - def __init__(self, module): - self.state_change = False - self.module = module - - def gather_facts(self): - """Get information about mysql status.""" - try: - status = subprocess.check_output(["mysql", "-e", "show status"], - stderr=subprocess.STDOUT) - global_vars = subprocess.check_output(["mysql", "-e", - "show global variables"], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - message = 'Mysql fact collection failed: "%s".' % e.output.strip() - self.module.fail_json(msg=message) - else: - lines = status.split('\n') - lines += global_vars.split('\n') - facts = dict(l.split('\t') for l in lines if l) - self.module.exit_json( - changed=self.state_change, - ansible_facts={'mysql_status': facts}) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - ), - supports_check_mode=False - ) - mysql_facts = MysqlStatusFacts(module) - mysql_facts.gather_facts() - -if __name__ == '__main__': - main() diff --git a/tasks/galera_bootstrap.yml b/tasks/galera_bootstrap.yml deleted file mode 100644 index 32256ff2..00000000 --- a/tasks/galera_bootstrap.yml +++ /dev/null @@ -1,100 +0,0 @@ ---- -# Copyright 2015, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- include: galera_running_check.yml - vars: - num_retries: 2 - wait_delay: 3 - -# If there is an existing cluster join it by starting mysql normally -- name: Start mysql node normally - service: - name: mysql - state: started - environment: - MYSQLD_STARTUP_TIMEOUT: 180 - until: mysql_started | success - retries: 3 - delay: 5 - when: mysql_running.rc != 0 - register: mysql_started - ignore_errors: true - tags: - - galera-bootstrap - -- name: Start galera cluster - command: galera_new_cluster - when: - - ansible_service_mgr == 'systemd' - - mysql_running.rc != 0 - - mysql_started | failed - # galera_new_cluster is not applicable for SUSE - - ansible_pkg_mgr != 'zypper' - register: start_cluster - failed_when: false - tags: - - galera-bootstrap - -# TODO: Remove this task after 10.0 is removed from upgrade path -- name: Start cluster with wsrep init fallback - command: "/etc/init.d/mysql bootstrap" - when: - - ansible_service_mgr == 'systemd' - - mysql_started | failed - - start_cluster | failed - - mysql_running.rc != 0 - - ansible_pkg_mgr != 'zypper' - tags: - - galera-bootstrap - -- block: - - name: "Set wsrep-new-cluster" - lineinfile: - line: 'wsrep-new-cluster' - insertafter: 'wsrep_cluster_name' - state: present - dest: "{{ galera_etc_include_dir }}/cluster.cnf" - - name: "Restaring the mysql service" - service: - name: mysql - state: restarted - register: start_cluster - when: - - mysql_running.rc != 0 - - mysql_started | failed - # galera_new_cluster is not applicable for SUSE - - ansible_pkg_mgr == 'zypper' - -- name: Wait for operational state - command: mysql --silent --skip-column-names -e 'SHOW STATUS LIKE "wsrep_evs_state"' - register: galera_check_wait - until: galera_check_wait|success - failed_when: not galera_check_wait.stdout | search("OPERATIONAL") - retries: 6 - delay: 5 - when: - - mysql_running.rc != 0 - tags: - - galera-operational - - galera-bootstrap - -- name: Set the galera running and bootstrapped fact - set_fact: - galera_running_and_bootstrapped: true - when: - - mysql_running.rc != 0 - tags: - - galera-operational - - galera-bootstrap diff --git a/tasks/galera_cluster_state.yml b/tasks/galera_cluster_state.yml index ed4ae6b2..58224e16 100644 --- a/tasks/galera_cluster_state.yml +++ b/tasks/galera_cluster_state.yml @@ -13,76 +13,39 @@ # See the License for the specific language governing permissions and # limitations under the License. -- include: galera_running_check.yml - vars: - num_retries: 1 - wait_delay: 3 - -- name: Check for cluster state failure - fail: - msg: | - The cluster may be broken, mysql is not running but appears to be - installed. Fix it before re-running the playbook or override with - 'openstack-ansible -e galera_ignore_cluster_state=true galera-install.yml'. - when: - - not galera_ignore_cluster_state | bool - - mysql_running.rc == 1 - - mysql_running.stderr | search("Check that mysqld is running and that the socket") - tags: - - galera-cluster-state-check - -- name: Gather mysql facts - mysql_status_facts: +- name: Check node status + command: > + mysql --silent --skip-column-names --connect-timeout=10 -e 'SHOW STATUS LIKE "wsrep_local_state";' failed_when: false - tags: - - galera-cluster-state-check + changed_when: false + register: node_status -- name: Check for cluster state failure - fail: - msg: | - The cluster may be broken, mysql is running but unable to gather mysql facts. - Fix it before re-running the playbook or override with - 'openstack-ansible -e galera_ignore_cluster_state=true galera-install.yml'. - when: - - not galera_ignore_cluster_state | bool - - mysql_running.rc == 0 - - mysql_status is not defined - tags: - - galera-cluster-state-check - -- name: Check for cluster state failure - fail: - msg: | - wsrep_incoming_addresses does not match across the cluster. Please fix before - re-running the playbooks or override with - 'openstack-ansible -e galera_ignore_cluster_state=true galera-install.yml'. - with_items: "{{ play_hosts }}" - when: - - not galera_ignore_cluster_state | bool - - mysql_running.rc == 0 - - mysql_status['wsrep_incoming_addresses'] != hostvars[item]['mysql_status']['wsrep_incoming_addresses'] - tags: - - galera-cluster-state-check - -- name: Fail if galera_cluster_name doesnt match file value +- name: Fail if cluster is out of sync fail: msg: > - "The galera_cluster_name variable does not match what is set in mysql. - Check your galera_cluster_name setting in your user_*.yml files in /etc/openstack_deploy - and compare to the current value in /etc/mysql/conf.d/cluster.cnf on the host, and - the wsrep_cluster_name value set in your running galera cluster. - If you are sure you want to change this variable you can force change your - galera_cluster_name variable by setting 'galera_force_change_cluster_name: True'" + The cluster may be broken, the cluster state is not known to be good. + Fix the cluster state before re-running the playbooks. To ignore the + cluster state set '-e galera_ignore_cluster_state=true'. when: - - mysql_running.rc == 0 - - mysql_status['wsrep_cluster_name'] != galera_cluster_name - - not galera_force_change_cluster_name | bool - tags: - - galera-cluster-state-check + - node_status.rc != 0 + - (node_status.stdout.split()[-1] | default(false)) in ["2", "4"] -- name: Set the galera existing cluster fact - set_fact: - galera_existing_cluster: true - when: mysql_running.rc == 0 - tags: - - galera-cluster-state-check +- name: Check cluster name + command: > + mysql --silent --skip-column-names --connect-timeout=10 -e 'SHOW VARIABLES LIKE "wsrep_cluster_name";' + failed_when: false + changed_when: false + register: cluster_name + +- name: Fail if galera_cluster_name doesnt match provided value + fail: + msg: > + The galera_cluster_name variable does not match what is set in mysql. + Check your galera_cluster_name setting in your user_*.yml files in + "/etc/openstack_deploy" and compare to the current value in + "/etc/mysql/conf.d/cluster.cnf" on the host, and the "wsrep_cluster_name" + value set in your running galera cluster. To ignore the + cluster state set '-e galera_ignore_cluster_state=true'. + when: + - cluster_name.rc != 0 + - (cluster_name.split()[-1] | default(false)) != galera_cluster_name diff --git a/tasks/galera_install.yml b/tasks/galera_install.yml index 0d1525d7..f2969f51 100644 --- a/tasks/galera_install.yml +++ b/tasks/galera_install.yml @@ -13,15 +13,65 @@ # See the License for the specific language governing permissions and # limitations under the License. +- name: Download xtrabackup + block: + - name: Download the percona-xtrabackup package + get_url: + url: "{{ percona_package_url }}" + dest: "{{ percona_package_path }}" + mode: "0644" + sha256sum: "{{ percona_package_sha256 }}" + validate_certs: "{{ percona_package_download_validate_certs }}" + register: package_download + retries: 3 + delay: 10 + until: package_download | success + rescue: + - name: Download the percona-xtrabackup package (fallback) + get_url: + url: "{{ percona_package_fallback_url }}" + dest: "{{ percona_package_path }}" + mode: "0644" + sha256sum: "{{ percona_package_sha256 }}" + validate_certs: "{{ percona_package_download_validate_certs }}" + register: package_download + retries: 3 + delay: 10 + until: package_download | success + when: + - not use_percona_upstream | bool + +- name: Download qpress + block: + - name: Download the qpress package + get_url: + url: "{{ qpress_package_url }}" + dest: "{{ qpress_package_path }}" + sha256sum: "{{ qpress_package_sha256 }}" + validate_certs: "{{ qpress_package_download_validate_certs }}" + register: package_download + retries: 3 + delay: 10 + until: package_download | success + rescue: + - name: Download the qpress package (fallback) + get_url: + url: "{{ qpress_package_fallback_url }}" + dest: "{{ qpress_package_path }}" + sha256sum: "{{ qpress_package_sha256 }}" + validate_certs: "{{ qpress_package_download_validate_certs }}" + register: package_download + retries: 3 + delay: 10 + until: package_download | success + when: + - not use_percona_upstream | bool + - name: Add percona external packages to the galera packages list set_fact: galera_install_packages_list: "{{ galera_packages_list | union(percona_packages_list) }}" - include: "galera_install_{{ ansible_pkg_mgr }}.yml" - tags: - - install-apt - - install-yum - - install-zypper - name: Install pip packages pip: @@ -34,5 +84,10 @@ until: install_packages|success retries: 5 delay: 2 - tags: - - galera-server-pip-packages + +- name: Record galera has been deployed + ini_file: + dest: "/etc/ansible/facts.d/openstack_ansible.fact" + section: galera + option: deployed + value: true diff --git a/tasks/galera_install_apt.yml b/tasks/galera_install_apt.yml index 4d65da77..5bd0ed7e 100644 --- a/tasks/galera_install_apt.yml +++ b/tasks/galera_install_apt.yml @@ -23,13 +23,10 @@ url: "{{ item.url | default(omit) }}" state: "present" register: add_keys - until: add_keys|success + until: add_keys | success retries: 5 delay: 2 with_items: "{{ galera_gpg_keys }}" - tags: - - galera-apt-keys - rescue: - name: Add keys (fallback keyserver) apt_key: @@ -38,14 +35,12 @@ url: "{{ item.fallback_url | default(omit) }}" state: "present" register: add_keys_fallback - until: add_keys_fallback|success + until: add_keys_fallback | success retries: 5 delay: 2 with_items: "{{ galera_gpg_keys }}" when: - item.fallback_keyserver is defined or item.fallback_url is defined - tags: - - galera-apt-keys - name: Remove old repos lineinfile: @@ -55,9 +50,6 @@ with_items: - { name: "MariaDB", repo: "{{ galera_repo.repo }}" } - { name: "Percona", repo: "{{ galera_percona_xtrabackup_repo.repo }}" } - tags: - - galera-client-repos - - percona-repos - name: Add galera repo apt_repository: @@ -68,8 +60,6 @@ until: add_repos|success retries: 5 delay: 2 - tags: - - galera-repos - name: Add percona repo apt_repository: @@ -80,8 +70,6 @@ until: add_repos|success retries: 5 delay: 2 - tags: - - percona-repos - name: Preseed galera password(s) debconf: @@ -90,8 +78,6 @@ value: "{{ item.value }}" vtype: "{{ item.vtype }}" with_items: "{{ galera_debconf_items }}" - tags: - - galera-debconf - name: Prevent galera from starting on install copy: @@ -99,6 +85,7 @@ dest: "/usr/sbin/policy-rc.d" mode: "0755" backup: yes + changed_when: false - name: Install galera_server role remote packages (apt) apt: @@ -118,5 +105,4 @@ file: path: "/usr/sbin/policy-rc.d" state: absent - tags: - - galera_server-config + changed_when: false diff --git a/tasks/galera_install_yum.yml b/tasks/galera_install_yum.yml index b0a8a848..a84c8edc 100644 --- a/tasks/galera_install_yum.yml +++ b/tasks/galera_install_yum.yml @@ -37,8 +37,6 @@ retries: 5 delay: 2 with_items: "{{ galera_gpg_keys }}" - tags: - - galera-gpg-keys rescue: - name: Add keys (fallback keyserver) @@ -51,8 +49,6 @@ delay: 2 with_items: "{{ galera_gpg_keys }}" when: item.fallback_keyserver is defined - tags: - - galera-gpg-keys - name: Add galera repo yum_repository: @@ -66,8 +62,6 @@ until: add_repos | success retries: 5 delay: 2 - tags: - - galera-repos # When changing the repo URL, the metadata does # not reliably update, resulting in the right @@ -80,7 +74,6 @@ warn: no when: add_repos | changed tags: - - galera-repos - skip_ansible_lint - name: Install percona repo @@ -92,53 +85,8 @@ retries: 5 delay: 2 when: use_percona_upstream | bool - tags: - - galera-pre-yum-packages - name: Install galera_server role remote packages package: name: "{{ galera_install_packages_list | selectattr('enabled') | sum(attribute='packages', start=[]) }}" state: "{{ galera_server_package_state }}" - -- name: Enable mysql to start at boot - service: - name: "mysql" - enabled: "yes" - tags: - - galera_server-config - - galera-enable - -# This glue to make the upgrade works. when testing the galera_server role we install version 10.0 -# of mariadb and so the path doesn't exist, let's clean it up when we do upgrade testing the way -# we do for other roles. -# TODO: cleanup when we change upgrade test. -- name: Check if we are on systemd service - stat: - path: "/etc/systemd/system/mariadb.service.d/" - register: systemd_mysql_service - -# See comments above 'galera_disable_privatedevices' in defaults/main.yml for -# links to relevant bugs and discussion. -- name: Remove PrivateDevices systemd options when in container - template: - src: without-privatedevices.conf.j2 - dest: "/etc/systemd/system/mariadb.service.d/without-privatedevices.conf" - when: - - ansible_pkg_mgr in ['yum', 'dnf'] - - systemd_mysql_service.stat.exists - notify: - - Manage LB - - Reload the systemd daemon - - Restart mysql - tags: - - galera-config - -# TODO: remove name argument when we upgrade to ansible 2.4 -- name: Reload the systemd daemon - systemd: - daemon_reload: yes - name: mysql - when: - - systemd_mysql_service.stat.exists - -- include: galera_secure_mysql.yml mysql_securely_configured='/etc/mysql/rhel_configured' diff --git a/tasks/galera_install_zypper.yml b/tasks/galera_install_zypper.yml index 0bb6b4fb..ad60ecc3 100644 --- a/tasks/galera_install_zypper.yml +++ b/tasks/galera_install_zypper.yml @@ -21,20 +21,8 @@ auto_import_keys: yes register: zypper_repository_added with_items: "{{ galera_repo }}" - tags: - - galera-repos - name: Install galera_server role remote packages (zypper) zypper: name: "{{ galera_packages_list | selectattr('enabled') | sum(attribute='packages', start=[]) }}" state: "{{ galera_server_package_state }}" - -- name: Enable mysql to start at boot - service: - name: "mysql" - enabled: "yes" - tags: - - galera_server-config - - galera-enable - -- include: galera_secure_mysql.yml mysql_securely_configured='/etc/my.cnf.d/suse_configured' diff --git a/tasks/galera_post_install.yml b/tasks/galera_post_install.yml index 3e1cf496..31fe24f2 100644 --- a/tasks/galera_post_install.yml +++ b/tasks/galera_post_install.yml @@ -13,6 +13,28 @@ # See the License for the specific language governing permissions and # limitations under the License. +# NOTE(cloudnull): The secure task is not needed on Debian based systems +# as all of these tasks will be run on Package install +# and running them again will cause a conflict within +# debian based deployments. +- name: Create galera initial secure tool + template: + src: "galera_secure_node.j2" + dest: "/usr/local/bin/galera_secure_node" + mode: "0750" + when: + - ansible_pkg_mgr != "apt" + +- name: Run galera secure + command: "/usr/local/bin/galera_secure_node" + args: + creates: "/var/lib/mysql/osa_default_secured" + warn: no + when: + - ansible_pkg_mgr != "apt" + tags: + - skip_ansible_lint + - name: Create the local directories file: path: "{{ item.path }}" @@ -25,15 +47,6 @@ - { path: "/var/lib/mysql", owner: "mysql", mode: "02755" } - { path: "/var/log/mysql", owner: "mysql", mode: "02755" } - { path: "/etc/mysql/conf.d" } - tags: - - galera-config - -- include: galera_ssl.yml - when: - - galera_use_ssl | bool - tags: - - galera-config - - galera-ssl - name: Behave properly if mysql_logs is a link shell: | @@ -53,7 +66,12 @@ state: "directory" owner: "mysql" mode: "02755" - when: log_dir.rc == 1 + when: + - log_dir.rc == 1 + +- include: galera_ssl.yml + when: + - galera_use_ssl | bool # NOTE: (hwoarang) mariadb packages may drop some default configuration files # in {{ galera_etc_include_dir }} so make sure they are gone if necessary in @@ -90,35 +108,22 @@ notify: - Manage LB - Restart all mysql - tags: - - galera-config - - galera-client-user-config - -# NOTE: (mancdaz) this should not be needed with mariadb-10.1 since its -# initscript sources /etc/default/mariadb -- name: fix mysql startup timeout - lineinfile: - dest: /etc/init.d/mysql - state: present - insertafter: '^export HOME=/etc/mysql/' - line: '[ -r /etc/default/mariadb ] && . /etc/default/mariadb' - backup: yes - when: ansible_pkg_mgr != 'zypper' - tags: - - galera-config - name: Apply service defaults template: src: "mysql_defaults.j2" dest: "/etc/default/mariadb" mode: "0644" - when: ansible_pkg_mgr != 'zypper' notify: - Manage LB - Restart all mysql - Reload the systemd daemon - tags: - - galera-config + +- name: Link mysql and mariadb config files + file: + src: "/etc/default/mariadb" + dest: "/etc/default/mysql" + state: "link" - name: Create mariadb systemd service config dir file: @@ -127,8 +132,6 @@ group: "root" owner: "root" mode: "0755" - when: - - ansible_service_mgr == 'systemd' - name: Apply systemd options template: @@ -140,34 +143,28 @@ - { src: "systemd.limits.conf.j2", dest: "limits.conf" } - { src: "systemd.timeout.conf.j2", dest: "timeout.conf" } - { src: "systemd.restart.conf.j2", dest: "restart.conf" } - when: - - ansible_service_mgr == 'systemd' + - { src: "without-privatedevices.conf.j2", dest: "without-privatedevices.conf" } notify: - Manage LB - Reload the systemd daemon - Restart all mysql - tags: - - galera-config - name: remove default mysql_safe_syslog file: path: "/etc/mysql/conf.d/mysqld_safe_syslog.cnf" state: absent - tags: - - galera-config -- name: Reload the systemd daemon - command: "systemctl daemon-reload" - when: - - ansible_service_mgr == 'systemd' +- name: Create new cluster tool + copy: + src: "galera_new_cluster" + dest: "/usr/local/bin/galera_new_cluster" + mode: "0750" - name: Create clustercheck script template: src: "clustercheck.j2" dest: "/usr/local/bin/clustercheck" mode: "0755" - tags: - - galera-config - name: Create mysqlchk config template: @@ -176,8 +173,6 @@ mode: "0644" notify: - Restart xinetd - tags: - - galera-config - name: Add galera service check to services lineinfile: @@ -186,5 +181,3 @@ regexp: '^mysqlchk' line: 'mysqlchk 9200/tcp # MySQL check' backup: yes - tags: - - galera-config diff --git a/tasks/galera_pre_install.yml b/tasks/galera_pre_install.yml deleted file mode 100644 index 56fde61b..00000000 --- a/tasks/galera_pre_install.yml +++ /dev/null @@ -1,74 +0,0 @@ ---- -# Copyright 2014, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- block: - - name: Download the percona-xtrabackup package - get_url: - url: "{{ percona_package_url }}" - dest: "{{ percona_package_path }}" - mode: "0644" - sha256sum: "{{ percona_package_sha256 }}" - validate_certs: "{{ percona_package_download_validate_certs }}" - register: package_download - retries: 3 - delay: 10 - until: package_download|success - when: not use_percona_upstream | bool - tags: - - percona-apt-packages - rescue: - - name: Download the percona-xtrabackup package (fallback) - get_url: - url: "{{ percona_package_fallback_url }}" - dest: "{{ percona_package_path }}" - mode: "0644" - sha256sum: "{{ percona_package_sha256 }}" - validate_certs: "{{ percona_package_download_validate_certs }}" - register: package_download - retries: 3 - delay: 10 - until: package_download|success - when: not use_percona_upstream | bool - tags: - - percona-apt-packages - -- block: - - name: Download the qpress package - get_url: - url: "{{ qpress_package_url }}" - dest: "{{ qpress_package_path }}" - sha256sum: "{{ qpress_package_sha256 }}" - validate_certs: "{{ qpress_package_download_validate_certs }}" - register: package_download - retries: 3 - delay: 10 - until: package_download|success - when: not use_percona_upstream | bool - tags: - - percona-apt-packages - rescue: - - name: Download the qpress package (fallback) - get_url: - url: "{{ qpress_package_fallback_url }}" - dest: "{{ qpress_package_path }}" - sha256sum: "{{ qpress_package_sha256 }}" - validate_certs: "{{ qpress_package_download_validate_certs }}" - register: package_download - retries: 3 - delay: 10 - until: package_download|success - when: not use_percona_upstream | bool - tags: - - percona-apt-packages diff --git a/tasks/galera_running_check.yml b/tasks/galera_running_check.yml deleted file mode 100644 index 1ec81df5..00000000 --- a/tasks/galera_running_check.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -# Copyright 2015, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- name: Set fact for extra arguments in MySQL commands - set_fact: - mysql_extra_args: "{{ (ansible_os_family == 'Debian') | ternary('--defaults-file=/etc/mysql/debian.cnf', '') }}" - tags: - - galera-cluster-state-check - - galera-bootstrap - -- name: Confirm service connectivity - command: "/usr/bin/mysqladmin {{ mysql_extra_args }} ping" - register: _mysql_running - until: _mysql_running.rc == 0 - retries: "{{ num_retries }}" - delay: "{{ wait_delay }}" - failed_when: false - changed_when: _mysql_running.rc != 0 - tags: - - galera-cluster-state-check - - galera-bootstrap - -- name: Check that WSREP is ready - shell: "/usr/bin/mysqladmin {{ mysql_extra_args }} extended-status | egrep '(wsrep_ready|wsrep_evs_state)'" - changed_when: > - _mysql_ready.rc != 0 - register: _mysql_ready - when: _mysql_running.rc == 0 - until: - - _mysql_ready.rc == 0 - - (_mysql_ready.stdout).find("ON") != -1 - retries: "{{ num_retries }}" - delay: "{{ wait_delay }}" - tags: - - galera-cluster-state-check - - galera-bootstrap - -- name: Set running state fact - set_fact: - mysql_running: "{{ _mysql_running }}" - tags: - - galera-cluster-state-check - - galera-bootstrap diff --git a/tasks/galera_secure_mysql.yml b/tasks/galera_secure_mysql.yml deleted file mode 100644 index 00792b49..00000000 --- a/tasks/galera_secure_mysql.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- -# Copyright 2016, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -#NOTE(cloudnull): This is an idempotent shell task is it will only run once -# provided the "/etc/mysql/rhel_configured" exists. This tasks automates the -# MySQL secure setup which is done automatically in Ubuntu deployments. -- name: "Update root user, connections, and grant options" - shell: | - service mysql start || true - # Reset the root password, at this time there is no password set - mysqladmin --no-defaults --port=3306 --socket=/var/run/mysqld/mysqld.sock --host=127.0.0.1 --user=root password "{{ galera_root_password }}" - # Setup the root user for MySQL - mysql -u root -h localhost -e "UPDATE mysql.user SET Password=PASSWORD('$rootpass') WHERE User='root';" - mysql -u root -h localhost -e "DELETE FROM mysql.user WHERE user='';" - mysql -u root -h localhost -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('%', 'localhost', '127.0.0.1', '::1');" - mysql -u root -h localhost -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';" - mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'localhost' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" - mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'127.0.0.1' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" - mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'::1' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" - mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'%' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" - mysql -u root -h localhost -e "FLUSH PRIVILEGES;" - # Create a marker file to ensure this script is not run again - touch "{{ mysql_securely_configured }}" - service mysql stop - args: - creates: "{{ mysql_securely_configured }}" - warn: no - tags: - - galera_server-config - - galera-rhel-config - - galera-suse-config - - skip_ansible_lint diff --git a/tasks/galera_setup.yml b/tasks/galera_setup.yml index c3af1bfa..181f7743 100644 --- a/tasks/galera_setup.yml +++ b/tasks/galera_setup.yml @@ -29,11 +29,21 @@ password: "{{ galera_root_password }}" priv: "*.*:ALL,GRANT" state: present + - name: "{{ galera_root_user }}" + host: "::1" + password: "{{ galera_root_password }}" + priv: "*.*:ALL,GRANT" + state: present + - name: "{{ galera_root_user }}" + host: "127.0.0.1" + password: "{{ galera_root_password }}" + priv: "*.*:ALL,GRANT" + state: present - name: "{{ galera_root_user }}" host: "localhost" password: "{{ galera_root_password }}" priv: "*.*:ALL" - state: absent + state: present - name: "{{ galera_monitoring_user }}" host: '%' password: "{{ galera_monitoring_user_password }}" @@ -46,7 +56,18 @@ state: present register: galera_users until: galera_users | success - retries: 10 - delay: 3 - tags: - - galera-user-create + retries: 3 + delay: 10 + delegate_to: "{{ galera_server_bootstrap_node }}" + run_once: true + +- name: Run MySQL Upgrade + command: "/usr/bin/mysql_upgrade" + register: galera_mysql_upgrade + changed_when: + - not galera_mysql_upgrade.stdout | search("already upgraded") + until: galera_mysql_upgrade | success + retries: 3 + delay: 10 + delegate_to: "{{ galera_server_bootstrap_node }}" + run_once: true diff --git a/tasks/galera_ssl.yml b/tasks/galera_ssl.yml index d16096ed..858d0118 100644 --- a/tasks/galera_ssl.yml +++ b/tasks/galera_ssl.yml @@ -13,22 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: Check if SSL bundle exists - stat: - path: "{{ item }}" - delegate_to: localhost - register: res - with_items: - - "{{ galera_user_ssl_ca_cert }}" - - "{{ galera_user_ssl_cert }}" - - "{{ galera_user_ssl_key }}" - -- include: galera_ssl_key_create.yml - when: > - ( not res.results[0].stat.exists or - not res.results[1].stat.exists or - not res.results[2].stat.exists ) - - name: Create ssl directory file: path: "/etc/mysql/ssl" @@ -37,13 +21,42 @@ group: "mysql" mode: "0750" -- name: Copy CA cert and key +- include: galera_ssl_key_create.yml + static: no + when: + - inventory_hostname == galera_server_bootstrap_node + - not galera_user_ssl_cert is defined + - not galera_user_ssl_key is defined + - not galera_user_ssl_ca_cert is defined + +- name: Copy CA cert and key (SELF) + copy: + content: "{{ hostvars[galera_server_bootstrap_node][item.key] | b64decode }}" + dest: "{{ item.dest }}" + owner: "mysql" + group: "mysql" + mode: "{{ item.mode | default('0640') }}" + with_items: + - key: "galera_server_ca_key" + dest: "{{ galera_ssl_ca_cert }}" + - key: "galera_user_ssl_cert" + dest: "{{ galera_ssl_cert }}" + - key: "galera_user_ssl_key" + dest: "{{ galera_ssl_key }}" + mode: "0600" + when: + - inventory_hostname != galera_server_bootstrap_node + - not galera_user_ssl_cert is defined + - not galera_user_ssl_key is defined + - not galera_user_ssl_ca_cert is defined + +- name: Copy CA cert and key (USER) copy: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: "mysql" group: "mysql" - mode: "{{ item.mode|default('0640') }}" + mode: "{{ item.mode | default('0640') }}" with_items: - src: "{{ galera_user_ssl_ca_cert }}" dest: "{{ galera_ssl_ca_cert }}" @@ -52,3 +65,7 @@ - src: "{{ galera_user_ssl_key }}" dest: "{{ galera_ssl_key }}" mode: "0600" + when: + - galera_user_ssl_cert is defined + - galera_user_ssl_key is defined + - galera_user_ssl_ca_cert is defined diff --git a/tasks/galera_ssl_key_create.yml b/tasks/galera_ssl_key_create.yml index 5372cf39..b4aad0ca 100644 --- a/tasks/galera_ssl_key_create.yml +++ b/tasks/galera_ssl_key_create.yml @@ -13,53 +13,72 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: Create ssl directory - file: - path: "{{ galera_user_ssl_ca_cert | dirname }}" - state: "directory" - delegate_to: localhost - - name: Remove self signed cert for regen file: dest: "{{ item }}" state: "absent" with_items: - - "{{ galera_user_ssl_ca_cert }}" - - "{{ galera_user_ssl_cert }}" - - "{{ galera_user_ssl_key }}" - - "{{ galera_user_ssl_ca_cert | dirname }}/galera-ca.key " - - "{{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem " - delegate_to: localhost - when: galera_ssl_self_signed_regen | bool + - "{{ galera_ssl_ca_cert }}" + - "{{ galera_ssl_cert }}" + - "{{ galera_ssl_key }}" + when: + - galera_ssl_self_signed_regen | bool - name: Create galera CA cert command: > openssl req -new -nodes -x509 -subj "{{ galera_ssl_ca_self_signed_subject }}" - -keyout {{ galera_user_ssl_ca_cert | dirname }}/galera-ca.key - -out {{ galera_user_ssl_ca_cert }} - creates={{ galera_user_ssl_ca_cert }} - delegate_to: localhost + -keyout {{ galera_ssl_ca_cert | dirname }}/galera-ca.key + -out {{ galera_ssl_ca_cert }} + creates={{ galera_ssl_ca_cert }} + +- name: Get CA key contents and store as var + slurp: + src: "{{ galera_ssl_ca_cert }}" + register: galera_ca + changed_when: false + +- name: Register a fact for the CA key + set_fact: + galera_server_ca_key: "{{ galera_ca.content }}" - name: Create galera ssl request command: > openssl req -new -nodes -sha256 -subj "{{ galera_ssl_self_signed_subject }}" -days 3650 - -keyout {{ galera_user_ssl_key }} - -out {{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem + -keyout {{ galera_ssl_key }} + -out {{ galera_ssl_ca_cert | dirname }}/galera-req.pem -extensions v3_ca - creates={{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem - delegate_to: localhost + creates={{ galera_ssl_ca_cert | dirname }}/galera-req.pem + +- name: Get REQ key contents and store as var + slurp: + src: "{{ galera_ssl_ca_cert | dirname }}/galera-req.pem" + register: galera_req + changed_when: false + +- name: Register a fact for the REQ key + set_fact: + galera_server_req_key: "{{ galera_req.content }}" - name: Create galera ssl cert command: > openssl x509 -req -days 3650 - -in {{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem - -CA {{ galera_user_ssl_ca_cert }} - -CAkey {{ galera_user_ssl_ca_cert | dirname }}/galera-ca.key - -out {{ galera_user_ssl_cert }} + -in {{ galera_ssl_ca_cert | dirname }}/galera-req.pem + -CA {{ galera_ssl_ca_cert }} + -CAkey {{ galera_ssl_ca_cert | dirname }}/galera-ca.key + -out {{ galera_ssl_cert }} -set_serial 01 - creates={{ galera_user_ssl_cert }} - delegate_to: localhost + creates={{ galera_ssl_cert }} + +- name: Get CERT key contents and store as var + slurp: + src: "{{ galera_ssl_cert }}" + register: galera_cert + changed_when: false + +- name: Register a fact for the CERT key + set_fact: + galera_server_cert_key: "{{ galera_cert.content }}" diff --git a/tasks/galera_upgrade.yml b/tasks/galera_upgrade.yml new file mode 100644 index 00000000..38898a52 --- /dev/null +++ b/tasks/galera_upgrade.yml @@ -0,0 +1,51 @@ +--- +# Copyright 2016, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Check mysql version + shell: > + mysqladmin --version | grep -w "{{ galera_major_version }}" + register: mysqladmin_version + changed_when: false + failed_when: false + tags: + - skip_ansible_lint + +- name: Check mysql running + command: > + systemctl status mysql + register: mysql_running + changed_when: false + failed_when: false + tags: + - skip_ansible_lint + +- name: Check if major version of Galera is installed + fail: + msg: > + To install a new major version of mariadb-galera-server set + '-e galera_upgrade=true'. + when: + - mysqladmin_version.rc != 0 + - mysql_running.rc == 0 + tags: + - galera_server-upgrade + +- include: galera_upgrade_pre.yml + static: no + when: + - (mysqladmin_version.rc != 0 and mysql_running.rc != 0) or + galera_upgrade | bool + tags: + - galera_server-upgrade diff --git a/tasks/galera_upgrade_check.yml b/tasks/galera_upgrade_check.yml deleted file mode 100644 index 7677a2b6..00000000 --- a/tasks/galera_upgrade_check.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -# Copyright 2016, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- include: galera_upgrade_check_{{ ansible_pkg_mgr }}.yml - tags: - - install-apt - - install-yum - - install-zypper - -- include: galera_upgrade_pre.yml - static: no - when: - - galera_upgrade | bool diff --git a/tasks/galera_upgrade_check_apt.yml b/tasks/galera_upgrade_check_apt.yml deleted file mode 100644 index a03265dc..00000000 --- a/tasks/galera_upgrade_check_apt.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -# Copyright 2016, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- name: Check major galera install version - command: "dpkg -s {{ galera_mariadb_server_package }}" - failed_when: false - register: installed_galera_specific - when: - - not galera_upgrade | bool - tags: - - galera-package-deb - - galera-apt-packages - - galera-upgrade - - skip_ansible_lint - -- name: Check for any galera install version - shell: | - dpkg --get-selections | grep mariadb-galera-server - failed_when: false - register: installed_galera_any - when: - - not galera_upgrade | bool - - installed_galera_specific.rc != 0 - tags: - - galera-package-deb - - galera-apt-packages - - galera-upgrade - - skip_ansible_lint - -- name: Check if major version of Galera is installed - fail: - msg: "To install a new major version of mariadb-galera-server set '-e galera_upgrade=true'." - when: - - not galera_upgrade | bool - - installed_galera_specific.rc != 0 and installed_galera_any.rc == 0 - tags: - - galera-package-deb - - galera-apt-packages - - galera-upgrade diff --git a/tasks/galera_upgrade_check_dnf.yml b/tasks/galera_upgrade_check_dnf.yml deleted file mode 120000 index 4fe70d87..00000000 --- a/tasks/galera_upgrade_check_dnf.yml +++ /dev/null @@ -1 +0,0 @@ -galera_upgrade_check_yum.yml \ No newline at end of file diff --git a/tasks/galera_upgrade_check_yum.yml b/tasks/galera_upgrade_check_yum.yml deleted file mode 100644 index 797a3592..00000000 --- a/tasks/galera_upgrade_check_yum.yml +++ /dev/null @@ -1,59 +0,0 @@ ---- -# Copyright 2016, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- name: Check major galera install version - command: "rpm -qi '{{ galera_mariadb_server_package }}'" - args: - warn: no - failed_when: false - register: installed_galera_specific - when: - - not galera_upgrade | bool - tags: - - galera-package-rpm - - galera-yum-packages - - galera-zypper-packages - - galera-upgrade - - skip_ansible_lint - -- name: Check for any galera install version - # NOTE(hwoarang): We may have many packages starting with - # {{ galera_mariadb_server_package }} so make sure we actually look - # for exact matches. - shell: | - rpm -qa --qf '%{NAME}\n'| grep -i "{{ galera_mariadb_server_package }}"$ - failed_when: false - register: installed_galera_any - when: - - not galera_upgrade | bool - - installed_galera_specific.rc != 0 - tags: - - galera-package-rpm - - galera-yum-packages - - galera-zypper-packages - - galera-upgrade - - skip_ansible_lint - -- name: Check if major version of Galera is installed - fail: - msg: "To install a new major version of MariaDB-Galera-server set '-e galera_upgrade=true'." - when: - - not galera_upgrade | bool - - installed_galera_specific.rc != 0 and installed_galera_any.rc == 0 - tags: - - galera-package-rpm - - galera-yum-packages - - galera-zypper-packages - - galera-upgrade diff --git a/tasks/galera_upgrade_check_zypper.yml b/tasks/galera_upgrade_check_zypper.yml deleted file mode 120000 index 4fe70d87..00000000 --- a/tasks/galera_upgrade_check_zypper.yml +++ /dev/null @@ -1 +0,0 @@ -galera_upgrade_check_yum.yml \ No newline at end of file diff --git a/tasks/galera_upgrade_post.yml b/tasks/galera_upgrade_post.yml deleted file mode 100644 index f1c73625..00000000 --- a/tasks/galera_upgrade_post.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -# Copyright 2016, Rackspace US, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- name: Start MySQL - service: - name: mysql - state: started - # NOTE (hwoarang) Sometimes the service fails to start on the first attempt - # so just try a few more times before giving up. Clearly this needs to be - # investigated at some point... - register: mysql_service_started - until: mysql_service_started | success - retries: "{{ num_retries }}" - delay: "{{ wait_delay }}" - tags: - - galera-upgrade - -- include: galera_running_check.yml - vars: - num_retries: 10 - wait_delay: 3 - -- name: Run MySQL Upgrade - command: "/usr/bin/mysql_upgrade" - changed_when: false - register: galera_mysql_upgrade - until: galera_mysql_upgrade | success - retries: 3 - delay: 10 - tags: - - galera-upgrade diff --git a/tasks/galera_upgrade_pre.yml b/tasks/galera_upgrade_pre.yml index 1a05ff06..5bf4b52b 100644 --- a/tasks/galera_upgrade_pre.yml +++ b/tasks/galera_upgrade_pre.yml @@ -13,12 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: Set fact to ignore cluster state - set_fact: - galera_ignore_cluster_state: true - tags: - - galera-upgrade - - name: Stop MariaDB service: name: mysql @@ -27,54 +21,6 @@ until: galera_restart_fall_back | success retries: 3 delay: 5 - tags: - - galera-upgrade - -# Stop through the init script in case the service -# was initially started outside of systemctl. -- name: Stop mysql - command: /etc/init.d/mysql stop - changed_when: false - # SUSE always uses the systemd service - when: ansible_pkg_mgr != "zypper" - tags: - - galera-upgrade - -# TODO: Remove the following three tasks in Pike -# They're only required during upgrades transitioning to a -# statically named apt sources file. -- name: Find old sources - command: > - grep -rnil maria /etc/apt/sources.list.d/ --exclude MariaDB.list - changed_when: false - failed_when: false - register: old_sources - tags: - - galera-upgrade - - galera-apt-packages - -- name: Remove old sources - file: - path: "{{ item }}" - state: absent - with_items: "{{ old_sources.stdout_lines | default([]) }}" - tags: - - galera-upgrade - - galera-apt-packages - -- name: Update apt sources (Forced) - apt: - update_cache: yes - cache_valid_time: 0 - register: apt_update - until: apt_update|success - retries: 5 - delay: 2 - when: - - ansible_pkg_mgr == 'apt' - tags: - - galera-upgrade - - galera-apt-packages - name: UN-Install galera-server package package: @@ -82,6 +28,32 @@ state: absent with_items: - "{{ galera_server_upgrade_packages_remove }}" - tags: - - galera-upgrade - - galera-apt-packages + +- name: Remove old apt sources + block: + # TODO: Remove the following three tasks in Pike + # They're only required during upgrades transitioning to a + # statically named apt sources file. + - name: Find old sources + command: > + grep -rnil maria /etc/apt/sources.list.d/ --exclude MariaDB.list + changed_when: false + failed_when: false + register: old_sources + + - name: Remove old sources + file: + path: "{{ item }}" + state: absent + with_items: "{{ old_sources.stdout_lines | default([]) }}" + + - name: Update apt sources (Forced) + apt: + update_cache: yes + cache_valid_time: 0 + register: apt_update + until: apt_update|success + retries: 5 + delay: 2 + when: + - ansible_pkg_mgr != "apt" diff --git a/tasks/main.yml b/tasks/main.yml index 59ae2b41..1f76aacc 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -17,6 +17,8 @@ fail: msg: "The host {{ inventory_hostname }} must be in galera_cluster_members." when: inventory_hostname not in galera_cluster_members + tags: + - always - name: Fail if the galera root password is not provided fail: @@ -24,6 +26,8 @@ Please set the galera_root_password variable prior to applying the galera role. when: (galera_root_password is undefined) or (galera_root_password is none) + tags: + - always - name: Gather variables for each operating system include_vars: "{{ item }}" @@ -36,43 +40,65 @@ tags: - always -- include: galera_upgrade_check.yml - tags: galera_server-upgrade +- name: initialize local facts + ini_file: + dest: "/etc/ansible/facts.d/openstack_ansible.fact" + section: "galera" + option: initialized + value: true + +- name: Refresh local facts + setup: + filter: ansible_local + gather_subset: "!all" + tags: + - always + +- name: Set the galera existing cluster fact + set_fact: + galera_deployed: "{{ ansible_local['openstack_ansible']['galera']['deployed'] | default(false) | bool }}" + tags: + - always + +- name: Cluster state notice + debug: + msg: > + The cluster state will be ignored. While the state checks are skipped, + the galera restart handlers will be triggered to ensure everything is + functional at the end of the playbook execution. + changed_when: true + when: + - (galera_ignore_cluster_state | bool) or (galera_force_bootstrap | bool) + notify: + - Manage LB + - Restart all mysql + tags: + - always - include: galera_cluster_state.yml - tags: galera_server-config + when: + - galera_deployed | bool + - not galera_ignore_cluster_state | bool + tags: + - always -- include: galera_pre_install.yml - tags: galera_server-install +- include: galera_upgrade.yml + when: + - galera_deployed | bool + tags: + - galera_server-upgrade - include: galera_install.yml - tags: galera_server-install + tags: + - galera_server-install - include: galera_post_install.yml - tags: galera_server-config - -- include: galera_bootstrap.yml - when: - - inventory_hostname == galera_server_bootstrap_node - tags: galera_server-config - -- include: galera_upgrade_post.yml - vars: - num_retries: 3 - wait_delay: 3 - tags: galera_server-upgrade - when: - - galera_upgrade | bool + tags: + - galera_server-config - name: Flush handlers meta: flush_handlers -- include: galera_running_check.yml - vars: - num_retries: 10 - wait_delay: 3 - tags: galera_server-config - - include: galera_setup.yml - when: inventory_hostname == galera_server_bootstrap_node - tags: galera_server-config + tags: + - galera_server-config diff --git a/templates/galera_secure_node.j2 b/templates/galera_secure_node.j2 new file mode 100644 index 00000000..e8786dea --- /dev/null +++ b/templates/galera_secure_node.j2 @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Copyright 2017, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ev + +STOP_MYSQL=false + +if ! systemctl status mysql; then + STOP_MYSQL=true + systemctl start mysql + sleep 10 + systemctl status mysql +fi + +if mysqladmin --no-defaults --port=3306 --socket=/var/run/mysqld/mysqld.sock --host=127.0.0.1 --user=root password "{{ galera_root_password }}"; then + mysql -u root -h localhost -e "UPDATE mysql.user SET Password=PASSWORD('$rootpass') WHERE User='root';" + mysql -u root -h localhost -e "DELETE FROM mysql.user WHERE user='';" + mysql -u root -h localhost -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('%', 'localhost', '127.0.0.1', '::1');" + mysql -u root -h localhost -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';" + mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'localhost' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" + mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'127.0.0.1' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" + mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'::1' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" + mysql -u root -h localhost -e "GRANT ALL PRIVILEGES ON *.* TO '{{ galera_root_user }}'@'%' IDENTIFIED BY '{{ galera_root_password }}' WITH GRANT OPTION;" + mysql -u root -h localhost -e "FLUSH PRIVILEGES;" +fi + +if [ "${STOP_MYSQL}" = true ]; then + systemctl stop mysql +fi + +# Create a marker file to ensure this script is not run again +touch "/var/lib/mysql/osa_default_secured" diff --git a/tox.ini b/tox.ini index e70ca026..ff10a833 100644 --- a/tox.ini +++ b/tox.ini @@ -44,6 +44,7 @@ extensions = .rst [testenv:releasenotes] commands = + bash -c "mkdir -p releasenotes/build/{doctrees,html}" sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html @@ -118,7 +119,7 @@ deps = {[testenv:ansible]deps} setenv = {[testenv]setenv} - ANSIBLE_PARAMETERS=-vvv -e galera_use_ssl=True -e galera_user_ssl_ca_cert="/tmp/self-signed-certs/galera-ca.crt" -e galera_user_ssl_cert="/tmp/self-signed-certs/galera.crt" -e galera_user_ssl_key="/tmp/self-signed-certs/galera.key" + ANSIBLE_PARAMETERS=-vvv -e galera_use_ssl=True commands = bash -c "{toxinidir}/tests/tests-repo-clone.sh" bash -c "{toxinidir}/tests/common/test-ansible-functional.sh" diff --git a/vars/redhat-7.yml b/vars/redhat-7.yml index 218c37a2..852c25b2 100644 --- a/vars/redhat-7.yml +++ b/vars/redhat-7.yml @@ -19,6 +19,12 @@ _galera_gpg_keys: keyserver: 'https://yum.mariadb.org' fallback_keyserver: 'https://yum.mariadb.org' +# Default private device setting +# This provides some additional security, but it causes problems with creating +# mount namespaces on CentOS 7 with systemd 219. Setting the following variable +# to 'yes' will disable the PrivateDevices +_galera_disable_privatedevices: yes + galera_server_required_distro_packages: - gnupg2 - libaio diff --git a/vars/suse-42.yml b/vars/suse-42.yml index 7d7a8402..57292d9e 100644 --- a/vars/suse-42.yml +++ b/vars/suse-42.yml @@ -17,6 +17,9 @@ _galera_repo: - name: "OBS:server_database" uri: "{{ galera_server_opensuse_mirror_obs_url | default('http://download.opensuse.org') }}/repositories/server:/database/openSUSE_Leap_{{ ansible_distribution_version }}" +# Default private device setting +_galera_disable_privatedevices: yes + galera_server_required_distro_packages: - galera-3 - gpg2 diff --git a/vars/ubuntu-16.04.yml b/vars/ubuntu-16.04.yml index de08c7ef..ee974047 100644 --- a/vars/ubuntu-16.04.yml +++ b/vars/ubuntu-16.04.yml @@ -16,6 +16,9 @@ ## APT Cache Options cache_timeout: 600 +# Default private device setting +_galera_disable_privatedevices: yes + # Galera GPG Keys _galera_gpg_keys: - key_name: 'mariadb'