diff --git a/roles/redis/README.md b/roles/redis/README.md new file mode 100644 index 0000000..d167ac2 --- /dev/null +++ b/roles/redis/README.md @@ -0,0 +1,10 @@ +# `finallycoffee.databases.redis` ansible role + +Redis is the self-proclaimed world's fastest data platform for caching, +vector search and NoSQL databases. Since version 7.2.4, it is no longer +considered "Free and open source software" (FOSS), with redis switching +their license to the "Serverside public license" (SSPL). + +Setting the `redis_version` to higher than `7.2.4` means you will deploy +the SSPL-licensed version to redis. + diff --git a/roles/redis/defaults/main/config.yml b/roles/redis/defaults/main/config.yml new file mode 100644 index 0000000..47b4a02 --- /dev/null +++ b/roles/redis/defaults/main/config.yml @@ -0,0 +1,23 @@ +--- +redis_config_bind: + - "127.0.0.1" + - "-::1" +redis_config_protected_mode: true +redis_config_port: 6379 +redis_config_user: + - "default on -DEBUG +@all ~* nopass" +redis_config_databases: 16 +redis_config_dbfilename: dump.rdb + +redis_base_config: + bind: "{{ redis_config_bind | join(' ') }}" + "protected-mode": "{{ redis_config_protected_mode | bool | ternary('yes', 'no') }}" + port: "{{ redis_config_port }}" + user: "{{ redis_config_user }}" + databases: "{{ redis_config_databases }}" + dbfilename: "{{ redis_config_dbfilename }}" + +redis_config: ~ +redis_config_merged: >-2 + {{ redis_config_base + | combine(redis_config | default({}, true), recursive=True) }} diff --git a/roles/redis/defaults/main/container.yml b/roles/redis/defaults/main/container.yml new file mode 100644 index 0000000..42f0fdc --- /dev/null +++ b/roles/redis/defaults/main/container.yml @@ -0,0 +1,48 @@ +--- +redis_container_image_registry: docker.io +redis_container_image_namespace: ~ +redis_container_image_name: redis +redis_container_image_tag: ~ +redis_container_image_flavour: alpine +redis_container_image_source: pull +redis_container_image_force_source: >-2 + {{ redis_container_image_tag | default(false, true) | bool }} +redis_container_image: >-2 + {{ + ([ + redis_container_image_registry | default([], true), + redis_container_image_namespace | default([], true), + redis_container_image_name, + ] | flatten | join('/')) + + ':' + + (redis_container_image_tag | default( + redis_version + ( + (redis_container_image_flavour | default(false, true) | bool) + | ternary('-' + (redis_container_image_flavour | default('')), '') + ), + true, + )) + }} + +redis_container_name: "redis{{ redis_instance_suffix }}" +redis_container_env: ~ +redis_container_user: >-2 + {{ redis_run_user_id }}:{{ redis_run_group_id }} +redis_container_ports: ~ +redis_container_labels: ~ +redis_container_volumes: ~ +redis_container_merged_volumes: >-2 + {{ redis_container_base_volumes + + redis_container_volumes | default([], true) }} +redis_container_command: + - "redis-server" + - "{{ redis_config_file }}" +redis_container_networks: ~ +redis_container_etc_hosts: ~ +redis_container_dns_servers: ~ +redis_container_restart_policy: "unless-stopped" +redis_container_state: >-2 + {{ (redis_state == 'present') | default('started', 'absent') }} +redis_container_base_volumes: + - "{{ redis_config_file }}:{{ redis_config_file }}:ro" + - "{{ redis_data_path }}:{{ redis_data_path }}:rw" diff --git a/roles/redis/defaults/main/main.yml b/roles/redis/defaults/main/main.yml new file mode 100644 index 0000000..c60586c --- /dev/null +++ b/roles/redis/defaults/main/main.yml @@ -0,0 +1,14 @@ +--- +redis_version: "7.2.4" +redis_instance: ~ +redis_instance_suffix: >-2 + {{ (redis_instance | default(false, true) | bool) + | ternary('-' + (redis_instance | default('')), '') }} +redis_user: >-2 + redis{{ redis_instance_suffix }} + +redis_config_path: "/etc/redis" +redis_config_file: >-2 + {{ redis_config_path }}/redis{{ redis_instance_suffix }}.conf +redis_data_path: "/var/lib/redis{{ redis_instance_suffix }}" +redis_deployment_method: docker diff --git a/roles/redis/defaults/main/user.yml b/roles/redis/defaults/main/user.yml new file mode 100644 index 0000000..47e7ef5 --- /dev/null +++ b/roles/redis/defaults/main/user.yml @@ -0,0 +1,10 @@ +--- +redis_run_user_id: >-2 + {{ redis_user_info.uid | default(redis_user, true) }} +redis_run_group_id: >-2 + {{ redis_user_info.group | default(redis_user, true) }} +redis_user_system: true +redis_user_create_home: false +redis_user_groups: ~ +redis_user_append_groups: >-2 + {{ redis_user_groups | default(true, false) | bool }} diff --git a/roles/redis/handlers/main.yml b/roles/redis/handlers/main.yml new file mode 100644 index 0000000..55c9198 --- /dev/null +++ b/roles/redis/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: Ensure redis container '{{ redis_container_name }}' is restarted + community.docker.docker_container: + name: "{{ redis_container_name }}" + state: "{{ redis_container_state }}" + restart: true + listen: redis-restart + when: + - deployment_method == 'docker' + - redis_state == 'present' diff --git a/roles/redis/meta/main.yml b/roles/redis/meta/main.yml new file mode 100644 index 0000000..b5f0f66 --- /dev/null +++ b/roles/redis/meta/main.yml @@ -0,0 +1,10 @@ +--- +allow_duplicates: true +dependencies: [] +galaxy_info: + role_name: redis + description: >-2 + Deploy and configure redis server + galaxy_tags: + - redis + - docker diff --git a/roles/redis/tasks/deploy-docker.yml b/roles/redis/tasks/deploy-docker.yml new file mode 100644 index 0000000..e0319a4 --- /dev/null +++ b/roles/redis/tasks/deploy-docker.yml @@ -0,0 +1,26 @@ +--- +- name: Ensure container image '{{ redis_container_image }}' is {{ redis_state }} + community.docker.docker_image: + name: "{{ redis_container_image }}" + state: "{{ redis_state }}" + source: "{{ redis_container_image_source }}" + force_source: "{{ redis_container_image_force_source }}" + register: redis_container_image_info + until: redis_container_image_info is success + retries: 5 + delay: 3 + +- name: Ensure container '{{ redis_container_name }}' is {{ redis_container_state }} + community.docker.docker_container: + name: "{{ redis_container_name }}" + image: "{{ redis_container_image }}" + env: "{{ redis_container_env | default(omit, true) }}" + user: "{{ redis_container_user }}" + ports: "{{ redis_container_ports | default(omit, true) }}" + labels: "{{ redis_container_labels | default(omit, true) }}" + command: "{{ redis_container_command }}" + volumes: "{{ redis_container_merged_volumes }}" + networks: "{{ redis_container_networks | default(omit, true) }}" + etc_hosts: "{{ redis_container_etc_hosts | default(omit, true) }}" + dns_servers: "{{ redis_container_dns_servers | default(omit, true) }}" + state: "{{ redis_container_state }}" diff --git a/roles/redis/tasks/main.yml b/roles/redis/tasks/main.yml new file mode 100644 index 0000000..7cca1a7 --- /dev/null +++ b/roles/redis/tasks/main.yml @@ -0,0 +1,68 @@ +--- +- name: Ensure state is valid + ansible.builtin.fail: + msg: >-2 + Unsupported state '{{ redis_state }}'. + Supported states are {{ redis_states | join(', ') }} + when: redis_state not in redis_states + +- name: Ensure deployment method is valid + ansible.builtin.fail: + msg: >-2 + Unsupported deployment method '{{ redis_deployment_method }}'! + Supported methods are {{ redis_deployment_method | join(', ') }} + when: redis_deployment_method not in redis_deployment_methods + +- name: Ensure redis user '{{ redis_user }}' is {{ redis_state }} + ansible.builtin.user: + name: "{{ redis_user }}" + state: "{{ redis_state }}" + system: "{{ redis_user_system }}" + create_home: "{{ redis_user_create_home }}" + groups: "{{ redis_user_groups | default(omit, true) }}" + append: "{{ redis_user_append_groups | default(omit, true) }}" + register: redis_user_info + +- name: Ensure redis config file '{{ redis_config_file }}' is {{ redis_state }} + ansible.builtin.file: + path: "{{ redis_config_file }}" + state: "{{ redis_state }}" + when: redis_state == 'absent' + +- name: Ensure redis host directories are {{ redis_state }} + ansible.builtin.file: + path: "{{ path.name }}" + state: >-2 + {{ (redis_state == 'present') | ternary('directory', 'absent') }} + owner: "{{ path.owner | default(redis_run_user_id) }}" + group: "{{ path.group | default(redis_run_group_id) }}" + mode: "{{ path.mode | default('0755') }}" + loop: + - name: "{{ redis_config_path }}" + - name: "{{ redis_data_path }}" + loop_control: + loop_var: "path" + label: "{{ path.name }}" + +- name: Ensure redis config file '{{ redis_config_file }}' is {{ redis_state }} + ansible.builtin.copy: + content: |+2 + {% for tuple in (redis_merged_config | dict2items) %} + {%- if tuple.value is string -%} + {{ tuple.key }} {{ tuple.value }} + {%- elsif -%} + {% for value in tuple.value %} + {{ tuple.key }} {{ value }} + {% endfor %} + {%- endif -%} + {% endfor %} + dest: "{{ redis_config_file }}" + owner: "{{ redis_run_user_id }}" + group: "{{ redis_run_group_id }}" + mode: "0640" + when: redis_state == 'present' + notify: redis-restart + +- name: Deploy redis using {{ redis_deployment_method }} + ansible.builtin.include_tasks: + file: "deploy-{{ redis_deployment_method }}.yml" diff --git a/roles/redis/vars/main.yml b/roles/redis/vars/main.yml new file mode 100644 index 0000000..ee16e40 --- /dev/null +++ b/roles/redis/vars/main.yml @@ -0,0 +1,6 @@ +--- +redis_states: + - present + - absent +redis_deployment_methods: + - docker