diff --git a/handlers/main.yml b/handlers/main.yml index 8c6985bc..1d058671 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -10,3 +10,6 @@ name: sentinel_{{ redis_sentinel_port }} state: restarted when: redis_as_service + +- name: "reconfigure sentinel {{ redis_sentinel_port }} monitors" + command: /etc/redis/sentinel_{{ redis_sentinel_port }}_config.sh diff --git a/tasks/dependencies.yml b/tasks/dependencies.yml index 8e4f7ee0..0cd25e38 100644 --- a/tasks/dependencies.yml +++ b/tasks/dependencies.yml @@ -9,6 +9,7 @@ - gcc - make - libc6-dev + - dnsutils # This should be `else omit`, but it fails on Ansible 1.x, so just duplicate gcc - "{{ 'libc6-dev-i386' if redis_make_32bit|bool else 'gcc' }}" when: ansible_os_family == "Debian" @@ -20,6 +21,7 @@ with_items: - gcc - make + - bind-utils when: ansible_os_family == "RedHat" # Conditionally install the i686 build of libgcc if we are building 32-bit diff --git a/tasks/sentinel.yml b/tasks/sentinel.yml index c53ebe55..03cbfe9d 100644 --- a/tasks/sentinel.yml +++ b/tasks/sentinel.yml @@ -101,14 +101,36 @@ - redis_sentinel_pidfile != '""' - not sentinel_piddir.stat.exists -- name: create sentinel config file +- name: check if sentinel dynamic config file exists + stat: + path: /etc/redis/sentinel_{{ redis_sentinel_port }}.conf + register: sentinel_config_file + +- name: create initial sentinel dynamic config file template: src: redis_sentinel.conf.j2 dest: /etc/redis/sentinel_{{ redis_sentinel_port }}.conf owner: "{{ redis_user }}" mode: 0640 + when: not sentinel_config_file.stat.exists + notify: "restart sentinel {{ redis_sentinel_port }}" + +- name: create static sentinel config file + template: + src: redis_sentinel.include.conf.j2 + dest: /etc/redis/sentinel_{{ redis_sentinel_port }}.include.conf + owner: "{{ redis_user }}" + mode: 0640 notify: "restart sentinel {{ redis_sentinel_port }}" +- name: create sentinel live config script + template: + src: redis_sentinel_config.sh.j2 + dest: /etc/redis/sentinel_{{ redis_sentinel_port }}_config.sh + owner: "{{ redis_user }}" + mode: 0750 + notify: "reconfigure sentinel {{ redis_sentinel_port }} monitors" + - name: add sentinel init config file template: dest: /etc/sysconfig/sentinel_{{ redis_sentinel_port }} diff --git a/tasks/server.yml b/tasks/server.yml index 84629e94..3a1e550f 100644 --- a/tasks/server.yml +++ b/tasks/server.yml @@ -101,12 +101,26 @@ - redis_pidfile != '""' - not piddir.stat.exists -- name: create redis config file +- name: check for dynamic redis config file + stat: + path: /etc/redis/{{ redis_port }}.conf + register: redis_config_file + +- name: create dynamic redis config file template: src: redis.conf.j2 dest: /etc/redis/{{ redis_port }}.conf owner: "{{ redis_user }}" mode: 0640 + when: not redis_config_file.stat.exists + notify: "restart redis {{ redis_port }}" + +- name: create static redis config file + template: + src: redis_include.conf.j2 + dest: /etc/redis/{{ redis_port }}.include.conf + owner: "{{ redis_user }}" + mode: 0640 notify: "restart redis {{ redis_port }}" - name: add redis init config file diff --git a/templates/redis.conf.j2 b/templates/redis.conf.j2 index d5bc6950..832ad9b1 100644 --- a/templates/redis.conf.j2 +++ b/templates/redis.conf.j2 @@ -1,99 +1,9 @@ # {{ ansible_managed }} +# Redis may rewrite this file, so most config can be found in the include. +# Those runtime Redis configs will be rewritten below the include, and override +# anything in it. -# General -daemonize {{ redis_daemonize }} -pidfile {{ redis_pidfile }} -dir {{ redis_dir }} -port {{ redis_port }} -bind {{ redis_bind }} -{% if redis_socket_path -%} -unixsocket {{ redis_socket_path }} -unixsocketperm {{ redis_socket_perm }} -{% endif -%} -timeout {{ redis_timeout }} -tcp-keepalive {{ redis_tcp_keepalive }} -tcp-backlog {{ redis_tcp_backlog }} -loglevel {{ redis_loglevel }} -logfile {{ redis_logfile }} -syslog-enabled {{ redis_syslog_enabled }} -syslog-ident {{ redis_syslog_ident }} -syslog-facility {{ redis_syslog_facility }} -databases {{ redis_databases }} +# If you need to revert to only the static config, remove everything after the +# include in this file. -# Snapshotting -{% for save in redis_save -%} -save {{ save }} -{% endfor -%} -stop-writes-on-bgsave-error {{ redis_stop_writes_on_bgsave_error|string }} -rdbcompression {{ redis_rdbcompression|string }} -rdbchecksum {{ redis_rdbchecksum|string }} -dbfilename dump.rdb - -# Replication -{% if redis_slaveof -%} -slaveof {{ redis_slaveof }} -{% endif -%} -slave-serve-stale-data yes -slave-read-only {{ redis_slave_read_only }} -repl-disable-tcp-nodelay no -{% if redis_repl_backlog_size -%} -repl-backlog-size {{ redis_repl_backlog_size }} -{% endif -%} -slave-priority {{ redis_slave_priority }} -{% if redis_min_slaves_to_write -%} -min-slaves-to-write {{ redis_min_slaves_to_write }} -{% endif -%} -{% if redis_min_slaves_max_lag -%} -min-slaves-max-lag {{ redis_min_slaves_max_lag }} -{% endif -%} -{% if redis_password -%} -masterauth {{ redis_password }} -{% endif -%} - -# Security -{% if redis_password -%} -requirepass {{ redis_password }} -{% endif -%} -{% for command in redis_rename_commands -%} -rename-command {{ command }} -{% endfor -%} - -# Limits -maxclients {{ redis_maxclients }} -{% if redis_maxmemory -%} -maxmemory {{ redis_maxmemory }} -{% endif -%} -maxmemory-policy {{ redis_maxmemory_policy }} - -# Append Only Mode -appendonly {{ redis_appendonly }} -appendfilename "{{ redis_appendfilename }}" -appendfsync {{ redis_appendfsync|string }} -no-appendfsync-on-rewrite {{ redis_no_appendfsync_on_rewrite }} -auto-aof-rewrite-percentage {{ redis_auto_aof_rewrite_percentage }} -auto-aof-rewrite-min-size {{ redis_auto_aof_rewrite_min_size }} - -# Lua -lua-time-limit 5000 - -# Slow Log -slowlog-log-slower-than {{ redis_slowlog_log_slower_than }} -slowlog-max-len {{ redis_slowlog_max_len }} - -# Event Notification -notify-keyspace-events {{ redis_notify_keyspace_events }} - -# Advanced -hash-max-ziplist-entries 512 -hash-max-ziplist-value 64 -list-max-ziplist-entries 512 -list-max-ziplist-value 64 -set-max-intset-entries 512 -zset-max-ziplist-entries 128 -zset-max-ziplist-value 64 -activerehashing yes -client-output-buffer-limit normal 0 0 0 -client-output-buffer-limit slave 256mb 64mb 60 -client-output-buffer-limit pubsub 32mb 8mb 60 -hz 10 -aof-rewrite-incremental-fsync yes +include /etc/redis/{{ redis_port }}.include.conf diff --git a/templates/redis_include.conf.j2 b/templates/redis_include.conf.j2 new file mode 100644 index 00000000..d5bc6950 --- /dev/null +++ b/templates/redis_include.conf.j2 @@ -0,0 +1,99 @@ +# {{ ansible_managed }} + +# General +daemonize {{ redis_daemonize }} +pidfile {{ redis_pidfile }} +dir {{ redis_dir }} +port {{ redis_port }} +bind {{ redis_bind }} +{% if redis_socket_path -%} +unixsocket {{ redis_socket_path }} +unixsocketperm {{ redis_socket_perm }} +{% endif -%} +timeout {{ redis_timeout }} +tcp-keepalive {{ redis_tcp_keepalive }} +tcp-backlog {{ redis_tcp_backlog }} +loglevel {{ redis_loglevel }} +logfile {{ redis_logfile }} +syslog-enabled {{ redis_syslog_enabled }} +syslog-ident {{ redis_syslog_ident }} +syslog-facility {{ redis_syslog_facility }} +databases {{ redis_databases }} + +# Snapshotting +{% for save in redis_save -%} +save {{ save }} +{% endfor -%} +stop-writes-on-bgsave-error {{ redis_stop_writes_on_bgsave_error|string }} +rdbcompression {{ redis_rdbcompression|string }} +rdbchecksum {{ redis_rdbchecksum|string }} +dbfilename dump.rdb + +# Replication +{% if redis_slaveof -%} +slaveof {{ redis_slaveof }} +{% endif -%} +slave-serve-stale-data yes +slave-read-only {{ redis_slave_read_only }} +repl-disable-tcp-nodelay no +{% if redis_repl_backlog_size -%} +repl-backlog-size {{ redis_repl_backlog_size }} +{% endif -%} +slave-priority {{ redis_slave_priority }} +{% if redis_min_slaves_to_write -%} +min-slaves-to-write {{ redis_min_slaves_to_write }} +{% endif -%} +{% if redis_min_slaves_max_lag -%} +min-slaves-max-lag {{ redis_min_slaves_max_lag }} +{% endif -%} +{% if redis_password -%} +masterauth {{ redis_password }} +{% endif -%} + +# Security +{% if redis_password -%} +requirepass {{ redis_password }} +{% endif -%} +{% for command in redis_rename_commands -%} +rename-command {{ command }} +{% endfor -%} + +# Limits +maxclients {{ redis_maxclients }} +{% if redis_maxmemory -%} +maxmemory {{ redis_maxmemory }} +{% endif -%} +maxmemory-policy {{ redis_maxmemory_policy }} + +# Append Only Mode +appendonly {{ redis_appendonly }} +appendfilename "{{ redis_appendfilename }}" +appendfsync {{ redis_appendfsync|string }} +no-appendfsync-on-rewrite {{ redis_no_appendfsync_on_rewrite }} +auto-aof-rewrite-percentage {{ redis_auto_aof_rewrite_percentage }} +auto-aof-rewrite-min-size {{ redis_auto_aof_rewrite_min_size }} + +# Lua +lua-time-limit 5000 + +# Slow Log +slowlog-log-slower-than {{ redis_slowlog_log_slower_than }} +slowlog-max-len {{ redis_slowlog_max_len }} + +# Event Notification +notify-keyspace-events {{ redis_notify_keyspace_events }} + +# Advanced +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 +list-max-ziplist-entries 512 +list-max-ziplist-value 64 +set-max-intset-entries 512 +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 +activerehashing yes +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit slave 256mb 64mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 +hz 10 +aof-rewrite-incremental-fsync yes diff --git a/templates/redis_sentinel.conf.j2 b/templates/redis_sentinel.conf.j2 index 624e5b1f..457da741 100644 --- a/templates/redis_sentinel.conf.j2 +++ b/templates/redis_sentinel.conf.j2 @@ -1,12 +1,6 @@ -# redis-sentinel {{ redis_version }} configuration file +# redis-sentinel {{ redis_version }} volatile configuration file # sentinel_{{ redis_sentinel_port }}.conf -daemonize {{ redis_daemonize }} -dir {{ redis_sentinel_dir }} -pidfile {{ redis_sentinel_pidfile }} -port {{ redis_sentinel_port }} -bind {{ redis_sentinel_bind }} - {% for master in redis_sentinel_monitors -%} sentinel monitor {{ master.name }} {{ master.host }} {{ master.port }} {{ master.quorum|d('2') }} {% for option in ('auth_pass', 'down_after_milliseconds', 'parallel_syncs', 'failover_timeout', 'notification_script', 'client_reconfig_script') -%} @@ -14,10 +8,6 @@ sentinel monitor {{ master.name }} {{ master.host }} {{ master.port }} {{ master sentinel {{ option|replace('_', '-') }} {{ master.name }} {{ master[option] }} {% endif %} {% endfor -%} - {% endfor -%} -logfile {{ redis_sentinel_logfile }} -syslog-enabled {{ redis_syslog_enabled }} -syslog-ident {{ redis_sentinel_syslog_ident }} -syslog-facility {{ redis_syslog_facility }} +include /etc/redis/sentinel_{{ redis_sentinel_port }}.include.conf diff --git a/templates/redis_sentinel.include.conf.j2 b/templates/redis_sentinel.include.conf.j2 new file mode 100644 index 00000000..a5a54bd5 --- /dev/null +++ b/templates/redis_sentinel.include.conf.j2 @@ -0,0 +1,12 @@ +# redis-sentinel {{ redis_version }} static configuration file +# sentinel_{{ redis_sentinel_port }}.include.conf + +daemonize {{ redis_daemonize }} +dir {{ redis_sentinel_dir }} +pidfile {{ redis_sentinel_pidfile }} +port {{ redis_sentinel_port }} +bind {{ redis_sentinel_bind }} +logfile {{ redis_sentinel_logfile }} +syslog-enabled {{ redis_syslog_enabled }} +syslog-ident {{ redis_sentinel_syslog_ident }} +syslog-facility {{ redis_syslog_facility }} diff --git a/templates/redis_sentinel_config.sh.j2 b/templates/redis_sentinel_config.sh.j2 new file mode 100644 index 00000000..54811ff4 --- /dev/null +++ b/templates/redis_sentinel_config.sh.j2 @@ -0,0 +1,12 @@ +#!/bin/sh +# This script is generated by Ansible to reconfigure Sentinel while running. +{% set cli = "/usr/bin/redis-cli -p " + (redis_sentinel_port|string) %} + +{% for master in redis_sentinel_monitors -%} +{{ cli }} sentinel monitor {{ master.name }} `dig +short {{ master.host }}` {{ master.port }} {{ master.quorum|d('2') }} +{% for option in ('auth_pass', 'down_after_milliseconds', 'parallel_syncs', 'failover_timeout', 'notification_script', 'client_reconfig_script') -%} +{% if master[option] is defined and master[option] -%} +{{ cli }} sentinel set {{ master.name }} {{ option|replace('_', '-') }} {{ master[option] }} +{% endif %} +{% endfor -%} +{% endfor -%} diff --git a/test/integration/default/serverspec/redis_spec.rb b/test/integration/default/serverspec/redis_spec.rb index faa4bcf3..9eeb25dd 100644 --- a/test/integration/default/serverspec/redis_spec.rb +++ b/test/integration/default/serverspec/redis_spec.rb @@ -11,6 +11,12 @@ end describe file('/etc/redis/6379.conf') do + it { should be_file } + it { should be_owned_by 'redis' } + its(:content) { should include "include /etc/redis/6379.include.conf" } + end + + describe file('/etc/redis/6379.include.conf') do it { should be_file } it { should be_owned_by 'redis' } its(:content) { should match /port 6379/ } diff --git a/test/integration/sentinel/serverspec/sentinel_spec.rb b/test/integration/sentinel/serverspec/sentinel_spec.rb index ff9d7dab..d4927eba 100644 --- a/test/integration/sentinel/serverspec/sentinel_spec.rb +++ b/test/integration/sentinel/serverspec/sentinel_spec.rb @@ -13,7 +13,20 @@ describe file('/etc/redis/sentinel_26379.conf') do it { should be_file } it { should be_owned_by 'redis' } - its(:content) { should match /port 26379/ } + its(:content) { should include "include /etc/redis/sentinel_26379.include.conf" } + end + + describe file('/etc/redis/sentinel_26379.include.conf') do + it { should be_file } + it { should be_owned_by 'redis' } + its(:content) { should include "port 26379" } + end + + describe file('/etc/redis/sentinel_26379_config.sh') do + it { should be_file } + it { should be_owned_by 'redis' } + it { should be_executable.by('group') } + its(:content) { should include "sentinel monitor master01 `dig +short localhost` 6379 2" } end describe file('/var/run/redis/sentinel_26379.pid') do