10 Commits

27 changed files with 452 additions and 5 deletions

View File

@ -10,3 +10,10 @@
- [`mariadb`](roles/mariadb/README.md): deploy mariadb
in a docker container
- [`postgresql`](roles/postgresql/README.md): deploy postgresql,
the worlds most advances open-source relational database
- [`valkey`](roles/valkey/README.md): deploy and configure valkey,
an open source in-memory data store under BSD license, forked
from redis.

View File

@ -1,6 +1,6 @@
namespace: finallycoffee
name: databases
version: 0.1.0
version: 0.1.1
readme: README.md
authors:
- transcaffeine <transcaffeine@finally.coffee>
@ -16,4 +16,7 @@ tags:
- elasticsearch
- redis
- mariadb
- postgresql
- postgres
- valkey
- docker

6
playbooks/postgresql.yml Normal file
View File

@ -0,0 +1,6 @@
---
- name: Deploy and configure PostgreSQL
hosts: "{{ postgresql_hosts | default('postgresql', true) }}"
become: "{{ postgresql_become | default(true, true) }}"
roles:
- role: finallycoffee.databases.postgresql

6
playbooks/valkey.yml Normal file
View File

@ -0,0 +1,6 @@
---
- name: Deploy and configure valkey
hosts: "{{ valkey_hosts | default('valkey', true) }}"
become: "{{ valkey_become | default(true, true) }}"
roles:
- finallycoffee.databases.valkey

View File

@ -1,5 +1,5 @@
---
elasticsearch_version: 8.15.3
elasticsearch_version: "8.17.0"
elasticsearch_state: present
elasticsearch_base_path: /opt/elasticsearch

View File

@ -34,6 +34,5 @@
volumes: "{{ elasticsearch_container_volumes }}"
ulimits: "{{ elasticsearch_container_ulimits }}"
networks: "{{ elasticsearch_container_networks | default(omit, True) }}"
purge_networks: "{{ elasticsearch_container_purge_networks | default(omit, True) }}"
restart_policy: "{{ elasticsearch_container_restart_policy }}"
state: "{{ elasticsearch_container_state }}"

View File

@ -1,5 +1,5 @@
---
mariadb_version: "10.11.9"
mariadb_version: "10.11.10"
mariadb_base_path: /var/lib/mariadb
mariadb_data_path: >-2
{{ mariadb_base_path }}/{{ mariadb_version | split('.') | first }}

View File

@ -16,6 +16,5 @@
volumes: "{{ mariadb_container_volumes }}"
networks: "{{ mariadb_container_networks | default(omit, true) }}"
etc_hosts: "{{ mariadb_container_etc_hosts | default(omit, true) }}"
purge_networks: "{{ mariadb_container_purge_networks | default(omit, true) }}"
restart_policy: "{{ mariadb_container_restart_policy }}"
state: "{{ mariadb_container_state }}"

View File

@ -0,0 +1,4 @@
# `finallycoffee.databases.postgresql` ansible role
PostgreSQL is the self proclaimed "world's most advanced" open source relational
database. This ansible role can deploy and configure postgresql.

View File

@ -0,0 +1,39 @@
---
postgresql_container_image_registry: docker.io
postgresql_container_image_namespace: ~
postgresql_container_image_name: postgres
postgresql_container_image_tag: ~
postgresql_container_image_source: pull
postgresql_container_image_force_source: >-2
{{ postgresql_container_image_tag | default(false, true) | bool }}
postgresql_container_image: >-2
{{
([
postgresql_container_image_registry | default([], true),
postgresql_container_image_namespace | default([], true),
postgresql_container_image_name
] | flatten | join('/'))
+ ':' + postgresql_container_image_tag | default(
postgresql_version + (
((postgresql_container_image_flavour is string)
and (postgresql_container_image_flavour | length > 0))
| ternary(
'_' + postgresql_container_image_flavour | default('', true),
'',
)
),
true
)
}}
postgresql_container_name: postgresql
postgresql_container_env: ~
postgresql_container_user: >-2
{{ postgresql_user_id }}:{{ postgresql_user_group_id }}
postgresql_container_ports: ~
postgresql_container_labels: ~
postgresql_container_networks: ~
postgresql_container_recreate: ~
postgresql_container_restart_policy: "on-failure"
postgresql_container_state: >-2
{{ (postgresql_state == 'present') | ternary('started', 'absent') }}

View File

@ -0,0 +1,18 @@
---
postgresql_user: postgresql
postgresql_version: >-2
{{ postgresql_version[postgres_major_version | string] }}
postgresql_major_version: 16
postgresql_versions:
"17": "17.2"
"16": "16.6"
"15": "15.10"
"14": "14.15"
postgresql_config_path: >-2
/etc/postgresql/{{ postgresql_major_version }}
postgresql_data_path: >-2
/var/lib/postgresql/{{ postgresql_major_version }}
postgresql_state: present
postgresql_deployment_method: docker

View File

@ -0,0 +1,10 @@
---
postgresql_user_system: true
postgresql_user_create_home: false
postgresql_user_groups: ~
postgresql_user_append: ~
postgresql_user_id: >-2
{{ postgresql_user_info.uid | default(postgresql_user, true) }}
postgresql_user_group_id: >-2
{{ postgresql_user_info.group | default(postgresql_user, true) }}

View File

@ -0,0 +1,12 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: postgresql
description: >-2
PostgreSQL is the self-proclaimed 'worlds most advanced' open source relational database
galaxy_tags:
- postgresql
- postgres
- database
- docker

View File

@ -0,0 +1,23 @@
---
- name: Ensure postgresql container image '{{ postgresql_container_image }}' is {{ postgresql_state }}
community.docker.docker_image:
name: "{{ postgresql_container_image }}"
state: "{{ postgresql_state }}"
source: "{{ postgresql_container_image_source }}"
force_source: "{{ postgresql_container_image_force_source }}"
register: postgresql_container_image_info
until: postgresql_container_image_info is success
retries: 5
delay: 4
- name: Ensure postgresql container '{{ postgresql_container_name }}' is {{ postgresql_container_state }}
community.docker.docker_container:
name: "{{ postgresql_container_name }}"
image: "{{ postgresql_container_image }}"
env: "{{ postgresql_container_env | default(omit, true) }}"
user: "{{ postgresql_container_user | default(omit, true) }}"
ports: "{{ postgresql_container_ports | default(omit, true) }}"
labels: "{{ postgresql_container_labels | default(omit, true) }}"
networks: "{{ postgresql_container_networks | default(omit, true) }}"
restart_policy: "{{ postgresql_container_restart_policy | default(omit, true) }}"
state: "{{ postgresql_container_state }}"

View File

@ -0,0 +1,63 @@
---
- name: Ensure state is valid
ansible.builtin.fail:
msg: >-2
Invalid state '{{ postgresql_state }}'! Supported
states are {{ postgresql_states | join(', ') }}.
when: postgresql_state not in postgresql_states
- name: Ensure deployment method is valid
ansible.builtin.fail:
msg: >-2
Unsupported deployment method '{{ postgresql_deployment_method }}!
Supported deployment methods are {{ postgresql_deployment_methods | join(', ') }}.
when: postgresql_deployment_method not in postgresql_deployment_methods
- name: Ensure postgresql user '{{ postgresql_user }}' is {{ postgresql_state }}
ansible.builtin.user:
name: "{{ postgresql_user }}"
state: "{{ postgresql_state }}"
system: "{{ postgresql_user_system | default(omit, true) }}"
create_home: "{{ postgresql_user_create_home | default(omit, true) }}"
groups: "{{ postgresql_user_groups | default(omit, true) }}"
append: "{{ postgresql_user_append | default(omit, true) }}"
register: postgresql_user_info
- name: Ensure directories are {{ postgresql_state }}
ansible.builtin.file:
path: "{{ path.name }}"
state: "{{ (postgresql_state == 'present') | ternary('directory', 'absent') }}"
owner: "{{ path.owner | default(postgresql_user_id, true) }}"
group: "{{ path.group | default(postgresql_user_group_id, true) }}"
mode: "{{ path.mode | default('0755', true) }}"
loop:
- name: "{{ postgresql_config_path }}"
- name: "{{ postgresql_data_path }}"
loop_control:
loop_var: path
label: "{{ path.name }}"
- name: Check for existing PG_VERSION file
ansible.builtin.stat:
path: "{{ postgresql_data_path }}/PG_VERSION"
register: postgresql_data_dir_version_info
- name: Read existing PG_VERSION file
ansible.builtin.slurp:
path: "{{ postgresql_data_path }}/PG_VERSION"
register: postgresql_data_dir_version_content
when:
- postgresql_data_dir_version_info.stat.exists
- name: Prevent major version changes
ansible.builtin.fail:
msg: >-2
Mismatched postgresql version for the data directory!
Aborting...
when:
- postgresql_data_dir_version_info.stat.exists
- "(postgresql_data_dir_version_content | b64decode | int) != (postgresql_major_version | int)"
- name: Deploy postgresql using {{ postgresql_deployment_method }}
ansible.builtin.include_tasks:
file: "deploy-{{ postgresql_deployment_method }}.yml"

View File

@ -0,0 +1,6 @@
---
postgresql_states:
- present
- absent
postgresql_deployment_methods:
- docker

View File

@ -23,4 +23,5 @@
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) }}"
restart_policy: "{{ redis_container_restart_policy | default(omit, true) }}"
state: "{{ redis_container_state }}"

13
roles/valkey/README.md Normal file
View File

@ -0,0 +1,13 @@
# `finallycoffee.databases.valkey` ansible role
Valkey is an open source (BSD 3 licensed), high-performance in-memory key/value
data store, ideal for workloads like caching or message queues. It has been
forked from redis 7.2.4 before redis license was changed to SSPL.
Valkey offers compatibility to redis and can be used as a drop-in replacement
for redis.
## Configuration
For the configuration, see the [`redis` role configuration](../redis/README.md#configuration),
and swap the `redis_` prefix of all variables for the `valkey_` prefix.

View File

@ -0,0 +1,41 @@
---
valkey_config_bind:
- "127.0.0.1"
- "-::1"
valkey_config_protected_mode: true
valkey_config_port: 6379
valkey_config_unixsocket: ~
valkey_config_unixsocketperm: '700'
valkey_config_user:
- "default on +@all -DEBUG ~* nopass"
valkey_config_databases: 16
valkey_config_supervised: false
valkey_config_daemonize: false
valkey_config_dbfilename: dump.rdb
valkey_config_dir: "{{ valkey_data_path }}"
valkey_config_save: "3600 1 300 100 60 10000"
valkey_config_appendfsync: everysec
valkey_base_config:
bind: "{{ valkey_config_bind | join(' ') }}"
"protected-mode": "{{ valkey_config_protected_mode | bool | ternary('yes', 'no') }}"
port: "{{ valkey_config_port }}"
user: "{{ valkey_config_user }}"
databases: "{{ valkey_config_databases }}"
daemonize: "{{ valkey_config_daemonize | bool | ternary('yes', 'no') }}"
supervised: "{{ valkey_config_supervised | bool | ternary('yes', 'no') }}"
save: "{{ valkey_config_save }}"
dbfilename: "{{ valkey_config_dbfilename }}"
dir: "{{ valkey_config_dir }}"
appendfsync: "{{ valkey_config_appendfsync }}"
valkey_config: ~
valkey_merged_config: >-2
{{ valkey_base_config
| combine(({
'unixsocket': valkey_config_unixsocket,
'unixsocketperm': valkey_config_unixsocketperm,
})
if (valkey_config_unixsocket | default(false, true)) else {},
recursive=True)
| combine(valkey_config | default({}, true), recursive=True) }}

View File

@ -0,0 +1,49 @@
---
valkey_container_image_registry: docker.io
valkey_container_image_namespace: valkey
valkey_container_image_name: valkey
valkey_container_image_tag: ~
valkey_container_image_flavour: alpine
valkey_container_image_source: pull
valkey_container_image_force_source: >-2
{{ valkey_container_image_tag | default(false, true) | bool }}
valkey_container_image: >-2
{{
([
valkey_container_image_registry | default([], true),
valkey_container_image_namespace | default([], true),
valkey_container_image_name,
] | flatten | join('/'))
+ ':' +
(valkey_container_image_tag | default(
valkey_version + (
((valkey_container_image_flavour is string)
and (valkey_container_image_flavour | length > 0))
| ternary('-' + (valkey_container_image_flavour | default('')), '')
),
true,
))
}}
valkey_container_name: "valkey{{ valkey_instance_suffix }}"
valkey_container_env: ~
valkey_container_user: >-2
{{ valkey_run_user_id }}:{{ valkey_run_group_id }}
valkey_container_ports: ~
valkey_container_labels: ~
valkey_container_volumes: ~
valkey_container_merged_volumes: >-2
{{ valkey_container_base_volumes
+ valkey_container_volumes | default([], true) }}
valkey_container_command:
- "valkey-server"
- "{{ valkey_config_file }}"
valkey_container_networks: ~
valkey_container_etc_hosts: ~
valkey_container_dns_servers: ~
valkey_container_restart_policy: "unless-stopped"
valkey_container_state: >-2
{{ (valkey_state == 'present') | ternary('started', 'absent') }}
valkey_container_base_volumes:
- "{{ valkey_config_file }}:{{ valkey_config_file }}:ro"
- "{{ valkey_data_path }}:{{ valkey_data_path }}:rw"

View File

@ -0,0 +1,15 @@
---
valkey_version: "8.0.1"
valkey_state: "present"
valkey_instance: ~
valkey_instance_suffix: >-2
{{ ((valkey_instance is string) and (valkey_instance | length > 0))
| ternary('-' + (valkey_instance | default('', true)), '') }}
valkey_user: >-2
valkey{{ valkey_instance_suffix }}
valkey_config_path: "/etc/valkey"
valkey_config_file: >-2
{{ valkey_config_path }}/valkey{{ valkey_instance_suffix }}.conf
valkey_data_path: "/var/lib/valkey{{ valkey_instance_suffix }}"
valkey_deployment_method: docker

View File

@ -0,0 +1,10 @@
---
valkey_run_user_id: >-2
{{ valkey_user_info.uid | default(valkey_user, true) }}
valkey_run_group_id: >-2
{{ valkey_user_info.group | default(valkey_user, true) }}
valkey_user_system: true
valkey_user_create_home: false
valkey_user_groups: ~
valkey_user_append_groups: >-2
{{ valkey_user_groups | default(true, false) | bool }}

View File

@ -0,0 +1,11 @@
---
- name: Ensure valkey container '{{ valkey_container_name }}' is restarted
community.docker.docker_container:
name: "{{ valkey_container_name }}"
state: "{{ valkey_container_state }}"
restart: true
listen: valkey-restart
when:
- valkey_deployment_method == 'docker'
- valkey_state == 'present'
ignore_errors: "{{ ansible_check_mode }}"

View File

@ -0,0 +1,11 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: valkey
description: >-2
An open source, in-memory datastore under BSD 3 license
galaxy_tags:
- valkey
- redis
- docker

View File

@ -0,0 +1,27 @@
---
- name: Ensure container image '{{ valkey_container_image }}' is {{ valkey_state }}
community.docker.docker_image:
name: "{{ valkey_container_image }}"
state: "{{ valkey_state }}"
source: "{{ valkey_container_image_source }}"
force_source: "{{ valkey_container_image_force_source }}"
register: valkey_container_image_info
until: valkey_container_image_info is success
retries: 5
delay: 3
- name: Ensure container '{{ valkey_container_name }}' is {{ valkey_container_state }}
community.docker.docker_container:
name: "{{ valkey_container_name }}"
image: "{{ valkey_container_image }}"
env: "{{ valkey_container_env | default(omit, true) }}"
user: "{{ valkey_container_user }}"
ports: "{{ valkey_container_ports | default(omit, true) }}"
labels: "{{ valkey_container_labels | default(omit, true) }}"
command: "{{ valkey_container_command }}"
volumes: "{{ valkey_container_merged_volumes }}"
networks: "{{ valkey_container_networks | default(omit, true) }}"
etc_hosts: "{{ valkey_container_etc_hosts | default(omit, true) }}"
dns_servers: "{{ valkey_container_dns_servers | default(omit, true) }}"
restart_policy: "{{ valkey_container_restart_policy | default(omit, true) }}"
state: "{{ valkey_container_state }}"

View File

@ -0,0 +1,68 @@
---
- name: Ensure state is valid
ansible.builtin.fail:
msg: >-2
Unsupported state '{{ valkey_state }}'.
Supported states are {{ valkey_states | join(', ') }}
when: valkey_state not in valkey_states
- name: Ensure deployment method is valid
ansible.builtin.fail:
msg: >-2
Unsupported deployment method '{{ valkey_deployment_method }}'!
Supported methods are {{ valkey_deployment_method | join(', ') }}
when: valkey_deployment_method not in valkey_deployment_methods
- name: Ensure valkey user '{{ valkey_user }}' is {{ valkey_state }}
ansible.builtin.user:
name: "{{ valkey_user }}"
state: "{{ valkey_state }}"
system: "{{ valkey_user_system }}"
create_home: "{{ valkey_user_create_home }}"
groups: "{{ valkey_user_groups | default(omit, true) }}"
append: "{{ valkey_user_append_groups | default(omit, true) }}"
register: valkey_user_info
- name: Ensure valkey config file '{{ valkey_config_file }}' is {{ valkey_state }}
ansible.builtin.file:
path: "{{ valkey_config_file }}"
state: "{{ valkey_state }}"
when: valkey_state == 'absent'
- name: Ensure valkey host directories are {{ valkey_state }}
ansible.builtin.file:
path: "{{ path.name }}"
state: >-2
{{ (valkey_state == 'present') | ternary('directory', 'absent') }}
owner: "{{ path.owner | default(valkey_run_user_id) }}"
group: "{{ path.group | default(valkey_run_group_id) }}"
mode: "{{ path.mode | default('0755') }}"
loop:
- name: "{{ valkey_config_path }}"
- name: "{{ valkey_data_path }}"
loop_control:
loop_var: "path"
label: "{{ path.name }}"
- name: Ensure valkey config file '{{ valkey_config_file }}' is {{ valkey_state }}
ansible.builtin.copy:
content: |+2
{% for tuple in (valkey_merged_config | dict2items) %}
{% if tuple.value is string or tuple.value is number %}
{{ tuple.key }} {{ tuple.value }}
{% else %}
{% for value in tuple.value %}
{{ tuple.key }} {{ value }}
{% endfor %}
{% endif %}
{% endfor %}
dest: "{{ valkey_config_file }}"
owner: "{{ valkey_run_user_id }}"
group: "{{ valkey_run_group_id }}"
mode: "0640"
when: valkey_state == 'present'
notify: valkey-restart
- name: Deploy valkey using {{ valkey_deployment_method }}
ansible.builtin.include_tasks:
file: "deploy-{{ valkey_deployment_method }}.yml"

View File

@ -0,0 +1,6 @@
---
valkey_states:
- present
- absent
valkey_deployment_methods:
- docker