Redis master/slave cluster with sentinel
diff --git a/redis/cluster.sls b/redis/cluster.sls
new file mode 100644
index 0000000..eb3a811
--- /dev/null
+++ b/redis/cluster.sls
@@ -0,0 +1,17 @@
+{%- from "redis/map.jinja" import server with context %}
+{%- from "redis/map.jinja" import cluster with context %}
+
+{%- if cluster.enabled %}
+
+{{ server.conf_dir }}/sentinel.conf:
+  file.managed:
+  - source: salt://redis/files/{{ server.version }}/sentinel.conf
+  - template: jinja
+  - user: root
+  - group: root
+  - mode: 644
+  - require:
+    - pkg: redis_packages
+
+{%- endif %}
+
diff --git a/redis/files/2.8/redis.conf b/redis/files/2.8/redis.conf
index 041d266..55bcc44 100644
--- a/redis/files/2.8/redis.conf
+++ b/redis/files/2.8/redis.conf
@@ -1,4 +1,5 @@
 {% from "redis/map.jinja" import server with context %}
+{% from "redis/map.jinja" import cluster with context %}
 
 # Redis configuration file example
 
@@ -80,7 +81,11 @@
 # On other kernels the period depends on the kernel configuration.
 #
 # A reasonable value for this option is 60 seconds.
+{%- if cluster.enabled %}
+tcp-keepalive 60
+{%- else %}
 tcp-keepalive 0
+{%- endif %}
 
 # Specify the server verbosity level.
 # This can be one of:
@@ -187,6 +192,9 @@
 # different interval, or to listen to another port, and so on.
 #
 # slaveof <masterip> <masterport>
+{%- if cluster.enabled and cluster.get("mode", "sentinel") == "sentinel" and cluster.role == "slave" %}
+slaveof {{ cluster.master.host }} {{ cluster.master.port }}
+{%- endif %}
 
 # If the master is password protected (using the "requirepass" configuration
 # directive below) it is possible to tell the slave to authenticate before
@@ -194,6 +202,9 @@
 # refuse the slave request.
 #
 # masterauth <master-password>
+{%- if cluster.enabled and cluster.get("mode", "sentinel") == "sentinel" and cluster.role == "slave" and cluster.get("password", None) %}
+masterauth {{ cluster.password }}
+{%- endif %}
 
 # When a slave loses its connection with the master, or when the replication
 # is still in progress, the slave can act in two different ways:
@@ -330,6 +341,9 @@
 # use a very strong password otherwise it will be very easy to break.
 #
 # requirepass foobared
+{%- if cluster.enabled and cluster.get("password", None) %}
+requirepass {{ cluster.password }}
+{%- endif %}
 
 # Command renaming.
 #
@@ -439,7 +453,11 @@
 #
 # Please check http://redis.io/topics/persistence for more information.
 
+{%- if cluster.enabled and cluster.get("mode", "sentinel") == "sentinel" and cluster.role == "master" %}
+appendonly yes
+{%- else %}
 appendonly no
+{%- endif %}
 
 # The name of the append only file (default: "appendonly.aof")
 
diff --git a/redis/files/2.8/sentinel.conf b/redis/files/2.8/sentinel.conf
new file mode 100644
index 0000000..716b4fd
--- /dev/null
+++ b/redis/files/2.8/sentinel.conf
@@ -0,0 +1,10 @@
+{% from "redis/map.jinja" import cluster with context %}
+port 26379
+sentinel monitor master_1 {{ cluster.master.host }} {{ cluster.master.port }} {{ cluster.quorum }}
+sentinel down-after-milliseconds master_1 5000
+sentinel failover-timeout master_1 60000
+sentinel config-epoch master_1 1
+{%- if cluster.enabled and cluster.get("password", None) %}
+sentinel auth-pass master_1 {{ cluster.password }}
+{%- endif %}
+
diff --git a/redis/files/supervisor.conf b/redis/files/supervisor.conf
new file mode 100644
index 0000000..5dac1f0
--- /dev/null
+++ b/redis/files/supervisor.conf
@@ -0,0 +1,10 @@
+{%- from "linux/map.jinja" import network with context %}
+{%- set service = salt['pillar.get']('supervisor:server:service:'+service_name) %}
+
+[program:{{ service.type }}_{{ service.name }}]
+command=redis-sentinel /etc/redis/sentinel.conf
+stdout_logfile=/var/log/redis/redis-sentinel.out.log
+stderr_logfile=/var/log/redis/redis-sentinel.err.log
+autostart=true
+autorestart=true
+
diff --git a/redis/init.sls b/redis/init.sls
index 77bb85e..df7a46e 100644
--- a/redis/init.sls
+++ b/redis/init.sls
@@ -3,3 +3,7 @@
 {% if pillar.redis.server is defined %}
 - redis.server
 {% endif %}
+{% if pillar.redis.cluster is defined %}
+- redis.cluster
+{% endif %}
+
diff --git a/redis/map.jinja b/redis/map.jinja
index 914081f..eb9e343 100755
--- a/redis/map.jinja
+++ b/redis/map.jinja
@@ -12,7 +12,7 @@
     'Debian': {
         'pkgs': ['redis-server'],
         'service': 'redis-server',
-        'conf_dir': '/etc/redis/redis.conf',
+        'conf_dir': '/etc/redis/',
         'bind': {
             'address': '127.0.0.1',
             'port': '6379'
@@ -28,3 +28,10 @@
         }
     },
 }, merge=salt['pillar.get']('redis:server')) %}
+
+{% set cluster = salt['grains.filter_by']({
+    'Debian': {
+      'enabled': False
+    },
+}, merge=salt['pillar.get']('redis:cluster')) %}
+
diff --git a/redis/server.sls b/redis/server.sls
index 3291ea6..6b8d303 100755
--- a/redis/server.sls
+++ b/redis/server.sls
@@ -10,7 +10,7 @@
   sysctl.present:
     - value: 1
 
-{{ server.conf_dir }}:
+{{ server.conf_dir }}/redis.conf:
   file.managed:
   - source: salt://redis/files/{{ server.version }}/redis.conf
   - template: jinja
@@ -25,6 +25,6 @@
   - enable: true
   - name: {{ server.service }}
   - watch:
-    - file: {{ server.conf_dir }}
+    - file: {{ server.conf_dir }}/redis.conf
 
 {%- endif %}