From e3423bea2f4e326acd1ee9711ba673a7c7d8bafc Mon Sep 17 00:00:00 2001
From: Mathias Ewald <mewald@evoila.de>
Date: Fri, 21 Jul 2017 07:08:54 +0000
Subject: [PATCH] Add Redis role

Rollout redis container in master/slave configuration

Deploy redis-sentinel and connect to redis cluster
Redis is needed for mistral coordination backend.

Partial-Bug: #1700591
Change-Id: Ic0269d0db10624925e7bcdbf0e33ae87b84a9cf2
---
 ansible/group_vars/all.yml                    |  4 ++
 ansible/inventory/all-in-one                  |  3 +
 ansible/inventory/multinode                   |  3 +
 ansible/roles/redis/defaults/main.yml         | 34 ++++++++++++
 ansible/roles/redis/handlers/main.yml         | 42 ++++++++++++++
 ansible/roles/redis/meta/main.yml             |  3 +
 ansible/roles/redis/tasks/config.yml          | 50 +++++++++++++++++
 ansible/roles/redis/tasks/deploy.yml          |  5 ++
 ansible/roles/redis/tasks/main.yml            |  2 +
 ansible/roles/redis/tasks/precheck.yml        | 20 +++++++
 ansible/roles/redis/tasks/pull.yml            | 10 ++++
 ansible/roles/redis/tasks/reconfigure.yml     |  2 +
 ansible/roles/redis/tasks/upgrade.yml         |  5 ++
 .../redis/templates/redis-sentinel.conf.j2    | 11 ++++
 .../redis/templates/redis-sentinel.json.j2    | 18 ++++++
 ansible/roles/redis/templates/redis.conf.j2   | 55 +++++++++++++++++++
 ansible/roles/redis/templates/redis.json.j2   | 18 ++++++
 ansible/site.yml                              | 10 ++++
 etc/kolla/globals.yml                         |  1 +
 etc/kolla/passwords.yml                       |  5 ++
 20 files changed, 301 insertions(+)
 create mode 100644 ansible/roles/redis/defaults/main.yml
 create mode 100644 ansible/roles/redis/handlers/main.yml
 create mode 100644 ansible/roles/redis/meta/main.yml
 create mode 100644 ansible/roles/redis/tasks/config.yml
 create mode 100644 ansible/roles/redis/tasks/deploy.yml
 create mode 100644 ansible/roles/redis/tasks/main.yml
 create mode 100644 ansible/roles/redis/tasks/precheck.yml
 create mode 100644 ansible/roles/redis/tasks/pull.yml
 create mode 100644 ansible/roles/redis/tasks/reconfigure.yml
 create mode 100644 ansible/roles/redis/tasks/upgrade.yml
 create mode 100644 ansible/roles/redis/templates/redis-sentinel.conf.j2
 create mode 100644 ansible/roles/redis/templates/redis-sentinel.json.j2
 create mode 100644 ansible/roles/redis/templates/redis.conf.j2
 create mode 100644 ansible/roles/redis/templates/redis.json.j2

diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 16443a2872..5e521f8aac 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -228,6 +228,9 @@ rabbitmq_management_port: "15672"
 rabbitmq_cluster_port: "25672"
 rabbitmq_epmd_port: "4369"
 
+redis_port: "6379"
+redis_sentinel_port: "26379"
+
 rdp_port: "8001"
 
 rgw_port: "6780"
@@ -375,6 +378,7 @@ enable_openvswitch: "{{ neutron_plugin_agent != 'linuxbridge' | bool }}"
 enable_osprofiler: "no"
 enable_panko: "no"
 enable_rally: "no"
+enable_redis: "no"
 enable_sahara: "no"
 enable_searchlight: "no"
 enable_senlin: "no"
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index 04f8b01313..01258a164a 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -209,6 +209,9 @@ control
 [skydive:children]
 monitoring
 
+[redis:children]
+control
+
 # Additional control implemented here. These groups allow you to control which
 # services run on which hosts at a per-service level.
 #
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 66ff970d6a..4adaf7732f 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -227,6 +227,9 @@ control
 [skydive:children]
 monitoring
 
+[redis:children]
+control
+
 # Additional control implemented here. These groups allow you to control which
 # services run on which hosts at a per-service level.
 #
diff --git a/ansible/roles/redis/defaults/main.yml b/ansible/roles/redis/defaults/main.yml
new file mode 100644
index 0000000000..3ff30a8c3c
--- /dev/null
+++ b/ansible/roles/redis/defaults/main.yml
@@ -0,0 +1,34 @@
+---
+project_name: "redis"
+
+redis_services:
+  redis:
+    container_name: redis
+    group: redis
+    enabled: true
+    image: "{{ redis_image_full }}"
+    volumes:
+      - "{{ node_config_directory }}/redis/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "{{ project_name }}:/var/lib/redis/"
+      - "kolla_logs:/var/log/kolla/"
+  redis-sentinel:
+    container_name: redis_sentinel
+    group: redis
+    enabled: true
+    image: "{{ redis_sentinel_image_full }}"
+    volumes:
+      - "{{ node_config_directory }}/redis-sentinel/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+
+####################
+# Docker
+####################
+redis_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-redis"
+redis_tag: "{{ openstack_release }}"
+redis_image_full: "{{ redis_image }}:{{ redis_tag }}"
+
+redis_sentinel_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-redis-sentinel"
+redis_sentinel_tag: "{{ openstack_release }}"
+redis_sentinel_image_full: "{{ redis_sentinel_image }}:{{ redis_tag }}"
diff --git a/ansible/roles/redis/handlers/main.yml b/ansible/roles/redis/handlers/main.yml
new file mode 100644
index 0000000000..a2dbf0a9c1
--- /dev/null
+++ b/ansible/roles/redis/handlers/main.yml
@@ -0,0 +1,42 @@
+---
+- name: Restart redis container
+  vars:
+    service_name: "redis"
+    service: "{{ redis_services[service_name] }}"
+    config_json: "{{ redis_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    redis_conf: "{{ redis_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    redis_container: "{{ check_redis_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    volumes: "{{ service.volumes }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or redis_confs.changed |bool
+      or redis_container.changed | bool
+
+- name: Restart redis-sentinel container
+  vars:
+    service_name: "redis-sentinel"
+    service: "{{ redis_services[service_name] }}"
+    config_json: "{{ redis_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    redis_conf: "{{ redis_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    redis_container: "{{ check_redis_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    volumes: "{{ service.volumes }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or redis_confs.changed |bool
+      or redis_container.changed | bool
diff --git a/ansible/roles/redis/meta/main.yml b/ansible/roles/redis/meta/main.yml
new file mode 100644
index 0000000000..6b4fff8fef
--- /dev/null
+++ b/ansible/roles/redis/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - { role: common }
diff --git a/ansible/roles/redis/tasks/config.yml b/ansible/roles/redis/tasks/config.yml
new file mode 100644
index 0000000000..7ae888ba31
--- /dev/null
+++ b/ansible/roles/redis/tasks/config.yml
@@ -0,0 +1,50 @@
+---
+- name: Ensuring config directories exist
+  file:
+    path: "{{ node_config_directory }}/{{ item.key }}"
+    state: "directory"
+    recurse: yes
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ redis_services }}"
+
+- name: Copying over default config.json files
+  template:
+    src: "{{ item.key }}.json.j2"
+    dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
+  register: redis_config_jsons
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ redis_services }}"
+  notify:
+    - Restart {{ item.key }} container
+
+- name: Copying over redis config files
+  template:
+    src: "{{ item.key }}.conf.j2"
+    dest: "{{ node_config_directory }}/{{ item.key }}/redis.conf"
+  register: redis_confs
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ redis_services }}"
+  notify:
+    - Restart {{ item.key }} container
+
+- name: Check redis containers
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ item.value.container_name }}"
+    image: "{{ item.value.image }}"
+    volumes: "{{ item.value.volumes }}"
+  register: check_redis_containers
+  when:
+    - action != "config"
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ redis_services }}"
+  notify:
+    - Restart {{ item.key }} container
diff --git a/ansible/roles/redis/tasks/deploy.yml b/ansible/roles/redis/tasks/deploy.yml
new file mode 100644
index 0000000000..dd26ecc34d
--- /dev/null
+++ b/ansible/roles/redis/tasks/deploy.yml
@@ -0,0 +1,5 @@
+---
+- include: config.yml
+
+- name: Flush handlers
+  meta: flush_handlers
diff --git a/ansible/roles/redis/tasks/main.yml b/ansible/roles/redis/tasks/main.yml
new file mode 100644
index 0000000000..b017e8b4ad
--- /dev/null
+++ b/ansible/roles/redis/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+- include: "{{ action }}.yml"
diff --git a/ansible/roles/redis/tasks/precheck.yml b/ansible/roles/redis/tasks/precheck.yml
new file mode 100644
index 0000000000..ec94321cdb
--- /dev/null
+++ b/ansible/roles/redis/tasks/precheck.yml
@@ -0,0 +1,20 @@
+---
+- name: Get container facts
+  kolla_container_facts:
+    name:
+      - redis
+  register: container_facts
+
+- name: Checking free port for Redis
+  vars:
+    redis: "{{ redis_services['redis'] }}"
+  wait_for:
+    host: "{{ api_interface_address }}"
+    port: "{{ redis_port }}"
+    connect_timeout: 1
+    timeout: 1
+    state: stopped
+  when:
+    - container_facts['redis'] is not defined
+    - inventory_hostname in groups[redis.group]
+    - redis.enabled | bool
diff --git a/ansible/roles/redis/tasks/pull.yml b/ansible/roles/redis/tasks/pull.yml
new file mode 100644
index 0000000000..6fefbdbf2c
--- /dev/null
+++ b/ansible/roles/redis/tasks/pull.yml
@@ -0,0 +1,10 @@
+---
+- name: Pulling redis images
+  kolla_docker:
+    action: "pull_image"
+    common_options: "{{ docker_common_options }}"
+    image: "{{ item.value.image }}"
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ redis_services }}"
diff --git a/ansible/roles/redis/tasks/reconfigure.yml b/ansible/roles/redis/tasks/reconfigure.yml
new file mode 100644
index 0000000000..56169f9727
--- /dev/null
+++ b/ansible/roles/redis/tasks/reconfigure.yml
@@ -0,0 +1,2 @@
+---
+- include: "deploy.yml"
diff --git a/ansible/roles/redis/tasks/upgrade.yml b/ansible/roles/redis/tasks/upgrade.yml
new file mode 100644
index 0000000000..dd26ecc34d
--- /dev/null
+++ b/ansible/roles/redis/tasks/upgrade.yml
@@ -0,0 +1,5 @@
+---
+- include: config.yml
+
+- name: Flush handlers
+  meta: flush_handlers
diff --git a/ansible/roles/redis/templates/redis-sentinel.conf.j2 b/ansible/roles/redis/templates/redis-sentinel.conf.j2
new file mode 100644
index 0000000000..0e034e9a33
--- /dev/null
+++ b/ansible/roles/redis/templates/redis-sentinel.conf.j2
@@ -0,0 +1,11 @@
+{% set redis_master_address = hostvars[groups['redis'][0]]['ansible_' + hostvars[groups['redis'][0]]['api_interface']]['ipv4']['address'] %}
+daemonize no
+pidfile "/var/run/redis/redis-sentinel.pid"
+logfile "/var/log/kolla/redis/redis-sentinel.log"
+bind {{ api_interface_address }}
+port {{ redis_sentinel_port }}
+sentinel monitor kolla {{ redis_master_address }} {{ redis_port }} 2
+sentinel auth-pass kolla {{ redis_master_password }}
+sentinel down-after-milliseconds kolla 5000
+sentinel failover-timeout kolla 60000
+sentinel parallel-syncs kolla 1
diff --git a/ansible/roles/redis/templates/redis-sentinel.json.j2 b/ansible/roles/redis/templates/redis-sentinel.json.j2
new file mode 100644
index 0000000000..b8df171bb0
--- /dev/null
+++ b/ansible/roles/redis/templates/redis-sentinel.json.j2
@@ -0,0 +1,18 @@
+{
+    "command": "redis-sentinel /etc/redis/redis.conf",
+    "config_files": [
+        {
+            "source": "{{ container_config_directory }}/redis.conf",
+            "dest": "/etc/redis/redis.conf",
+            "owner": "redis",
+            "perm": "0600"
+        }
+    ],
+    "permissions": [
+        {
+            "path": "/var/log/kolla/redis",
+            "owner": "redis:redis",
+            "recurse": true
+        }
+    ]
+}
diff --git a/ansible/roles/redis/templates/redis.conf.j2 b/ansible/roles/redis/templates/redis.conf.j2
new file mode 100644
index 0000000000..e96f359d59
--- /dev/null
+++ b/ansible/roles/redis/templates/redis.conf.j2
@@ -0,0 +1,55 @@
+bind {{ api_interface_address }}
+port {{ redis_port }}
+tcp-backlog 511
+timeout 0
+tcp-keepalive 300
+daemonize no
+pidfile /var/run/redis/redis-server.pid
+loglevel notice
+logfile /var/log/kolla/redis/redis.log
+databases 16
+save 900 1
+save 300 10
+save 60 10000
+stop-writes-on-bgsave-error yes
+rdbcompression yes
+rdbchecksum yes
+dbfilename dump.rdb
+dir /var/lib/redis
+slave-serve-stale-data yes
+slave-read-only yes
+repl-diskless-sync no
+repl-diskless-sync-delay 5
+repl-disable-tcp-nodelay no
+slave-priority 100
+appendonly yes
+appendfilename "redis-staging-ao.aof"
+appendfsync everysec
+no-appendfsync-on-rewrite no
+auto-aof-rewrite-percentage 100
+auto-aof-rewrite-min-size 64mb
+aof-load-truncated yes
+lua-time-limit 5000
+slowlog-log-slower-than 10000
+slowlog-max-len 128
+latency-monitor-threshold 0
+notify-keyspace-events ""
+hash-max-ziplist-entries 512
+hash-max-ziplist-value 64
+set-max-intset-entries 512
+zset-max-ziplist-entries 128
+zset-max-ziplist-value 64
+hll-sparse-max-bytes 3000
+activerehashing yes
+client-output-buffer-limit normal 0 0 0
+client-output-buffer-limit slave 256mb 64mb 60
+client-output-buffer-limit pubsub 32mb 8mb 60
+hz 10
+aof-rewrite-incremental-fsync yes
+requirepass {{ redis_master_password }}
+masterauth {{ redis_master_password }}
+
+{% if inventory_hostname != groups['redis'][0] %}
+{% set redis_master_address = hostvars[groups['redis'][0]]['ansible_' + hostvars[groups['redis'][0]]['api_interface']]['ipv4']['address'] %}
+slaveof {{ redis_master_address }} 6379
+{% endif %}
diff --git a/ansible/roles/redis/templates/redis.json.j2 b/ansible/roles/redis/templates/redis.json.j2
new file mode 100644
index 0000000000..063c2ad69f
--- /dev/null
+++ b/ansible/roles/redis/templates/redis.json.j2
@@ -0,0 +1,18 @@
+{
+    "command": "redis-server /etc/redis/redis.conf",
+    "config_files": [
+        {
+            "source": "{{ container_config_directory }}/redis.conf",
+            "dest": "/etc/redis/redis.conf",
+            "owner": "redis",
+            "perm": "0600"
+        }
+    ],
+    "permissions": [
+        {
+            "path": "/var/log/kolla/redis",
+            "owner": "redis:redis",
+            "recurse": true
+        }
+    ]
+}
diff --git a/ansible/site.yml b/ansible/site.yml
index f8f1cc3505..4e3ec623f8 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -103,6 +103,16 @@
         tags: telegraf,
         when: enable_telegraf | bool }
 
+- name: Apply role redis
+  gather_facts: false
+  hosts:
+    - redis
+  serial: '{{ serial|default("0") }}'
+  roles:
+    - { role: redis,
+        tags: redis,
+        when: enable_redis | bool }
+
 - name: Apply role haproxy
   gather_facts: false
   hosts:
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index bff5bb94fa..87cc095fe9 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -186,6 +186,7 @@ kolla_internal_vip_address: "10.10.10.254"
 #enable_osprofiler: "no"
 #enable_panko: "no"
 #enable_rally: "no"
+#enable_redis: "no"
 #enable_sahara: "no"
 #enable_searchlight: "no"
 #enable_senlin: "no"
diff --git a/etc/kolla/passwords.yml b/etc/kolla/passwords.yml
index 50b99c5351..97d1e34570 100644
--- a/etc/kolla/passwords.yml
+++ b/etc/kolla/passwords.yml
@@ -198,3 +198,8 @@ kibana_password:
 # etcd options
 ####################
 etcd_cluster_token:
+
+####################
+# redis options
+####################
+redis_master_password: