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'