├── .gitignore ├── .kitchen.yml ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── tasks ├── check_vars.yml ├── dependencies.yml ├── download.yml ├── install.yml ├── install_from_repo.yml ├── local_facts.yml ├── main.yml ├── sentinel.yml └── server.yml ├── templates ├── Debian │ ├── redis.init.j2 │ └── redis_sentinel.init.j2 ├── RedHat │ ├── redis.init.j2 │ └── redis_sentinel.init.j2 ├── default │ ├── redis.init.j2 │ ├── redis.service.j2 │ ├── redis_sentinel.init.j2 │ └── redis_sentinel.service.j2 ├── etc │ ├── ansible │ │ └── facts.d │ │ │ └── redis.fact.j2 │ └── tmpfiles.d │ │ └── redis.conf.j2 ├── redis.conf.j2 ├── redis.init.conf.j2 └── redis_sentinel.conf.j2 ├── test ├── integration │ ├── checksum │ │ ├── default.yml │ │ └── serverspec │ │ │ ├── redis_spec.rb │ │ │ └── spec_helper.rb │ ├── default │ │ ├── default.yml │ │ └── serverspec │ │ │ ├── redis_spec.rb │ │ │ └── spec_helper.rb │ ├── logfile │ │ ├── default.yml │ │ └── serverspec │ │ │ ├── log_spec.rb │ │ │ └── spec_helper.rb │ ├── sentinel │ │ ├── default.yml │ │ └── serverspec │ │ │ ├── sentinel_spec.rb │ │ │ └── spec_helper.rb │ └── service-name │ │ ├── default.yml │ │ └── serverspec │ │ ├── redis_spec.rb │ │ └── spec_helper.rb ├── test_all.yml ├── test_sentinel.yml └── test_server.yml └── vars └── main.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .kitchen/ 3 | .bundle 4 | .vagrant 5 | *.retry 6 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | provisioner: 6 | name: ansible_playbook 7 | ansible_verbose: true 8 | ansible_verbosity: 2 9 | require_ruby_for_busser: false 10 | require_chef_for_busser: true 11 | hosts: all 12 | 13 | platforms: 14 | - name: ubuntu-14.04 15 | - name: centos-6.7 16 | driver_config: 17 | box: wittman/centos-6.8-ansible 18 | - name: centos-7.3 19 | driver_config: 20 | box: wittman/centos-7.3-ansible 21 | - name: ubuntu-16.04 22 | 23 | suites: 24 | - name: default 25 | - name: logfile 26 | - name: sentinel 27 | - name: checksum 28 | - name: service-name 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | python: "2.7" 4 | 5 | env: 6 | - ANSIBLE_VERSION=2.4.0 7 | - ANSIBLE_VERSION=latest 8 | 9 | before_install: 10 | - sudo apt-get update -qq 11 | 12 | install: 13 | - if [ "$ANSIBLE_VERSION" = "latest" ]; then pip install ansible; else pip install ansible==$ANSIBLE_VERSION; fi 14 | - "{ echo '[defaults]'; echo 'roles_path = ../'; } >> ansible.cfg" 15 | 16 | script: 17 | # Syntax check 18 | - "ansible-playbook -i localhost, test/test_server.yml --syntax-check" 19 | - "ansible-playbook -i localhost, test/test_sentinel.yml --syntax-check" 20 | # Test Redis Server 21 | - "ansible-playbook -i localhost, test/test_server.yml --connection=local --become" 22 | # Idempotency check 23 | - > 24 | ansible-playbook -i localhost, test/test_server.yml --connection=local --become 25 | | grep -q 'changed=0.*failed=0' 26 | && (echo 'Idempotency: PASS' && exit 0) 27 | || (echo 'Idempotency: FAIL' && exit 1) 28 | # Test Redis Sentinel 29 | - "ansible-playbook -i localhost, test/test_sentinel.yml --connection=local --become" 30 | - > 31 | ansible-playbook -i localhost, test/test_sentinel.yml --connection=local --become 32 | | grep -q 'changed=0.*failed=0' 33 | && (echo 'Idempotency: PASS' && exit 0) 34 | || (echo 'Idempotency: FAIL' && exit 1) 35 | # Connection test 36 | - "/opt/redis/bin/redis-cli PING" 37 | - "/opt/redis/bin/redis-cli -p 26379 PING" 38 | # Facts syntax check 39 | - > 40 | sudo cat /etc/ansible/facts.d/redis.fact 41 | | python -m json.tool 42 | && (echo 'Facts syntax: PASS' && exit 0) 43 | || (echo 'Facts syntax: FAIL' && exit 1) 44 | # Test all replication components (server, slave, sentinel) 45 | # No idempotency check here (yet) because the sentinel config writes to itself 46 | # after a config is discovered from the Redis server. 47 | - ansible-playbook -i localhost, test/test_all.yml --connection=local --become 48 | 49 | notifications: 50 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 51 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "test-kitchen" 4 | gem "kitchen-ansible" 5 | gem "kitchen-vagrant" 6 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | builder (3.2.3) 5 | erubis (2.7.0) 6 | ffi (1.12.1) 7 | gssapi (1.2.0) 8 | ffi (>= 1.0.1) 9 | gyoku (1.3.1) 10 | builder (>= 2.1.2) 11 | httpclient (2.8.3) 12 | kitchen-ansible (0.48.1) 13 | net-ssh (>= 3) 14 | test-kitchen (~> 1.4) 15 | kitchen-vagrant (1.3.0) 16 | test-kitchen (~> 1.4) 17 | little-plugger (1.1.4) 18 | logging (2.2.2) 19 | little-plugger (~> 1.1) 20 | multi_json (~> 1.10) 21 | mixlib-install (3.9.3) 22 | mixlib-shellout 23 | mixlib-versioning 24 | thor 25 | mixlib-shellout (2.3.2) 26 | mixlib-versioning (1.2.2) 27 | multi_json (1.13.1) 28 | net-scp (1.2.1) 29 | net-ssh (>= 2.6.5) 30 | net-ssh (4.2.0) 31 | net-ssh-gateway (1.3.0) 32 | net-ssh (>= 2.6.5) 33 | nori (2.6.0) 34 | rubyntlm (0.6.2) 35 | rubyzip (1.3.0) 36 | test-kitchen (1.20.0) 37 | mixlib-install (~> 3.6) 38 | mixlib-shellout (>= 1.2, < 3.0) 39 | net-scp (~> 1.1) 40 | net-ssh (>= 2.9, < 5.0) 41 | net-ssh-gateway (~> 1.2) 42 | thor (~> 0.19, < 0.19.2) 43 | winrm (~> 2.0) 44 | winrm-elevated (~> 1.0) 45 | winrm-fs (~> 1.1.0) 46 | thor (0.19.1) 47 | winrm (2.2.3) 48 | builder (>= 2.1.2) 49 | erubis (~> 2.7) 50 | gssapi (~> 1.2) 51 | gyoku (~> 1.0) 52 | httpclient (~> 2.2, >= 2.2.0.2) 53 | logging (>= 1.6.1, < 3.0) 54 | nori (~> 2.0) 55 | rubyntlm (~> 0.6.0, >= 0.6.1) 56 | winrm-elevated (1.1.0) 57 | winrm (~> 2.0) 58 | winrm-fs (~> 1.0) 59 | winrm-fs (1.1.1) 60 | erubis (~> 2.7) 61 | logging (>= 1.6.1, < 3.0) 62 | rubyzip (~> 1.1) 63 | winrm (~> 2.0) 64 | 65 | PLATFORMS 66 | ruby 67 | 68 | DEPENDENCIES 69 | kitchen-ansible 70 | kitchen-vagrant 71 | test-kitchen 72 | 73 | BUNDLED WITH 74 | 1.13.6 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 David Wittman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansible-redis 2 | 3 | [![Build Status](https://travis-ci.org/DavidWittman/ansible-redis.svg?branch=master)](https://travis-ci.org/DavidWittman/ansible-redis) [![Ansible Galaxy](https://img.shields.io/badge/galaxy-DavidWittman.redis-blue.svg?style=flat)](https://galaxy.ansible.com/davidwittman/redis) 4 | 5 | - Ansible 2.4+ 6 | - Compatible with most versions of Ubuntu/Debian and RHEL/CentOS 6.x 7 | 8 | ## Contents 9 | 10 | 1. [Installation](#installation) 11 | 2. [Getting Started](#getting-started) 12 | 1. [Single Redis node](#single-redis-node) 13 | 2. [Master-Slave Replication](#master-slave-replication) 14 | 3. [Redis Sentinel](#redis-sentinel) 15 | 3. [Advanced Options](#advanced-options) 16 | 1. [Verifying checksums](#verifying-checksums) 17 | 2. [Install from local tarball](#install-from-local-tarball) 18 | 3. [Building 32-bit binaries](#building-32-bit-binaries) 19 | 4. [Role Variables](#role-variables) 20 | 21 | ## Installation 22 | 23 | ``` bash 24 | $ ansible-galaxy install davidwittman.redis 25 | ``` 26 | 27 | ## Getting started 28 | 29 | Below are a few example playbooks and configurations for deploying a variety of Redis architectures. 30 | 31 | This role expects to be run as root or as a user with sudo privileges. 32 | 33 | ### Single Redis node 34 | 35 | Deploying a single Redis server node is pretty trivial; just add the role to your playbook and go. Here's an example which we'll make a little more exciting by setting the bind address to 127.0.0.1: 36 | 37 | ``` yml 38 | --- 39 | - hosts: redis01.example.com 40 | vars: 41 | - redis_bind: 127.0.0.1 42 | roles: 43 | - davidwittman.redis 44 | ``` 45 | 46 | ``` bash 47 | $ ansible-playbook -i redis01.example.com, redis.yml 48 | ``` 49 | 50 | **Note:** You may have noticed above that I just passed a hostname in as the Ansible inventory file. This is an easy way to run Ansible without first having to create an inventory file, you just need to suffix the hostname with a comma so Ansible knows what to do with it. 51 | 52 | That's it! You'll now have a Redis server listening on 127.0.0.1 on redis01.example.com. By default, the Redis binaries are installed under /opt/redis, though this can be overridden by setting the `redis_install_dir` variable. 53 | 54 | ### Master-Slave replication 55 | 56 | Configuring [replication](http://redis.io/topics/replication) in Redis is accomplished by deploying multiple nodes, and setting the `redis_slaveof` variable on the slave nodes, just as you would in the redis.conf. In the example that follows, we'll deploy a Redis master with three slaves. 57 | 58 | In this example, we're going to use groups to separate the master and slave nodes. Let's start with the inventory file: 59 | 60 | ``` ini 61 | [redis-master] 62 | redis-master.example.com 63 | 64 | [redis-slave] 65 | redis-slave0[1:3].example.com 66 | ``` 67 | 68 | And here's the playbook: 69 | 70 | ``` yml 71 | --- 72 | - name: configure the master redis server 73 | hosts: redis-master 74 | roles: 75 | - davidwittman.redis 76 | 77 | - name: configure redis slaves 78 | hosts: redis-slave 79 | vars: 80 | - redis_slaveof: redis-master.example.com 6379 81 | roles: 82 | - davidwittman.redis 83 | ``` 84 | 85 | In this case, I'm assuming you have DNS records set up for redis-master.example.com, but that's not always the case. You can pretty much go crazy with whatever you need this to be set to. In many cases, I tell Ansible to use the eth1 IP address for the master. Here's a more flexible value for the sake of posterity: 86 | 87 | ``` yml 88 | redis_slaveof: "{{ hostvars['redis-master.example.com'].ansible_eth1.ipv4.address }} {{ redis_port }}" 89 | ``` 90 | 91 | Now you're cooking with gas! Running this playbook should have you ready to go with a Redis master and three slaves. 92 | 93 | ### Redis Sentinel 94 | 95 | #### Introduction 96 | 97 | Using Master-Slave replication is great for durability and distributing reads and writes, but not so much for high availability. If the master node fails, a slave must be manually promoted to master, and connections will need to be redirected to the new master. The solution for this problem is [Redis Sentinel](http://redis.io/topics/sentinel), a distributed system which uses Redis itself to communicate and handle automatic failover in a Redis cluster. 98 | 99 | Sentinel itself uses the same redis-server binary that Redis uses, but runs with the `--sentinel` flag and with a different configuration file. All of this, of course, is abstracted with this Ansible role, but it's still good to know. 100 | 101 | #### Configuration 102 | 103 | To add a Sentinel node to an existing deployment, assign this same `redis` role to it, and set the variable `redis_sentinel` to True on that particular host. This can be done in any number of ways, and for the purposes of this example I'll extend on the inventory file used above in the Master/Slave configuration: 104 | 105 | ``` ini 106 | [redis-master] 107 | redis-master.example.com 108 | 109 | [redis-slave] 110 | redis-slave0[1:3].example.com 111 | 112 | [redis-sentinel] 113 | redis-sentinel0[1:3].example.com redis_sentinel=True 114 | ``` 115 | 116 | Above, we've added three more hosts in the **redis-sentinel** group (though this group serves no purpose within the role, it's merely an identifier), and set the `redis_sentinel` variable inline within the inventory file. 117 | 118 | Now, all we need to do is set the `redis_sentinel_monitors` variable to define the Redis masters which Sentinel should monitor. In this case, I'm going to do this within the playbook: 119 | 120 | ``` yml 121 | - name: configure the master redis server 122 | hosts: redis-master 123 | roles: 124 | - davidwittman.redis 125 | 126 | - name: configure redis slaves 127 | hosts: redis-slave 128 | vars: 129 | - redis_slaveof: redis-master.example.com 6379 130 | roles: 131 | - davidwittman.redis 132 | 133 | - name: configure redis sentinel nodes 134 | hosts: redis-sentinel 135 | vars: 136 | - redis_sentinel_monitors: 137 | - name: master01 138 | host: redis-master.example.com 139 | port: 6379 140 | roles: 141 | - davidwittman.redis 142 | ``` 143 | 144 | This will configure the Sentinel nodes to monitor the master we created above using the identifier `master01`. By default, Sentinel will use a quorum of 2, which means that at least 2 Sentinels must agree that a master is down in order for a failover to take place. This value can be overridden by setting the `quorum` key within your monitor definition. See the [Sentinel docs](http://redis.io/topics/sentinel) for more details. 145 | 146 | Along with the variables listed above, Sentinel has a number of its own configurables just as Redis server does. These are prefixed with `redis_sentinel_`, and are enumerated in the **Role Variables** section below. 147 | 148 | ### Multiple role inclusions 149 | 150 | Should you need to execute the role several times, have a look at `test/test_all.yml` to see how to proceed. See [here](https://github.com/DavidWittman/ansible-redis/issues/133) and [here](https://github.com/DavidWittman/ansible-redis/issues/193) for context. 151 | 152 | 153 | ## Advanced Options 154 | 155 | ### Verifying checksums 156 | 157 | Set the `redis_verify_checksum` variable to true to use the checksum verification option for `get_url`. Note that this will only verify checksums when Redis is downloaded from a URL, not when one is provided in a tarball with `redis_tarball`. 158 | 159 | When using Ansible 2.x, this role will verify the sha1 checksum of the download against checksums defined in the `redis_checksums` variable in `vars/main.yml`. If your version is not defined in here or you wish to override the checksum with one of your own, simply set the `redis_checksum` variable. As in the example below, you will need to prefix the checksum with the type of hash which you are using. 160 | 161 | ``` yaml 162 | - name: install redis on ansible 1.x and verify checksums 163 | hosts: all 164 | roles: 165 | - role: davidwittman.redis 166 | redis_version: 3.0.7 167 | redis_verify_checksum: true 168 | redis_checksum: "sha256:b2a791c4ea3bb7268795c45c6321ea5abcc24457178373e6a6e3be6372737f23" 169 | ``` 170 | 171 | ### Install from local tarball 172 | 173 | If the environment your server resides in does not allow downloads (i.e. if the machine is sitting in a dmz) set the variable `redis_tarball` to the path of a locally downloaded Redis tarball to use instead of downloading over HTTP from redis.io. 174 | 175 | Do not forget to set the version variable to the same version of the tarball to avoid confusion! For example: 176 | 177 | ```yml 178 | vars: 179 | redis_version: 2.8.14 180 | redis_tarball: /path/to/redis-2.8.14.tar.gz 181 | ``` 182 | 183 | In this case the source archive is copied to the server over SSH rather than downloaded. 184 | 185 | ### Building 32 bit binaries 186 | 187 | To build 32-bit binaries of Redis (which can be used for [memory optimization](https://redis.io/topics/memory-optimization)), set `redis_make_32bit: true`. This installs the necessary dependencies (x86 glibc) on RHEL/Debian/SuSE and sets the option '32bit' when running make. 188 | 189 | ### Building with TLS support 190 | 191 | To build Redis with [TLS support](https://redis.io/topics/encryption) (Added in version `6`), set `redis_make_tls: true`. This requires OpenSSL development libraries (e.g. libssl-dev on Debian/Ubuntu). 192 | 193 | ## Role Variables 194 | 195 | Here is a list of all the default variables for this role, which are also available in defaults/main.yml. One of these days I'll format these into a table or something. 196 | 197 | ``` yml 198 | --- 199 | ## Installation options 200 | redis_version: 2.8.24 201 | redis_install_dir: /opt/redis 202 | redis_dir: /var/lib/redis/{{ redis_port }} 203 | redis_config_file_name: "{{ redis_port }}.conf" 204 | redis_download_url: "http://download.redis.io/releases/redis-{{ redis_version }}.tar.gz" 205 | # Set this to true to validate redis tarball checksum against vars/main.yml 206 | redis_verify_checksum: false 207 | # Set this value to a local path of a tarball to use for installation instead of downloading 208 | redis_tarball: false 209 | # Set this to true to build 32-bit binaries of Redis 210 | redis_make_32bit: false 211 | # Set this to true to build redis with TLS support, available only for versions >= 6 (require OpenSSL development libraries) 212 | redis_make_tls: false 213 | 214 | redis_user: redis 215 | redis_group: "{{ redis_user }}" 216 | 217 | # The open file limit for Redis/Sentinel 218 | redis_nofile_limit: 16384 219 | 220 | ## Role options 221 | # Configure Redis as a service 222 | # This creates the init scripts for Redis and ensures the process is running 223 | # Also applies for Redis Sentinel 224 | redis_as_service: true 225 | # Add local facts to /etc/ansible/facts.d for Redis 226 | redis_local_facts: true 227 | # Service name 228 | redis_service_name: "redis_{{ redis_port }}" 229 | 230 | ## Networking/connection options 231 | redis_bind: false 232 | redis_port: 6379 233 | redis_password: false 234 | # Slave replication options 235 | redis_min_slaves_to_write: 0 236 | redis_min_slaves_max_lag: 10 237 | redis_tcp_backlog: 511 238 | redis_tcp_keepalive: 0 239 | # Max connected clients at a time 240 | redis_maxclients: 10000 241 | redis_timeout: 0 242 | # Socket options 243 | # Set socket_path to the desired path to the socket. E.g. /var/run/redis/{{ redis_port }}.sock 244 | redis_socket_path: false 245 | redis_socket_perm: 755 246 | 247 | ## Replication options 248 | # Set slaveof just as you would in redis.conf. (e.g. "redis01 6379") 249 | redis_slaveof: false 250 | # Make slaves read-only. "yes" or "no" 251 | redis_slave_read_only: "yes" 252 | redis_slave_priority: 100 253 | redis_repl_backlog_size: false 254 | 255 | ## Logging 256 | redis_logfile: '""' 257 | # Enable syslog. "yes" or "no" 258 | redis_syslog_enabled: "yes" 259 | redis_syslog_ident: "{{ redis_service_name }}" 260 | # Syslog facility. Must be USER or LOCAL0-LOCAL7 261 | redis_syslog_facility: USER 262 | 263 | ## General configuration 264 | redis_daemonize: "yes" 265 | redis_pidfile: /var/run/redis/{{ redis_port }}.pid 266 | # Number of databases to allow 267 | redis_databases: 16 268 | redis_loglevel: notice 269 | # Log queries slower than this many milliseconds. -1 to disable 270 | redis_slowlog_log_slower_than: 10000 271 | # Maximum number of slow queries to save 272 | redis_slowlog_max_len: 128 273 | # Redis memory limit (e.g. 4294967296, 4096mb, 4gb) 274 | redis_maxmemory: false 275 | redis_maxmemory_policy: noeviction 276 | redis_rename_commands: [] 277 | redis_db_filename: dump.rdb 278 | # How frequently to snapshot the database to disk 279 | # e.g. "900 1" => 900 seconds if at least 1 key changed 280 | redis_save: 281 | - 900 1 282 | - 300 10 283 | - 60 10000 284 | redis_stop_writes_on_bgsave_error: "yes" 285 | redis_rdbcompression: "yes" 286 | redis_rdbchecksum: "yes" 287 | redis_appendonly: "no" 288 | redis_appendfilename: "appendonly.aof" 289 | redis_appendfsync: "everysec" 290 | redis_no_appendfsync_on_rewrite: "no" 291 | redis_auto_aof_rewrite_percentage: "100" 292 | redis_auto_aof_rewrite_min_size: "64mb" 293 | redis_notify_keyspace_events: '""' 294 | 295 | ## Additional configuration options 296 | # leave empty if not required. Use a block style scalar to add options, e.g. 297 | # redis_config_additional: | 298 | # io-threads 4 299 | # io-threads-do-reads yes 300 | redis_config_additional: "" 301 | 302 | ## Redis sentinel configs 303 | # Set this to true on a host to configure it as a Sentinel 304 | redis_sentinel: false 305 | redis_sentinel_dir: /var/lib/redis/sentinel_{{ redis_sentinel_port }} 306 | redis_sentinel_bind: 0.0.0.0 307 | redis_sentinel_port: 26379 308 | redis_sentinel_password: false 309 | redis_sentinel_pidfile: /var/run/redis/sentinel_{{ redis_sentinel_port }}.pid 310 | redis_sentinel_logfile: '""' 311 | redis_sentinel_syslog_ident: sentinel_{{ redis_sentinel_port }} 312 | redis_sentinel_monitors: 313 | - name: master01 314 | host: localhost 315 | port: 6379 316 | quorum: 2 317 | auth_pass: ant1r3z 318 | down_after_milliseconds: 30000 319 | parallel_syncs: 1 320 | failover_timeout: 180000 321 | notification_script: false 322 | client_reconfig_script: false 323 | rename_commands: [] 324 | ``` 325 | 326 | ## Facts 327 | 328 | The following facts are accessible in your inventory or tasks outside of this role. 329 | 330 | - `{{ ansible_local.redis.bind }}` 331 | - `{{ ansible_local.redis.port }}` 332 | - `{{ ansible_local.redis.sentinel_bind }}` 333 | - `{{ ansible_local.redis.sentinel_port }}` 334 | - `{{ ansible_local.redis.sentinel_monitors }}` 335 | 336 | To disable these facts, set `redis_local_facts` to a false value. 337 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ## Installation options 3 | redis_version: 2.8.24 4 | redis_install_dir: /opt/redis 5 | redis_install_from_source: true 6 | redis_dir: /var/lib/redis/{{ redis_port }} 7 | redis_config_file_name: "{{ redis_port }}.conf" 8 | redis_download_url: "http://download.redis.io/redis-{{ redis_version }}.tar.gz" 9 | 10 | redis_protected_mode: "yes" 11 | # Set this to true to validate redis tarball checksum against vars/main.yml 12 | redis_verify_checksum: false 13 | # Set this value to a local path of a tarball to use for installation instead of downloading 14 | redis_tarball: false 15 | # Set this to true to build 32-bit binaries of Redis 16 | redis_make_32bit: false 17 | # Set this to true to build redis with TLS support, available only for versions >= 6 (require OpenSSL development libraries) 18 | redis_make_tls: false 19 | 20 | redis_user: redis 21 | redis_group: "{{ redis_user }}" 22 | 23 | # The open file limit for Redis/Sentinel 24 | redis_nofile_limit: 16384 25 | redis_oom_score_adjust: 0 26 | 27 | ## Role options 28 | # Configure Redis as a service 29 | # This creates the init scripts for Redis and ensures the process is running 30 | # Also applies for Redis Sentinel 31 | redis_as_service: true 32 | # Add local facts to /etc/ansible/facts.d for Redis 33 | redis_local_facts: true 34 | # Service name 35 | redis_service_name: "redis_{{ redis_port }}" 36 | 37 | ## Networking/connection options 38 | redis_bind: false 39 | redis_port: 6379 40 | redis_password: false 41 | # Slave replication options 42 | redis_min_slaves_to_write: 0 43 | redis_min_slaves_max_lag: 10 44 | redis_tcp_backlog: 511 45 | redis_tcp_keepalive: 0 46 | # Max connected clients at a time 47 | redis_maxclients: 10000 48 | redis_timeout: 0 49 | # Socket options 50 | # Set socket_path to the desired path to the socket. E.g. /var/run/redis/{{ redis_port }}.sock 51 | redis_socket_path: false 52 | redis_socket_perm: 755 53 | 54 | ## Replication options 55 | # Set slaveof just as you would in redis.conf. (e.g. "redis01 6379") 56 | redis_slaveof: false 57 | # Make slaves read-only. "yes" or "no" 58 | redis_slave_read_only: "yes" 59 | redis_slave_priority: 100 60 | redis_repl_backlog_size: false 61 | 62 | ## Logging 63 | redis_logfile: '""' 64 | # Enable syslog. "yes" or "no" 65 | redis_syslog_enabled: "yes" 66 | redis_syslog_ident: "{{ redis_service_name }}" 67 | # Syslog facility. Must be USER or LOCAL0-LOCAL7 68 | redis_syslog_facility: USER 69 | 70 | ## General configuration 71 | redis_daemonize: "yes" 72 | redis_pidfile: /var/run/redis/{{ redis_port }}.pid 73 | # Number of databases to allow 74 | redis_databases: 16 75 | redis_loglevel: notice 76 | # Log queries slower than this many milliseconds. -1 to disable 77 | redis_slowlog_log_slower_than: 10000 78 | # Maximum number of slow queries to save 79 | redis_slowlog_max_len: 128 80 | # Redis memory limit (e.g. 4294967296, 4096mb, 4gb) 81 | redis_maxmemory: false 82 | redis_maxmemory_policy: noeviction 83 | redis_rename_commands: [] 84 | 85 | # Lua script time limit 86 | redis_lua_time_limit: 5000 87 | 88 | # the file name for the RDB Backup 89 | redis_db_filename: "dump.rdb" 90 | 91 | # How frequently to snapshot the database to disk 92 | # e.g. "900 1" => 900 seconds if at least 1 key changed 93 | redis_save: 94 | - 900 1 95 | - 300 10 96 | - 60 10000 97 | redis_stop_writes_on_bgsave_error: "yes" 98 | redis_rdbcompression: "yes" 99 | redis_rdbchecksum: "yes" 100 | redis_appendonly: "no" 101 | redis_appendfilename: "appendonly.aof" 102 | redis_appendfsync: "everysec" 103 | redis_no_appendfsync_on_rewrite: "no" 104 | redis_auto_aof_rewrite_percentage: "100" 105 | redis_auto_aof_rewrite_min_size: "64mb" 106 | redis_notify_keyspace_events: '""' 107 | 108 | redis_client_output_buffer_limit_normal: 0 0 0 109 | redis_client_output_buffer_limit_slave: 256mb 64mb 60 110 | redis_client_output_buffer_limit_pubsub: 32mb 8mb 60 111 | 112 | redis_hz: 10 113 | 114 | ## Additional configuration options 115 | # leave empty if not required. Use a block style scalar to add options, e.g. 116 | # redis_config_additional: | 117 | # io-threads 4 118 | # io-threads-do-reads yes 119 | redis_config_additional: "" 120 | 121 | ## Redis sentinel configs 122 | # Set this to true on a host to configure it as a Sentinel 123 | redis_sentinel: false 124 | redis_sentinel_protected_mode: "yes" 125 | redis_sentinel_dir: /var/lib/redis/sentinel_{{ redis_sentinel_port }} 126 | redis_sentinel_bind: 0.0.0.0 127 | redis_sentinel_port: 26379 128 | redis_sentinel_password: false 129 | redis_sentinel_pidfile: /var/run/redis/sentinel_{{ redis_sentinel_port }}.pid 130 | redis_sentinel_logfile: '""' 131 | redis_sentinel_syslog_ident: sentinel_{{ redis_sentinel_port }} 132 | redis_sentinel_oom_score_adjust: 0 133 | redis_sentinel_monitors: 134 | - name: master01 135 | host: localhost 136 | port: 6379 137 | quorum: 2 138 | auth_pass: ant1r3z 139 | down_after_milliseconds: 30000 140 | parallel_syncs: 1 141 | failover_timeout: 180000 142 | notification_script: false 143 | client_reconfig_script: false 144 | rename_commands: [] 145 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "restart redis" 3 | service: 4 | name: "{{ redis_service_name }}" 5 | state: restarted 6 | when: redis_as_service 7 | 8 | - name: "restart sentinel" 9 | service: 10 | name: sentinel_{{ redis_sentinel_port }} 11 | state: restarted 12 | when: redis_as_service 13 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: David Wittman 4 | description: Highly configurable role to install Redis and Redis Sentinel from source 5 | min_ansible_version: 2.4.0 6 | license: MIT 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | - name: Debian 12 | versions: 13 | - all 14 | - name: EL 15 | versions: 16 | - 6 17 | - name: SLES 18 | versions: 19 | - 11 20 | - 12 21 | galaxy_tags: 22 | - database 23 | - nosql 24 | 25 | dependencies: [] 26 | -------------------------------------------------------------------------------- /tasks/check_vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: check for ansible 1.x 4 | fail: 5 | msg: > 6 | This role no longer supports Ansible 1.x. The last known good tag 7 | for Ansible 1.x support in this role is 1.2.5. 8 | when: 9 | - ansible_version.major < 2 10 | 11 | - name: check for checksum 12 | fail: 13 | msg: > 14 | There is no sha1 checksum defined for version {{ redis_version }} in 15 | vars/main.yml. Set redis_checksum manually or submit a PR to add this 16 | version. 17 | when: 18 | - redis_verify_checksum|bool 19 | - redis_checksum is not defined 20 | - redis_version not in redis_checksums 21 | -------------------------------------------------------------------------------- /tasks/dependencies.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install debian dependencies 3 | apt: 4 | pkg: 5 | - gcc 6 | - make 7 | - libc6-dev 8 | # This should be `else omit`, but that doesn't quite work, so duplicate gcc 9 | - "{{ 'libc6-dev-i386' if redis_make_32bit|bool else 'gcc' }}" 10 | update_cache: yes 11 | cache_valid_time: 86400 12 | state: present 13 | when: ansible_os_family == "Debian" 14 | 15 | - name: install redhat dependencies 16 | yum: 17 | name: 18 | - gcc 19 | - make 20 | state: present 21 | when: ansible_os_family == "RedHat" 22 | 23 | # Conditionally install the i686 build of libgcc if we are building 32-bit 24 | # It must be version-locked with x64 libgcc, so use 'latest' to update libgcc first 25 | # Otherwise you get a version mismatch error from yum when installing. 26 | - name: update libgcc on rhel for 32-bit dependencies 27 | yum: 28 | name: libgcc 29 | state: latest 30 | when: ansible_os_family == "RedHat" and redis_make_32bit|bool 31 | tags: 32 | - skip_ansible_lint 33 | 34 | - name: install redhat 32-bit dependencies 35 | yum: 36 | name: 37 | - libgcc.i686 38 | - glibc-devel.i686 39 | state: latest 40 | when: ansible_os_family == "RedHat" and redis_make_32bit|bool 41 | tags: 42 | - skip_ansible_lint 43 | 44 | - name: install suse dependencies 45 | zypper: 46 | name: 47 | - gcc 48 | - make 49 | # These should be `else omit`, but that doesn't quite work, so duplicate gcc 50 | - "{{ 'gcc-32bit' if redis_make_32bit|bool else 'gcc' }}" 51 | - "{{ 'libgcc_s1-32bit' if redis_make_32bit|bool else 'gcc' }}" 52 | state: present 53 | when: ansible_os_family == 'Suse' 54 | -------------------------------------------------------------------------------- /tasks/download.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Redis uses a mix of sha1 and sha256 checksums. 4 | # Determine the type of checksum based on its length and prefix the variable appropriately 5 | - name: set redis checksum 6 | set_fact: 7 | redis_checksum: "{{ 'sha1' if redis_checksums[redis_version]|length == 40 else 'sha256' }}:{{ redis_checksums[redis_version] }}" 8 | when: 9 | - redis_verify_checksum|bool 10 | - redis_checksum is not defined 11 | - redis_version in redis_checksums 12 | 13 | - name: download redis 14 | get_url: 15 | url: "{{ redis_download_url }}" 16 | dest: /usr/local/src/redis-{{ redis_version }}.tar.gz 17 | checksum: "{{ redis_checksum|default(omit) }}" 18 | when: not redis_tarball 19 | 20 | - name: upload redis 21 | copy: 22 | src: "{{ redis_tarball }}" 23 | dest: /usr/local/src/redis-{{ redis_version }}.tar.gz 24 | when: redis_tarball|default(false) 25 | 26 | - name: extract redis tarball 27 | unarchive: 28 | src: /usr/local/src/redis-{{ redis_version }}.tar.gz 29 | dest: /usr/local/src 30 | creates: /usr/local/src/redis-{{ redis_version }}/Makefile 31 | copy: no 32 | when: not ansible_check_mode 33 | -------------------------------------------------------------------------------- /tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: enable overcommit in sysctl 3 | sysctl: 4 | name: vm.overcommit_memory 5 | value: "1" 6 | state: present 7 | reload: yes 8 | ignoreerrors: yes 9 | when: redis_travis_ci is not defined 10 | 11 | - name: compile redis 12 | shell: umask 0022 && make -j{{ ansible_processor_cores|default(1) + 1 }}{{ ' 32bit' if redis_make_32bit|bool else '' }}{{ ' BUILD_TLS=yes' if redis_make_tls|bool else '' }} 13 | args: 14 | chdir: /usr/local/src/redis-{{ redis_version }} 15 | creates: /usr/local/src/redis-{{ redis_version }}/src/redis-server 16 | 17 | - name: create redis install directory 18 | file: 19 | path: "{{ redis_install_dir }}" 20 | state: directory 21 | mode: 0755 22 | 23 | - name: check if redis user exists (ignore errors) 24 | command: id {{ redis_user }} 25 | ignore_errors: yes 26 | changed_when: false 27 | register: user_exists 28 | 29 | - name: add redis group 30 | group: 31 | name: "{{ redis_group }}" 32 | state: present 33 | when: user_exists is failed 34 | 35 | - name: add redis user 36 | user: 37 | name: "{{ redis_user }}" 38 | group: "{{ redis_group }}" 39 | comment: "Redis" 40 | home: "{{ redis_install_dir }}" 41 | shell: /bin/false 42 | system: yes 43 | when: user_exists is failed 44 | 45 | - name: create /etc/redis 46 | file: 47 | path: /etc/redis 48 | state: directory 49 | mode: 0755 50 | owner: "{{ redis_user }}" 51 | 52 | - name: create /var/run/redis 53 | file: 54 | path: /var/run/redis 55 | state: directory 56 | owner: "{{ redis_user }}" 57 | 58 | - name: install redis 59 | shell: umask 0022 && make PREFIX={{ redis_install_dir }} install 60 | args: 61 | chdir: /usr/local/src/redis-{{ redis_version }} 62 | creates: "{{ redis_install_dir }}/bin/redis-server" 63 | 64 | - name: list redis binaries to add to alternatives 65 | command: ls -1 {{ redis_install_dir }}/bin 66 | register: redis_binaries 67 | changed_when: false 68 | check_mode: false 69 | 70 | - name: add redis binaries to alternatives 71 | alternatives: 72 | name: "{{ item }}" 73 | path: "{{ redis_install_dir }}/bin/{{ item }}" 74 | link: "/usr/bin/{{ item }}" 75 | with_items: "{{ redis_binaries.stdout_lines }}" 76 | when: redis_binaries is succeeded 77 | -------------------------------------------------------------------------------- /tasks/install_from_repo.yml: -------------------------------------------------------------------------------- 1 | - name: Install redis from repo 2 | package: 3 | name: redis 4 | 5 | - name: Install redis-sentinel from repo 6 | package: 7 | name: redis-sentinel 8 | when: redis_sentinel 9 | -------------------------------------------------------------------------------- /tasks/local_facts.yml: -------------------------------------------------------------------------------- 1 | - name: create facts directory 2 | file: 3 | path: /etc/ansible/facts.d 4 | state: directory 5 | 6 | - name: create redis facts 7 | template: 8 | src: etc/ansible/facts.d/redis.fact.j2 9 | dest: /etc/ansible/facts.d/redis.fact 10 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: check_vars.yml 3 | 4 | - include_tasks: download.yml 5 | when: redis_install_from_source 6 | tags: 7 | - download 8 | 9 | - include_tasks: dependencies.yml 10 | when: redis_install_from_source 11 | tags: 12 | - install 13 | 14 | - include_tasks: install.yml 15 | when: redis_install_from_source 16 | tags: 17 | - install 18 | 19 | - include_tasks: install_from_repo.yml 20 | when: not redis_install_from_source 21 | tags: 22 | - install 23 | 24 | - include_tasks: server.yml 25 | when: not redis_sentinel 26 | tags: 27 | - config 28 | 29 | - include_tasks: sentinel.yml 30 | when: redis_sentinel 31 | tags: 32 | - config 33 | 34 | - include_tasks: local_facts.yml 35 | when: redis_local_facts|bool 36 | -------------------------------------------------------------------------------- /tasks/sentinel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create sentinel working directory 3 | file: 4 | path: "{{ redis_sentinel_dir }}" 5 | state: directory 6 | recurse: yes 7 | owner: "{{ redis_user }}" 8 | 9 | - name: create sentinel init script 10 | template: 11 | src: "{{ item }}" 12 | dest: /etc/init.d/sentinel_{{ redis_sentinel_port }} 13 | mode: 0755 14 | # Choose the distro-specific template. We must specify the templates 15 | # path here because with_first_found tries to find files in files/ 16 | with_first_found: 17 | - files: 18 | - "{{ ansible_os_family }}/redis_sentinel.init.j2" 19 | - default/redis_sentinel.init.j2 20 | paths: 21 | - ../templates 22 | when: redis_as_service and ansible_service_mgr|default() != "systemd" and not (not redis_install_from_source and redis_service_name == 'redis') 23 | 24 | - name: create sentinel systemd service 25 | template: 26 | src: "{{ item }}" 27 | dest: /etc/systemd/system/sentinel_{{ redis_sentinel_port }}.service 28 | mode: 0644 29 | with_first_found: 30 | - files: 31 | - "{{ ansible_os_family }}/redis_sentinel.service.j2" 32 | - default/redis_sentinel.service.j2 33 | paths: 34 | - ../templates 35 | register: sentinel_unit_file 36 | when: redis_as_service and ansible_service_mgr|default() == "systemd" and not (not redis_install_from_source and redis_service_name == 'redis') 37 | 38 | - name: create systemd tmpfiles configuration 39 | template: 40 | src: etc/tmpfiles.d/redis.conf.j2 41 | dest: /etc/tmpfiles.d/redis.conf 42 | mode: 0644 43 | when: 44 | - redis_as_service 45 | - ansible_service_mgr|default() == "systemd" 46 | - (redis_sentinel_pidfile|dirname).startswith("/var/run") or (redis_sentinel_pidfile|dirname).startswith("/run") 47 | - not (not redis_install_from_source and redis_service_name == 'redis') 48 | 49 | - name: reload systemd daemon 50 | systemd: 51 | daemon_reload: true 52 | when: 53 | - redis_as_service 54 | - ansible_service_mgr|default() == "systemd" 55 | - sentinel_unit_file is changed 56 | 57 | - name: set sentinel to start at boot 58 | service: 59 | name: sentinel_{{ redis_sentinel_port }} 60 | enabled: yes 61 | when: redis_as_service 62 | 63 | # Check then create log dir to prevent aggressively overwriting permissions 64 | - name: check if sentinel log directory exists 65 | stat: 66 | path: "{{ redis_sentinel_logfile|dirname }}" 67 | register: sentinel_logdir 68 | changed_when: false 69 | when: redis_sentinel_logfile != '""' 70 | 71 | - name: create sentinel log directory if it does not exist 72 | file: 73 | state: directory 74 | path: "{{ redis_sentinel_logfile|dirname }}" 75 | owner: "{{ redis_user }}" 76 | group: "{{ redis_group }}" 77 | when: 78 | - redis_sentinel_logfile != '""' 79 | - not sentinel_logdir.stat.exists 80 | 81 | - name: touch the sentinel log file 82 | file: 83 | state: touch 84 | path: "{{ redis_sentinel_logfile }}" 85 | owner: "{{ redis_user }}" 86 | group: "{{ redis_group }}" 87 | when: redis_sentinel_logfile != '""' 88 | 89 | - name: check if sentinel pid directory exists 90 | stat: 91 | path: "{{ redis_sentinel_pidfile|dirname }}" 92 | register: sentinel_piddir 93 | changed_when: false 94 | when: redis_sentinel_pidfile != '""' 95 | 96 | - name: create sentinel pid directory if it does not exist 97 | file: 98 | state: directory 99 | path: "{{ redis_sentinel_pidfile|dirname }}" 100 | owner: "{{ redis_user }}" 101 | group: "{{ redis_group }}" 102 | when: 103 | - redis_sentinel_pidfile != '""' 104 | - not sentinel_piddir.stat.exists 105 | 106 | - name: create sentinel config file 107 | template: 108 | src: redis_sentinel.conf.j2 109 | dest: /etc/redis/sentinel_{{ redis_sentinel_port }}.conf 110 | owner: "{{ redis_user }}" 111 | mode: 0640 112 | notify: "restart sentinel" 113 | 114 | - name: add sentinel init config file 115 | template: 116 | dest: /etc/sysconfig/sentinel_{{ redis_sentinel_port }} 117 | src: redis.init.conf.j2 118 | when: ansible_os_family == "RedHat" 119 | notify: "restart sentinel" 120 | 121 | - name: add sentinel init config file 122 | template: 123 | dest: /etc/default/sentinel_{{ redis_sentinel_port }} 124 | src: redis.init.conf.j2 125 | when: ansible_os_family == "Debian" 126 | notify: "restart sentinel" 127 | 128 | # Flush handlers before ensuring the service is started to prevent 129 | # a start and then restart 130 | - name: flush handlers to apply config changes 131 | meta: flush_handlers 132 | 133 | - name: ensure sentinel is running 134 | service: 135 | name: sentinel_{{ redis_sentinel_port }} 136 | state: started 137 | when: redis_as_service 138 | -------------------------------------------------------------------------------- /tasks/server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create redis working directory 3 | file: 4 | path: "{{ redis_dir }}" 5 | state: directory 6 | recurse: yes 7 | owner: "{{ redis_user }}" 8 | 9 | - name: create redis init script 10 | template: 11 | src: "{{ item }}" 12 | dest: /etc/init.d/{{ redis_service_name }} 13 | mode: 0755 14 | # Choose the distro-specific template. We must specify the templates 15 | # path here because with_first_found tries to find files in files/ 16 | with_first_found: 17 | - files: 18 | - "{{ ansible_os_family }}/redis.init.j2" 19 | - default/redis.init.j2 20 | paths: 21 | - ../templates 22 | when: redis_as_service and ansible_service_mgr|default() != "systemd" and not (not redis_install_from_source and redis_service_name == 'redis') 23 | 24 | - name: create redis systemd service 25 | template: 26 | src: "{{ item }}" 27 | dest: /etc/systemd/system/{{ redis_service_name }}.service 28 | mode: 0644 29 | with_first_found: 30 | - files: 31 | - "{{ ansible_os_family }}/redis.service.j2" 32 | - default/redis.service.j2 33 | paths: 34 | - ../templates 35 | register: redis_unit_file 36 | when: redis_as_service and ansible_service_mgr|default() == "systemd" and not (not redis_install_from_source and redis_service_name == 'redis') 37 | 38 | - name: create systemd tmpfiles configuration 39 | template: 40 | src: etc/tmpfiles.d/redis.conf.j2 41 | dest: /etc/tmpfiles.d/redis.conf 42 | mode: 0644 43 | when: 44 | - redis_as_service 45 | - ansible_service_mgr|default() == 'systemd' 46 | - (redis_pidfile|dirname).startswith('/var/run') or (redis_pidfile|dirname).startswith('/run') 47 | - not (not redis_install_from_source and redis_service_name == 'redis') 48 | 49 | - name: reload systemd daemon 50 | systemd: 51 | daemon_reload: true 52 | when: 53 | - redis_as_service 54 | - ansible_service_mgr|default() == "systemd" 55 | - redis_unit_file is changed 56 | 57 | - name: set redis to start at boot 58 | service: 59 | name: "{{ redis_service_name }}" 60 | enabled: yes 61 | when: redis_as_service 62 | 63 | # Check then create log dir to prevent aggressively overwriting permissions 64 | - name: check if log directory exists 65 | stat: 66 | path: "{{ redis_logfile|dirname }}" 67 | register: logdir 68 | changed_when: false 69 | when: redis_logfile != '""' 70 | 71 | - name: create log directory if it does not exist 72 | file: 73 | state: directory 74 | path: "{{ redis_logfile|dirname }}" 75 | owner: "{{ redis_user }}" 76 | group: "{{ redis_group }}" 77 | when: 78 | - redis_logfile != '""' 79 | - not logdir.stat.exists 80 | 81 | - name: create log file if it does not exist 82 | copy: 83 | dest: "{{ redis_logfile }}" 84 | content: "" 85 | force: false # Don't override file contet if the file already exits 86 | owner: "{{ redis_user }}" 87 | group: "{{ redis_group }}" 88 | when: redis_logfile != '""' 89 | 90 | - name: update permissions of log file if needed 91 | file: 92 | state: file 93 | path: "{{ redis_logfile }}" 94 | owner: "{{ redis_user }}" 95 | group: "{{ redis_group }}" 96 | when: redis_logfile != '""' 97 | 98 | - name: check if pid directory exists 99 | stat: 100 | path: "{{ redis_pidfile|dirname }}" 101 | register: piddir 102 | changed_when: false 103 | when: redis_pidfile != '""' 104 | 105 | - name: create pid directory if it does not exist 106 | file: 107 | state: directory 108 | path: "{{ redis_pidfile|dirname }}" 109 | owner: "{{ redis_user }}" 110 | group: "{{ redis_group }}" 111 | when: 112 | - redis_pidfile != '""' 113 | - not piddir.stat.exists 114 | 115 | - name: create redis config file 116 | template: 117 | src: redis.conf.j2 118 | dest: /etc/redis/{{ redis_config_file_name }} 119 | owner: "{{ redis_user }}" 120 | mode: 0640 121 | notify: "restart redis" 122 | 123 | - name: add redis init config file 124 | template: 125 | dest: /etc/sysconfig/{{ redis_service_name }} 126 | src: redis.init.conf.j2 127 | mode: 0600 128 | when: ansible_os_family == "RedHat" 129 | notify: "restart redis" 130 | 131 | - name: add redis init config file 132 | template: 133 | dest: /etc/default/{{ redis_service_name }} 134 | src: redis.init.conf.j2 135 | mode: 0600 136 | when: ansible_os_family == "Debian" 137 | notify: "restart redis" 138 | 139 | # Flush handlers before ensuring the service is started to prevent 140 | # a start and then restart 141 | - name: flush handlers to apply config changes 142 | meta: flush_handlers 143 | 144 | - name: ensure redis is running 145 | service: 146 | name: "{{ redis_service_name }}" 147 | state: started 148 | when: redis_as_service 149 | -------------------------------------------------------------------------------- /templates/Debian/redis.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Redis init script for Debian-based distros 4 | # 5 | # 6 | ### BEGIN INIT INFO 7 | # Provides: redis_{{ redis_port }} 8 | # Required-Start: $network $local_fs $remote_fs 9 | # Required-Stop: $network $local_fs $remote_fs 10 | # Default-Start: 2 3 4 5 11 | # Default-Stop: 0 1 6 12 | # Should-Start: $syslog $named 13 | # Should-Stop: $syslog $named 14 | # Short-Description: Start and stop redis_{{ redis_port }} 15 | # Description: Redis key-value store 16 | ### END INIT INFO 17 | 18 | # Source the Linux Standard Base functions 19 | . /lib/lsb/init-functions 20 | 21 | REDIS_PORT={{ redis_port }} 22 | NAME=redis_${REDIS_PORT} 23 | DAEMON={{ redis_install_dir }}/bin/redis-server 24 | PIDFILE={{ redis_pidfile }} 25 | PIDFILE_DIR=$(dirname "${PIDFILE}") 26 | 27 | REDIS_USER={{ redis_user }} 28 | CONF="/etc/redis/{{ redis_config_file_name }}" 29 | CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${REDIS_PORT}" 30 | 31 | if [ -r /etc/default/{{ redis_service_name }} ]; then 32 | . /etc/default/{{ redis_service_name }} 33 | fi 34 | 35 | if [ -n "$REDIS_PASSWORD" ]; then 36 | CLIEXEC="${CLIEXEC} -a ${REDIS_PASSWORD}" 37 | fi 38 | 39 | if [ -n "$BIND_ADDRESS" ]; then 40 | CLIEXEC="${CLIEXEC} -h ${BIND_ADDRESS}" 41 | fi 42 | 43 | case "$1" in 44 | start) 45 | if [ -f "$PIDFILE" ]; then 46 | status_of_proc -p "$PIDFILE" $DAEMON "$NAME process" && return 0 47 | fi 48 | 49 | if [ -n "$NOFILE_LIMIT" ]; then 50 | ulimit -n $NOFILE_LIMIT 51 | fi 52 | 53 | if [ ! -d "$PIDFILE_DIR" ]; then 54 | mkdir "$PIDFILE_DIR" 55 | chown ${REDIS_USER}:${REDIS_USER} "$PIDFILE_DIR" 56 | chmod 0755 "$PIDFILE_DIR" 57 | fi 58 | 59 | log_daemon_msg "Starting $NAME..." 60 | if start-stop-daemon --start -q --oknodo -p "$PIDFILE" -c $REDIS_USER --exec $DAEMON -- $CONF; then 61 | log_end_msg 0 62 | else 63 | log_end_msg 1 64 | fi 65 | ;; 66 | stop) 67 | if [ -f "$PIDFILE" ]; then 68 | PID=$(cat "$PIDFILE") 69 | log_daemon_msg "Stopping $NAME..." 70 | $CLIEXEC shutdown 71 | while [ -x /proc/${PID} ]; do 72 | log_daemon_msg "Waiting for Redis to shutdown ..." 73 | sleep 1 74 | done 75 | log_end_msg 0 76 | else 77 | log_daemon_msg "$NAME is not running" 78 | log_end_msg 0 79 | fi 80 | ;; 81 | status) 82 | status_of_proc -p "$PIDFILE" $DAEMON "$NAME" && exit 0 || exit $? 83 | ;; 84 | restart|force-reload) 85 | ${0} stop 86 | ${0} start 87 | ;; 88 | *) 89 | echo "Usage: /etc/init.d/$NAME {start|stop|status|restart|force-reload}" >&2 90 | exit 1 91 | ;; 92 | esac 93 | 94 | exit 0 95 | -------------------------------------------------------------------------------- /templates/Debian/redis_sentinel.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Redis init script for Debian-based distros 4 | # 5 | # 6 | ### BEGIN INIT INFO 7 | # Provides: sentinel_{{ redis_sentinel_port }} 8 | # Required-Start: $network $local_fs $remote_fs 9 | # Required-Stop: $network $local_fs $remote_fs 10 | # Default-Start: 2 3 4 5 11 | # Default-Stop: 0 1 6 12 | # Should-Start: $syslog $named 13 | # Should-Stop: $syslog $named 14 | # Short-Description: Start and stop sentinel_{{ redis_sentinel_port }} 15 | # Description: Redis Sentinel monitor 16 | ### END INIT INFO 17 | 18 | # Source the Linux Standard Base functions 19 | . /lib/lsb/init-functions 20 | 21 | SENTINEL_PORT={{ redis_sentinel_port }} 22 | NAME="sentinel_${SENTINEL_PORT}" 23 | DAEMON={{ redis_install_dir }}/bin/redis-server 24 | PIDFILE={{ redis_sentinel_pidfile }} 25 | PIDFILE_DIR=$(dirname "${PIDFILE}") 26 | 27 | REDIS_USER={{ redis_user }} 28 | CONF="/etc/redis/sentinel_${SENTINEL_PORT}.conf" 29 | CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${SENTINEL_PORT}" 30 | 31 | if [ -r /etc/default/sentinel_${SENTINEL_PORT} ]; then 32 | . /etc/default/sentinel_${SENTINEL_PORT} 33 | fi 34 | 35 | if [ -n "$REDIS_PASSWORD" ]; then 36 | CLIEXEC="${CLIEXEC} -a ${REDIS_PASSWORD}" 37 | fi 38 | 39 | if [ -n "$BIND_ADDRESS" ]; then 40 | CLIEXEC="${CLIEXEC} -h ${BIND_ADDRESS}" 41 | fi 42 | 43 | case "$1" in 44 | start) 45 | if [ -f "$PIDFILE" ]; then 46 | status_of_proc -p "$PIDFILE" $DAEMON "$NAME process" && return 0 47 | fi 48 | 49 | if [ -n "$NOFILE_LIMIT" ]; then 50 | ulimit -n $NOFILE_LIMIT 51 | fi 52 | 53 | if [ ! -d "$PIDFILE_DIR" ]; then 54 | mkdir "$PIDFILE_DIR" 55 | chown ${REDIS_USER}:${REDIS_USER} "$PIDFILE_DIR" 56 | chmod 0755 "$PIDFILE_DIR" 57 | fi 58 | 59 | log_daemon_msg "Starting $NAME..." 60 | if start-stop-daemon --start -q --oknodo -p "$PIDFILE" -c $REDIS_USER --exec $DAEMON -- $CONF --sentinel; then 61 | log_end_msg 0 62 | else 63 | log_end_msg 1 64 | fi 65 | ;; 66 | stop) 67 | if [ -f "$PIDFILE" ]; then 68 | PID=$(cat "$PIDFILE") 69 | log_daemon_msg "Stopping $NAME..." 70 | $CLIEXEC shutdown 71 | while [ -x /proc/${PID} ]; do 72 | log_daemon_msg "Waiting for Redis Sentinel to shutdown ..." 73 | sleep 1 74 | done 75 | log_end_msg 0 76 | else 77 | log_daemon_msg "$NAME is not running" 78 | log_end_msg 0 79 | fi 80 | ;; 81 | status) 82 | status_of_proc -p "$PIDFILE" $DAEMON "$NAME" && exit 0 || exit $? 83 | ;; 84 | restart|force-reload) 85 | ${0} stop 86 | ${0} start 87 | ;; 88 | *) 89 | echo "Usage: /etc/init.d/$NAME {start|stop|status|restart|force-reload}" >&2 90 | exit 1 91 | ;; 92 | esac 93 | 94 | exit 0 95 | -------------------------------------------------------------------------------- /templates/RedHat/redis.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Simple Redis init.d script for RHEL-based distros 4 | # 5 | # chkconfig: - 58 74 6 | # description: Redis key-value store 7 | # 8 | # Source function library 9 | . /etc/init.d/functions 10 | 11 | REDIS_PORT={{ redis_port }} 12 | NAME="redis_${REDIS_PORT}" 13 | 14 | if [ -r /etc/sysconfig/redis_${REDIS_PORT} ]; then 15 | . /etc/sysconfig/redis_${REDIS_PORT} 16 | fi 17 | 18 | REDIS_USER={{ redis_user }} 19 | PIDFILE={{ redis_pidfile }} 20 | CONF="/etc/redis/{{ redis_config_file_name }}" 21 | EXEC={{ redis_install_dir }}/bin/redis-server 22 | CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${REDIS_PORT}" 23 | 24 | if [ -n "$REDIS_PASSWORD" ]; then 25 | CLIEXEC="${CLIEXEC} -a ${REDIS_PASSWORD}" 26 | fi 27 | 28 | if [ -n "$BIND_ADDRESS" ]; then 29 | CLIEXEC="${CLIEXEC} -h ${BIND_ADDRESS}" 30 | fi 31 | 32 | case "$1" in 33 | start) 34 | if [ -f $PIDFILE ] 35 | then 36 | echo "$PIDFILE exists, process is already running or crashed" 37 | else 38 | if [ -n "$NOFILE_LIMIT" ]; then 39 | ulimit -n $NOFILE_LIMIT 40 | fi 41 | echo "Starting Redis server..." 42 | daemon --user $REDIS_USER $EXEC $CONF 43 | fi 44 | ;; 45 | stop) 46 | if [ ! -f $PIDFILE ] 47 | then 48 | echo "$PIDFILE does not exist, process is not running" 49 | else 50 | PID=$(cat $PIDFILE) 51 | echo "Stopping ..." 52 | $CLIEXEC shutdown 53 | while [ -x /proc/${PID} ] 54 | do 55 | echo "Waiting for Redis to shutdown ..." 56 | sleep 1 57 | done 58 | echo "Redis stopped" 59 | fi 60 | ;; 61 | status) 62 | status -p "${PIDFILE}" "redis_${REDIS_PORT}" 63 | ;; 64 | restart|force-reload) 65 | ${0} stop 66 | ${0} start 67 | ;; 68 | *) 69 | echo "Usage: /etc/init.d/$NAME {start|stop|status|restart|force-reload}" >&2 70 | exit 1 71 | ;; 72 | esac 73 | 74 | exit 0 75 | -------------------------------------------------------------------------------- /templates/RedHat/redis_sentinel.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Redis Sentinel init script for RHEL-based distros 4 | # 5 | # chkconfig: - 58 74 6 | # description: Redis Sentinel monitor 7 | # 8 | # Source function library 9 | . /etc/init.d/functions 10 | 11 | SENTINEL_PORT={{ redis_sentinel_port }} 12 | NAME="sentinel_${SENTINEL_PORT}" 13 | 14 | if [ -r /etc/sysconfig/sentinel_${SENTINEL_PORT} ]; then 15 | . /etc/sysconfig/sentinel_${SENTINEL_PORT} 16 | fi 17 | 18 | REDIS_USER={{ redis_user }} 19 | BIND_ADDRESS={{ redis_sentinel_bind }} 20 | PIDFILE={{ redis_sentinel_pidfile }} 21 | CONF="/etc/redis/sentinel_${SENTINEL_PORT}.conf" 22 | EXEC={{ redis_install_dir }}/bin/redis-server 23 | CLIEXEC="{{ redis_install_dir }}/bin/redis-cli -p ${SENTINEL_PORT}" 24 | 25 | if [ -n "$REDIS_PASSWORD" ]; then 26 | CLIEXEC="${CLIEXEC} -a ${REDIS_PASSWORD}" 27 | fi 28 | 29 | if [ -n "$BIND_ADDRESS" ]; then 30 | CLIEXEC="${CLIEXEC} -h ${BIND_ADDRESS}" 31 | fi 32 | 33 | case "$1" in 34 | start) 35 | if [ -f $PIDFILE ] 36 | then 37 | echo "$PIDFILE exists, process is already running or crashed" 38 | else 39 | if [ -n "$NOFILE_LIMIT" ]; then 40 | ulimit -n $NOFILE_LIMIT 41 | fi 42 | echo "Starting Redis Sentinel..." 43 | daemon --user $REDIS_USER $EXEC $CONF --sentinel 44 | fi 45 | ;; 46 | stop) 47 | if [ ! -f $PIDFILE ] 48 | then 49 | echo "$PIDFILE does not exist, process is not running" 50 | else 51 | PID=$(cat $PIDFILE) 52 | echo "Stopping ..." 53 | $CLIEXEC shutdown 54 | while [ -x /proc/${PID} ] 55 | do 56 | echo "Waiting for Redis Sentinel to shutdown ..." 57 | sleep 1 58 | done 59 | echo "Redis stopped" 60 | fi 61 | ;; 62 | status) 63 | status -p "${PIDFILE}" "sentinel_${SENTINEL_PORT}" 64 | ;; 65 | restart|force-reload) 66 | ${0} stop 67 | ${0} start 68 | ;; 69 | *) 70 | echo "Usage: /etc/init.d/$NAME {start|stop|status|restart|force-reload}" >&2 71 | exit 1 72 | ;; 73 | esac 74 | 75 | exit 0 76 | -------------------------------------------------------------------------------- /templates/default/redis.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Simple Redis init.d script conceived to work on Linux systems 4 | # as it does use of the /proc filesystem. 5 | 6 | REDIS_PORT={{ redis_port }} 7 | REDIS_USER={{ redis_user }} 8 | EXEC={{ redis_install_dir }}/bin/redis-server 9 | {% if redis_password -%} 10 | CLIEXEC='{{ redis_install_dir }}/bin/redis-cli -a {{ redis_password }}' 11 | {% else -%} 12 | CLIEXEC={{ redis_install_dir }}/bin/redis-cli 13 | {% endif %} 14 | 15 | PIDFILE={{ redis_pidfile }} 16 | CONF="/etc/redis/{{ redis_config_file_name }}" 17 | 18 | case "$1" in 19 | start) 20 | if [ -f $PIDFILE ] 21 | then 22 | echo "$PIDFILE exists, process is already running or crashed" 23 | else 24 | ulimit -n {{ redis_nofile_limit }} 25 | echo "Starting Redis server..." 26 | su $REDIS_USER -c "$EXEC $CONF" 27 | fi 28 | ;; 29 | stop) 30 | if [ ! -f $PIDFILE ] 31 | then 32 | echo "$PIDFILE does not exist, process is not running" 33 | else 34 | PID=$(cat $PIDFILE) 35 | echo "Stopping ..." 36 | $CLIEXEC -p $REDIS_PORT shutdown 37 | while [ -x /proc/${PID} ] 38 | do 39 | echo "Waiting for Redis to shutdown ..." 40 | sleep 1 41 | done 42 | echo "Redis stopped" 43 | fi 44 | ;; 45 | restart|force-reload) 46 | ${0} stop 47 | ${0} start 48 | ;; 49 | *) 50 | echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2 51 | exit 1 52 | ;; 53 | esac 54 | 55 | exit 0 56 | -------------------------------------------------------------------------------- /templates/default/redis.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Advanced key-value store 3 | After=network.target 4 | Documentation=http://redis.io/documentation, man:redis-server(1) 5 | 6 | [Service] 7 | Type={{ 'forking' if redis_daemonize == 'yes' else 'simple' }} 8 | ExecStart={{ redis_install_dir }}/bin/redis-server /etc/redis/{{ redis_config_file_name }} 9 | EnvironmentFile=-/etc/default/{{ redis_service_name }} 10 | PIDFile={{ redis_pidfile }} 11 | TimeoutStopSec=0 12 | Restart=always 13 | User={{ redis_user }} 14 | Group={{ redis_group }} 15 | 16 | {% if redis_oom_score_adjust != 0 %} 17 | OOMScoreAdjust={{ redis_oom_score_adjust }} 18 | {% endif %} 19 | 20 | UMask=007 21 | PrivateTmp=yes 22 | LimitNOFILE={{ redis_nofile_limit }} 23 | PrivateDevices=yes 24 | ProtectHome=yes 25 | ReadOnlyDirectories=/ 26 | ReadWriteDirectories=-{{ redis_dir }} 27 | {% if redis_logfile != '""' %} 28 | ReadWriteDirectories=-{{ redis_logfile|dirname }} 29 | {% endif %} 30 | ReadWriteDirectories=-{{ redis_pidfile|dirname }} 31 | CapabilityBoundingSet=~CAP_SYS_PTRACE 32 | 33 | # redis-server writes its own config file when in cluster mode so we allow 34 | # writing there (NB. ProtectSystem=true over ProtectSystem=full) 35 | ProtectSystem=true 36 | ReadWriteDirectories=-/etc/redis 37 | 38 | [Install] 39 | WantedBy=multi-user.target 40 | -------------------------------------------------------------------------------- /templates/default/redis_sentinel.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Simple Redis Sentinel init.d script conceived to work on 4 | # Linux systems as it does use of the /proc filesystem. 5 | 6 | SENTINEL_PORT={{ redis_sentinel_port }} 7 | REDIS_USER={{ redis_user }} 8 | BIND_ADDRESS={{ redis_sentinel_bind }} 9 | EXEC={{ redis_install_dir }}/bin/redis-server 10 | {% if redis_password -%} 11 | CLIEXEC='{{ redis_install_dir }}/bin/redis-cli -a {{ redis_password }}' 12 | {% else -%} 13 | CLIEXEC={{ redis_install_dir }}/bin/redis-cli 14 | {% endif %} 15 | 16 | PIDFILE={{ redis_sentinel_pidfile }} 17 | CONF="/etc/redis/sentinel_${SENTINEL_PORT}.conf" 18 | 19 | case "$1" in 20 | start) 21 | if [ -f $PIDFILE ] 22 | then 23 | echo "$PIDFILE exists, process is already running or crashed" 24 | else 25 | ulimit -n {{ redis_nofile_limit }} 26 | echo "Starting Redis Sentinel..." 27 | su $REDIS_USER -c "$EXEC $CONF --sentinel" 28 | fi 29 | ;; 30 | stop) 31 | if [ ! -f $PIDFILE ] 32 | then 33 | echo "$PIDFILE does not exist, process is not running" 34 | else 35 | PID=$(cat $PIDFILE) 36 | echo "Stopping ..." 37 | $CLIEXEC -p $SENTINEL_PORT -h $BIND_ADDRESS shutdown 38 | while [ -x /proc/${PID} ] 39 | do 40 | echo "Waiting for Redis Sentinel to shutdown ..." 41 | sleep 1 42 | done 43 | echo "Redis stopped" 44 | fi 45 | ;; 46 | restart|force-reload) 47 | ${0} stop 48 | ${0} start 49 | ;; 50 | *) 51 | echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2 52 | exit 1 53 | ;; 54 | esac 55 | 56 | exit 0 57 | -------------------------------------------------------------------------------- /templates/default/redis_sentinel.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Advanced key-value store 3 | After=network.target 4 | Documentation=http://redis.io/documentation, man:redis-sentinel(1) 5 | 6 | [Service] 7 | Type={{ 'forking' if redis_daemonize == 'yes' else 'simple' }} 8 | ExecStart={{ redis_install_dir }}/bin/redis-server /etc/redis/sentinel_{{ redis_sentinel_port }}.conf --sentinel 9 | EnvironmentFile=-/etc/default/sentinel_{{ redis_sentinel_port }} 10 | PIDFile={{ redis_sentinel_pidfile }} 11 | TimeoutStopSec=0 12 | Restart=always 13 | User={{ redis_user }} 14 | Group={{ redis_group }} 15 | 16 | {% if redis_sentinel_oom_score_adjust != 0 %} 17 | OOMScoreAdjust={{ redis_sentinel_oom_score_adjust }} 18 | {% endif %} 19 | 20 | UMask=007 21 | PrivateTmp=yes 22 | LimitNOFILE={{ redis_nofile_limit }} 23 | PrivateDevices=yes 24 | ProtectHome=yes 25 | ReadOnlyDirectories=/ 26 | ReadWriteDirectories=-{{ redis_sentinel_dir }} 27 | {% if redis_sentinel_logfile != '""' %} 28 | ReadWriteDirectories=-{{ redis_sentinel_logfile|dirname }} 29 | {% endif %} 30 | ReadWriteDirectories=-{{ redis_sentinel_pidfile|dirname }} 31 | CapabilityBoundingSet=~CAP_SYS_PTRACE 32 | 33 | # redis-sentinel writes its own config file so we allow writing there (NB. 34 | # ProtectSystem=true over ProtectSystem=full) 35 | ProtectSystem=true 36 | ReadWriteDirectories=-/etc/redis 37 | 38 | [Install] 39 | WantedBy=multi-user.target 40 | -------------------------------------------------------------------------------- /templates/etc/ansible/facts.d/redis.fact.j2: -------------------------------------------------------------------------------- 1 | { 2 | "bind": "{{ redis_bind }}", 3 | "port": "{{ redis_port }}", 4 | "sentinel_bind": "{{ redis_sentinel_bind }}", 5 | "sentinel_port": "{{ redis_sentinel_port }}", 6 | "sentinel_monitors": {{ redis_sentinel_monitors | to_nice_json }} 7 | } 8 | -------------------------------------------------------------------------------- /templates/etc/tmpfiles.d/redis.conf.j2: -------------------------------------------------------------------------------- 1 | d {{ redis_pidfile|dirname }} 0755 {{ redis_user }} {{ redis_group }} 2 | {% if redis_pidfile|dirname != redis_sentinel_pidfile|dirname -%} 3 | d {{ redis_sentinel_pidfile|dirname }} 0755 {{ redis_user }} {{ redis_group }} 4 | {% endif -%} 5 | -------------------------------------------------------------------------------- /templates/redis.conf.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed | comment }} 2 | 3 | # General 4 | daemonize {{ redis_daemonize }} 5 | protected-mode {{ redis_protected_mode }} 6 | pidfile {{ redis_pidfile }} 7 | dir {{ redis_dir }} 8 | port {{ redis_port }} 9 | {% if redis_bind -%} 10 | bind {{ redis_bind }} 11 | {% endif -%} 12 | {% if redis_socket_path -%} 13 | unixsocket {{ redis_socket_path }} 14 | unixsocketperm {{ redis_socket_perm }} 15 | {% endif -%} 16 | timeout {{ redis_timeout }} 17 | tcp-keepalive {{ redis_tcp_keepalive }} 18 | tcp-backlog {{ redis_tcp_backlog }} 19 | loglevel {{ redis_loglevel }} 20 | logfile {{ redis_logfile }} 21 | syslog-enabled {{ redis_syslog_enabled }} 22 | syslog-ident {{ redis_syslog_ident }} 23 | syslog-facility {{ redis_syslog_facility }} 24 | databases {{ redis_databases }} 25 | 26 | # Snapshotting 27 | {% for save in redis_save -%} 28 | save {{ save }} 29 | {% endfor -%} 30 | stop-writes-on-bgsave-error {{ redis_stop_writes_on_bgsave_error|string }} 31 | rdbcompression {{ redis_rdbcompression|string }} 32 | rdbchecksum {{ redis_rdbchecksum|string }} 33 | dbfilename {{ redis_db_filename|string }} 34 | 35 | # Replication 36 | {% if redis_slaveof -%} 37 | slaveof {{ redis_slaveof }} 38 | {% endif -%} 39 | slave-serve-stale-data yes 40 | slave-read-only {{ redis_slave_read_only }} 41 | repl-disable-tcp-nodelay no 42 | {% if redis_repl_backlog_size -%} 43 | repl-backlog-size {{ redis_repl_backlog_size }} 44 | {% endif -%} 45 | slave-priority {{ redis_slave_priority }} 46 | {% if redis_min_slaves_to_write -%} 47 | min-slaves-to-write {{ redis_min_slaves_to_write }} 48 | {% endif -%} 49 | {% if redis_min_slaves_max_lag -%} 50 | min-slaves-max-lag {{ redis_min_slaves_max_lag }} 51 | {% endif -%} 52 | {% if redis_password -%} 53 | masterauth {{ redis_password }} 54 | {% endif -%} 55 | 56 | # Security 57 | {% if redis_password -%} 58 | requirepass {{ redis_password }} 59 | {% endif -%} 60 | {% for command in redis_rename_commands -%} 61 | rename-command {{ command }} 62 | {% endfor -%} 63 | 64 | # Limits 65 | maxclients {{ redis_maxclients }} 66 | {% if redis_maxmemory -%} 67 | maxmemory {{ redis_maxmemory }} 68 | {% endif -%} 69 | maxmemory-policy {{ redis_maxmemory_policy }} 70 | 71 | # Append Only Mode 72 | appendonly {{ redis_appendonly }} 73 | appendfilename "{{ redis_appendfilename }}" 74 | appendfsync {{ redis_appendfsync|string }} 75 | no-appendfsync-on-rewrite {{ redis_no_appendfsync_on_rewrite }} 76 | auto-aof-rewrite-percentage {{ redis_auto_aof_rewrite_percentage }} 77 | auto-aof-rewrite-min-size {{ redis_auto_aof_rewrite_min_size }} 78 | 79 | # Lua 80 | lua-time-limit {{ redis_lua_time_limit }} 81 | 82 | # Slow Log 83 | slowlog-log-slower-than {{ redis_slowlog_log_slower_than }} 84 | slowlog-max-len {{ redis_slowlog_max_len }} 85 | 86 | # Event Notification 87 | notify-keyspace-events {{ redis_notify_keyspace_events }} 88 | 89 | # Advanced 90 | hash-max-ziplist-entries 512 91 | hash-max-ziplist-value 64 92 | list-max-ziplist-entries 512 93 | list-max-ziplist-value 64 94 | set-max-intset-entries 512 95 | zset-max-ziplist-entries 128 96 | zset-max-ziplist-value 64 97 | activerehashing yes 98 | client-output-buffer-limit normal {{ redis_client_output_buffer_limit_normal }} 99 | client-output-buffer-limit slave {{ redis_client_output_buffer_limit_slave }} 100 | client-output-buffer-limit pubsub {{ redis_client_output_buffer_limit_pubsub }} 101 | hz {{ redis_hz }} 102 | aof-rewrite-incremental-fsync yes 103 | 104 | {% if redis_config_additional|length -%} 105 | # Additional 106 | {{ redis_config_additional -}} 107 | {% endif -%} -------------------------------------------------------------------------------- /templates/redis.init.conf.j2: -------------------------------------------------------------------------------- 1 | # Init script variables for Redis and Redis Sentinel 2 | # Stored in /etc/{sysconfig,default}/{redis,sentinel}_$port 3 | 4 | {% if redis_password %} 5 | REDIS_PASSWORD='{{ redis_password }}' 6 | {% endif %} 7 | NOFILE_LIMIT='{{ redis_nofile_limit }}' 8 | {% if redis_sentinel %} 9 | BIND_ADDRESS='{{ redis_sentinel_bind.split()[0] }}' 10 | {% elif redis_bind%} 11 | BIND_ADDRESS='{{ redis_bind.split()[0] }}' 12 | {% endif %} 13 | -------------------------------------------------------------------------------- /templates/redis_sentinel.conf.j2: -------------------------------------------------------------------------------- 1 | # redis-sentinel {{ redis_version }} configuration file 2 | # sentinel_{{ redis_sentinel_port }}.conf 3 | 4 | daemonize {{ redis_daemonize }} 5 | protected-mode {{ redis_sentinel_protected_mode }} 6 | dir {{ redis_sentinel_dir }} 7 | pidfile {{ redis_sentinel_pidfile }} 8 | port {{ redis_sentinel_port }} 9 | bind {{ redis_sentinel_bind }} 10 | 11 | # Security 12 | {% if redis_sentinel_password %} 13 | requirepass {{ redis_sentinel_password }} 14 | {% endif %} 15 | 16 | {% for master in redis_sentinel_monitors -%} 17 | sentinel monitor {{ master.name }} {{ master.host }} {{ master.port }} {{ master.quorum|d('2') }} 18 | {% for option in ('auth_pass', 'down_after_milliseconds', 'parallel_syncs', 'failover_timeout', 'notification_script', 'client_reconfig_script') -%} 19 | {% if master[option] is defined and master[option] -%} 20 | sentinel {{ option|replace('_', '-') }} {{ master.name }} {{ master[option] }} 21 | {% endif %} 22 | {% endfor -%} 23 | {% if master['rename_commands'] is defined -%} 24 | {% for command in master['rename_commands'] -%} 25 | sentinel rename-command {{ master.name }} {{ command }} 26 | {% endfor -%} 27 | {% endif -%} 28 | {% endfor -%} 29 | 30 | logfile {{ redis_sentinel_logfile }} 31 | syslog-enabled {{ redis_syslog_enabled }} 32 | syslog-ident {{ redis_sentinel_syslog_ident }} 33 | syslog-facility {{ redis_syslog_facility }} 34 | -------------------------------------------------------------------------------- /test/integration/checksum/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | vars: 4 | redis_verify_checksum: true 5 | redis_version: 3.0.7 6 | pre_tasks: 7 | - name: set checksum value for Ansible 1.x 8 | set_fact: 9 | redis_checksum: b2a791c4ea3bb7268795c45c6321ea5abcc24457178373e6a6e3be6372737f23 10 | when: ansible_version.major < 2 11 | roles: 12 | - ansible-redis 13 | -------------------------------------------------------------------------------- /test/integration/checksum/serverspec/redis_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Redis' do 4 | describe service('redis_6379') do 5 | it { should be_enabled } 6 | it { should be_running } 7 | end 8 | 9 | describe port(6379) do 10 | it { should be_listening.on('0.0.0.0').with('tcp') } 11 | end 12 | 13 | describe file('/etc/redis/6379.conf') do 14 | it { should be_file } 15 | it { should be_owned_by 'redis' } 16 | its(:content) { should match /port 6379/ } 17 | end 18 | 19 | describe file('/var/run/redis/6379.pid') do 20 | it { should be_file } 21 | it { should be_owned_by 'redis' } 22 | its(:size) { should > 0 } 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/integration/checksum/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | set :backend, :exec 3 | -------------------------------------------------------------------------------- /test/integration/default/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | roles: 4 | - ansible-redis 5 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/redis_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Redis' do 4 | describe service('redis_6379') do 5 | it { should be_enabled } 6 | it { should be_running } 7 | end 8 | 9 | describe port(6379) do 10 | it { should be_listening.on('0.0.0.0').with('tcp') } 11 | end 12 | 13 | describe file('/etc/redis/6379.conf') do 14 | it { should be_file } 15 | it { should be_owned_by 'redis' } 16 | its(:content) { should match /port 6379/ } 17 | end 18 | 19 | describe file('/var/run/redis/6379.pid') do 20 | it { should be_file } 21 | it { should be_owned_by 'redis' } 22 | its(:size) { should > 0 } 23 | end 24 | 25 | describe file('/proc/sys/vm/overcommit_memory') do 26 | it { should be_file } 27 | it { should contain '1' } 28 | end 29 | 30 | describe file('/usr/bin/redis-server') do 31 | it { should be_symlink } 32 | end 33 | 34 | describe file('/usr/bin/redis-cli') do 35 | it { should be_symlink } 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | set :backend, :exec 3 | -------------------------------------------------------------------------------- /test/integration/logfile/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | roles: 4 | - role: ansible-redis 5 | redis_logfile: "/var/log/redis.log" 6 | -------------------------------------------------------------------------------- /test/integration/logfile/serverspec/log_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Redis' do 4 | describe service('redis_6379') do 5 | it { should be_enabled } 6 | it { should be_running } 7 | end 8 | 9 | describe port(6379) do 10 | it { should be_listening.with('tcp') } 11 | end 12 | 13 | describe file('/var/log/redis.log') do 14 | it { should be_file } 15 | it { should be_owned_by 'redis' } 16 | its(:size) { should > 0 } 17 | end 18 | 19 | describe file('/var/log') do 20 | it { should be_directory } 21 | it { should_not be_owned_by('redis') } 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /test/integration/logfile/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | set :backend, :exec 3 | -------------------------------------------------------------------------------- /test/integration/sentinel/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | roles: 4 | - role: ansible-redis 5 | redis_sentinel: true 6 | redis_sentinel_logfile: "/var/log/redis_sentinel.log" 7 | -------------------------------------------------------------------------------- /test/integration/sentinel/serverspec/sentinel_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Redis' do 4 | describe service('sentinel_26379') do 5 | it { should be_enabled } 6 | it { should be_running } 7 | end 8 | 9 | describe port(26379) do 10 | it { should be_listening.on('0.0.0.0').with('tcp') } 11 | end 12 | 13 | describe file('/etc/redis/sentinel_26379.conf') do 14 | it { should be_file } 15 | it { should be_owned_by 'redis' } 16 | its(:content) { should match /port 26379/ } 17 | end 18 | 19 | describe file('/var/run/redis/sentinel_26379.pid') do 20 | it { should be_file } 21 | it { should be_owned_by 'redis' } 22 | its(:size) { should > 0 } 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/integration/sentinel/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | set :backend, :exec 3 | -------------------------------------------------------------------------------- /test/integration/service-name/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | roles: 4 | - role: ansible-redis 5 | redis_service_name: redis 6 | -------------------------------------------------------------------------------- /test/integration/service-name/serverspec/redis_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Redis' do 4 | describe service('redis') do 5 | it { should be_enabled } 6 | it { should be_running } 7 | end 8 | 9 | describe port(6379) do 10 | it { should be_listening.on('0.0.0.0').with('tcp') } 11 | end 12 | 13 | describe file('/etc/redis/6379.conf') do 14 | it { should be_file } 15 | it { should be_owned_by 'redis' } 16 | its(:content) { should match /port 6379/ } 17 | end 18 | 19 | describe file('/var/run/redis/6379.pid') do 20 | it { should be_file } 21 | it { should be_owned_by 'redis' } 22 | its(:size) { should > 0 } 23 | end 24 | 25 | describe file('/proc/sys/vm/overcommit_memory') do 26 | it { should be_file } 27 | it { should contain '1' } 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/integration/service-name/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | set :backend, :exec 3 | -------------------------------------------------------------------------------- /test/test_all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Test for all replication components of Redis 3 | # We're using non-standard ports here so they don't conflict with other 4 | # tests on Travis. 5 | - hosts: all 6 | remote_user: root 7 | vars: 8 | redis_version: 3.0.7 9 | redis_password: ant1r3z 10 | redis_travis_ci: true 11 | tasks: 12 | - import_role: 13 | name: ../../ansible-redis 14 | vars: 15 | redis_port: 7379 16 | 17 | - meta: flush_handlers 18 | 19 | - import_role: 20 | name: ../../ansible-redis 21 | vars: 22 | redis_port: 8379 23 | redis_slaveof: 127.0.0.1 7379 24 | redis_local_facts: false 25 | 26 | - meta: flush_handlers 27 | 28 | - import_role: 29 | name: ../../ansible-redis 30 | vars: 31 | redis_sentinel: true 32 | redis_sentinel_port: 27379 33 | redis_sentinel_monitors: 34 | - name: master01 35 | host: 127.0.0.1 36 | port: 7379 37 | quorum: 1 38 | auth_pass: "{{ redis_password }}" 39 | redis_local_facts: false 40 | -------------------------------------------------------------------------------- /test/test_sentinel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | remote_user: root 4 | vars: 5 | redis_travis_ci: true 6 | redis_sentinel: true 7 | redis_sentinel_monitors: 8 | - name: master01 9 | host: localhost 10 | port: 6379 11 | roles: 12 | - ../../ansible-redis 13 | -------------------------------------------------------------------------------- /test/test_server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | remote_user: root 4 | vars: 5 | redis_travis_ci: true 6 | roles: 7 | - ../../ansible-redis 8 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | # From https://github.com/antirez/redis-hashes 2 | # Generate with: 3 | # $ curl -s https://raw.githubusercontent.com/antirez/redis-hashes/master/README | gawk '/^hash/ { print gensub(/redis-(.*)\.tar\.gz/, "\\1", "g", $2) ": " $4 }' |sort --version-sort 4 | redis_checksums: 5 | 2.6.17: b5423e1c423d502074cbd0b21bd4e820409d2003 6 | 2.8.0-rc5: bd27589b71a0b406b982485051f32b7c40c9d2c1 7 | 2.8.0-rc6: d13db76145a9844e2a3302f561e907056f9e21a0 8 | 2.8.0: 41fd86128995f06502954dd6d6269c22f5e389f7 9 | 2.8.1: 1bb493318ff6c0c87334eb95640b89a16e4357d8 10 | 2.8.2: 3be038b9d095ce3dece7918aae810d14fe770400 11 | 2.8.3: a751371eeed5f5f02965eb34d989c1963dd8d8c7 12 | 2.8.4: 79b156cc9d8bff5a022fdc6d28d5c42999ddcb4f 13 | 2.8.5: f0eb48609ff66ead3c7f06bbe8a8dd1aa7341b73 14 | 2.8.6: 8680046580c75987961241f2e1e417c242b91a49 15 | 2.8.7: acc369093ec74223e6da207921595187f7e64998 16 | 2.8.8: aa811f399db58c92c8ec5e48271d307e9ab8eb81 17 | 2.8.9: 003ccdc175816e0a751919cf508f1318e54aac1e 18 | 2.8.10: 339ddf82e01a16ad912d1c1d59b02f3fab58d9d9 19 | 2.8.11: 3e3a4603781514f239f040287d3ef1097eb02a76 20 | 2.8.12: 56c86a4f9eccaf29f934433c7c67a175e404b2f6 21 | 2.8.13: a72925a35849eb2d38a1ea076a3db82072d4ee43 22 | 2.8.14: fd0edc045f2b53057d7f6ab38e2fe99086c87e8d 23 | 2.8.15: afc0d753cea68a26038775df2dea75a76e3d0e1d 24 | 2.8.16: 198045c8291dd832788ac8a17d2e565752499942 25 | 2.8.17: 913479f9d2a283bfaadd1444e17e7bab560e5d1e 26 | 2.8.18: 129629262fea2bc60daa542f52457e65e6aa7fd5 27 | 2.8.19: 3e362f4770ac2fdbdce58a5aa951c1967e0facc8 28 | 2.8.20: 45f134113fb3d75b8c37f7968e46565a70800091 29 | 2.8.21: 52f619d3d301fc7ae498a1d4cb4d44ecebc5b0f9 30 | 2.8.22: 78a70b32cdd3a4ccc58880d1821fb828d091bb36 31 | 2.8.23: 828fc5d4011e6141fabb2ad6ebc193e8f0d08cfa 32 | 3.0.0-rc1: f0934db86791e32053f8b21ddec5965793edff19 33 | 3.0.0: c75fd32900187a7c9f9d07c412ea3b3315691c65 34 | 3.0.1: fe1d06599042bfe6a0e738542f302ce9533dde88 35 | 3.0.2: a38755fe9a669896f7c5d8cd3ebbf76d59712002 36 | 3.0.3: 0e2d7707327986ae652df717059354b358b83358 37 | 3.0.4: cccc58b2b8643930840870f17280fcae57ed7675 38 | 3.0.5: ad3ee178c42bfcfd310c72bbddffbbe35db9b4a6 39 | 3.0.6: 4b1c7b1201984bca8f7f9c6c58862f6928cf0a25 40 | 3.0.7: e56b4b7e033ae8dbf311f9191cf6fdf3ae974d1c 41 | 3.2.0: 0c1820931094369c8cc19fc1be62f598bc5961ca 42 | 3.2.1: 26c0fc282369121b4e278523fce122910b65fbbf 43 | 3.2.2: 3141be9757532139f445bd5f6f4fae293bc33d27 44 | 3.2.3: 92d6d93ef2efc91e595c8bf578bf72baff397507 45 | 3.2.4: f0fe685cbfdb8c2d8c74613ad8a5a5f33fba40c9 46 | 3.2.5: 6f6333db6111badaa74519d743589ac4635eba7a 47 | 3.2.6: 0c7bc5c751bdbc6fabed178db9cdbdd948915d1b 48 | 3.2.7: 6889af053020cd72ebb16805ead0ce9b3a69a9ef 49 | 3.2.8: 6780d1abb66f33a97aad0edbe020403d0a15b67f 50 | 3.2.9: 6eaacfa983b287e440d0839ead20c2231749d5d6b78bbe0e0ffa3a890c59ff26 51 | 3.2.10: 411c604a716104f7f5a326abfad32de9cea10f15f987bec45cf86f315e9e63a0 52 | 3.2.11: 31ae927cab09f90c9ca5954aab7aeecc3bb4da6087d3d12ba0a929ceb54081b5 53 | 3.2.12: 98c4254ae1be4e452aa7884245471501c9aa657993e0318d88f048093e7f88fd 54 | 3.2.13: 862979c9853fdb1d275d9eb9077f34621596fec1843e3e7f2e2f09ce09a387ba 55 | 4.0.0: d539ae309295721d5c3ed7298939645b6f86ab5d25fdf2a0352ab575c159df2d 56 | 4.0.1: 2049cd6ae9167f258705081a6ef23bb80b7eff9ff3d0d7481e89510f27457591 57 | 4.0.2: b1a0915dbc91b979d06df1977fe594c3fa9b189f1f3d38743a2948c9f7634813 58 | 4.0.3: 412f2634e55fe19e8826fae47935a8efe1e60ba2a48a8953c65e7a6caa459e41 59 | 4.0.4: 35768145335e874b1b810e23494ad3daa6f442c3dc1d7e3784992ba50799c0cd 60 | 4.0.5: d52bf355b96e20905916482962235e0442634c849934adb034f85362b31ed978 61 | 4.0.6: 769b5d69ec237c3e0481a262ff5306ce30db9b5c8ceb14d1023491ca7be5f6fa 62 | 4.0.7: 1bba546d44fb40e1fd8be1a15e1a9cc6484bceeea0bbd52919eebc656661ecd1 63 | 4.0.8: ff0c38b8c156319249fec61e5018cf5b5fe63a65b61690bec798f4c998c232ad 64 | 4.0.9: df4f73bc318e2f9ffb2d169a922dec57ec7c73dd07bccf875695dbeecd5ec510 65 | 4.0.10: 1db67435a704f8d18aec9b9637b373c34aa233d65b6e174bdac4c1b161f38ca4 66 | 4.0.11: fc53e73ae7586bcdacb4b63875d1ff04f68c5474c1ddeda78f00e5ae2eed1bbb 67 | 4.0.12: 6447259d2eed426a949c9c13f8fdb2d91fb66d9dc915dd50db13b87f46d93162 68 | 4.0.13: 17d955227966dcd68590be6139e5fe7f2d19fc4fb7334248a904ea9cdd30c1d4 69 | 4.0.14: 1e1e18420a86cfb285933123b04a82e1ebda20bfb0a289472745a087587e93a7 70 | 5.0-rc4: bfc7a27d3ba990e154e5b56484061f01962d40b7c77b520ed7a940914b267cec 71 | 5.0-rc5.tar.gz: d070c8a3514e40da5cef9ec26dfd594df0468c203c36398ef2d359a32502b548 72 | 5.0-rc6: 5e5ffc9184021178c1d89375c5132a2b872a9f77569e8c08ccbdf322acff7ace 73 | 5.0.0: 70c98b2d0640b2b73c9d8adb4df63bcb62bad34b788fe46d1634b6cf87dc99a4 74 | 5.0.1: 82a67c0eec97f9ad379384c30ec391b269e17a3e4596393c808f02db7595abcb 75 | 5.0.2: 937dde6164001c083e87316aa20dad2f8542af089dfcb1cbb64f9c8300cd00ed 76 | 5.0.3: e290b4ddf817b26254a74d5d564095b11f9cd20d8f165459efa53eb63cd93e02 77 | 5.0.4: 3ce9ceff5a23f60913e1573f6dfcd4aa53b42d4a2789e28fa53ec2bd28c987dd 78 | 5.0.5: 2139009799d21d8ff94fc40b7f36ac46699b9e1254086299f8d3b223ca54a375 79 | 5.0.6: 6624841267e142c5d5d5be292d705f8fb6070677687c5aad1645421a936d22b3 80 | 5.0.7: 61db74eabf6801f057fd24b590232f2f337d422280fd19486eca03be87d3a82b 81 | 5.0.8: f3c7eac42f433326a8d981b50dba0169fdfaf46abb23fcda2f933a7552ee4ed7 82 | 5.0.9: 53d0ae164cd33536c3d4b720ae9a128ea6166ebf04ff1add3b85f1242090cb85 83 | 5.0.10: e30a5e7d1593a715cdda2a82deb90190816d06c9d1dc1ef5b36874878c683382 84 | 5.0.11: 418135c453a94aac24c24243b041fb978fcc3ea4e1e1f996c1d64b16ae6ac1aa 85 | 5.0.12: 7040eba5910f7c3d38f05ea5a1d88b480488215bdbd2e10ec70d18380108e31e 86 | 5.0.13: 2b617aa2d6ad66c6a5d99fc8590c6b83b40d391fd1184c6eeab30df31f6a7208 87 | 5.0.14: 3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32 88 | 6.0-rc1: 3e11d148de0b3c3e573a31b6abb3cba56812aefe3f9a917a445768cc510b5fe3 89 | 6.0-rc2: 60dc45d8ab41de59a12d1163f7f79911f289f4d73b5066e027942eddec259a88 90 | 6.0-rc3: aa5916b7ee9a7098032cb875f3f0bfb4405f6e2533d7f6284dfbca21f55fc289 91 | 6.0-rc4: 7fdc37fd9451571e90186115a67d7595d49206f90bd7c2b7505b197fd6544358 92 | 6.0.0: 16d13ec1c3255206deb4818ed444dca6dda1482b551736f0033253c211b788fc 93 | 6.0.1: b8756e430479edc162ba9c44dc89ac394316cd482f2dc6b91bcd5fe12593f273 94 | 6.0.2: 9c37cd4228a57e82e7037094751c63349302b0b86c5e30b778a63a802dfd0109 95 | 6.0.3: bca46dce81fe92f7b2de4cf8ae41fbc4b94fbd5674def7f12c87e7f9165cbb3a 96 | 6.0.4: 3337005a1e0c3aa293c87c313467ea8ac11984921fab08807998ba765c9943de 97 | 6.0.5: 42cf86a114d2a451b898fcda96acd4d01062a7dbaaad2801d9164a36f898f596 98 | 6.0.6: 12ad49b163af5ef39466e8d2f7d212a58172116e5b441eebecb4e6ca22363d94 99 | 6.0.7: c2aaa1a4c7e72c70adedf976fdd5e1d34d395989283dab9d7840e0a304bb2393 100 | 6.0.8: 04fa1fddc39bd1aecb6739dd5dd73858a3515b427acd1e2947a66dadce868d68 101 | 6.0.9: dc2bdcf81c620e9f09cfd12e85d3bc631c897b2db7a55218fd8a65eaa37f86dd 102 | 6.0.10: 79bbb894f9dceb33ca699ee3ca4a4e1228be7fb5547aeb2f99d921e86c1285bd 103 | 6.0.11: c927f2d110e88fda308526a1809a4d7dfcd004319f0de66d40a58a42aec23c5f 104 | 6.0.12: f16ad973d19f80f121e53794d5eb48a997e2c6a85b5be41bb3b66750cc17bf6b 105 | 6.0.13: 3049763f4553ddd5a69552f41da3dd7dde9fbc524dbb15e517fee24cc73b790c 106 | 6.0.14: c3e60c928b183ca9fe8e878936a6f8ba99e0441b9b6e04d2412a750ea576c649 107 | 6.0.15: 4bc295264a95bc94423c162a9eee66135a24a51eefe5f53f18fc9bde5c3a9f74 108 | 6.0.16: 3639bbf29aca1a1670de1ab2ce224d6511c63969e7e590d3cdf8f7888184fa19 109 | 6.2-rc1: 92fc13f57b31cb6425c590b9c6b0bf611450f66b18fe92b9d5893b3a9760c438 110 | 6.2-rc2: 7153bbbd751f61ea70e649e0d19be6e7e78da9864527d46d10519e9a03cb0924 111 | 6.2-rc3: f35bba2af553fb58b2068ee581f316cefe0c00041e48fc944bd962e65777851c 112 | 6.2.0: 67d624c25d962bd68aff8812a135df85bad07556b8825f3bcd5b522a9932dbca 113 | 6.2.1: cd222505012cce20b25682fca931ec93bd21ae92cb4abfe742cf7b76aa907520 114 | 6.2.2: 7a260bb74860f1b88c3d5942bf8ba60ca59f121c6dce42d3017bed6add0b9535 115 | 6.2.3: 98ed7d532b5e9671f5df0825bb71f0f37483a16546364049384c63db8764512b 116 | 6.2.4: ba32c406a10fc2c09426e2be2787d74ff204eb3a2e496d87cff76a476b6ae16e 117 | 6.2.5: 4b9a75709a1b74b3785e20a6c158cab94cf52298aa381eea947a678a60d551ae 118 | 6.2.6: 5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab 119 | --------------------------------------------------------------------------------