Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

25 changed files with 250 additions and 248 deletions

View File

@ -5,6 +5,10 @@
This ansible collection provides various roles for installing This ansible collection provides various roles for installing
and configuring basic system utilities like gnupg, ssh etc and configuring basic system utilities like gnupg, ssh etc
- [`elasticsearch`](roles/elasticsearch/README.md): Deploy [elasticsearch](https://www.docker.elastic.co/r/elasticsearch/elasticsearch-oss),
a popular (distributed) search and analytics engine, mostly known by it's
letter "E" in the ELK-stack.
- [`git`](roles/git/README.md): configures git on the target system - [`git`](roles/git/README.md): configures git on the target system
- [`gnupg`](roles/gnupg/README.md): configures gnupg on the target system - [`gnupg`](roles/gnupg/README.md): configures gnupg on the target system
@ -12,6 +16,8 @@ and configuring basic system utilities like gnupg, ssh etc
- [`lego`](roles/lego/README.md): runs [lego (LetsEncrypt Go)](https://github.com/go-acme/lego), - [`lego`](roles/lego/README.md): runs [lego (LetsEncrypt Go)](https://github.com/go-acme/lego),
a ACME client written in go, using systemd (timers). Multi-instance capable. a ACME client written in go, using systemd (timers). Multi-instance capable.
- [`mariadb`](roles/mariadb/README.md): runs [MariaDB Server](https://mariadb.org/), one of the world's most popular open source relational database
- [`minio`](roles/minio/README.md): Deploy [min.io](https://min.io), an - [`minio`](roles/minio/README.md): Deploy [min.io](https://min.io), an
s3-compatible object storage server, using docker containers. s3-compatible object storage server, using docker containers.

View File

@ -1,12 +1,12 @@
namespace: finallycoffee namespace: finallycoffee
name: base name: base
version: 0.2.1 version: 0.1.2
readme: README.md readme: README.md
authors: authors:
- transcaffeine <transcaffeine@finally.coffee> - transcaffeine <transcaffeine@finally.coffee>
description: Roles for base services which are common dependencies other services like databases description: Roles for base services which are common dependencies other services like databases
dependencies: dependencies:
"community.docker": "^4.2.0" "community.docker": "^3.0.0"
license_file: LICENSE.md license_file: LICENSE.md
build_ignore: build_ignore:
- '*.tar.gz' - '*.tar.gz'
@ -14,7 +14,9 @@ repository: https://git.finally.coffee/finallycoffee/base
issues: https://codeberg.org/finallycoffee/ansible-collection-base/issues issues: https://codeberg.org/finallycoffee/ansible-collection-base/issues
tags: tags:
- docker - docker
- elastic
- lego - lego
- mariadb
- minio - minio
- nginx - nginx
- restic - restic

View File

@ -1,7 +0,0 @@
---
- name: Configure user accounts
hosts: "{{ user_hosts | default('all', true) }}"
become: "{{ user_role_become | default(false, true) }}"
gather_facts: "{{ user_role_gather_facts | default(false, true) }}"
roles:
- role: finallycoffee.base.user

View File

@ -0,0 +1,22 @@
# `finallycoffee.base.elastiscsearch`
A simple ansible role which deploys a single-node elastic container to provide
an easy way to do some indexing.
## Usage
Per default, `/opt/elasticsearch/data` is used to persist data, it is
customizable by using either `elasticsearch_base_path` or `elasticsearch_data_path`.
As elasticsearch be can be quite memory heavy, the maximum amount of allowed RAM
can be configured using `elasticsearch_allocated_ram_mb`, defaulting to 512 (mb).
The cluster name and discovery type can be overridden using
`elasticsearch_config_cluster_name` (default: elastic) and
`elasticsearch_config_discovery_type` (default: single-node), should one
need a multi-node elasticsearch deployment.
Per default, no ports or networks are mapped, and explizit mapping using
either ports (`elasticsearch_container_ports`) or networks
(`elasticsearch_container_networks`) is required in order for other services
to use elastic.

View File

@ -0,0 +1,35 @@
---
elasticsearch_version: 7.17.7
elasticsearch_base_path: /opt/elasticsearch
elasticsearch_data_path: "{{ elasticsearch_base_path }}/data"
elasticsearch_config_cluster_name: elastic
elasticsearch_config_discovery_type: single-node
elasticsearch_config_boostrap_memory_lock: true
elasticsearch_allocated_ram_mb: 512
elasticsearch_container_image_name: docker.elastic.co/elasticsearch/elasticsearch-oss
elasticsearch_container_image_tag: ~
elasticsearch_container_image: >-
{{ elasticsearch_container_image_name }}:{{ elasticsearch_container_image_tag | default(elasticsearch_version, true) }}
elasticsearch_container_name: elasticsearch
elasticsearch_container_env:
"ES_JAVA_OPTS": "-Xms{{ elasticsearch_allocated_ram_mb }}m -Xmx{{ elasticsearch_allocated_ram_mb }}m"
"cluster.name": "{{ elasticsearch_config_cluster_name }}"
"discovery.type": "{{ elasticsearch_config_discovery_type }}"
"bootstrap.memory_lock": "{{ 'true' if elasticsearch_config_boostrap_memory_lock else 'false' }}"
elasticsearch_container_user: ~
elasticsearch_container_ports: ~
elasticsearch_container_labels:
version: "{{ elasticsearch_version }}"
elasticsearch_container_ulimits:
# - "memlock:{{ (1.5 * 1024 * elasticsearch_allocated_ram_mb) | int }}:{{ (1.5 * 1024 * elasticsearch_allocated_ram_mb) | int }}"
- "memlock:-1:-1"
elasticsearch_container_volumes:
- "{{ elasticsearch_data_path }}:/usr/share/elasticsearch/data:z"
elasticsearch_container_networks: ~
elasticsearch_container_purge_networks: ~
elasticsearch_container_restart_policy: unless-stopped

View File

@ -0,0 +1,32 @@
---
- name: Ensure host directories are present
file:
path: "{{ item }}"
state: directory
mode: "0777"
loop:
- "{{ elasticsearch_base_path }}"
- "{{ elasticsearch_data_path }}"
- name: Ensure elastic container image is present
docker_image:
name: "{{ elasticsearch_container_image }}"
state: present
source: pull
force_source: "{{ elasticsearch_container_image_tag|default(false, true)|bool }}"
- name: Ensure elastic container is running
docker_container:
name: "{{ elasticsearch_container_name }}"
image: "{{ elasticsearch_container_image }}"
env: "{{ elasticsearch_container_env | default(omit, True) }}"
user: "{{ elasticsearch_container_user | default(omit, True) }}"
ports: "{{ elasticsearch_container_ports | default(omit, True) }}"
labels: "{{ elasticsearch_container_labels | default(omit, True) }}"
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: started

View File

@ -1,6 +1,6 @@
--- ---
lego_user: "lego" lego_user: "lego"
lego_version: "4.23.0" lego_version: "4.18.0"
lego_instance: default lego_instance: default
lego_base_path: "/opt/lego" lego_base_path: "/opt/lego"
lego_cert_user: "acme-{{ lego_instance }}" lego_cert_user: "acme-{{ lego_instance }}"

View File

@ -1,35 +1,22 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail
LEGO_BINARY=$(/usr/bin/env which lego) LEGO_BINARY=$(/usr/bin/env which lego)
if [[ -n "${LEGO_HTTP_FALLBACK_PORT:-}" ]]; then if [[ -n "$LEGO_HTTP_FALLBACK_PORT" ]]; then
if ! nc_binary="$(type -p 'nc')" || [[ -z $nc_binary ]]; then
echo "nc not found (in PATH), exiting"
exit 1
fi
nc -z 127.0.0.1 $LEGO_HTTP_PORT; nc -z 127.0.0.1 $LEGO_HTTP_PORT;
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
LEGO_HTTP_PORT=$LEGO_HTTP_FALLBACK_PORT LEGO_HTTP_PORT=$LEGO_HTTP_FALLBACK_PORT
fi fi
fi fi
if [[ -n "${LEGO_PRE_RENEWAL_HOOK:-}" ]]; then
$LEGO_PRE_RENEWAL_HOOK
fi
LEGO_COMMAND_ARGS_EXPANDED=$(bash -c "echo $LEGO_COMMAND_ARGS") # This is a bit icky LEGO_COMMAND_ARGS_EXPANDED=$(bash -c "echo $LEGO_COMMAND_ARGS") # This is a bit icky
FILES_IN_DIR=$(find "$LEGO_CERT_STORE_PATH/certificates" -type f | wc -l) FILES_IN_DIR=$(find "$LEGO_CERT_STORE_PATH/certificates" | wc -l)
if [[ $FILES_IN_DIR -gt 2 ]]; then if [[ $FILES_IN_DIR -gt 2 ]]; then
$LEGO_BINARY $LEGO_COMMAND_ARGS_EXPANDED renew --days=$LEGO_CERT_DAYS_TO_RENEW $LEGO_BINARY $LEGO_COMMAND_ARGS_EXPANDED renew --days=$LEGO_CERT_DAYS_TO_RENEW
else else
$LEGO_BINARY $LEGO_COMMAND_ARGS_EXPANDED run $LEGO_BINARY $LEGO_COMMAND_ARGS_EXPANDED run
fi fi
find "$LEGO_CERT_STORE_PATH/certificates" -type f | xargs -I{} -n 1 chmod "$LEGO_CERT_MODE" "{}" ls "$LEGO_CERT_STORE_PATH/certificates" | xargs -I{} -n 1 chmod "$LEGO_CERT_MODE" "$LEGO_CERT_STORE_PATH/certificates/{}"
find "$LEGO_CERT_STORE_PATH/certificates" -type f | xargs -I{} -n 1 chown "${LEGO_CERT_USER}:${LEGO_CERT_GROUP}" "{}" ls "$LEGO_CERT_STORE_PATH/certificates" | xargs -I{} -n 1 chown "$LEGO_CERT_USER":"$LEGO_CERT_GROUP" "$LEGO_CERT_STORE_PATH/certificates/{}"
if [[ -n "${LEGO_POST_RENEWAL_HOOK:-}" ]]; then
$LEGO_POST_RENEWAL_HOOK
fi

View File

@ -25,44 +25,35 @@
- "{{ lego_cert_group }}" - "{{ lego_cert_group }}"
append: true append: true
- name: Check if lego is present
ansible.builtin.command:
cmd: which lego
changed_when: false
failed_when: false
register: lego_binary_info
check_mode: false
- name: Check which version of lego is present
ansible.builtin.command:
cmd: "lego --version"
changed_when: false
failed_when: false
register: lego_binary_version_info
when: lego_binary_info.rc == 0
check_mode: false
- name: Ensure lego is installed - name: Ensure lego is installed
when: (lego_binary_info.rc != 0) or (lego_version not in lego_binary_version_info.stdout)
block: block:
- name: Check if lego is present
ansible.builtin.command:
cmd: which lego
changed_when: false
failed_when: false
register: lego_binary_info
- name: Download lego from source - name: Download lego from source
ansible.builtin.get_url: ansible.builtin.get_url:
url: "{{ lego_release_archive_url }}" url: "{{ lego_release_archive_url }}"
url_username: "{{ lego_release_archive_url_username | default(omit) }}" url_username: "{{ lego_release_archive_url_username | default(omit) }}"
url_password: "{{ lego_release_archive_url_password | default(omit) }}" url_password: "{{ lego_release_archive_url_password | default(omit) }}"
dest: "{{ lego_release_archive_file_path }}" dest: "{{ lego_release_archive_file_path }}"
when: lego_binary_info.rc != 0
- name: Create folder to uncompress into - name: Create folder to uncompress into
ansible.builtin.file: ansible.builtin.file:
dest: "{{ lego_release_archive_path }}" dest: "{{ lego_release_archive_path }}"
state: directory state: directory
when: lego_binary_info.rc != 0
- name: Uncompress lego source archive - name: Uncompress lego source archive
ansible.builtin.unarchive: ansible.builtin.unarchive:
src: "{{ lego_release_archive_file_path }}" src: "{{ lego_release_archive_file_path }}"
dest: "{{ lego_release_archive_path }}" dest: "{{ lego_release_archive_path }}"
remote_src: true remote_src: true
ignore_errors: "{{ ansible_check_mode }}" when: lego_binary_info.rc != 0
- name: Ensure lego binary is present in PATH - name: Ensure lego binary is present in PATH
ansible.builtin.copy: ansible.builtin.copy:
@ -70,7 +61,14 @@
dest: "/usr/local/bin/lego" dest: "/usr/local/bin/lego"
mode: "u+rwx,g+rx,o+rx" mode: "u+rwx,g+rx,o+rx"
remote_src: true remote_src: true
ignore_errors: "{{ ansible_check_mode }}" when: lego_binary_info.rc != 0
- name: Ensure lego is allowed to bind to ports < 1024
community.general.capabilities:
path: "/usr/local/bin/lego"
capability: "cap_net_bind_service+ep"
state: present
when: lego_binary_allow_net_bind_service
- name: Ensure intermediate data is gone - name: Ensure intermediate data is gone
ansible.builtin.file: ansible.builtin.file:
@ -79,13 +77,7 @@
loop: loop:
- "{{ lego_release_archive_path }}" - "{{ lego_release_archive_path }}"
- "{{ lego_release_archive_file_path }}" - "{{ lego_release_archive_file_path }}"
when: lego_binary_info.rc != 0
- name: Ensure lego is allowed to bind to ports < 1024
community.general.capabilities:
path: "/usr/local/bin/lego"
capability: "cap_net_bind_service+ep"
state: present
when: lego_binary_allow_net_bind_service
- name: Ensure lego base path exists - name: Ensure lego base path exists
ansible.builtin.file: ansible.builtin.file:

19
roles/mariadb/README.md Normal file
View File

@ -0,0 +1,19 @@
# `finallycoffee.base.mariadb` ansible role
This role deploys a MariaDB instance in a docker container.
## Usage
The role expects the following variables to be populated with values and/or secrets:
```yaml
mariadb_root_password: #mariadb root password
mariadb_database: # name of the database to create
mariadb_username: # name of a user to auto-create and assign permission on the mariadb_database
mariadb_password: # password of the user in mariadb_username
```
## Requirements
- Docker installed
- python-docker present on target system for ansible to be able to talk with the docker API.

View File

@ -0,0 +1,32 @@
---
mariadb_version: "10.11.9"
mariadb_base_path: /var/lib/mariadb
mariadb_data_path: "{{ mariadb_base_path }}/{{ mariadb_version }}"
mariadb_root_password: ~
mariadb_database: ~
mariadb_username: ~
mariadb_password: ~
mariadb_container_base_environment:
MARIADB_ROOT_PASSWORD: "{{ mariadb_root_password }}"
mariadb_container_extra_environment: {}
mariadb_container_name: mariadb
mariadb_container_image_name: docker.io/mariadb
mariadb_container_image_tag: ~
mariadb_container_image: "{{ mariadb_container_image_name }}:{{ mariadb_container_image_tag | default(mariadb_version, true) }}"
mariadb_container_base_volumes:
- "{{ mariadb_data_path }}:{{ mariadb_container_data_path }}:z"
mariadb_container_extra_volumes: []
mariadb_container_base_labels:
version: "{{ mariadb_version }}"
mariadb_container_extra_labels: {}
mariadb_container_restart_policy: "unless-stopped"
mariadb_container_environment: >-2
{{ mariadb_container_base_environment
| combine(mariadb_container_database_environment
if (mariadb_database and mariadb_username and mariadb_password)
else {}, recursive=True)
| combine(mariadb_container_extra_environment) }}

View File

@ -0,0 +1,20 @@
---
- name: Ensure mariaDB container image is present on host
community.docker.docker_image:
name: "{{ mariadb_container_image }}"
state: present
source: pull
- name: Ensure mariaDB {{ mariadb_version }} is running as '{{ mariadb_container_name }}'
community.docker.docker_container:
name: "{{ mariadb_container_name }}"
image: "{{ mariadb_container_image }}"
env: "{{ mariadb_container_environment }}"
ports: "{{ mariadb_container_ports }}"
labels: "{{ mariadb_container_labels }}"
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: started

View File

@ -0,0 +1,10 @@
---
mariadb_container_database_environment:
MARIADB_DATABASE: "{{ mariadb_database }}"
MARIADB_USER: "{{ mariadb_username }}"
MARIADB_PASSWORD: "{{ mariadb_password }}"
mariadb_container_data_path: /var/lib/mysql
mariadb_container_volumes: "{{ mariadb_container_base_volumes + mariadb_container_extra_volumes }}"
mariadb_container_labels: "{{ mariadb_container_base_labels | combine(mariadb_container_extra_labels, recursive=True) }}"

View File

@ -1,7 +1,17 @@
--- ---
minio_user: ~
minio_data_path: /opt/minio
minio_create_user: false
minio_manage_host_filesystem: false
minio_root_username: root
minio_root_password: ~
minio_container_name: minio minio_container_name: minio
minio_container_image_name: "docker.io/minio/minio" minio_container_image_name: docker.io/minio/minio
minio_container_image_tag: "RELEASE.2025-04-08T15-41-24Z" minio_container_image_tag: latest
minio_container_image: "{{ minio_container_image_name }}:{{ minio_container_image_tag }}" minio_container_image: "{{ minio_container_image_name }}:{{ minio_container_image_tag }}"
minio_container_networks: [] minio_container_networks: []
minio_container_ports: [] minio_container_ports: []
@ -24,8 +34,6 @@ minio_container_command:
- ":{{ minio_container_listen_port_console }}" - ":{{ minio_container_listen_port_console }}"
minio_container_restart_policy: "unless-stopped" minio_container_restart_policy: "unless-stopped"
minio_container_image_force_source: "{{ (minio_container_image_tag == 'latest')|bool }}" minio_container_image_force_source: "{{ (minio_container_image_tag == 'latest')|bool }}"
minio_container_state: >-2
{{ (minio_state == 'present') | ternary('started', 'absent') }}
minio_container_listen_port_api: 9000 minio_container_listen_port_api: 9000
minio_container_listen_port_console: 8900 minio_container_listen_port_console: 8900

View File

@ -1,12 +0,0 @@
---
minio_user: ~
minio_data_path: /opt/minio
minio_create_user: false
minio_manage_host_filesystem: false
minio_root_username: root
minio_root_password: ~
minio_state: present
minio_deployment_method: docker

View File

@ -1,29 +0,0 @@
---
- name: Ensure filesystem mounts ({{ minio_data_path }}) for container volumes are present
ansible.builtin.file:
path: "{{ minio_data_path }}"
state: directory
user: "{{ minio_user|default(omit, True) }}"
group: "{{ minio_user|default(omit, True) }}"
when: minio_manage_host_filesystem
- name: Ensure container image '{{ minio_container_image }}' is {{ minio_state }}
community.docker.docker_image:
name: "{{ minio_container_image }}"
state: "{{ minio_state }}"
source: pull
force_source: "{{ minio_container_image_force_source }}"
- name: Ensure container '{{ minio_container_name }}' is {{ minio_container_state }}
community.docker.docker_container:
name: "{{ minio_container_name }}"
image: "{{ minio_container_image }}"
volumes: "{{ minio_container_volumes }}"
env: "{{ minio_container_env }}"
labels: "{{ minio_container_labels }}"
networks: "{{ minio_container_networks }}"
ports: "{{ minio_container_ports }}"
user: "{{ minio_user|default(omit, True) }}"
command: "{{ minio_container_command }}"
restart_policy: "{{ minio_container_restart_policy }}"
state: "{{ minio_container_state }}"

View File

@ -1,25 +1,37 @@
--- ---
- name: Ensure 'minio_state' is valid
ansible.builtin.fail:
msg: >-
Unsupported state '{{ minio_state }}'!
Supported states are {{ minio_states | join(', ') }}.
when: minio_state not in minio_states
- name: Ensure 'minio_deployment_method' is valid - name: Ensure minio run user is present
ansible.builtin.fail: user:
msg: >-
Unsupported state '{{ minio_deployment_method }}'!
Supported states are {{ minio_deployment_methods | join(', ') }}.
when: minio_deployment_method not in minio_deployment_methods
- name: Ensure minio run user is {{ minio_state }}
ansible.builtin.user:
name: "{{ minio_user }}" name: "{{ minio_user }}"
state: "{{ minio_state }}" state: present
system: true system: yes
when: minio_create_user when: minio_create_user
- name: Deploy minio using {{ minio_deployment_method }} - name: Ensure filesystem mounts ({{ minio_data_path }}) for container volumes are present
ansible.builtin.include_tasks: file:
file: "deploy-{{ minio_deployment_method }}.yml" path: "{{ minio_data_path }}"
state: directory
user: "{{ minio_user|default(omit, True) }}"
group: "{{ minio_user|default(omit, True) }}"
when: minio_manage_host_filesystem
- name: Ensure container image for minio is present
community.docker.docker_image:
name: "{{ minio_container_image }}"
state: present
source: pull
force_source: "{{ minio_container_image_force_source }}"
- name: Ensure container {{ minio_container_name }} is running
docker_container:
name: "{{ minio_container_name }}"
image: "{{ minio_container_image }}"
volumes: "{{ minio_container_volumes }}"
env: "{{ minio_container_env }}"
labels: "{{ minio_container_labels }}"
networks: "{{ minio_container_networks }}"
ports: "{{ minio_container_ports }}"
user: "{{ minio_user|default(omit, True) }}"
command: "{{ minio_container_command }}"
restart_policy: "{{ minio_container_restart_policy }}"
state: started

View File

@ -1,9 +1,5 @@
--- ---
minio_states:
- present
- absent
minio_deployment_methods:
- docker
minio_container_volumes: "{{ minio_container_base_volumes + minio_container_extra_volumes }}" minio_container_volumes: "{{ minio_container_base_volumes + minio_container_extra_volumes }}"
minio_container_env: "{{ minio_container_base_env | combine(minio_container_extra_env) }}" minio_container_env: "{{ minio_container_base_env | combine(minio_container_extra_env) }}"

View File

@ -1,5 +1,5 @@
--- ---
nginx_version: "1.27.5" nginx_version: "1.27.2"
nginx_flavour: alpine nginx_flavour: alpine
nginx_base_path: /opt/nginx nginx_base_path: /opt/nginx
nginx_config_file: "{{ nginx_base_path }}/nginx.conf" nginx_config_file: "{{ nginx_base_path }}/nginx.conf"

View File

@ -1,37 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ -n ${RESTIC_PRE_BACKUP_HOOK-} ]]; then
/bin/bash -c "$RESTIC_PRE_BACKUP_HOOK"
fi
echo "List existing snapshots or attempt to initialize/unlock repository"
restic snapshots || restic init || restic unlock
sleep 1;
echo "Attempting to remove lock if present"
restic unlock
sleep 2
echo "Start backup on ${@:1}"
restic --verbose --retry-lock=${RESTIC_RETRY_LOCK:-5m} backup "${@:1}"
sleep 2
echo "Forget and prune old snapshots"
restic forget --prune --retry-lock=${RESTIC_RETRY_LOCK:-5m} \
--keep-within=${RESTIC_FORGET_KEEP_WITHIN:-1d} \
--keep-hourly=${RESTIC_FORGET_KEEP_HOURLY:-6} \
--keep-daily=${RESTIC_FORGET_KEEP_DAILY:-2} \
--keep-weekly=${RESTIC_FORGET_KEEP_WEEKLY:-7} \
--keep-monthly=${RESTIC_FORGET_KEEP_MONTHLY:-4} \
--verbose
sleep 2
echo "Generate snapshot metrics"
restic --json snapshots | /opt/restic-generate-snapshot-metrics.sh \
> /var/lib/node_exporter/restic-snapshots-${RESTIC_JOBNAME:-unknown}.prom-src
sleep 2
echo "Check repository"
restic check

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
RESTIC_JSON=$(</dev/stdin)
echo $RESTIC_JSON | jq -r '.[]
| {
"hostname": .hostname,
"username": .username,
"short_id": .short_id,
"time": ((((.time | split(".")[0]) + "Z") | fromdate) - (3600 * (.time | split("+")[1] | split(":")[0] | tonumber + 1))),
"paths": .paths[]
} | "restic_snapshots{hostname=\"\(.hostname)\",username=\"\(.username)\",short_id=\"\(.short_id)\",paths=\"\(.paths)\"} \(.time)"'

View File

@ -1,23 +0,0 @@
# `finallycoffee.base.user` ansible role
Provision and manage user accounts on the remote host. Supports setting user
home, gecos (display name) and shell.
Warning: if the users' home exists and is changed, the role will attempt to
move the home directory. Set `move_home` to false on the user to disable this
behaviour.
## Examples
```yaml
- hosts: all
roles:
- role: finallycoffee.base.user
vars:
users:
- name: root
- name: alice
- name: bob
state: present
- name: eve
state: absent
```

View File

@ -1,2 +0,0 @@
---
users: []

View File

@ -1,41 +0,0 @@
---
- name: Ensure user '{{ user.name }}' is {{ user_state }}
ansible.builtin.user:
name: "{{ user.name }}"
state: "{{ user_state }}"
system: "{{ user.system | default(false, true) }}"
shell: "{{ user.shell | default(omit, true) }}"
home: "{{ user.home | default(omit, true) }}"
create_home: "{{ user.create_home | default(true, true) }}"
move_home: "{{ user.move_home | default(true, true) }}"
skeleton: >-2
{{ (user.create_home | default(true, true) and 'skeleton' in user)
| ternary(user.skeleton | default(''), omit) }}
comment: "{{ user.comment | default(user.gecos | default(omit, true), true) }}"
vars:
user_state: "{{ user.state | default('present', false) }}"
- name: Ensure SSH authorized keys for '{{ user.name }}' are {{ user_state }}
vars:
user_state: "{{ user.state | default('present', false) }}"
when:
- user_state == 'present'
- user.authorized_keys | default([]) | length > 0
block:
- name: Ensure .ssh directory for user '{{ user.name }}' exists
ansible.builtin.file:
path: "{{ user.home | default('/home/' + user.name) + '/.ssh' }}"
state: "directory"
owner: "{{ user.name }}"
group: "{{ user.name }}"
mode: "0700"
- name: Ensure key is up to date
ansible.posix.authorized_key:
user: "{{ user.name }}"
state: "{{ key.state | default('present', true) }}"
key: "{{ key.type }} {{ key.key }}"
comment: "{{ user.name }}-{{ key.comment }}"
loop: "{{ user.authorized_keys }}"
loop_control:
loop_var: key
label: "{{ user.name }}-{{ key.comment }}"

View File

@ -1,8 +0,0 @@
---
- name: Ensure users are configured
ansible.builtin.include_tasks:
file: "configure-user.yml"
loop: "{{ users }}"
loop_control:
loop_var: user
label: "{{ user.name }}"