From efbfd7912b5fff41a3d3060af9e64c35c7e89f3b Mon Sep 17 00:00:00 2001 From: Sam Yaple Date: Thu, 25 Jun 2015 14:33:28 +0000 Subject: [PATCH] Ansible Mariadb w/ Galera support Adds initial support for Mariadb with Galera replication in Ansible using the CONFIG_EXTERNAL methods. Additionally, this refactors some of the Galera config script to allow for reuse by CONFIG_EXTERNAL. Partially Implements: blueprint ansible-service Change-Id: I566fea0376ecca39fc8a5167f9ff9ff434ea7b7e --- ansible/library/merge_configs | 3 + ansible/roles/database/defaults/main.yml | 21 +++++++ ansible/roles/database/tasks/bootstrap.yml | 61 +++++++++++++++++++ ansible/roles/database/tasks/config.yml | 10 +++ ansible/roles/database/tasks/main.yml | 18 ++++-- ansible/roles/database/tasks/register.yml | 18 ++++++ ansible/roles/database/tasks/start.yml | 13 ++++ .../roles/database/templates/galera.cnf.j2 | 18 ++++++ ansible/roles/start.yml | 10 +-- docker/centos/binary/galera/Dockerfile | 5 +- .../centos/binary/galera/config-external.sh | 1 + .../centos/binary/galera/config-internal.sh | 1 + docker/common/base/kolla-common.sh | 10 +-- docker/common/galera/config-external.sh | 8 +++ docker/common/galera/config-galera.sh | 20 +++--- docker/common/galera/config-internal.sh | 20 ++++++ docker/common/galera/start.sh | 26 +++++--- 17 files changed, 226 insertions(+), 37 deletions(-) create mode 100644 ansible/roles/database/defaults/main.yml create mode 100644 ansible/roles/database/tasks/bootstrap.yml create mode 100644 ansible/roles/database/tasks/config.yml create mode 100644 ansible/roles/database/tasks/register.yml create mode 100644 ansible/roles/database/tasks/start.yml create mode 100644 ansible/roles/database/templates/galera.cnf.j2 create mode 120000 docker/centos/binary/galera/config-external.sh create mode 120000 docker/centos/binary/galera/config-internal.sh create mode 100644 docker/common/galera/config-external.sh create mode 100755 docker/common/galera/config-internal.sh diff --git a/ansible/library/merge_configs b/ansible/library/merge_configs index 9991833aac..b1baeb3d14 100644 --- a/ansible/library/merge_configs +++ b/ansible/library/merge_configs @@ -14,6 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# TODO(SamYaple): Provide idempotency for module (Note to self: pull logic from +# pervious bslurp module in yaodu) + DOCUMENTATION = ''' --- module: merge_configs diff --git a/ansible/roles/database/defaults/main.yml b/ansible/roles/database/defaults/main.yml new file mode 100644 index 0000000000..469ad83550 --- /dev/null +++ b/ansible/roles/database/defaults/main.yml @@ -0,0 +1,21 @@ +--- +project_name: "mariadb" + +#################### +# Database +#################### +database_cluster_name: "kolla" + + +#################### +# Docker +#################### +docker_database_registry: "{{ docker_registry }}" +docker_database_namespace: "{{ docker_namespace }}" +kolla_database_base_distro: "{{ kolla_base_distro }}" +kolla_database_install_type: "{{ kolla_install_type }}" +kolla_database_container_name: "galera" + +docker_database_image: "{{ docker_database_registry }}{{ docker_database_namespace }}/{{ kolla_database_base_distro }}-{{ kolla_database_install_type }}-{{ kolla_database_container_name }}" +docker_database_tag: "{{ openstack_release }}" +docker_database_image_full: "{{ docker_database_image }}:{{ docker_database_tag }}" diff --git a/ansible/roles/database/tasks/bootstrap.yml b/ansible/roles/database/tasks/bootstrap.yml new file mode 100644 index 0000000000..4a46ee7cb0 --- /dev/null +++ b/ansible/roles/database/tasks/bootstrap.yml @@ -0,0 +1,61 @@ +--- +- name: Creating temp file on localhost + local_action: shell echo 'None' > /tmp/kolla_mariadb_cluster + register: status + changed_when: False + failed_when: status.rc != 0 + always_run: True + run_once: True + +# TODO(SamYaple): Improve failed_when check +- name: Checking if a previous cluster exists + command: docker exec mariadb stat /var/lib/mysql/grastate.dat + register: exists + changed_when: False + failed_when: False + always_run: True + run_once: True + +- name: Writing hostname of host with existing cluster files to temp file + local_action: shell echo "{{ ansible_hostname }}" > /tmp/kolla_mariadb_cluster + register: status + changed_when: False + failed_when: status.rc != 0 + always_run: True + when: exists.rc == 0 + +- name: Registering host from temp file + set_fact: + delegate_host: "{{ lookup('file', '/tmp/kolla_mariadb_cluster') }}" + +- name: Cleaning up temp file on localhost + local_action: shell rm /tmp/kolla_mariadb_cluster + register: status + changed_when: False + failed_when: status.rc != 0 + always_run: True + run_once: True + +- include: ../../start.yml + vars: + container_environment: + KOLLA_BOOTSTRAP: + container_image: "{{ docker_database_image_full }}" + container_name: "mariadb_data" + container_volumes: + - "/var/lib/mysql/" + container_command: "/bin/sleep infinity" + +- include: ../../start.yml + vars: + container_environment: + KOLLA_BOOTSTRAP: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + DB_ROOT_PASSWORD: "{{ database_password }}" + container_image: "{{ docker_database_image_full }}" + container_name: "mariadb" + container_volumes: + - "{{ node_config_directory }}/mariadb/:/opt/kolla/mariadb/:ro" + container_volumes_from: + - "mariadb_data" + when: delegate_host == 'None' and inventory_hostname == groups['database'][0] diff --git a/ansible/roles/database/tasks/config.yml b/ansible/roles/database/tasks/config.yml new file mode 100644 index 0000000000..a5f55483f5 --- /dev/null +++ b/ansible/roles/database/tasks/config.yml @@ -0,0 +1,10 @@ +--- + + +- include: ../../config.yml + vars: + config_source: + - "roles/database/templates/galera.cnf.j2" + config_template_dest: + - "{{ node_templates_directory }}/mariadb/galera.cnf_minimal" + config_dest: "{{ node_config_directory }}/mariadb/galera.cnf" diff --git a/ansible/roles/database/tasks/main.yml b/ansible/roles/database/tasks/main.yml index 559b4bd1cc..c7474dde55 100644 --- a/ansible/roles/database/tasks/main.yml +++ b/ansible/roles/database/tasks/main.yml @@ -1,7 +1,13 @@ --- -- name: Bringing up mariadb service(s) - docker_compose: - project_name: mariadb - compose_file: "{{ koalla_directory }}/compose/mariadb.yml" - command: up - no_recreate: true +- include: config.yml + +- include: bootstrap.yml + +- include: start.yml + +- include: register.yml + +# This will restart the container we initially used to bootstrap the cluster to +# make it match the other containers environment-wise. This also prevents a +# change from showing up when rerunning the playbooks +- include: start.yml diff --git a/ansible/roles/database/tasks/register.yml b/ansible/roles/database/tasks/register.yml new file mode 100644 index 0000000000..ba6021090d --- /dev/null +++ b/ansible/roles/database/tasks/register.yml @@ -0,0 +1,18 @@ +--- +- name: Creating haproxy mysql user + mysql_user: + login_host: "{{ database_address }}" + login_user: "{{ database_user }}" + login_password: "{{ database_password }}" + name: "haproxy" + password: "" + host: "%" + priv: "*.*:USAGE" + register: status + until: status|success + retries: 10 + delay: 5 + +- name: Cleaning up facts + set_fact: + delegate_host: "bootstraped" diff --git a/ansible/roles/database/tasks/start.yml b/ansible/roles/database/tasks/start.yml new file mode 100644 index 0000000000..e60d49d4e1 --- /dev/null +++ b/ansible/roles/database/tasks/start.yml @@ -0,0 +1,13 @@ +--- +- include: ../../start.yml + vars: + container_environment: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + container_image: "{{ docker_database_image_full }}" + container_name: "mariadb" + container_volumes: + - "{{ node_config_directory }}/mariadb/:/opt/kolla/mariadb/:ro" + container_volumes_from: + - "mariadb_data" + when: delegate_host != 'None' or + ( delegate_host == 'None' and inventory_hostname != groups['database'][0]) diff --git a/ansible/roles/database/templates/galera.cnf.j2 b/ansible/roles/database/templates/galera.cnf.j2 new file mode 100644 index 0000000000..9d9d725d4c --- /dev/null +++ b/ansible/roles/database/templates/galera.cnf.j2 @@ -0,0 +1,18 @@ +[mysqld] +bind-address={{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }} +binlog_format=ROW +default-storage-engine=innodb +innodb_autoinc_lock_mode=2 +query_cache_size=0 +query_cache_type=0 +innodb_log_file_size=48M + +wsrep_provider=/usr/lib64/galera/libgalera_smm.so +wsrep_cluster_address=gcomm://{% for host in groups['database'] %}{{ hostvars[host]['ansible_hostname'] }}{% if not loop.last %},{% endif %}{% endfor %} + +wsrep_cluster_name="{{ database_cluster_name }}" +wsrep_node_address={{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }} +wsrep_node_name={{ ansible_hostname }} +wsrep_sst_method=xtrabackup-v2 +wsrep_sst_auth={{ database_user }}:{{ database_password }} +wsrep_slave_threads=4 diff --git a/ansible/roles/start.yml b/ansible/roles/start.yml index 44d9b0c67c..8aadfb3fc2 100644 --- a/ansible/roles/start.yml +++ b/ansible/roles/start.yml @@ -9,22 +9,24 @@ # docker_api_version from docker-py, so we specify it here. This will be # removed when the bugfix makes it downstream -- name: Starting the container +- name: Starting container(s) docker: + command: "{{ container_command | default(None) }}" detach: "{{ container_detach | default('True') }}" - env: "{{ container_environment }}" + env: "{{ container_environment | default(None) }}" docker_api_version: "{{ docker_api_version }}" image: "{{ container_image }}" insecure_registry: "{{ docker_insecure_registry }}" name: "{{ container_name }}" - net: host + net: "host" password: "{{ docker_registry_password }}" privileged: "{{ container_privileged | default('False') }}" pull: "{{ docker_pull_policy }}" registry: "{{ docker_registry }}" restart_policy: "{{ docker_restart_policy }}" restart_policy_retry: "{{ docker_restart_policy_retry }}" - state: reloaded + state: "reloaded" username: "{{ docker_registry_username }}" volumes: "{{ container_volumes }}" + volumes_from: "{{ container_volumes_from | default([]) }}" run_once: "{{ run_once | default('False') }}" diff --git a/docker/centos/binary/galera/Dockerfile b/docker/centos/binary/galera/Dockerfile index ce5477097b..6e0e90f258 100644 --- a/docker/centos/binary/galera/Dockerfile +++ b/docker/centos/binary/galera/Dockerfile @@ -21,7 +21,8 @@ RUN echo "[mariadb]" > /etc/yum.repos.d/MariaDB.repo && \ tar \ expect -COPY config-galera.sh /opt/kolla/config-galera.sh -COPY start.sh /start.sh +COPY config-galera.sh /opt/kolla/config/ +COPY config-internal.sh config-external.sh /opt/kolla/ +COPY start.sh / CMD ["/start.sh"] diff --git a/docker/centos/binary/galera/config-external.sh b/docker/centos/binary/galera/config-external.sh new file mode 120000 index 0000000000..72a04836e7 --- /dev/null +++ b/docker/centos/binary/galera/config-external.sh @@ -0,0 +1 @@ +../../../common/galera/config-external.sh \ No newline at end of file diff --git a/docker/centos/binary/galera/config-internal.sh b/docker/centos/binary/galera/config-internal.sh new file mode 120000 index 0000000000..edab3d51fb --- /dev/null +++ b/docker/centos/binary/galera/config-internal.sh @@ -0,0 +1 @@ +../../../common/galera/config-internal.sh \ No newline at end of file diff --git a/docker/common/base/kolla-common.sh b/docker/common/base/kolla-common.sh index bd6a539a0b..5c07b375de 100644 --- a/docker/common/base/kolla-common.sh +++ b/docker/common/base/kolla-common.sh @@ -175,19 +175,19 @@ set_configs() { exec /opt/kolla/config-internal.sh ;; CONFIG_EXTERNAL_COPY_ALWAYS) - source /opt/kolla/config-exernal.sh + source /opt/kolla/config-external.sh ;; CONFIG_EXTERNAL_COPY_ONCE) if [[ -f /configured ]]; then echo 'INFO - This container has already been configured; Refusing to copy new configs' - return + else + source /opt/kolla/config-external.sh + touch /configured fi - source /opt/kolla/config-exernal.sh - touch /configured ;; *) - echo '$CONFIG_STRATEGY is not set properly' + echo '$KOLLA_CONFIG_STRATEGY is not set properly' exit 1 ;; esac diff --git a/docker/common/galera/config-external.sh b/docker/common/galera/config-external.sh new file mode 100644 index 0000000000..a90f7fe6f3 --- /dev/null +++ b/docker/common/galera/config-external.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Cluster configuration +if [[ -f /opt/kolla/mariadb/galera.cnf ]]; then + cp /opt/kolla/mariadb/galera.cnf /etc/my.cnf.d/galera.cnf + chown mysql: /etc/my.cnf.d/galera.cnf + chmod 0600 /etc/my.cnf.d/galera.cnf +fi diff --git a/docker/common/galera/config-galera.sh b/docker/common/galera/config-galera.sh index 9cbd2c7642..8aab3cfe11 100755 --- a/docker/common/galera/config-galera.sh +++ b/docker/common/galera/config-galera.sh @@ -1,13 +1,5 @@ #!/bin/bash -. /opt/kolla/kolla-common.sh - -check_required_vars DB_CLUSTER_BIND_ADDRESS DB_CLUSTER_NAME DB_CLUSTER_NODES \ - DB_ROOT_PASSWORD DB_CLUSTER_WSREP_METHOD - -CFG=/etc/my.cnf.d/server.cnf -DB_CLUSTER_INIT_SQL=/tmp/mysql-first-time.sql - function configure_files { crudini --set $CFG mariadb bind-address "${DB_CLUSTER_BIND_ADDRESS}" crudini --set $CFG mariadb binlog_format "ROW" @@ -30,8 +22,9 @@ function configure_files { crudini --set $CFG mariadb wsrep_sst_method "${DB_CLUSTER_WSREP_METHOD}" } -function bootstrap_database { - mysqld_safe & +function bootstrap_db { + mysqld_safe --wsrep-new-cluster & + # Waiting for deamon sleep 10 expect -c ' @@ -54,11 +47,14 @@ function bootstrap_database { expect "Reload privilege tables now?" send "y\r" expect eof' + + mysql -u root --password="${DB_ROOT_PASSWORD}" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '${DB_ROOT_PASSWORD}' WITH GRANT OPTION;" + mysql -u root --password="${DB_ROOT_PASSWORD}" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '${DB_ROOT_PASSWORD}' WITH GRANT OPTION;" mysqladmin -p"${DB_ROOT_PASSWORD}" shutdown } function configure_db { - bootstrap_database + bootstrap_db echo "GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '$DB_ROOT_PASSWORD' ;" > $DB_CLUSTER_INIT_SQL @@ -81,7 +77,7 @@ function populate_db { if [[ $(ls /var/lib/mysql) == "" ]]; then echo "POPULATING NEW DB" mysql_install_db - chown -R mysql /var/lib/mysql + chown -R mysql: /var/lib/mysql else echo "DB ALREADY EXISTS" fi diff --git a/docker/common/galera/config-internal.sh b/docker/common/galera/config-internal.sh new file mode 100755 index 0000000000..5e55dcde44 --- /dev/null +++ b/docker/common/galera/config-internal.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +. /opt/kolla/kolla-common.sh +. /opt/kolla/config-galera.sh + +check_required_vars DB_CLUSTER_BIND_ADDRESS DB_CLUSTER_NAME DB_CLUSTER_NODES \ + DB_ROOT_PASSWORD DB_CLUSTER_WSREP_METHOD DB_CLUSTER_INIT_DB + +CFG=/etc/my.cnf.d/server.cnf +DB_CLUSTER_INIT_SQL=/tmp/mysql-first-time.sql + +prepare_db + +if [[ "${DB_CLUSTER_INIT_DB}" == "true" ]] && ! [[ -a /var/lib/mysql/cluster.exists ]]; then + DB_CLUSTER_IS_MASTER_NODE="--wsrep-new-cluster" + touch /var/lib/mysql/cluster.exists +fi + +mysqld_safe --init-file=$DB_CLUSTER_INIT_SQL $DB_CLUSTER_IS_MASTER_NODE + diff --git a/docker/common/galera/start.sh b/docker/common/galera/start.sh index 2ac683f110..42bd882b1a 100755 --- a/docker/common/galera/start.sh +++ b/docker/common/galera/start.sh @@ -1,15 +1,25 @@ #!/bin/bash -. /opt/kolla/kolla-common.sh -. /opt/kolla/config-galera.sh +set -o errexit -check_required_vars DB_CLUSTER_INIT_DB -prepare_db +CMD="/usr/bin/mysqld_safe" +ARGS="" -if [[ "${DB_CLUSTER_INIT_DB}" == "true" ]] && ! [[ -a /var/lib/mysql/cluster.exists ]]; then - DB_CLUSTER_IS_MASTER_NODE="--wsrep-new-cluster" +# loading common functions +source /opt/kolla/kolla-common.sh + +# config-internal script exec out of this function, it does not return here +set_configs + +# loading functions +source /opt/kolla/config/config-galera.sh + +# This catches all cases of the BOOTSTRAP variable being set, including empty +if [[ "${!KOLLA_BOOTSTRAP[@]}" ]] && [[ ! -e /var/lib/mysql/cluster.exists ]]; then + ARGS="--wsrep-new-cluster" touch /var/lib/mysql/cluster.exists + populate_db + bootstrap_db fi -mysqld_safe --init-file=$DB_CLUSTER_INIT_SQL $DB_CLUSTER_IS_MASTER_NODE - +exec $CMD $ARGS