From e348b895149e11fd97638d5c967c182762f49453 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Tue, 15 Nov 2016 16:14:00 -0200 Subject: [PATCH 01/17] Add fact scripts to retrieve per-instance information Export Redis information (as retrieved by the INFO) command as local facts for each configured server/sentinel instance. Those facts are created in addition to the existing global facts, and are identified by keys in the form of `redis_{{ redis_port }}` and `redis_sentinel_{{ redis_sentinel_port }}`. --- README.md | 7 ++++ tasks/local_facts.yml | 15 ++++++++ templates/etc/ansible/facts.d/redis.fact.j2 | 2 +- .../ansible/facts.d/redis_instance.fact.j2 | 37 +++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 templates/etc/ansible/facts.d/redis_instance.fact.j2 diff --git a/README.md b/README.md index 4c519894..49cda874 100644 --- a/README.md +++ b/README.md @@ -307,4 +307,11 @@ The following facts are accessible in your inventory or tasks outside of this ro - `{{ ansible_local.redis.sentinel_port }}` - `{{ ansible_local.redis.sentinel_monitors }}` +Variables provided by the 'info' Redis command are also made available for each +configured server or sentinel instance. For example: + +- `{{ ansible_local.redis_6379.redis_version }}` +- `{{ ansible_local.redis_6379.role }}` +- `{{ ansible_local.redis_sentinel_26379.sentinel_masters }}` + To disable these facts, set `redis_local_facts` to a false value. diff --git a/tasks/local_facts.yml b/tasks/local_facts.yml index 0020d283..27447e19 100644 --- a/tasks/local_facts.yml +++ b/tasks/local_facts.yml @@ -2,8 +2,23 @@ file: path: /etc/ansible/facts.d state: directory + mode: 0755 - name: create redis facts template: src: etc/ansible/facts.d/redis.fact.j2 dest: /etc/ansible/facts.d/redis.fact + +- name: create redis instance facts + template: + src: etc/ansible/facts.d/redis_instance.fact.j2 + dest: /etc/ansible/facts.d/redis_{{ redis_port }}.fact + mode: 0755 + when: not redis_sentinel + +- name: create redis sentinel facts + template: + src: etc/ansible/facts.d/redis_instance.fact.j2 + dest: /etc/ansible/facts.d/redis_sentinel_{{ redis_sentinel_port }}.fact + mode: 0755 + when: redis_sentinel diff --git a/templates/etc/ansible/facts.d/redis.fact.j2 b/templates/etc/ansible/facts.d/redis.fact.j2 index a22aa173..d57998d1 100644 --- a/templates/etc/ansible/facts.d/redis.fact.j2 +++ b/templates/etc/ansible/facts.d/redis.fact.j2 @@ -4,4 +4,4 @@ "sentinel_bind": "{{ redis_sentinel_bind }}", "sentinel_port": "{{ redis_sentinel_port }}", "sentinel_monitors": {{ redis_sentinel_monitors | to_json }} -} \ No newline at end of file +} diff --git a/templates/etc/ansible/facts.d/redis_instance.fact.j2 b/templates/etc/ansible/facts.d/redis_instance.fact.j2 new file mode 100644 index 00000000..13a12de4 --- /dev/null +++ b/templates/etc/ansible/facts.d/redis_instance.fact.j2 @@ -0,0 +1,37 @@ +#!/bin/sh + +set -e + +REDIS_CLI="'{{ redis_install_dir }}/bin/redis-cli' -p {{ redis_sentinel_port if redis_sentinel else redis_port }}" +{% if redis_password %} +REDIS_CLI="$REDIS_CLI -a '{{ redis_password }}'" +{% endif %} + +{% if redis_sentinel | default %} +info_section=default +{% else %} +info_section=all +{% endif %} + +parse_info() { + first=1 + tr -d '\r' | while IFS=':' read key value; do + case "$key" in + ""|\#*) continue ;; + esac + + if [ $first -eq 1 ]; then + first=0 + printf '{\n' + else + printf ',\n' + fi + + printf ' "%s": "%s"' "$key" "$(echo "$value")" + done + unset first +} + +eval $REDIS_CLI info "$info_section" | parse_info + +printf '\n}\n' From 7adbe5435b7a61d61b6ac0a968e463230a804276 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Tue, 15 Nov 2016 20:16:19 -0200 Subject: [PATCH 02/17] Add instance facts tests --- .kitchen.yml | 1 + test/integration/facts/default.yml | 10 +++++++ .../facts/serverspec/facts_spec.rb | 30 +++++++++++++++++++ .../facts/serverspec/spec_helper.rb | 2 ++ 4 files changed, 43 insertions(+) create mode 100644 test/integration/facts/default.yml create mode 100644 test/integration/facts/serverspec/facts_spec.rb create mode 100644 test/integration/facts/serverspec/spec_helper.rb diff --git a/.kitchen.yml b/.kitchen.yml index 2eac8e04..679e528e 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -26,3 +26,4 @@ suites: - name: sentinel - name: checksum - name: service-name + - name: facts diff --git a/test/integration/facts/default.yml b/test/integration/facts/default.yml new file mode 100644 index 00000000..1c49dc63 --- /dev/null +++ b/test/integration/facts/default.yml @@ -0,0 +1,10 @@ +--- +- hosts: localhost + roles: + - role: ansible-redis + redis_sentinel: true + redis_local_facts: true + + - role: ansible-redis + redis_sentinel: false + redis_local_facts: true diff --git a/test/integration/facts/serverspec/facts_spec.rb b/test/integration/facts/serverspec/facts_spec.rb new file mode 100644 index 00000000..8418a2da --- /dev/null +++ b/test/integration/facts/serverspec/facts_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' +require 'json' + +describe 'Redis' do + describe service('redis_6379') do + it { should be_running } + end + + describe service('sentinel_26379') do + it { should be_running } + end + + describe command('/etc/ansible/facts.d/redis_6379.fact') do + its(:exit_status) { should eq 0 } + + it 'should return redis facts' do + facts = JSON.parse(subject.stdout) + facts.should have_key('redis_version') + end + end + + describe command('/etc/ansible/facts.d/redis_sentinel_26379.fact') do + its(:exit_status) { should eq 0 } + + it 'should return sentinel facts' do + facts = JSON.parse(subject.stdout) + facts.should have_key('sentinel_masters') + end + end +end diff --git a/test/integration/facts/serverspec/spec_helper.rb b/test/integration/facts/serverspec/spec_helper.rb new file mode 100644 index 00000000..590c2fa9 --- /dev/null +++ b/test/integration/facts/serverspec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'serverspec' +set :backend, :exec From c9b8b1f295186cbbb4adcca63bd0a25852fdeb02 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Wed, 16 Nov 2016 02:48:18 -0200 Subject: [PATCH 03/17] Add option to detect master/slave status from runtime status --- defaults/main.yml | 2 ++ tasks/local_facts.yml | 6 ++++++ tasks/main.yml | 8 ++++++-- tasks/runtime_roles.yml | 13 +++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tasks/runtime_roles.yml diff --git a/defaults/main.yml b/defaults/main.yml index 0d77e87d..efa6f0c4 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -41,6 +41,8 @@ redis_socket_perm: 755 ## Replication options # Set slaveof just as you would in redis.conf. (e.g. "redis01 6379") redis_slaveof: false +# Ignore manually assigned roles for instances if runtime status can be used instead +redis_runtime_replication_role: yes # Make slaves read-only. "yes" or "no" redis_slave_read_only: "yes" redis_slave_priority: 100 diff --git a/tasks/local_facts.yml b/tasks/local_facts.yml index 27447e19..701d5f7c 100644 --- a/tasks/local_facts.yml +++ b/tasks/local_facts.yml @@ -15,6 +15,7 @@ dest: /etc/ansible/facts.d/redis_{{ redis_port }}.fact mode: 0755 when: not redis_sentinel + register: redis_facts_install_result - name: create redis sentinel facts template: @@ -22,3 +23,8 @@ dest: /etc/ansible/facts.d/redis_sentinel_{{ redis_sentinel_port }}.fact mode: 0755 when: redis_sentinel + register: redis_sentinel_facts_install_result + +- name: refresh facts due to new fact scripts + setup: + when: redis_facts_install_result.changed or redis_sentinel_facts_install_result.changed diff --git a/tasks/main.yml b/tasks/main.yml index 0e6db240..476d7bb8 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,6 +1,12 @@ --- - include: check_vars.yml +- include: local_facts.yml + when: redis_local_facts|bool + +- include: runtime_roles.yml + when: not redis_sentinel and redis_runtime_replication_role + - include: install.yml - include: server.yml @@ -13,5 +19,3 @@ tags: - config -- include: local_facts.yml - when: redis_local_facts|bool diff --git a/tasks/runtime_roles.yml b/tasks/runtime_roles.yml new file mode 100644 index 00000000..f7d48dd7 --- /dev/null +++ b/tasks/runtime_roles.yml @@ -0,0 +1,13 @@ +- name: set redis to slave automatically + set_fact: + redis_slaveof: >- + {{ ansible_local[redis_service_name].master_host }} + {{ ansible_local[redis_service_name].master_port }} + when: > + ansible_local[redis_service_name].role|default() == 'slave' + +- name: set redis to master automatically + set_fact: + redis_slaveof: ~ + when: > + ansible_local[redis_service_name].role|default() == 'master' From 2f1d2addf65b8bfabea51d27a21116ed7eebc426 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 18:46:39 -0200 Subject: [PATCH 04/17] Don't enforce runtime master role if no slaves are connected --- tasks/runtime_roles.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tasks/runtime_roles.yml b/tasks/runtime_roles.yml index f7d48dd7..0de40c66 100644 --- a/tasks/runtime_roles.yml +++ b/tasks/runtime_roles.yml @@ -3,11 +3,12 @@ redis_slaveof: >- {{ ansible_local[redis_service_name].master_host }} {{ ansible_local[redis_service_name].master_port }} - when: > + when: >- ansible_local[redis_service_name].role|default() == 'slave' - name: set redis to master automatically set_fact: redis_slaveof: ~ - when: > - ansible_local[redis_service_name].role|default() == 'master' + when: >- + ansible_local[redis_service_name].role|default() == 'master' and + ansible_local[redis_service_name].connected_slaves|default(0)|int > 0 From ce93af807061e8058efb7e5edbb479ca3b508a77 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 18:47:19 -0200 Subject: [PATCH 05/17] Ensure /etc/redis is created with correct ownership --- tasks/install.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tasks/install.yml b/tasks/install.yml index 5ed37920..2c23cc34 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -91,11 +91,6 @@ path: "{{ redis_install_dir }}" state: directory -- name: create /etc/redis - file: - path: /etc/redis - state: directory - - name: add redis user user: name: "{{ redis_user }}" @@ -104,6 +99,12 @@ shell: /bin/false system: yes +- name: create /etc/redis + file: + path: /etc/redis + state: directory + owner: "{{ redis_user }}" + - name: create /var/run/redis file: path: /var/run/redis From de3f7dd0aca0f22cf0378d4ca181e223fe7d71ff Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 18:59:12 -0200 Subject: [PATCH 06/17] Install pre-daemon script to preserve config rewrites The script will copy over the contents of the main configuration file, then any new lines added to the running config file after the CONFIG REWRITE tag line. This way Redis Sentinel information and dynamic master/slave status is not lost when re-configuring instances. --- defaults/main.yml | 4 ++++ tasks/install.yml | 6 ++++++ templates/prepare-config.sh.j2 | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 templates/prepare-config.sh.j2 diff --git a/defaults/main.yml b/defaults/main.yml index efa6f0c4..afaffa67 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -59,6 +59,8 @@ redis_syslog_facility: USER ## General configuration redis_daemonize: "yes" redis_pidfile: /var/run/redis/{{ redis_port }}.pid +redis_dynamic_config_file: /etc/redis/{{ redis_port }}.run.conf + # Number of databases to allow redis_databases: 16 redis_loglevel: notice @@ -94,6 +96,8 @@ redis_sentinel_bind: 0.0.0.0 redis_sentinel_port: 26379 redis_sentinel_pidfile: /var/run/redis/sentinel_{{ redis_sentinel_port }}.pid redis_sentinel_logfile: '""' +redis_sentinel_dynamic_config_file: /etc/redis/sentinel_{{ redis_sentinel_port }}.run.conf + redis_sentinel_syslog_ident: sentinel_{{ redis_sentinel_port }} redis_sentinel_monitors: - name: master01 diff --git a/tasks/install.yml b/tasks/install.yml index 2c23cc34..067cfbee 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -116,3 +116,9 @@ args: chdir: /usr/local/src/redis-{{ redis_version }} creates: "{{ redis_install_dir }}/bin/redis-server" + +- name: add config preparation script + template: + dest: "{{ redis_install_dir }}/bin/prepare-config.sh" + src: prepare-config.sh.j2 + mode: 0755 diff --git a/templates/prepare-config.sh.j2 b/templates/prepare-config.sh.j2 new file mode 100644 index 00000000..5094bff8 --- /dev/null +++ b/templates/prepare-config.sh.j2 @@ -0,0 +1,34 @@ +#!/bin/bash + +set -ex + +static_cfg="$1" +dyn_cfg="$2" + +[ -f "$static_cfg" ] || exit 1 + +filter_cfg() { + local myid_seen=0 + while read line; do + if [[ "$line" == 'sentinel myid'* ]]; then + if [ $myid_seen -eq 0]; then + myid_seen=1 + else + continue + fi + fi + + echo "$line" + done +} + +mkdir -p "$(dirname "$dyn_cfg")" +if [ ! -f "$dyn_cfg" ]; then + cp "$static_cfg" "$dyn_cfg" +else + dyn_cfg_data=$(sed -n '/CONFIG REWRITE/,$p' "$dyn_cfg"; + grep -F 'sentinel myid' "$dyn_cfg" || :) + cat "$static_cfg" - <<< "$dyn_cfg_data" | filter_cfg > "$dyn_cfg" +fi + +chown -R redis:redis "$(dirname "$dyn_cfg")" From 05886a69ec0cb60c3514be0cb7dc6e974eb62741 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 18:59:41 -0200 Subject: [PATCH 07/17] Run pre-daemon config script (Debian) --- templates/Debian/redis.init.j2 | 7 ++++++- templates/Debian/redis_sentinel.init.j2 | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/templates/Debian/redis.init.j2 b/templates/Debian/redis.init.j2 index dd34995f..28e01135 100644 --- a/templates/Debian/redis.init.j2 +++ b/templates/Debian/redis.init.j2 @@ -26,7 +26,10 @@ PIDFILE_DIR=$(dirname "${PIDFILE}") REDIS_USER={{ redis_user }} CONF="/etc/redis/${REDIS_PORT}.conf" +DYN_CONF="{{ redis_dynamic_config_file }}" + CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${REDIS_PORT}" +PREPARE_CONFIG_SCRIPT={{ redis_install_dir }}/bin/prepare-config.sh if [ -r /etc/default/redis_${REDIS_PORT} ]; then . /etc/default/redis_${REDIS_PORT} @@ -50,6 +53,8 @@ case "$1" in ulimit -n $NOFILE_LIMIT fi + $PREPARE_CONFIG_SCRIPT "$CONF" "$DYN_CONF" + if [ ! -d "$PIDFILE_DIR" ]; then mkdir "$PIDFILE_DIR" chown ${REDIS_USER}:${REDIS_USER} "$PIDFILE_DIR" @@ -57,7 +62,7 @@ case "$1" in fi log_daemon_msg "Starting $NAME..." - if start-stop-daemon --start -q --oknodo -p "$PIDFILE" -c $REDIS_USER --exec $DAEMON -- $CONF; then + if start-stop-daemon --start -q --oknodo -p "$PIDFILE" -c $REDIS_USER --exec $DAEMON -- $DYN_CONF; then log_end_msg 0 else log_end_msg 1 diff --git a/templates/Debian/redis_sentinel.init.j2 b/templates/Debian/redis_sentinel.init.j2 index 9ee1b158..1f2ca737 100644 --- a/templates/Debian/redis_sentinel.init.j2 +++ b/templates/Debian/redis_sentinel.init.j2 @@ -26,7 +26,10 @@ PIDFILE_DIR=$(dirname "${PIDFILE}") REDIS_USER={{ redis_user }} CONF="/etc/redis/sentinel_${SENTINEL_PORT}.conf" +DYN_CONF="{{ redis_sentinel_dynamic_config_file }}" + CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${SENTINEL_PORT}" +PREPARE_CONFIG_SCRIPT={{ redis_install_dir }}/bin/prepare-config.sh if [ -r /etc/default/sentinel_${SENTINEL_PORT} ]; then . /etc/default/sentinel_${SENTINEL_PORT} @@ -50,6 +53,8 @@ case "$1" in ulimit -n $NOFILE_LIMIT fi + $PREPARE_CONFIG_SCRIPT "$CONF" "$DYN_CONF" + if [ ! -d "$PIDFILE_DIR" ]; then mkdir "$PIDFILE_DIR" chown ${REDIS_USER}:${REDIS_USER} "$PIDFILE_DIR" From b4ba39711207a5b0cf896a086145ab7d30b99ee1 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 19:00:53 -0200 Subject: [PATCH 08/17] Run pre-daemon config script (RedHat) --- templates/RedHat/redis.init.j2 | 7 ++++++- templates/RedHat/redis_sentinel.init.j2 | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/templates/RedHat/redis.init.j2 b/templates/RedHat/redis.init.j2 index 2b34d7ad..6db0ef7d 100644 --- a/templates/RedHat/redis.init.j2 +++ b/templates/RedHat/redis.init.j2 @@ -18,8 +18,10 @@ fi REDIS_USER={{ redis_user }} PIDFILE={{ redis_pidfile }} CONF="/etc/redis/${REDIS_PORT}.conf" +DYN_CONF="{{ redis_dynamic_config_file }}" EXEC={{ redis_install_dir }}/bin/redis-server CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${REDIS_PORT}" +PREPARE_CONFIG_SCRIPT={{ redis_install_dir }}/bin/prepare-config.sh if [ -n "$REDIS_PASSWORD" ]; then CLIEXEC="${CLIEXEC} -a ${REDIS_PASSWORD}" @@ -38,8 +40,11 @@ case "$1" in if [ -n "$NOFILE_LIMIT" ]; then ulimit -n $NOFILE_LIMIT fi + + $PREPARE_CONFIG_SCRIPT "$CONF" "$DYN_CONF" + echo "Starting Redis server..." - daemon --user $REDIS_USER $EXEC $CONF + daemon --user $REDIS_USER $EXEC $DYN_CONF fi ;; stop) diff --git a/templates/RedHat/redis_sentinel.init.j2 b/templates/RedHat/redis_sentinel.init.j2 index a6f8754d..4b687df3 100644 --- a/templates/RedHat/redis_sentinel.init.j2 +++ b/templates/RedHat/redis_sentinel.init.j2 @@ -19,8 +19,10 @@ REDIS_USER={{ redis_user }} BIND_ADDRESS={{ redis_sentinel_bind }} PIDFILE={{ redis_sentinel_pidfile }} CONF="/etc/redis/sentinel_${SENTINEL_PORT}.conf" +DYN_CONF="{{ redis_sentinel_dynamic_config_file }}" EXEC={{ redis_install_dir }}/bin/redis-server CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${SENTINEL_PORT}" +PREPARE_CONFIG_SCRIPT={{ redis_install_dir }}/bin/prepare-config.sh if [ -n "$REDIS_PASSWORD" ]; then CLIEXEC="${CLIEXEC} -a ${REDIS_PASSWORD}" @@ -39,8 +41,11 @@ case "$1" in if [ -n "$NOFILE_LIMIT" ]; then ulimit -n $NOFILE_LIMIT fi + + $PREPARE_CONFIG_SCRIPT "$CONF" "$DYN_CONF" + echo "Starting Redis Sentinel..." - daemon --user $REDIS_USER $EXEC $CONF --sentinel + daemon --user $REDIS_USER $EXEC $DYN_CONF --sentinel fi ;; stop) From 8483d8721f98bf206a1c6d68abe950d6be312582 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 19:01:32 -0200 Subject: [PATCH 09/17] Run pre-daemon config script (generic) --- templates/default/redis.init.j2 | 7 ++++++- templates/default/redis_sentinel.init.j2 | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/templates/default/redis.init.j2 b/templates/default/redis.init.j2 index 9090cb1c..765366fe 100644 --- a/templates/default/redis.init.j2 +++ b/templates/default/redis.init.j2 @@ -6,6 +6,7 @@ REDIS_PORT={{ redis_port }} REDIS_USER={{ redis_user }} EXEC={{ redis_install_dir }}/bin/redis-server +PREPARE_CONFIG_SCRIPT={{ redis_install_dir }}/bin/prepare-config.sh {% if redis_password -%} CLIEXEC='{{ redis_install_dir }}/bin/redis-cli -a {{ redis_password }}' {% else -%} @@ -14,6 +15,7 @@ CLIEXEC={{ redis_install_dir }}/bin/redis-cli PIDFILE={{ redis_pidfile }} CONF="/etc/redis/${REDIS_PORT}.conf" +DYN_CONF="{{ redis_dynamic_config_file }}" case "$1" in start) @@ -22,8 +24,11 @@ case "$1" in echo "$PIDFILE exists, process is already running or crashed" else ulimit -n {{ redis_nofile_limit }} + + $PREPARE_CONFIG_SCRIPT "$CONF" "$DYN_CONF" + echo "Starting Redis server..." - su $REDIS_USER -c "$EXEC $CONF" + su $REDIS_USER -c "$EXEC $DYN_CONF" fi ;; stop) diff --git a/templates/default/redis_sentinel.init.j2 b/templates/default/redis_sentinel.init.j2 index 90088894..d5a20e12 100644 --- a/templates/default/redis_sentinel.init.j2 +++ b/templates/default/redis_sentinel.init.j2 @@ -7,6 +7,7 @@ SENTINEL_PORT={{ redis_sentinel_port }} REDIS_USER={{ redis_user }} BIND_ADDRESS={{ redis_sentinel_bind }} EXEC={{ redis_install_dir }}/bin/redis-server +PREPARE_CONFIG_SCRIPT={{ redis_install_dir }}/bin/prepare-config.sh {% if redis_password -%} CLIEXEC='{{ redis_install_dir }}/bin/redis-cli -a {{ redis_password }}' {% else -%} @@ -15,6 +16,7 @@ CLIEXEC={{ redis_install_dir }}/bin/redis-cli PIDFILE={{ redis_sentinel_pidfile }} CONF="/etc/redis/sentinel_${SENTINEL_PORT}.conf" +DYN_CONF="{{ redis_sentinel_dynamic_config_file }}" case "$1" in start) @@ -23,8 +25,11 @@ case "$1" in echo "$PIDFILE exists, process is already running or crashed" else ulimit -n {{ redis_nofile_limit }} + + $PREPARE_CONFIG_SCRIPT "$CONF" "$DYN_CONF" + echo "Starting Redis Sentinel..." - su $REDIS_USER -c "$EXEC $CONF --sentinel" + su $REDIS_USER -c "$EXEC $DYN_CONF --sentinel" fi ;; stop) From 11503090f142ea400eedbbbb1158df2ded48833d Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 19:01:55 -0200 Subject: [PATCH 10/17] Run pre-daemon config script (systemd) --- templates/default/redis.service.j2 | 3 ++- templates/default/redis_sentinel.service.j2 | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/default/redis.service.j2 b/templates/default/redis.service.j2 index 563ea6f2..e50aa3f3 100644 --- a/templates/default/redis.service.j2 +++ b/templates/default/redis.service.j2 @@ -7,7 +7,8 @@ Documentation=http://redis.io/documentation, man:redis-server(1) Type={{ 'forking' if redis_daemonize == 'yes' else 'simple' }} ExecStartPre=-/bin/mkdir {{ redis_pidfile|dirname }} ExecStartPre=/bin/chown -R {{ redis_user }}:{{ redis_group }} {{ redis_pidfile|dirname }} -ExecStart={{ redis_install_dir }}/bin/redis-server /etc/redis/{{ redis_port }}.conf +ExecStartPre={{ redis_install_dir }}/bin/prepare-config.sh /etc/redis/{{ redis_port }}.conf {{ redis_dynamic_config_file }} +ExecStart="{{ redis_install_dir }}/bin/redis-server" "{{ redis_dynamic_config_file }}" EnvironmentFile=-/etc/default/redis_{{ redis_port }} PIDFile={{ redis_pidfile }} TimeoutStopSec=0 diff --git a/templates/default/redis_sentinel.service.j2 b/templates/default/redis_sentinel.service.j2 index d5c7bbdf..34c2cdb7 100644 --- a/templates/default/redis_sentinel.service.j2 +++ b/templates/default/redis_sentinel.service.j2 @@ -7,7 +7,8 @@ Documentation=http://redis.io/documentation, man:redis-sentinel(1) Type={{ 'forking' if redis_daemonize == 'yes' else 'simple' }} ExecStartPre=-/bin/mkdir {{ redis_sentinel_pidfile|dirname }} ExecStartPre=/bin/chown -R {{ redis_user }}:{{ redis_group }} {{ redis_sentinel_pidfile|dirname }} -ExecStart={{ redis_install_dir }}/bin/redis-server /etc/redis/sentinel_{{ redis_sentinel_port }}.conf --sentinel +ExecStartPre={{ redis_install_dir }}/bin/prepare-config.sh /etc/redis/sentinel_{{ redis_sentinel_port }}.conf {{ redis_sentinel_dynamic_config_file }} +ExecStart={{ redis_install_dir }}/bin/redis-server {{ redis_sentinel_dynamic_config_file }} --sentinel EnvironmentFile=-/etc/default/sentinel_{{ redis_sentinel_port }} PIDFile={{ redis_sentinel_pidfile }} TimeoutStopSec=0 From 102b7f87ff34f6ec14573db51b2783acf1fc2ec0 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 19:31:03 -0200 Subject: [PATCH 11/17] Don't daemonize by default when systemd is used --- defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defaults/main.yml b/defaults/main.yml index afaffa67..67f69917 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -57,7 +57,7 @@ redis_syslog_ident: "{{ redis_service_name }}" redis_syslog_facility: USER ## General configuration -redis_daemonize: "yes" +redis_daemonize: "{{ 'no' if ansible_service_mgr|default() == 'systemd' else 'yes' }}" redis_pidfile: /var/run/redis/{{ redis_port }}.pid redis_dynamic_config_file: /etc/redis/{{ redis_port }}.run.conf From 14e1ac72787aed8797f97d4b0ae8a09be7fcfb5b Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Thu, 24 Nov 2016 19:45:38 -0200 Subject: [PATCH 12/17] Fix role detection when instance facts are not loaded --- tasks/runtime_roles.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasks/runtime_roles.yml b/tasks/runtime_roles.yml index 0de40c66..10320e38 100644 --- a/tasks/runtime_roles.yml +++ b/tasks/runtime_roles.yml @@ -4,11 +4,13 @@ {{ ansible_local[redis_service_name].master_host }} {{ ansible_local[redis_service_name].master_port }} when: >- + redis_service_name in ansible_local and ansible_local[redis_service_name].role|default() == 'slave' - name: set redis to master automatically set_fact: redis_slaveof: ~ when: >- + redis_service_name in ansible_local and ansible_local[redis_service_name].role|default() == 'master' and ansible_local[redis_service_name].connected_slaves|default(0)|int > 0 From 2717edfe1c7eab791a9b8e099df33482333ce29c Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Fri, 25 Nov 2016 17:42:30 -0200 Subject: [PATCH 13/17] Restart services when init scripts/services change --- tasks/sentinel.yml | 3 +++ tasks/server.yml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tasks/sentinel.yml b/tasks/sentinel.yml index ec5e6645..bc7eaeb3 100644 --- a/tasks/sentinel.yml +++ b/tasks/sentinel.yml @@ -20,6 +20,7 @@ paths: - ../templates when: redis_as_service and ansible_service_mgr|default() != 'systemd' + notify: restart sentinel - name: create sentinel systemd service template: @@ -33,6 +34,8 @@ paths: - ../templates when: redis_as_service and ansible_service_mgr|default() == 'systemd' + notify: restart sentinel + - name: set sentinel to start at boot service: diff --git a/tasks/server.yml b/tasks/server.yml index 54067244..67c300c3 100644 --- a/tasks/server.yml +++ b/tasks/server.yml @@ -20,6 +20,7 @@ paths: - ../templates when: redis_as_service and ansible_service_mgr | default != 'systemd' + notify: restart redis - name: create redis systemd service template: @@ -33,6 +34,7 @@ paths: - ../templates when: redis_as_service and ansible_service_mgr | default == 'systemd' + notify: restart redis - name: set redis to start at boot service: From 6d5b53fed23e551cdb7696d8eacc86945a55d0f7 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Fri, 25 Nov 2016 17:43:33 -0200 Subject: [PATCH 14/17] Explicitly run systemd module with daemon-reload when necessary The service module doesn't accept implementation-specific arguments before Ansible 2.2. --- tasks/sentinel.yml | 9 +++++++-- tasks/server.yml | 14 ++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tasks/sentinel.yml b/tasks/sentinel.yml index bc7eaeb3..03478426 100644 --- a/tasks/sentinel.yml +++ b/tasks/sentinel.yml @@ -36,13 +36,18 @@ when: redis_as_service and ansible_service_mgr|default() == 'systemd' notify: restart sentinel +- name: set sentinel to start at boot (systemd) + systemd: + name: sentinel_{{ redis_sentinel_port }} + enabled: yes + daemon_reload: yes + when: redis_as_service and ansible_service_mgr|default() == 'systemd' - name: set sentinel to start at boot service: name: sentinel_{{ redis_sentinel_port }} enabled: yes - daemon_reload: "{{ True if ansible_service_mgr|default() == 'systemd' else omit }}" - when: redis_as_service + when: redis_as_service and ansible_service_mgr|default() != 'systemd' # Check then create log dir to prevent aggressively overwriting permissions - name: check if sentinel log directory exists diff --git a/tasks/server.yml b/tasks/server.yml index 67c300c3..5c5f7ad1 100644 --- a/tasks/server.yml +++ b/tasks/server.yml @@ -19,7 +19,7 @@ - default/redis.init.j2 paths: - ../templates - when: redis_as_service and ansible_service_mgr | default != 'systemd' + when: redis_as_service and ansible_service_mgr|default != 'systemd' notify: restart redis - name: create redis systemd service @@ -33,15 +33,21 @@ - default/redis.service.j2 paths: - ../templates - when: redis_as_service and ansible_service_mgr | default == 'systemd' + when: redis_as_service and ansible_service_mgr|default == 'systemd' notify: restart redis +- name: set redis to start at boot (systemd) + systemd: + name: "{{ redis_service_name }}" + enabled: yes + daemon_reload: yes + when: redis_as_service and ansible_service_mgr|default == 'systemd' + - name: set redis to start at boot service: name: "{{ redis_service_name }}" enabled: yes - daemon_reload: "{{ True if ansible_service_mgr | default == 'systemd' else omit }}" - when: redis_as_service + when: redis_as_service and ansible_service_mgr|default != 'systemd' # Check then create log dir to prevent aggressively overwriting permissions - name: check if log directory exists From 06ceaa08da03eb06604bf30a451e3b5ab186cb69 Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Fri, 25 Nov 2016 17:45:27 -0200 Subject: [PATCH 15/17] Fix Redis sentinel configuration file permissions The Sentinel config file contains the Redis password, and therefore, cannot be publicly readable. Also ensure files have the redis group set. --- tasks/sentinel.yml | 3 +++ tasks/server.yml | 1 + 2 files changed, 4 insertions(+) diff --git a/tasks/sentinel.yml b/tasks/sentinel.yml index 03478426..88a7fc94 100644 --- a/tasks/sentinel.yml +++ b/tasks/sentinel.yml @@ -97,6 +97,7 @@ src: redis_sentinel.conf.j2 dest: /etc/redis/sentinel_{{ redis_sentinel_port }}.conf owner: "{{ redis_user }}" + group: "{{ redis_group }}" mode: 0640 notify: restart sentinel @@ -104,6 +105,7 @@ template: dest: /etc/sysconfig/sentinel_{{ redis_sentinel_port }} src: redis.init.conf.j2 + mode: 0600 when: ansible_os_family == "RedHat" notify: restart sentinel @@ -111,6 +113,7 @@ template: dest: /etc/default/sentinel_{{ redis_sentinel_port }} src: redis.init.conf.j2 + mode: 0600 when: ansible_os_family == "Debian" notify: restart sentinel diff --git a/tasks/server.yml b/tasks/server.yml index 5c5f7ad1..9e5b5313 100644 --- a/tasks/server.yml +++ b/tasks/server.yml @@ -97,6 +97,7 @@ src: redis.conf.j2 dest: /etc/redis/{{ redis_port }}.conf owner: "{{ redis_user }}" + group: "{{ redis_group }}" mode: 0640 notify: restart redis From fa8e1a8a75b3915995b991201c2c13e4419be60e Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Fri, 25 Nov 2016 17:49:10 -0200 Subject: [PATCH 16/17] Update prepare-config script - Reduce verbosity - Only set permissions of dynamic config file (not it's containing directory) - Correctly use redis user and group from template --- templates/prepare-config.sh.j2 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/templates/prepare-config.sh.j2 b/templates/prepare-config.sh.j2 index 5094bff8..47c6bb80 100644 --- a/templates/prepare-config.sh.j2 +++ b/templates/prepare-config.sh.j2 @@ -1,6 +1,9 @@ #!/bin/bash -set -ex +set -e + +redis_user="{{ redis_user }}" +redis_group="{{ redis_group }}" static_cfg="$1" dyn_cfg="$2" @@ -29,6 +32,6 @@ else dyn_cfg_data=$(sed -n '/CONFIG REWRITE/,$p' "$dyn_cfg"; grep -F 'sentinel myid' "$dyn_cfg" || :) cat "$static_cfg" - <<< "$dyn_cfg_data" | filter_cfg > "$dyn_cfg" + chown "$redis_user:$redis_group" "$dyn_cfg" + chmod 0640 "$dyn_cfg" fi - -chown -R redis:redis "$(dirname "$dyn_cfg")" From 14e92d672e02177e701b396efb5ce18182475b2f Mon Sep 17 00:00:00 2001 From: Daniel Miranda Date: Fri, 25 Nov 2016 20:19:23 -0200 Subject: [PATCH 17/17] Fix systemd daemon-reload in pre-2.2 Ansible --- tasks/sentinel.yml | 12 +++++------- tasks/server.yml | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/tasks/sentinel.yml b/tasks/sentinel.yml index 88a7fc94..7d970ed2 100644 --- a/tasks/sentinel.yml +++ b/tasks/sentinel.yml @@ -34,20 +34,18 @@ paths: - ../templates when: redis_as_service and ansible_service_mgr|default() == 'systemd' + register: redis_sentinel_systemd_service_install notify: restart sentinel -- name: set sentinel to start at boot (systemd) - systemd: - name: sentinel_{{ redis_sentinel_port }} - enabled: yes - daemon_reload: yes - when: redis_as_service and ansible_service_mgr|default() == 'systemd' +- name: systemd daemon reload + command: systemctl daemon-reload + when: redis_sentinel_systemd_service_install.changed - name: set sentinel to start at boot service: name: sentinel_{{ redis_sentinel_port }} enabled: yes - when: redis_as_service and ansible_service_mgr|default() != 'systemd' + when: redis_as_service # Check then create log dir to prevent aggressively overwriting permissions - name: check if sentinel log directory exists diff --git a/tasks/server.yml b/tasks/server.yml index 9e5b5313..ea874272 100644 --- a/tasks/server.yml +++ b/tasks/server.yml @@ -34,20 +34,18 @@ paths: - ../templates when: redis_as_service and ansible_service_mgr|default == 'systemd' + register: redis_systemd_service_install notify: restart redis -- name: set redis to start at boot (systemd) - systemd: - name: "{{ redis_service_name }}" - enabled: yes - daemon_reload: yes - when: redis_as_service and ansible_service_mgr|default == 'systemd' +- name: systemd daemon reload + command: systemctl daemon-reload + when: redis_systemd_service_install.changed - name: set redis to start at boot service: name: "{{ redis_service_name }}" enabled: yes - when: redis_as_service and ansible_service_mgr|default != 'systemd' + when: redis_as_service # Check then create log dir to prevent aggressively overwriting permissions - name: check if log directory exists