summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deploy.yml3
-rw-r--r--group_vars/all.yml2
-rw-r--r--group_vars/labdns.yml1
-rw-r--r--group_vars/mail.yml13
-rw-r--r--group_vars/oci.yml3
-rw-r--r--group_vars/swarm_cluster.yml3
-rw-r--r--inventory3
-rw-r--r--playbooks/oci.yml7
-rw-r--r--playbooks/roles/ci/templates/stacks/docker-compose.yml75
-rw-r--r--playbooks/roles/ci/templates/volumes/laminar/.gitkeep0
-rwxr-xr-xplaybooks/roles/ci/templates/volumes/laminar/jobs/build_image.run36
-rwxr-xr-xplaybooks/roles/ci/templates/volumes/laminar/jobs/playbook.run25
-rwxr-xr-xplaybooks/roles/ci/templates/volumes/laminar/scripts/get_secret35
-rwxr-xr-xplaybooks/roles/ci/templates/volumes/laminar/scripts/log3
-rw-r--r--playbooks/roles/labdns/templates/volumes/unbound/a-records.conf2
-rw-r--r--playbooks/roles/mail/templates/stacks/docker-compose.yml6
-rw-r--r--playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf2
-rw-r--r--playbooks/roles/oci/tasks/main.yml8
-rw-r--r--playbooks/roles/oci/templates/stacks/docker-compose.yml48
-rw-r--r--playbooks/roles/oci/templates/volumes/config.toml35
-rw-r--r--playbooks/roles/oci/templates/volumes/images/.gitkeep0
-rw-r--r--playbooks/roles/outbound/templates/headscale/config/acl.json15
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf19
-rw-r--r--playbooks/roles/src/templates/stacks/docker-compose.yml46
-rw-r--r--playbooks/roles/src/templates/volumes/cgit.nginx.conf49
-rw-r--r--playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.pngbin0 -> 25036 bytes
-rw-r--r--playbooks/roles/src/templates/volumes/cgit/index.html1
-rw-r--r--playbooks/roles/swarm_cluster/tasks/main.yml4
-rw-r--r--secrets.txt5
-rw-r--r--tasks/copy-rendered-templates-recursive.yml60
-rw-r--r--tasks/manage-docker-swarm-service.yml2
31 files changed, 412 insertions, 99 deletions
diff --git a/deploy.yml b/deploy.yml
index 8b9578b..dc91530 100644
--- a/deploy.yml
+++ b/deploy.yml
@@ -59,3 +59,6 @@
- name: ci
ansible.builtin.import_playbook: playbooks/ci.yml
+
+- name: oci
+ ansible.builtin.import_playbook: playbooks/oci.yml
diff --git a/group_vars/all.yml b/group_vars/all.yml
index f6747d0..717a983 100644
--- a/group_vars/all.yml
+++ b/group_vars/all.yml
@@ -22,6 +22,8 @@ domain: "liz.coffee"
idm_domain: "idm.{{ domain }}"
headscale_host: "vpn.{{ domain }}"
mail_domain: "mail.{{ domain }}"
+oci_domain: "oci.{{ domain }}"
+passwd_domain: "passwd.{{ domain }}"
info_mail_user: "info"
info_mail: "{{ info_mail_user }}@{{ domain }}"
diff --git a/group_vars/labdns.yml b/group_vars/labdns.yml
index c1985c9..d0b0c6a 100644
--- a/group_vars/labdns.yml
+++ b/group_vars/labdns.yml
@@ -3,6 +3,7 @@
labdns_base: "{{ swarm_base }}/labdns"
internal_services:
+ - oci.{{ domain }}
- ci.{{ domain }}
- test.{{ domain }}
- bin.{{ domain }}
diff --git a/group_vars/mail.yml b/group_vars/mail.yml
index 1114ca8..0a964e2 100644
--- a/group_vars/mail.yml
+++ b/group_vars/mail.yml
@@ -16,15 +16,16 @@ ldap_server_host: "ldaps://{{ ldap_server }}:3636"
ldap_search_base: "{{ 'dc=' ~ idm_domain | regex_replace('\\.', ',dc=') }}"
ldap_bind_dn: "dn=token"
-ldap_query_filter_user: "(&(class=account)(emailprimary=%s))"
-ldap_query_filter_group: "(&(class=group)(mail=%s))"
-ldap_query_filter_alias: "(&(class=account)(emailalternative=%s))"
+ldap_memberof_query: "(memberof=mail)"
+ldap_query_filter_user: "(&(class=account)(emailprimary=%s){{ ldap_memberof_query }})"
+ldap_query_filter_group: "(&(class=group)(mail=%s){{ ldap_memberof_query }})"
+ldap_query_filter_alias: "(&(class=account)(emailalternative=%s)(memberof=mail){{ ldap_memberof_query }})"
ldap_query_filter_domain: "(mail=*@%s)"
-ldap_query_filter_senders: "(&(class=account)(|(emailprimary=%s)(emailalternative=%s)))"
+ldap_query_filter_senders: "(&(class=account)(|(emailprimary=%s)(emailalternative=%s)){{ ldap_memberof_query }})"
dovecot_user_filter: >
- (&(class=account)(name=%u)
- (memberOf=cn=mail,{{ ldap_search_base }}))
+ (&(class=account)(name=%u){{ ldap_memberof_query }})
+
dovecot_auth_bind_userdn: "name=%u,{{ ldap_search_base }}"
roundcube_default_host: "ssl://{{ mail_domain }}"
diff --git a/group_vars/oci.yml b/group_vars/oci.yml
new file mode 100644
index 0000000..7bc2db0
--- /dev/null
+++ b/group_vars/oci.yml
@@ -0,0 +1,3 @@
+---
+
+oci_base: "{{ swarm_base }}/oci"
diff --git a/group_vars/swarm_cluster.yml b/group_vars/swarm_cluster.yml
index bf0744d..25324ae 100644
--- a/group_vars/swarm_cluster.yml
+++ b/group_vars/swarm_cluster.yml
@@ -1,3 +1,6 @@
---
swarm_base: "{{ ceph_base }}/docker"
+
+oci_username: "readonly"
+oci_password: "readonly"
diff --git a/inventory b/inventory
index 86135a8..a15b7ba 100644
--- a/inventory
+++ b/inventory
@@ -68,3 +68,6 @@ swarm-one ansible_host=10.128.0.201 ansible_user=serve ansible_connectio
[ci]
swarm-one ansible_host=10.128.0.201 ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}'
+[oci]
+swarm-one ansible_host=10.128.0.201 ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}'
+
diff --git a/playbooks/oci.yml b/playbooks/oci.yml
new file mode 100644
index 0000000..be8a007
--- /dev/null
+++ b/playbooks/oci.yml
@@ -0,0 +1,7 @@
+---
+
+- name: oci setup
+ hosts: oci
+ become: true
+ roles:
+ - oci
diff --git a/playbooks/roles/ci/templates/stacks/docker-compose.yml b/playbooks/roles/ci/templates/stacks/docker-compose.yml
index e2358e5..38e1b1c 100644
--- a/playbooks/roles/ci/templates/stacks/docker-compose.yml
+++ b/playbooks/roles/ci/templates/stacks/docker-compose.yml
@@ -1,69 +1,26 @@
-services:
- db:
- image: postgres
- environment:
- POSTGRES_DB: concourse
- POSTGRES_PASSWORD: concourse_pass
- POSTGRES_USER: concourse_user
- PGDATA: /database
- POSTGRES_HOST_AUTH_METHOD: trust
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U concourse_user -d concourse"]
- interval: 3s
- timeout: 3s
- retries: 5
- networks:
- - ci
-
- worker:
- image: concourse/concourse
- command: worker
- privileged: true
- depends_on:
- web:
- condition: service_healthy
- volumes:
- - {{ ci_base }}/volumes/keys/worker:/concourse-keys
- networks:
- - ci
- stop_signal: SIGUSR2
- environment:
- CONCOURSE_TSA_HOST: web:2222
- CONCOURSE_GARDEN_DNS_PROXY_ENABLE: "true"
+---
- web:
- image: concourse
- depends_on:
- db:
- condition: service_healthy
+services:
+ laminard:
+ image: oci.liz.coffee/img/laminar-ciworker:latest
volumes:
- - {{ ci_base }}/volumes/keys/web:/concourse-keys
+ - {{ ci_base }}/volumes/laminar:/var/lib/laminar
+ - /var/run/docker.sock:/var/run/docker.sock
+ healthcheck:
+ test: ["CMD-SHELL", "/usr/bin/laminarc show-jobs"]
+ timeout: 15s
+ interval: 30s
+ retries: 3
+ start_period: 5s
environment:
+ - BW_CLIENTID={{ vaultwarden_client_id }}
+ - BW_CLIENTSECRET={{ vaultwarden_client_secret }}
+ - BW_PASSWORD={{ vaultwarden_master_password }}
- TZ={{ timezone }}
- DEPLOYMENT_TIME={{ deployment_time }}
- - CONCOURSE_POSTGRES_HOST: db
- - CONCOURSE_POSTGRES_USER: concourse_user
- - CONCOURSE_POSTGRES_PASSWORD: concourse_pass
- - CONCOURSE_POSTGRES_DATABASE: concourse
- - CONCOURSE_EXTERNAL_URL: https://{{ ci_domain }}
-
- - # instead of relying on the default "detect"
- - CONCOURSE_WORKER_BAGGAGECLAIM_DRIVER=overlay
- - CONCOURSE_CLUSTER_NAME={{ ci_domain }}
-
- - CONCOURSE_OIDC_DISPLAY_NAME={{ domain }} <3
- - CONCOURSE_OIDC_CLIENT_ID=concourse
- - CONCOURSE_OIDC_CLIENT_SECRET={{ concourse_secret_key }}
- - CONCOURSE_OID_ISSUER=https://{{ idm_domain }}/oauth2/openid/concourse/
networks:
- ci
- proxy
- healthcheck:
- test: ["CMD-SHELL", "curl", "--fail", "http://localhost:8080"]
- timeout: 15s
- interval: 30s
- retries: 3
- start_period: 5s
deploy:
mode: replicated
update_config:
@@ -84,5 +41,7 @@ services:
networks:
ci:
+ driver: overlay
+ attachable: true
proxy:
external: true
diff --git a/playbooks/roles/ci/templates/volumes/laminar/.gitkeep b/playbooks/roles/ci/templates/volumes/laminar/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/playbooks/roles/ci/templates/volumes/laminar/.gitkeep
diff --git a/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run b/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run
new file mode 100755
index 0000000..ed7bf21
--- /dev/null
+++ b/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run
@@ -0,0 +1,36 @@
+#!/bin/bash
+# usage: laminarc queue build_publish_image registry="oci.liz.coffee" \
+# repo="src/cgit" tag="latest" remote="ssh://src.liz.coffee:2222/cgit" \
+# rev="<sha>" image_file="Dockerfile"
+
+set -e
+
+declare -a args=("$registry" "$repo" "$tag" "$remote" "$rev" "$image_file")
+for arg in "${args[@]}"
+do
+ if [[ ! "$arg" =~ ^[[:alnum:]:_\.\/\-]*$ ]]; then
+ echo "Invalid argument format. Don't be sneaky snek (-_-)."
+ exit 1
+ fi
+done
+
+log "Logging into registry $registry"
+registry_username="$(get_secret $registry | jq -r ".login.username")"
+get_secret $registry | jq -r ".login.password" \
+ | docker login --username "$registry_username" --password-stdin "$registry"
+
+log "Cloning remote $remote"
+r=$(echo "build-$(date --iso-8601=seconds)")
+git clone "$remote" "$r" && cd "$r"
+git checkout "$rev"
+
+image_tag="$registry/$repo:$tag"
+log "Building image $image_tag"
+env -i HOME="$HOME" bash -l -c "docker build . -t '$image_tag' -f '$image_file'"
+
+log "Pushing $image_tag"
+docker push "$image_tag"
+
+cd -
+rm -rf "$r"
+docker logout "$registry"
diff --git a/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run b/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run
new file mode 100755
index 0000000..181a050
--- /dev/null
+++ b/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run
@@ -0,0 +1,25 @@
+#!/bin/bash
+# usage: laminarc queue playbook remote="ssh://src.liz.coffee:2222/infra" playbooks="deploy.yml playbooks/labdns.yml"
+
+set -e
+
+declare -a args=("$remote" "$playbooks")
+for arg in "${args[@]}"
+do
+ if [[ ! "$arg" =~ ^[[:alnum:]:_\ \.\/\-]*$ ]]; then
+ echo "Invalid argument format. Don't be sneaky snek (-_-)."
+ exit 1
+ fi
+done
+
+log "Cloning remote $remote"
+r=$(echo "ansible-$(date --iso-8601=seconds)")
+git clone "$remote" "$r" && cd "$r"
+
+get_secret "ansible_secrets" | jq -r '.notes' > secrets.yml
+private_key=$(get_secret "ssh_key" | jq -r '.notes')
+
+env -i HOME="$HOME" ssh-agent bash -c "ssh-add <(echo \"$private_key\") && ansible-playbook -e @secrets.yml $playbooks"
+
+cd -
+rm -rf "$r"
diff --git a/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret b/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret
new file mode 100755
index 0000000..2774651
--- /dev/null
+++ b/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+bw config server "https://{{ passwd_domain }}"
+bw login --apikey --quiet
+bw unlock --passwordenv BW_PASSWORD --quiet
+
+# https://github.com/bitwarden/clients/issues/3366
+function bw_get() {
+ local pwd
+ local count
+ local organisation=${2:-notnull}
+
+ count=$(bw list items --pretty --organizationid ${organisation} | jq -r '[.[] | select(.name=="'$1'")] | length')
+
+ if [[ "$count" -gt 1 ]]; then
+ echo "Multiple items found"
+ return 1
+ fi
+
+ if [[ "$count" -lt 1 ]]; then
+ echo "No items found"
+ return 1
+ fi
+
+ pwd=$(bw list items --pretty --organizationid ${organisation} | jq -r '.[] | select(.name=="'$1'")')
+ if [[ -z "$pwd" ]]; then
+ echo "Password not found"
+ return 1
+ fi
+
+ echo "$pwd"
+}
+
+bw_get $@
+bw --quiet lock
diff --git a/playbooks/roles/ci/templates/volumes/laminar/scripts/log b/playbooks/roles/ci/templates/volumes/laminar/scripts/log
new file mode 100755
index 0000000..180fa33
--- /dev/null
+++ b/playbooks/roles/ci/templates/volumes/laminar/scripts/log
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo `date +"%d-%m-%Y %H:%M:%S"` " - " "${@}"
diff --git a/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf b/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf
index 5eefeb5..d0c9517 100644
--- a/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf
+++ b/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf
@@ -3,6 +3,6 @@
local-data: "{{ service }}. A {{ loadbalancer_ip }}"
{% endfor %}
-# lucina.cloud
+# TODO: for lucina.cloud, for now...
local-zone: "lucina.cloud." redirect
local-data: "lucina.cloud. A 10.128.0.44"
diff --git a/playbooks/roles/mail/templates/stacks/docker-compose.yml b/playbooks/roles/mail/templates/stacks/docker-compose.yml
index 38e63cb..d7f8984 100644
--- a/playbooks/roles/mail/templates/stacks/docker-compose.yml
+++ b/playbooks/roles/mail/templates/stacks/docker-compose.yml
@@ -1,7 +1,6 @@
services:
roundcube:
image: roundcube/roundcubemail:latest
- restart: always
volumes:
- {{ mail_base }}/volumes/data/roundcube/db:/var/roundcube/db
- {{ mail_base }}/volumes/data/roundcube/config:/var/roundcube/config/
@@ -38,9 +37,9 @@ services:
mailserver:
image: ghcr.io/docker-mailserver/docker-mailserver:latest
hostname: {{ mail_domain }}
+{% if homelab_build %}
command:
- /scripts/wait-for-cert.sh
-{% if homelab_build %}
healthcheck:
disable: true
{% else %}
@@ -59,7 +58,6 @@ services:
- '4190:4190'
- '110:110'
- '995:995'
- stop_grace_period: 30s
deploy:
mode: replicated
replicas: 1
@@ -104,8 +102,6 @@ services:
- SASLAUTHD_MECHANISMS=rimap
- SASLAUTHD_MECH_OPTIONS=127.0.0.1
- - DOVECOT_USER_FILTER={{ dovecot_user_filter }}
-
- ENABLE_OAUTH2=1
- OAUTH2_INTROSPECTION_URL={{ roundcube_oauth2_user_uri }}
diff --git a/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf b/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf
index 6a14553..e55a861 100644
--- a/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf
+++ b/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf
@@ -8,3 +8,5 @@ dnpass = {{ email_ldap_api_token }}
auth_bind = yes
auth_bind_userdn = {{ dovecot_auth_bind_userdn }}
+user_filter = {{ dovecot_user_filter }}
+pass_filter = {{ dovecot_user_filter }}
diff --git a/playbooks/roles/oci/tasks/main.yml b/playbooks/roles/oci/tasks/main.yml
new file mode 100644
index 0000000..d9c3b56
--- /dev/null
+++ b/playbooks/roles/oci/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+
+- name: Deploy oci
+ ansible.builtin.import_tasks: manage-docker-swarm-service.yml
+ vars:
+ service_name: oci
+ template_render_dir: "../templates"
+ service_destination_dir: "{{ oci_base }}"
diff --git a/playbooks/roles/oci/templates/stacks/docker-compose.yml b/playbooks/roles/oci/templates/stacks/docker-compose.yml
new file mode 100644
index 0000000..8b40356
--- /dev/null
+++ b/playbooks/roles/oci/templates/stacks/docker-compose.yml
@@ -0,0 +1,48 @@
+services:
+ valkey:
+ image: valkey/valkey:8.0.2
+ networks:
+ - oci
+
+ oci:
+ image: ghcr.io/simple-registry/simple-registry:main
+ command: "server"
+ volumes:
+ - {{ oci_base }}/volumes/config.toml:/config.toml
+ - {{ oci_base }}/volumes/images:/images
+ environment:
+ - TZ={{ timezone }}
+ - DEPLOYMENT_TIME={{ deployment_time }}
+ - RUST_LOG=info
+ networks:
+ - proxy
+ - oci
+ healthcheck:
+ test: ["CMD", "/simple-registry", "scrub"]
+ timeout: 10s
+ interval: 30s
+ retries: 2
+ start_period: 5s
+ deploy:
+ mode: replicated
+ update_config:
+ parallelism: 1
+ failure_action: rollback
+ order: start-first
+ monitor: 5s
+ replicas: 1
+ labels:
+ - traefik.enable=true
+ - traefik.swarm.network=proxy
+ - traefik.http.routers.oci.tls=true
+ - traefik.http.routers.oci.tls.certResolver=letsencrypt
+ - traefik.http.routers.oci.rule=Host(`{{ oci_domain }}`)
+ - traefik.http.routers.oci.entrypoints=websecure
+ - traefik.http.services.oci.loadbalancer.server.port=8000
+
+networks:
+ oci:
+ attachable: true
+ driver: overlay
+ proxy:
+ external: true
diff --git a/playbooks/roles/oci/templates/volumes/config.toml b/playbooks/roles/oci/templates/volumes/config.toml
new file mode 100644
index 0000000..6d2f199
--- /dev/null
+++ b/playbooks/roles/oci/templates/volumes/config.toml
@@ -0,0 +1,35 @@
+[server]
+bind_address = "0.0.0.0"
+port = 8000
+streaming_chunk_size = "5MiB"
+
+[lock_store.redis]
+url = "redis://valkey:6379"
+ttl = 5
+
+[cache_store.redis]
+url = "redis://valkey:6379"
+ttl = 5
+
+[storage.fs]
+root_dir = "/images"
+
+[observability.tracing]
+endpoint = "http://127.0.0.1:4317"
+sampling_rate = 1.0
+
+[identity.ci]
+username = "ci"
+password = "{{ simple_registry_password_argon_encoded }}"
+
+[identity.readonly]
+username = "readonly"
+password = "$argon2i$v=19$m=16,t=2,p=1$TjJyTEdIZUJ6dFZkdlZvSg$qf8vG09O93Z/9vUMCgWNtA" # readonly
+
+[repository."img"]
+
+[repository."img".access_policy]
+default_allow = false
+rules = [
+ 'request.action.startsWith("get-") || request.action.startsWith("list-") || identity.id == "ci"'
+]
diff --git a/playbooks/roles/oci/templates/volumes/images/.gitkeep b/playbooks/roles/oci/templates/volumes/images/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/playbooks/roles/oci/templates/volumes/images/.gitkeep
diff --git a/playbooks/roles/outbound/templates/headscale/config/acl.json b/playbooks/roles/outbound/templates/headscale/config/acl.json
index 449207d..242d01e 100644
--- a/playbooks/roles/outbound/templates/headscale/config/acl.json
+++ b/playbooks/roles/outbound/templates/headscale/config/acl.json
@@ -1,17 +1,24 @@
{
"groups": {
- "group:internal": ["liz{{ oauth_user_suffix }}", "lucina{{ oauth_user_suffix }}", "riley{{ oauth_user_suffix }}"],
+ "group:coffee_admins": ["liz{{ oauth_user_suffix }}", "lucina{{ oauth_user_suffix }}"],
},
"acls": [
+{% for user in ["liz", "lucina", "riley"] %}
+ {
+ "action": "accept",
+ "src": ["{{ user }}{{ oauth_user_suffix }}"],
+ "dst": ["{{ user }}{{ oauth_user_suffix }}:*"]
+ },
+{% endfor %}
{
"action": "accept",
"src": ["{{ auth_key_user }}"],
- "dst": ["{{ auth_key_user }}:*", "10.0.0.0/8:*"]
+ "dst": ["{{ auth_key_user }}:*", "{{ loadbalancer_ip }}/32:*"]
},
{
"action": "accept",
- "src": ["group:internal"],
- "dst": ["10.0.0.0/8:*"]
+ "src": ["group:coffee_admins"],
+ "dst": ["{{ loadbalancer_ip }}/32:*"]
}
]
}
diff --git a/playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf
new file mode 100644
index 0000000..5e68fc3
--- /dev/null
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf
@@ -0,0 +1,19 @@
+server {
+ listen 80;
+ server_name oci.liz.coffee;
+
+ real_ip_header X-Forwarded-For;
+ real_ip_recursive on;
+ set_real_ip_from {{ docker_network }};
+
+ location / {
+ proxy_pass https://{{ loadbalancer_ip }};
+ proxy_ssl_verify off;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ }
+}
diff --git a/playbooks/roles/src/templates/stacks/docker-compose.yml b/playbooks/roles/src/templates/stacks/docker-compose.yml
index 46f253d..547020d 100644
--- a/playbooks/roles/src/templates/stacks/docker-compose.yml
+++ b/playbooks/roles/src/templates/stacks/docker-compose.yml
@@ -1,4 +1,40 @@
services:
+ frontend:
+ image: emarcs/nginx-cgit
+ volumes:
+ - {{ src_base }}/volumes/data/repos:/srv/git:ro
+ - {{ src_base }}/volumes/cgit/:/usr/share/cgit:ro
+ - {{ src_base }}/volumes/cgit.nginx.conf:/etc/nginx/sites-available/default
+ environment:
+ CGIT_TITLE: '{{ src_domain }}'
+ CGIT_DESC: '<3 {{ domain }}'
+ CGIT_VROOT: '/cgit'
+ CGIT_SECTION_FROM_STARTPATH: 1
+ CGIT_MAX_REPO_COUNT: 100
+ networks:
+ - proxy
+ healthcheck:
+ test: ["CMD-SHELL", "curl --fail http://localhost"]
+ timeout: 15s
+ interval: 30s
+ retries: 3
+ start_period: 5s
+ deploy:
+ mode: replicated
+ update_config:
+ parallelism: 1
+ failure_action: rollback
+ order: start-first
+ monitor: 10s
+ labels:
+ - traefik.enable=true
+ - traefik.swarm.network=proxy
+ - traefik.http.routers.src.tls=true
+ - traefik.http.routers.src.tls.certResolver=letsencrypt
+ - traefik.http.routers.src.rule=Host(`{{ src_domain }}`)
+ - traefik.http.routers.src.entrypoints=websecure
+ - traefik.http.services.src.loadbalancer.server.port=80
+
src:
image: charmcli/soft-serve
volumes:
@@ -17,8 +53,6 @@ services:
- SOFT_SERVE_INITIAL_ADMIN_KEYS={{ src_admin_keys }}
- SOFT_SERVE_GIT_MAX_CONNECTIONS=20
- SOFT_SERVE_LOG_FORMAT=json
- networks:
- - proxy
healthcheck:
test: ["CMD-SHELL", "netstat -tuln | grep 2222"]
timeout: 15s
@@ -33,14 +67,6 @@ services:
order: stop-first
monitor: 10s
replicas: 1
- labels:
- - traefik.enable=true
- - traefik.swarm.network=proxy
- - traefik.http.routers.src.tls=true
- - traefik.http.routers.src.tls.certResolver=letsencrypt
- - traefik.http.routers.src.rule=Host(`{{ src_domain }}`)
- - traefik.http.routers.src.entrypoints=websecure
- - traefik.http.services.src.loadbalancer.server.port=8000
networks:
proxy:
diff --git a/playbooks/roles/src/templates/volumes/cgit.nginx.conf b/playbooks/roles/src/templates/volumes/cgit.nginx.conf
new file mode 100644
index 0000000..5abe189
--- /dev/null
+++ b/playbooks/roles/src/templates/volumes/cgit.nginx.conf
@@ -0,0 +1,49 @@
+server {
+ listen 80;
+ server_name localhost;
+
+ #charset koi8-r;
+ #access_log /var/log/nginx/log/host.access.log main;
+
+ location / {
+ root /usr/share/cgit/;
+ }
+
+ location /cgit {
+ try_files $uri @cgit;
+ }
+
+ location @cgit {
+ fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
+
+ fastcgi_param HTTP_HOST $server_name;
+ fastcgi_split_path_info ^(/cgit/?)(.+)$;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param QUERY_INFO $uri;
+
+ include fastcgi_params;
+
+ fastcgi_pass unix:/var/run/fcgiwrap.socket;
+ }
+
+ location /cgit-css/ {
+ rewrite ^/cgit-css(/.*)$ $1 break;
+ root /usr/share/cgit/cgit-css/;
+ }
+
+ error_page 404 /404.html;
+ error_page 401 /401.html;
+
+ # redirect server error pages to the static page /50x.html
+ error_page 500 502 503 504 /50x.html;
+ location = /50x.html {
+ root /usr/share/nginx/html;
+ }
+
+ # deny access to .htaccess files, if Apache's document root
+ # concurs with nginx's one
+ #
+ location ~ /\.ht {
+ deny all;
+ }
+}
diff --git a/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png b/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png
new file mode 100644
index 0000000..bb7ffa1
--- /dev/null
+++ b/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png
Binary files differ
diff --git a/playbooks/roles/src/templates/volumes/cgit/index.html b/playbooks/roles/src/templates/volumes/cgit/index.html
new file mode 100644
index 0000000..4b06983
--- /dev/null
+++ b/playbooks/roles/src/templates/volumes/cgit/index.html
@@ -0,0 +1 @@
+<h1>hai</h1>
diff --git a/playbooks/roles/swarm_cluster/tasks/main.yml b/playbooks/roles/swarm_cluster/tasks/main.yml
index d2507af..961d6f5 100644
--- a/playbooks/roles/swarm_cluster/tasks/main.yml
+++ b/playbooks/roles/swarm_cluster/tasks/main.yml
@@ -18,3 +18,7 @@
when: ansible_hostname != swarm_initializer_host
ansible.builtin.import_tasks: swarm_join/tasks/main.yml
+- name: Login to OCI
+ when: not homelab_build
+ ansible.builtin.command: "docker login {{ oci_domain }} --username {{ oci_username }} --password {{ oci_password }}"
+
diff --git a/secrets.txt b/secrets.txt
index 4fd2647..e23eeba 100644
--- a/secrets.txt
+++ b/secrets.txt
@@ -17,4 +17,7 @@ roundcube_oauth2_client_basic_secret
info_mail_password
yubico_client_id
yubico_secret_key
-concourse_secret_key
+simple_registry_password_argon_encoded
+vaultwarden_client_id
+vaultwarden_client_secret
+vaultwarden_master_password
diff --git a/tasks/copy-rendered-templates-recursive.yml b/tasks/copy-rendered-templates-recursive.yml
index 0733493..2b83834 100644
--- a/tasks/copy-rendered-templates-recursive.yml
+++ b/tasks/copy-rendered-templates-recursive.yml
@@ -7,7 +7,7 @@
state: directory
register: tempdir
-- name: Ensure parent directories exist for rendered templates
+- name: Ensure parent directories exist for all files
delegate_to: localhost
become: false
ansible.builtin.file:
@@ -17,36 +17,69 @@
with_filetree: "{{ render_dir }}"
when: item.state == "file"
-- name: Recursively render templates
+- name: Check if each file is text or binary
+ delegate_to: localhost
+ become: false
+ ansible.builtin.command:
+ cmd: file --mime-type "{{ item.src }}"
+ register: file_type_check
+ changed_when: false
+ with_filetree: "{{ render_dir }}"
+ when: item.state == "file"
+ loop_control:
+ label: "{{ item.path }}"
+
+- name: Separate text and binary files
+ set_fact:
+ text_files: >-
+ {{
+ file_type_check.results
+ | selectattr('stdout', 'defined')
+ | selectattr('stdout', 'search', '^.*: text/')
+ | map(attribute='item')
+ | list
+ }}
+ binary_files: >-
+ {{
+ file_type_check.results
+ | selectattr('stdout', 'defined')
+ | rejectattr('stdout', 'search', '^.*: text/')
+ | map(attribute='item')
+ | list
+ }}
+
+- name: Render templates (text files only)
delegate_to: localhost
become: false
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ tempdir.path }}/{{ item.path }}"
mode: "{{ mode | default('0755') }}"
- with_filetree: "{{ render_dir }}"
- when: item.state == "file"
+ loop: "{{ text_files }}"
-- name: Sync rendered templates to remote host
+- name: Copy binary files directly
delegate_to: localhost
become: false
- ansible.builtin.synchronize:
- src: "{{ tempdir.path }}/"
- dest: "{{ tempdir.path }}/"
+ ansible.builtin.copy:
+ src: "{{ item.src }}"
+ dest: "{{ tempdir.path }}/{{ item.path }}"
+ mode: "{{ mode | default('0644') }}"
+ loop: "{{ binary_files }}"
-- name: Remove local temporary directory
+- name: Sync rendered and copied files to remote host
delegate_to: localhost
become: false
- ansible.builtin.file:
- path: "{{ tempdir.path }}"
- state: absent
+ ansible.builtin.synchronize:
+ src: "{{ tempdir.path }}/"
+ dest: "{{ tempdir.path }}/"
+ recursive: true
- name: Ensure destination exists
ansible.builtin.file:
path: "{{ destination_dir }}"
state: directory
-- name: Update remote files
+- name: Copy files to final destination
ansible.builtin.command:
cmd: bash -c 'cp -r {{ tempdir.path }}/* {{ destination_dir }}/'
@@ -61,3 +94,4 @@
ansible.builtin.file:
path: "{{ tempdir.path }}"
state: absent
+
diff --git a/tasks/manage-docker-swarm-service.yml b/tasks/manage-docker-swarm-service.yml
index 5332a3f..3d01e1c 100644
--- a/tasks/manage-docker-swarm-service.yml
+++ b/tasks/manage-docker-swarm-service.yml
@@ -9,7 +9,7 @@
- name: "Deploy stack for {{ service_name }}"
ansible.builtin.command:
- cmd: "docker stack deploy --resolve-image changed --detach=false --compose-file {{ stack_file | default(service_destination_dir + '/stacks/docker-compose.yml') }} {{ service_name }}"
+ cmd: "docker stack deploy --with-registry-auth --prune --detach=false --resolve-image=always --compose-file {{ stack_file | default(service_destination_dir + '/stacks/docker-compose.yml') }} {{ service_name }}"
register: stack_result
changed_when: true
failed_when: stack_result.rc != 0