aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaditya Dhruv <[email protected]>2025-04-22 17:29:46 -0500
committerAaditya Dhruv <[email protected]>2025-05-01 20:19:51 -0500
commit55298a51cb0cc5e68c5a43869f2f32b899d3a622 (patch)
tree50d271288502bcff6f0a5133ce0839d883ee8ef7
init
-rw-r--r--.gitignore7
-rw-r--r--LICENSE0
-rw-r--r--README.md114
-rw-r--r--TODO.md9
-rw-r--r--config.yaml51
-rw-r--r--inventories/homelab.ini16
-rw-r--r--inventories/inventory.ini10
-rw-r--r--playbooks/master.yaml50
-rw-r--r--playbooks/setup_k3s.yaml13
-rw-r--r--playbooks/setup_services.yaml32
-rw-r--r--playbooks/setup_single.yaml7
-rw-r--r--roles/actual/defaults/main.yaml9
-rw-r--r--roles/actual/files/actual/.helmignore23
-rw-r--r--roles/actual/files/actual/Chart.yaml6
-rw-r--r--roles/actual/files/actual/templates/deployment.yaml26
-rw-r--r--roles/actual/files/actual/templates/ingress.yaml34
-rw-r--r--roles/actual/files/actual/templates/pv.yaml16
-rw-r--r--roles/actual/files/actual/templates/pvc.yaml14
-rw-r--r--roles/actual/files/actual/templates/service.yaml14
-rw-r--r--roles/actual/tasks/main.yaml17
-rw-r--r--roles/archivebox/defaults/main.yaml9
-rw-r--r--roles/archivebox/files/archivebox/.helmignore23
-rw-r--r--roles/archivebox/files/archivebox/Chart.yaml5
-rw-r--r--roles/archivebox/files/archivebox/templates/deployment.yaml45
-rw-r--r--roles/archivebox/files/archivebox/templates/ingress.yaml23
-rw-r--r--roles/archivebox/files/archivebox/templates/pv.yaml16
-rw-r--r--roles/archivebox/files/archivebox/templates/pvc.yaml14
-rw-r--r--roles/archivebox/files/archivebox/templates/service.yaml14
-rw-r--r--roles/archivebox/tasks/main.yaml17
-rw-r--r--roles/ca/files/ca.yaml32
-rw-r--r--roles/ca/files/lets-encrypt-dev.yaml18
-rw-r--r--roles/ca/files/lets-encrypt-prod.yaml18
-rw-r--r--roles/ca/tasks/main.yaml32
-rw-r--r--roles/cgit/defaults/main.yaml12
-rw-r--r--roles/cgit/files/cgit/Chart.yaml5
-rw-r--r--roles/cgit/files/cgit/templates/configmap.yaml31
-rw-r--r--roles/cgit/files/cgit/templates/deployment.yaml38
-rw-r--r--roles/cgit/files/cgit/templates/ingress.yaml47
-rw-r--r--roles/cgit/files/cgit/templates/pv.yaml16
-rw-r--r--roles/cgit/files/cgit/templates/pvc.yaml14
-rw-r--r--roles/cgit/files/cgit/templates/service.yaml21
-rw-r--r--roles/cgit/files/image/Caddyfile13
-rw-r--r--roles/cgit/files/image/Dockerfile12
-rwxr-xr-xroles/cgit/files/image/start.sh4
-rw-r--r--roles/cgit/files/image/syntax-highlighting.py55
-rw-r--r--roles/cgit/files/image/theme.css172
-rw-r--r--roles/cgit/files/image/theme.html1
-rw-r--r--roles/cgit/tasks/main.yaml21
-rw-r--r--roles/cloud/defaults/main.yaml6
-rw-r--r--roles/cloud/files/cloud/Chart.yaml6
-rw-r--r--roles/cloud/files/cloud/templates/cloud.yaml40
-rw-r--r--roles/cloud/files/cloud/templates/ingress.yaml33
-rw-r--r--roles/cloud/files/cloud/templates/pv.yaml16
-rw-r--r--roles/cloud/files/cloud/templates/pvc.yaml14
-rw-r--r--roles/cloud/files/cloud/templates/service.yaml13
-rw-r--r--roles/cloud/tasks/main.yaml17
-rw-r--r--roles/fishnet/defaults/main.yaml3
-rw-r--r--roles/fishnet/files/fishnet/Chart.yaml6
-rw-r--r--roles/fishnet/files/fishnet/templates/deployment.yaml32
-rw-r--r--roles/fishnet/tasks/main.yaml12
-rw-r--r--roles/gonic/defaults/main.yaml9
-rw-r--r--roles/gonic/files/gonic/.helmignore23
-rw-r--r--roles/gonic/files/gonic/Chart.yaml5
-rw-r--r--roles/gonic/files/gonic/templates/deployment.yaml33
-rw-r--r--roles/gonic/files/gonic/templates/ingress.yaml34
-rw-r--r--roles/gonic/files/gonic/templates/pv.yaml16
-rw-r--r--roles/gonic/files/gonic/templates/pvc.yaml14
-rw-r--r--roles/gonic/files/gonic/templates/service.yaml14
-rw-r--r--roles/gonic/tasks/main.yaml17
-rw-r--r--roles/jellyfin/defaults/main.yaml5
-rw-r--r--roles/jellyfin/files/jellyfin/ingress.yaml33
-rw-r--r--roles/jellyfin/files/jellyfin/pv.yaml34
-rw-r--r--roles/jellyfin/files/jellyfin/pvc.yaml30
-rw-r--r--roles/jellyfin/tasks/main.yaml68
-rw-r--r--roles/k3s/tasks/main.yaml34
-rw-r--r--roles/metallb/defaults/main.yaml3
-rw-r--r--roles/metallb/tasks/main.yaml36
-rw-r--r--roles/monitoring/tasks/main.yaml17
-rw-r--r--roles/network/defaults/main.yaml2
-rw-r--r--roles/network/tasks/dns.yaml14
-rw-r--r--roles/network/tasks/main.yaml11
-rw-r--r--roles/network/tasks/misc.yaml12
-rw-r--r--roles/network/tasks/vlans.yaml39
-rw-r--r--roles/network/tasks/vps.yaml0
-rw-r--r--roles/photos/defaults/main.yaml9
-rw-r--r--roles/photos/files/core/Chart.yaml6
-rw-r--r--roles/photos/files/core/templates/ingress.yaml33
-rw-r--r--roles/photos/files/core/templates/pv.yaml16
-rw-r--r--roles/photos/files/core/templates/pvc.yaml14
-rw-r--r--roles/photos/files/postgres/Chart.yaml6
-rw-r--r--roles/photos/files/postgres/templates/database.yaml37
-rw-r--r--roles/photos/files/postgres/templates/pv.yaml16
-rw-r--r--roles/photos/files/postgres/templates/pvc.yaml14
-rw-r--r--roles/photos/files/postgres/templates/service.yaml12
-rw-r--r--roles/photos/tasks/main.yaml60
-rw-r--r--roles/pihole/defaults/main.yaml8
-rw-r--r--roles/pihole/files/pihole.service14
-rw-r--r--roles/pihole/files/pihole/.helmignore23
-rw-r--r--roles/pihole/files/pihole/Chart.yaml6
-rw-r--r--roles/pihole/files/pihole/templates/deployment.yaml37
-rw-r--r--roles/pihole/files/pihole/templates/ingress.yaml34
-rw-r--r--roles/pihole/files/pihole/templates/pv.yaml16
-rw-r--r--roles/pihole/files/pihole/templates/pvc.yaml14
-rw-r--r--roles/pihole/files/pihole/templates/service.yaml21
-rw-r--r--roles/pihole/tasks/k8s.yaml15
-rw-r--r--roles/pihole/tasks/main.yaml10
-rw-r--r--roles/pihole/tasks/pihole.yaml73
-rw-r--r--roles/pihole/templates/pihole.yaml.j220
-rw-r--r--roles/system/defaults/main.yaml18
-rw-r--r--roles/system/files/packages/k9s/k9s.spec37
-rw-r--r--roles/system/tasks/main.yaml7
-rw-r--r--roles/wireguard/defaults/main.yaml2
-rw-r--r--roles/wireguard/tasks/main.yaml3
-rw-r--r--roles/wireguard/tasks/wireguard.yaml93
-rw-r--r--roles/wireguard/templates/wireguard.master.j26
-rw-r--r--roles/wireguard/templates/wireguard.slave.j211
-rwxr-xr-xscripts/backups/backup.sh29
117 files changed, 2617 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5d3beea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+**values.yaml**
+**env**
+**secret**
+**vault**
+_archive
+.vim
+scripts/backups/*password
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/LICENSE
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..92bdecb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,114 @@
+### Purpose
+
+This monorepo has 3 uses:
+
+1. Setup infrastructure
+2. Maintain infrastructure
+3. Document infrastructure
+
+The inventory defines the lab's infrastructure. The config defines the state we
+want the infrastructure to be in. For a given inventory, the playbook should be
+idempotent.
+
+### Structure
+
+```
+src/
+├── network
+│   ├── tasks
+│   └── templates
+├── pi
+│   ├── files
+│   ├── tasks
+│   ├── templates
+│   └── vars
+└── servers
+ ├── files
+ ├── tasks
+ └── vars
+```
+
+### Network
+
+1. Wireguard (Idempotent if atomic)
+
+Sets up the VPN on the master and slaves.
+Idempotent only if run on all the nodes and slaves at once (atomic)
+
+
+2. VLANs
+
+To be run only on router. Idempotency not guaranteed.
+
+3. DNS
+
+Setup DNS on all the hosts. Idempotent.
+
+
+### Pi
+
+1. PiHole
+
+Setup the PiHole service. Idempotent.
+
+
+2. PXE
+
+Setup PXE boot serviec. Idempotent.
+
+
+### Servers
+
+
+1. Base
+
+Install required packages on the hosts. Idempotent.
+
+
+2. Services
+
+Install and setup services on hosts. Idempotent.
+
+
+
+## Playbook Loops
+
+Each loop is a idempotent loop playbook which does certain actions.
+
+### Setup Playbook
+
+Used for the inital homelab setup.
+
+Steps:
+
+1. src/pi
+ - Start PXE
+ - Start PiHole
+2. PXE boot all hosts with kickstart files
+3. src/network
+ - Apply VLAN settings
+ - Apply DNS settings
+ - Apply VPN settings
+4. src/servers
+ - Install base packages
+ - Start up required services on cluster
+5. Misc - Print manual config - router, NAS etc.
+
+### Maintenance Playbook
+
+Used for upgrades, backups, and bringing services/networks up and down.
+
+Steps:
+
+1. src/pi
+ - Start PXE
+ - Start PiHole
+2. PXE boot all hosts with kickstart files
+3. src/network
+ - Apply VLAN settings
+ - Apply DNS settings
+ - Apply VPN settings
+4. src/servers
+ - Install base packages
+ - Start up required services on cluster
+5. Misc - Print manual config - router, NAS etc.
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..567b7b0
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,9 @@
+### General
+
+1. Setup playbooks for individual services
+- Upgrade, reset, migrate etc.
+2. Setup backup role
+- Run systemd unit to backup to backblaze
+3. Setup artifact store for custom images and packages
+### Docs
+Explain each role and usage
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 0000000..2f30f02
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,51 @@
+nfs:
+ server: 192.168.20.5
+actual:
+ enabled: true
+ version: 25.2.1
+jellyfin:
+ version: 10.10.0
+ enabled: true
+gonic:
+ version: 1c23771 #v0.16.4
+ enabled: true
+cgit:
+ version: v2.5
+ enabled: true
+pihole:
+ enabled: true
+ baremetal: false
+ version: 2024.01.0
+metallb:
+ enabled: true
+ pool: 192.168.20.100-192.168.20.250
+cloud:
+ enabled: true
+immich:
+ enabled: true
+ postgres:
+ version: pg14-v0.2.0
+fishnet:
+ enabled: true
+ replicas: 5
+archivebox:
+ enabled: true
+servers:
+ base: true
+ca:
+ enabled: true
+k3s:
+ enabled: true
+ token: 12345
+network:
+ router:
+ enabled: false
+ wireguard:
+ enabled: false
+ port: 43000
+ path: "/etc/wireguard/"
+ dns: 192.168.1.1
+ vlans:
+ - 10
+ - 20
+ - 30
diff --git a/inventories/homelab.ini b/inventories/homelab.ini
new file mode 100644
index 0000000..ae11ff9
--- /dev/null
+++ b/inventories/homelab.ini
@@ -0,0 +1,16 @@
+[servers]
+ampharos
+regirock
+#snorlax
+regice
+[cloud]
+altaria
+[router]
+porygon
+[pi]
+goomy
+[k3s-master]
+ampharos
+[k3s-agent]
+regirock
+regice
diff --git a/inventories/inventory.ini b/inventories/inventory.ini
new file mode 100644
index 0000000..b4c2474
--- /dev/null
+++ b/inventories/inventory.ini
@@ -0,0 +1,10 @@
+[servers]
+192.168.122.101
+192.168.122.33
+[cloud]
+192.168.122.33
+[router]
+[pi]
+goomy
+[k3s-master]
+[k3s-agent]
diff --git a/playbooks/master.yaml b/playbooks/master.yaml
new file mode 100644
index 0000000..8a84097
--- /dev/null
+++ b/playbooks/master.yaml
@@ -0,0 +1,50 @@
+---
+- name: Lab Configuration
+ hosts: all
+ tasks:
+ - name: Setup Network
+ include_role:
+ name: network
+ - name: Setup Systems
+ include_role:
+ name: system
+ - name: Setup Wireguard
+ include_role:
+ name: wireguard
+ - name: Setup K3S
+ include_role:
+ name: k3s
+ when: inventory_hostname in groups["servers"]
+ - name: Setup MetalLB
+ include_role:
+ name: metallb
+ - name: Setup CA
+ include_role:
+ name: ca
+ - name: Setup PiHole
+ include_role:
+ name: pihole
+ - name: Setup Cloud
+ include_role:
+ name: cloud
+ - name: Setup Immich
+ include_role:
+ name: immich
+ - name: Setup Jellyfin
+ include_role:
+ name: jellyfin
+ - name: Setup Actual
+ include_role:
+ name: actual
+ - name: Setup Git
+ include_role:
+ name: cgit
+ - name: Setup Fishnet
+ include_role:
+ name: fishnet
+ - name: Setup Prometheus
+ include_role:
+ name: prometheus
+ - name: Setup Fishnet
+ include_role:
+ name: fishnet
diff --git a/playbooks/setup_k3s.yaml b/playbooks/setup_k3s.yaml
new file mode 100644
index 0000000..912cca7
--- /dev/null
+++ b/playbooks/setup_k3s.yaml
@@ -0,0 +1,13 @@
+---
+- name: Lab Configuration
+ hosts: all
+ tasks:
+ - name: Setup K3S
+ include_role:
+ name: k3s
+ - name: Setup MetalLB
+ include_role:
+ name: metallb
+ - name: Setup CA
+ include_role:
+ name: ca
diff --git a/playbooks/setup_services.yaml b/playbooks/setup_services.yaml
new file mode 100644
index 0000000..91a5b22
--- /dev/null
+++ b/playbooks/setup_services.yaml
@@ -0,0 +1,32 @@
+---
+- name: Setup Services
+ hosts: all
+ gather_facts: false
+ tasks:
+ - name: Setup PiHole
+ include_role:
+ name: pihole
+ - name: Setup Cloud
+ include_role:
+ name: cloud
+ - name: Setup Immich
+ include_role:
+ name: immich
+ - name: Setup Jellyfin
+ include_role:
+ name: jellyfin
+ - name: Setup Actual
+ include_role:
+ name: actual
+ - name: Setup Git
+ include_role:
+ name: cgit
+ - name: Setup Fishnet
+ include_role:
+ name: fishnet
+ - name: Setup Prometheus
+ include_role:
+ name: prometheus
+ - name: Setup Fishnet
+ include_role:
+ name: fishnet
diff --git a/playbooks/setup_single.yaml b/playbooks/setup_single.yaml
new file mode 100644
index 0000000..f080bf9
--- /dev/null
+++ b/playbooks/setup_single.yaml
@@ -0,0 +1,7 @@
+- name: Setup Services
+ hosts: all
+ gather_facts: false
+ tasks:
+ - name: Setup cgit
+ include_role:
+ name: "roles/cgit"
diff --git a/roles/actual/defaults/main.yaml b/roles/actual/defaults/main.yaml
new file mode 100644
index 0000000..9ac174f
--- /dev/null
+++ b/roles/actual/defaults/main.yaml
@@ -0,0 +1,9 @@
+actual:
+ enabled: false
+ replicas: 1
+ port: 80
+ image: actualbudget/actual-server
+ version: 24.9.0
+
+nfs:
+ path: "/mnt/nfs/k3s/actual/"
diff --git a/roles/actual/files/actual/.helmignore b/roles/actual/files/actual/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/roles/actual/files/actual/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/roles/actual/files/actual/Chart.yaml b/roles/actual/files/actual/Chart.yaml
new file mode 100644
index 0000000..c3755a4
--- /dev/null
+++ b/roles/actual/files/actual/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: actual
+description: Actual Budget for budgeting
+type: application
+
+version: 0.1.0
diff --git a/roles/actual/files/actual/templates/deployment.yaml b/roles/actual/files/actual/templates/deployment.yaml
new file mode 100644
index 0000000..3336ee5
--- /dev/null
+++ b/roles/actual/files/actual/templates/deployment.yaml
@@ -0,0 +1,26 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: actual
+ image: "{{ .Values.image }}:{{ .Values.version }}"
+ volumeMounts:
+ - mountPath: "/data"
+ name: "{{ .Chart.Name }}-volume"
+ volumes:
+ - name: "{{ .Chart.Name }}-volume"
+ persistentVolumeClaim:
+ claimName: "{{ .Chart.Name }}-pvc"
diff --git a/roles/actual/files/actual/templates/ingress.yaml b/roles/actual/files/actual/templates/ingress.yaml
new file mode 100644
index 0000000..749ff0b
--- /dev/null
+++ b/roles/actual/files/actual/templates/ingress.yaml
@@ -0,0 +1,34 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: actual
+ annotations:
+ cert-manager.io/cluster-issuer: "ca-issuer"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - finance.aadityadhruv.com
+ - finance.home
+ secretName: actual-tls
+ rules:
+ - host: finance.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: actual-service
+ port:
+ number: 80
+ - host: finance.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: actual-service
+ port:
+ number: 80
diff --git a/roles/actual/files/actual/templates/pv.yaml b/roles/actual/files/actual/templates/pv.yaml
new file mode 100644
index 0000000..498fbd5
--- /dev/null
+++ b/roles/actual/files/actual/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "{{ .Chart.Name }}-pv"
+ labels:
+ app: "{{ .Chart.Name }}-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/actual/files/actual/templates/pvc.yaml b/roles/actual/files/actual/templates/pvc.yaml
new file mode 100644
index 0000000..71b9b85
--- /dev/null
+++ b/roles/actual/files/actual/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Chart.Name }}-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 2Gi
+ selector:
+ matchLabels:
+ app: "{{ .Chart.Name }}-pv"
diff --git a/roles/actual/files/actual/templates/service.yaml b/roles/actual/files/actual/templates/service.yaml
new file mode 100644
index 0000000..5d9b8bc
--- /dev/null
+++ b/roles/actual/files/actual/templates/service.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}-service
+spec:
+ type: ClusterIP
+ selector:
+ app: {{ .Chart.Name }}
+ ports:
+ - protocol: TCP
+ port: {{ .Values.port }}
+ targetPort: 5006
+ name: webui
+
diff --git a/roles/actual/tasks/main.yaml b/roles/actual/tasks/main.yaml
new file mode 100644
index 0000000..1733c68
--- /dev/null
+++ b/roles/actual/tasks/main.yaml
@@ -0,0 +1,17 @@
+---
+- name: Deploy Actual
+ kubernetes.core.helm:
+ name: actual
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/actual/files/actual"
+ namespace: default
+ state: "{%- if actual.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ replicas: "{{ actual.replicas}}"
+ port: "{{ actual.port }}"
+ image: "{{ actual.image }}"
+ version: "{{ actual.version }}"
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ nfs.path }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/archivebox/defaults/main.yaml b/roles/archivebox/defaults/main.yaml
new file mode 100644
index 0000000..0afc620
--- /dev/null
+++ b/roles/archivebox/defaults/main.yaml
@@ -0,0 +1,9 @@
+archivebox:
+ enabled: false
+ replicas: 1
+ port: 8000
+ image: archivebox/archivebox
+ version: 0.7
+
+nfs:
+ path: "/mnt/nfs/k3s/archivebox"
diff --git a/roles/archivebox/files/archivebox/.helmignore b/roles/archivebox/files/archivebox/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/roles/archivebox/files/archivebox/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/roles/archivebox/files/archivebox/Chart.yaml b/roles/archivebox/files/archivebox/Chart.yaml
new file mode 100644
index 0000000..40b00c9
--- /dev/null
+++ b/roles/archivebox/files/archivebox/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: archivebox
+description: Archival system
+type: application
+version: 0.1.0
diff --git a/roles/archivebox/files/archivebox/templates/deployment.yaml b/roles/archivebox/files/archivebox/templates/deployment.yaml
new file mode 100644
index 0000000..02a3bfb
--- /dev/null
+++ b/roles/archivebox/files/archivebox/templates/deployment.yaml
@@ -0,0 +1,45 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: archivebox
+ image: "{{ .Values.image }}:{{ .Values.version }}"
+ env:
+ - name: PUBLIC_INDEX
+ value: "False"
+ - name: PUBLIC_SNAPSHOTS
+ value: "False"
+ - name: PUID
+ value: "1000"
+ - name: PGID
+ value: "1000"
+ - name: SAVE_ARCHIVE_DOT_ORG
+ value: "False"
+ - name: SAVE_SCREENSHOT
+ value: "False"
+ - name: SAVE_DOM
+ value: "False"
+ - name: SAVE_SINGLEFILE
+ value: "False"
+
+ volumeMounts:
+ - mountPath: "/data"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: data
+ volumes:
+ - name: "{{ .Chart.Name }}-volume"
+ persistentVolumeClaim:
+ claimName: "{{ .Chart.Name }}-pvc"
diff --git a/roles/archivebox/files/archivebox/templates/ingress.yaml b/roles/archivebox/files/archivebox/templates/ingress.yaml
new file mode 100644
index 0000000..2601655
--- /dev/null
+++ b/roles/archivebox/files/archivebox/templates/ingress.yaml
@@ -0,0 +1,23 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: archivebox
+ annotations:
+ cert-manager.io/cluster-issuer: "ca-issuer"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - archive.home
+ secretName: archivebox-tls
+ rules:
+ - host: archive.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: archivebox-service
+ port:
+ number: 80
diff --git a/roles/archivebox/files/archivebox/templates/pv.yaml b/roles/archivebox/files/archivebox/templates/pv.yaml
new file mode 100644
index 0000000..869b121
--- /dev/null
+++ b/roles/archivebox/files/archivebox/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "{{ .Chart.Name }}-pv"
+ labels:
+ app: "{{ .Chart.Name }}-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 100Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/archivebox/files/archivebox/templates/pvc.yaml b/roles/archivebox/files/archivebox/templates/pvc.yaml
new file mode 100644
index 0000000..10a5ced
--- /dev/null
+++ b/roles/archivebox/files/archivebox/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Chart.Name }}-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 100Gi
+ selector:
+ matchLabels:
+ app: "{{ .Chart.Name }}-pv"
diff --git a/roles/archivebox/files/archivebox/templates/service.yaml b/roles/archivebox/files/archivebox/templates/service.yaml
new file mode 100644
index 0000000..bb8bcc2
--- /dev/null
+++ b/roles/archivebox/files/archivebox/templates/service.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}-service
+spec:
+ type: ClusterIP
+ selector:
+ app: {{ .Chart.Name }}
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 8000
+ name: webui
+
diff --git a/roles/archivebox/tasks/main.yaml b/roles/archivebox/tasks/main.yaml
new file mode 100644
index 0000000..a4abe9f
--- /dev/null
+++ b/roles/archivebox/tasks/main.yaml
@@ -0,0 +1,17 @@
+---
+- name: Deploy Archivebox
+ kubernetes.core.helm:
+ name: archivebox
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/archivebox/files/archivebox"
+ namespace: default
+ state: "{%- if archivebox.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ replicas: "{{ archivebox.replicas }}"
+ port: "{{ archivebox.port }}"
+ image: "{{ archivebox.image }}"
+ version: "{{ archivebox.version }}"
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ nfs.path }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/ca/files/ca.yaml b/roles/ca/files/ca.yaml
new file mode 100644
index 0000000..a77b415
--- /dev/null
+++ b/roles/ca/files/ca.yaml
@@ -0,0 +1,32 @@
+---
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: selfsigned-issuer
+spec:
+ selfSigned: {}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: selfsigned-ca
+ namespace: cert-manager
+spec:
+ isCA: true
+ commonName: selfsigned-ca
+ secretName: root-secret
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ issuerRef:
+ name: selfsigned-issuer
+ kind: ClusterIssuer
+ group: cert-manager.io
+---
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: ca-issuer
+spec:
+ ca:
+ secretName: root-secret
diff --git a/roles/ca/files/lets-encrypt-dev.yaml b/roles/ca/files/lets-encrypt-dev.yaml
new file mode 100644
index 0000000..e84120d
--- /dev/null
+++ b/roles/ca/files/lets-encrypt-dev.yaml
@@ -0,0 +1,18 @@
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ ingressClassName: traefik
diff --git a/roles/ca/files/lets-encrypt-prod.yaml b/roles/ca/files/lets-encrypt-prod.yaml
new file mode 100644
index 0000000..fb9b541
--- /dev/null
+++ b/roles/ca/files/lets-encrypt-prod.yaml
@@ -0,0 +1,18 @@
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-prod
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-prod
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ ingressClassName: traefik
diff --git a/roles/ca/tasks/main.yaml b/roles/ca/tasks/main.yaml
new file mode 100644
index 0000000..36b17e1
--- /dev/null
+++ b/roles/ca/tasks/main.yaml
@@ -0,0 +1,32 @@
+- name: Setup Cert-manager chart
+ kubernetes.core.helm_repository:
+ name: jetstack
+ repo_url: "https://charts.jetstack.io"
+
+- name: Deploy Cert manager
+ kubernetes.core.helm:
+ name: cert-manager
+ chart_ref: jetstack/cert-manager
+ release_namespace: cert-manager
+ create_namespace: true
+ set_values:
+ - value: installCRDs=true
+ value_type: string
+
+- name: Create CA
+ kubernetes.core.k8s:
+ state: "{%- if servers.ca.enabled -%} present {%- else -%} absent {%- endif -%}"
+ src: "{{ lookup('env', 'PWD') }}/roles/ca/files/ca.yaml"
+ namespace: cert-manager
+
+- name: Add Lets Encrypt Dev
+ kubernetes.core.k8s:
+ state: "{%- if roles/ca.ca.enabled -%} present {%- else -%} absent {%- endif -%}"
+ src: "{{ lookup('env', 'PWD') }}/roles/ca/files/lets-encrypt-dev.yaml"
+ namespace: cert-manager
+
+- name: Add Lets Encrypt Dev
+ kubernetes.core.k8s:
+ state: "{%- if roles/ca.ca.enabled -%} present {%- else -%} absent {%- endif -%}"
+ src: "{{ lookup('env', 'PWD') }}/roles/ca/files/lets-encrypt-prod.yaml"
+ namespace: cert-manager
diff --git a/roles/cgit/defaults/main.yaml b/roles/cgit/defaults/main.yaml
new file mode 100644
index 0000000..727c4a9
--- /dev/null
+++ b/roles/cgit/defaults/main.yaml
@@ -0,0 +1,12 @@
+cgit:
+ enabled: false
+ replicas: 1
+ port: 80
+ image: aadityadhruv/cgit
+ version: latest
+softserve:
+ image: charmcli/soft-serve
+ version: v0.8.5
+
+nfs:
+ path: "/mnt/nfs/k3s/cgit"
diff --git a/roles/cgit/files/cgit/Chart.yaml b/roles/cgit/files/cgit/Chart.yaml
new file mode 100644
index 0000000..a5722d5
--- /dev/null
+++ b/roles/cgit/files/cgit/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: cgit
+description: Subsonic compatible music server
+type: application
+version: 0.1.0
diff --git a/roles/cgit/files/cgit/templates/configmap.yaml b/roles/cgit/files/cgit/templates/configmap.yaml
new file mode 100644
index 0000000..e64de68
--- /dev/null
+++ b/roles/cgit/files/cgit/templates/configmap.yaml
@@ -0,0 +1,31 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ .Chart.Name }}-config
+data:
+ cgitrc: |
+ cache-size=1000
+ #css=/cgit.css
+ enable-http-clone=1
+ enable-blame=1
+ enable-commit-graph=1
+ enable-log-filecount=1
+ enable-log-linecount=1
+ enable-git-config=1
+ head-include=/usr/share/cgit/theme.html
+ enable-index-owner=0
+ favicon=/favicon.ico
+ logo=/cgit.png
+ root-title=Space Junk
+ mimetype.gif=image/gif
+ mimetype.html=text/html
+ mimetype.jpg=image/jpeg
+ mimetype.jpeg=image/jpeg
+ mimetype.pdf=application/pdf
+ mimetype.png=image/png
+ mimetype.svg=image/svg+xml
+ source-filter=/usr/lib/cgit/syntax-highlighting.py
+ readme=:README.md
+ robots=noindex, nofollow
+ scan-path=/srv/git/
+
diff --git a/roles/cgit/files/cgit/templates/deployment.yaml b/roles/cgit/files/cgit/templates/deployment.yaml
new file mode 100644
index 0000000..6ad9c6e
--- /dev/null
+++ b/roles/cgit/files/cgit/templates/deployment.yaml
@@ -0,0 +1,38 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: cgit
+ image: "{{ .Values.cgit.image }}:{{ .Values.cgit.version }}"
+ volumeMounts:
+ - mountPath: "/etc/cgitrc"
+ name: "config"
+ subPath: cgitrc
+ - mountPath: "/srv/git"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: repos
+ - name: soft-serve
+ image: "{{ .Values.softserve.image }}:{{ .Values.softserve.version }}"
+ volumeMounts:
+ - mountPath: "/soft-serve"
+ name: "{{ .Chart.Name }}-volume"
+ volumes:
+ - name: "config"
+ configMap:
+ name: "{{ .Chart.Name }}-config"
+ - name: "{{ .Chart.Name }}-volume"
+ persistentVolumeClaim:
+ claimName: "{{ .Chart.Name }}-pvc"
diff --git a/roles/cgit/files/cgit/templates/ingress.yaml b/roles/cgit/files/cgit/templates/ingress.yaml
new file mode 100644
index 0000000..2b33366
--- /dev/null
+++ b/roles/cgit/files/cgit/templates/ingress.yaml
@@ -0,0 +1,47 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: cgit-le
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - git.aadityadhruv.com
+ secretName: cgit-tls-le
+ rules:
+ - host: git.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: cgit-service
+ port:
+ number: 80
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: cgit-ca
+ annotations:
+ cert-manager.io/cluster-issuer: "ca-issuer"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - git.home
+ secretName: cgit-tls-ca
+ rules:
+ - host: git.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: cgit-service
+ port:
+ number: 80
diff --git a/roles/cgit/files/cgit/templates/pv.yaml b/roles/cgit/files/cgit/templates/pv.yaml
new file mode 100644
index 0000000..f62ea30
--- /dev/null
+++ b/roles/cgit/files/cgit/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "{{ .Chart.Name }}-pv"
+ labels:
+ app: "{{ .Chart.Name }}-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 20Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/cgit/files/cgit/templates/pvc.yaml b/roles/cgit/files/cgit/templates/pvc.yaml
new file mode 100644
index 0000000..e6153d1
--- /dev/null
+++ b/roles/cgit/files/cgit/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Chart.Name }}-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 20Gi
+ selector:
+ matchLabels:
+ app: "{{ .Chart.Name }}-pv"
diff --git a/roles/cgit/files/cgit/templates/service.yaml b/roles/cgit/files/cgit/templates/service.yaml
new file mode 100644
index 0000000..945bac0
--- /dev/null
+++ b/roles/cgit/files/cgit/templates/service.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}-service
+spec:
+ type: LoadBalancer
+ selector:
+ app: {{ .Chart.Name }}
+ ports:
+ - protocol: TCP
+ targetPort: 23231
+ port: 22
+ name: ssh
+ - protocol: TCP
+ port: 81
+ targetPort: 23232
+ name: http
+ - protocol: TCP
+ port: {{ .Values.port }}
+ targetPort: 80
+ name: webui
diff --git a/roles/cgit/files/image/Caddyfile b/roles/cgit/files/image/Caddyfile
new file mode 100644
index 0000000..35a29b8
--- /dev/null
+++ b/roles/cgit/files/image/Caddyfile
@@ -0,0 +1,13 @@
+:80 {
+ @assets path /cgit.css /cgit.png /favicon.ico /theme.css /theme.html
+ handle @assets {
+ root * /usr/share/cgit
+ file_server
+ }
+
+ reverse_proxy unix//run/fcgiwrap.socket {
+ transport fastcgi {
+ env SCRIPT_FILENAME /var/www/cgi-bin/cgit
+ }
+ }
+}
diff --git a/roles/cgit/files/image/Dockerfile b/roles/cgit/files/image/Dockerfile
new file mode 100644
index 0000000..894e68a
--- /dev/null
+++ b/roles/cgit/files/image/Dockerfile
@@ -0,0 +1,12 @@
+FROM docker.io/fedora:41
+
+RUN dnf install cgit caddy fcgiwrap openssh-server python3-pygments -y
+COPY Caddyfile /etc/caddy/Caddyfile
+COPY start.sh start.sh
+RUN mkdir /usr/lib/cgit -p
+COPY theme.css /usr/share/cgit/theme.css
+COPY theme.html /usr/share/cgit/theme.html
+COPY syntax-highlighting.py /usr/lib/cgit/syntax-highlighting.py
+RUN chmod 777 /usr/lib/cgit/syntax-highlighting.py
+RUN adduser -m git
+CMD ["./start.sh"]
diff --git a/roles/cgit/files/image/start.sh b/roles/cgit/files/image/start.sh
new file mode 100755
index 0000000..96a279b
--- /dev/null
+++ b/roles/cgit/files/image/start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+/usr/sbin/fcgiwrap -s unix:/run/fcgiwrap.socket &
+caddy run --config /etc/caddy/Caddyfile
+
diff --git a/roles/cgit/files/image/syntax-highlighting.py b/roles/cgit/files/image/syntax-highlighting.py
new file mode 100644
index 0000000..e912594
--- /dev/null
+++ b/roles/cgit/files/image/syntax-highlighting.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+
+# This script uses Pygments and Python3. You must have both installed
+# for this to work.
+#
+# http://pygments.org/
+# http://python.org/
+#
+# It may be used with the source-filter or repo.source-filter settings
+# in cgitrc.
+#
+# The following environment variables can be used to retrieve the
+# configuration of the repository for which this script is called:
+# CGIT_REPO_URL ( = repo.url setting )
+# CGIT_REPO_NAME ( = repo.name setting )
+# CGIT_REPO_PATH ( = repo.path setting )
+# CGIT_REPO_OWNER ( = repo.owner setting )
+# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
+# CGIT_REPO_SECTION ( = section setting )
+# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
+
+
+import sys
+import io
+from pygments import highlight
+from pygments.util import ClassNotFound
+from pygments.lexers import TextLexer
+from pygments.lexers import guess_lexer
+from pygments.lexers import guess_lexer_for_filename
+from pygments.formatters import HtmlFormatter
+
+
+sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8', errors='replace')
+sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
+data = sys.stdin.read()
+filename = sys.argv[1]
+formatter = HtmlFormatter(style='pastie', nobackground=True)
+
+try:
+ lexer = guess_lexer_for_filename(filename, data)
+except ClassNotFound:
+ # check if there is any shebang
+ if data[0:2] == '#!':
+ lexer = guess_lexer(data)
+ else:
+ lexer = TextLexer()
+except TypeError:
+ lexer = TextLexer()
+
+# highlight! :-)
+# printout pygments' css definitions as well
+sys.stdout.write('<style>')
+sys.stdout.write(formatter.get_style_defs('.highlight'))
+sys.stdout.write('</style>')
+sys.stdout.write(highlight(data, lexer, formatter, outfile=None))
diff --git a/roles/cgit/files/image/theme.css b/roles/cgit/files/image/theme.css
new file mode 100644
index 0000000..54357b1
--- /dev/null
+++ b/roles/cgit/files/image/theme.css
@@ -0,0 +1,172 @@
+:root {
+ --bg_h: #1d2021;
+ --bg: #282828;
+ --bg_s: #32302f;
+ --bg1: #3c3836;
+ --bg2: #504945;
+ --bg3: #665c54;
+ --bg4: #7c6f64;
+
+ --fg: #fbf1c7;
+ --fg1: #ebdbb2;
+ --fg2: #d5c4a1;
+ --fg3: #bdae93;
+ --fg4: #a89984;
+
+ --red: #fb4934;
+ --green: #b8bb26;
+ --yellow: #fabd2f;
+ --blue: #83a598;
+ --purple: #d3869b;
+ --aqua: #8ec07c;
+ --gray: #928374;
+ --orange: #fe8019;
+
+ --red-dim: #cc2412;
+ --green-dim: #98971a;
+ --yellow-dim: #d79921;
+ --blue-dim: #458588;
+ --purple-dim: #b16286;
+ --aqua-dim: #689d6a;
+ --gray-dim: #a89984;
+ --orange-dim: #d65d0e;
+}
+
+body, #cgit, .path, div#cgit table.blob td.hashes,
+div#cgit table.blob td.lines, div#cgit div.cgit-panel table,
+div#cgit table.diffstat {
+ background: var(--bg) !important;
+ color: var(--fg) !important;
+ border: none
+}
+
+a {
+ color: var(--fg) !important;
+ text-decoration: underline !important;
+}
+
+select, input {
+ border: none;
+ background: var(--bg2);
+ color: var(--fg);
+}
+
+/**************/
+/*** TABLES ***/
+/**************/
+div#cgit table.tabs td a.active {
+ background: var(--bg) !important;
+ color: var(--yellow) !important;
+}
+
+div#cgit table.tabs, div#cgit div.content,
+div#cgit table#header td.sub {
+ border: none;
+}
+
+div#cgit table.list tr.nohover,
+div#cgit table.list tr:nth-child(2n) {
+ background: var(--bg) !important;
+}
+
+div#cgit table.list tr:nth-child(2n+1) {
+ background: var(--bg_s) !important;
+}
+
+div#cgit table.list tr:hover:not(.nohover) {
+ background: var(--bg1) !important;
+}
+
+/************/
+/*** CODE ***/
+/************/
+div#cgit table.blob td.linenumbers,
+div#cgit table.blob {
+ border-color: var(--gray);
+}
+
+div#cgit table.blob td.linenumbers a {
+ color: var(--gray) !important;
+ text-decoration: none !important;
+}
+
+.markdown-body code, .markdown-body tt,
+.markdown-body .highlight pre, .markdown-body pre {
+ background: var(--bg1) !important;
+}
+
+/************/
+/*** AGES ***/
+/************/
+.age-hours {
+ color: var(--aqua) !important;
+}
+
+.age-days {
+ color: var(--aqua-dim) !important;
+}
+
+.age-weeks {
+ color: var(--fg) !important;
+}
+
+.age-months {
+ color: var(--fg2) !important;
+}
+
+.age-years {
+ color: var(--fg4) !important;
+}
+
+/******************/
+/*** DECORATORS ***/
+/******************/
+div#cgit a.branch-deco {
+ background: var(--aqua);
+ border: none;
+ color: var(--bg) !important;
+}
+
+div#cgit a.deco {
+ background: var(--yellow);
+ border: none;
+ color: var(--bg) !important;
+}
+
+div#cgit a.tag-deco {
+ background: var(--gray);
+ border: none;
+ color: var(--bg) !important;
+}
+
+/************/
+/*** DIFF ***/
+/************/
+div#cgit table.diff td div.hunk {
+ color: var(--blue);
+}
+
+div#cgit table.diff td div.del {
+ color: var(--red);
+}
+
+div#cgit table.diff td div.add {
+ color: var(--green);
+}
+
+div#cgit table.diff td div.ctx {
+ color: var(--gray);
+}
+
+div#cgit table.diff td div.head {
+ color: var(--fg);
+}
+
+div#cgit table.diffstat td.graph td.add {
+ background: var(--green);
+}
+
+div#cgit table.diffstat td.graph td.rem {
+ background: var(--red);
+}
+
diff --git a/roles/cgit/files/image/theme.html b/roles/cgit/files/image/theme.html
new file mode 100644
index 0000000..f95b5d1
--- /dev/null
+++ b/roles/cgit/files/image/theme.html
@@ -0,0 +1 @@
+<link rel="stylesheet" type="text/css" href="/theme.css">
diff --git a/roles/cgit/tasks/main.yaml b/roles/cgit/tasks/main.yaml
new file mode 100644
index 0000000..0a99ce3
--- /dev/null
+++ b/roles/cgit/tasks/main.yaml
@@ -0,0 +1,21 @@
+---
+- name: Deploy cgit
+ kubernetes.core.helm:
+ name: cgit
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/cgit/files/cgit"
+ namespace: default
+ state: "{%- if cgit.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ replicas: "{{ cgit.replicas }}"
+ port: "{{ cgit.port }}"
+ cgit:
+ image: "{{ cgit.image }}"
+ version: "{{ cgit.version }}"
+ softserve:
+ image: "{{ softserve.image }}"
+ version: "{{ softserve.version }}"
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ nfs.path }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/cloud/defaults/main.yaml b/roles/cloud/defaults/main.yaml
new file mode 100644
index 0000000..23f8615
--- /dev/null
+++ b/roles/cloud/defaults/main.yaml
@@ -0,0 +1,6 @@
+cloud:
+ version: v2.26.0
+ replicas: 1
+ enabled: false
+ port: 80
+ path: "/mnt/nfs/k3s/cloud/"
diff --git a/roles/cloud/files/cloud/Chart.yaml b/roles/cloud/files/cloud/Chart.yaml
new file mode 100644
index 0000000..0665bb9
--- /dev/null
+++ b/roles/cloud/files/cloud/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: cloud
+description: Filebrowser for Files
+type: application
+
+version: 0.1.0
diff --git a/roles/cloud/files/cloud/templates/cloud.yaml b/roles/cloud/files/cloud/templates/cloud.yaml
new file mode 100644
index 0000000..d688901
--- /dev/null
+++ b/roles/cloud/files/cloud/templates/cloud.yaml
@@ -0,0 +1,40 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: filebrowser
+ image: "{{ .Values.image }}:{{ .Values.version }}"
+ ports:
+ - name: http
+ containerPort: 80
+ volumeMounts:
+ - mountPath: "/Drive"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: "Drive"
+ - mountPath: "/database.db"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: "db/database.db"
+ - mountPath: "/.filebrowser.json"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: "config/filebrowser.json"
+ volumes:
+ - name: "{{ .Chart.Name }}-volume"
+ persistentVolumeClaim:
+ claimName: {{ .Chart.Name }}-pvc
+# securityContext:
+# runAsUser: 1001
+# runAsGroup: 1001
+# fsGroup: 1001
diff --git a/roles/cloud/files/cloud/templates/ingress.yaml b/roles/cloud/files/cloud/templates/ingress.yaml
new file mode 100644
index 0000000..22f55b1
--- /dev/null
+++ b/roles/cloud/files/cloud/templates/ingress.yaml
@@ -0,0 +1,33 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: cloud
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - drive.aadityadhruv.com
+ secretName: cloud-tls
+ rules:
+ - host: drive.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: cloud-service
+ port:
+ number: 80
+ - host: drive.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: cloud-service
+ port:
+ number: 80
diff --git a/roles/cloud/files/cloud/templates/pv.yaml b/roles/cloud/files/cloud/templates/pv.yaml
new file mode 100644
index 0000000..21b3611
--- /dev/null
+++ b/roles/cloud/files/cloud/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: {{ .Chart.Name }}-pv
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 16Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/cloud/files/cloud/templates/pvc.yaml b/roles/cloud/files/cloud/templates/pvc.yaml
new file mode 100644
index 0000000..1324417
--- /dev/null
+++ b/roles/cloud/files/cloud/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Chart.Name }}-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 16Gi
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
diff --git a/roles/cloud/files/cloud/templates/service.yaml b/roles/cloud/files/cloud/templates/service.yaml
new file mode 100644
index 0000000..c412876
--- /dev/null
+++ b/roles/cloud/files/cloud/templates/service.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}-service
+spec:
+ type: ClusterIP
+ selector:
+ app: {{ .Chart.Name }}
+ ports:
+ - protocol: TCP
+ port: {{ .Values.port }}
+ targetPort: http
+ name: webui
diff --git a/roles/cloud/tasks/main.yaml b/roles/cloud/tasks/main.yaml
new file mode 100644
index 0000000..4a3a168
--- /dev/null
+++ b/roles/cloud/tasks/main.yaml
@@ -0,0 +1,17 @@
+---
+- name: Deploy Cloud
+ kubernetes.core.helm:
+ name: cloud
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/cloud/files/cloud"
+ namespace: default
+ state: "{%- if cloud.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ image: filebrowser/filebrowser
+ replicas: "{{ cloud.replicas }}"
+ version: "{{ cloud.version }}"
+ port: "{{ cloud.port }}"
+ nfs:
+ path: "{{ cloud.path }}"
+ server: "{{ nfs.server }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/fishnet/defaults/main.yaml b/roles/fishnet/defaults/main.yaml
new file mode 100644
index 0000000..fa99b84
--- /dev/null
+++ b/roles/fishnet/defaults/main.yaml
@@ -0,0 +1,3 @@
+fishnet:
+ enabled: false
+ replicas: 1
diff --git a/roles/fishnet/files/fishnet/Chart.yaml b/roles/fishnet/files/fishnet/Chart.yaml
new file mode 100644
index 0000000..5c0e9f8
--- /dev/null
+++ b/roles/fishnet/files/fishnet/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: fishnet
+description: Distributed analysis for lichess
+type: application
+
+version: 0.1.0
diff --git a/roles/fishnet/files/fishnet/templates/deployment.yaml b/roles/fishnet/files/fishnet/templates/deployment.yaml
new file mode 100644
index 0000000..4cdc4b4
--- /dev/null
+++ b/roles/fishnet/files/fishnet/templates/deployment.yaml
@@ -0,0 +1,32 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: fishnet
+ image: niklasf/fishnet:2
+ imagePullPolicy: Always
+ env:
+ # - name: CORES
+ # valueFrom:
+ # configMapKeyRef:
+ # name: fishnet-config
+ # key: cores
+ - name: KEY
+ valueFrom:
+ secretKeyRef:
+ name: lichess
+ key: fishnet-private-key
+ restartPolicy: Always
diff --git a/roles/fishnet/tasks/main.yaml b/roles/fishnet/tasks/main.yaml
new file mode 100644
index 0000000..57e8b7e
--- /dev/null
+++ b/roles/fishnet/tasks/main.yaml
@@ -0,0 +1,12 @@
+---
+- name: Deploy Fishnet
+ kubernetes.core.helm:
+ name: fishnet
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/fishnet/files/fishnet"
+ namespace: default
+ state: "{%- if fishnet.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ replicas: "{{ fishnet.replicas }}"
+ key: "{{ fishnet.key }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/gonic/defaults/main.yaml b/roles/gonic/defaults/main.yaml
new file mode 100644
index 0000000..d0e845c
--- /dev/null
+++ b/roles/gonic/defaults/main.yaml
@@ -0,0 +1,9 @@
+gonic:
+ enabled: false
+ replicas: 1
+ port: 80
+ image: sentriz/gonic
+ version: v0.16.4
+
+nfs:
+ path: "/mnt/nfs/k3s/gonic"
diff --git a/roles/gonic/files/gonic/.helmignore b/roles/gonic/files/gonic/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/roles/gonic/files/gonic/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/roles/gonic/files/gonic/Chart.yaml b/roles/gonic/files/gonic/Chart.yaml
new file mode 100644
index 0000000..2bdf9fd
--- /dev/null
+++ b/roles/gonic/files/gonic/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: gonic
+description: Subsonic compatible music server
+type: application
+version: 0.1.0
diff --git a/roles/gonic/files/gonic/templates/deployment.yaml b/roles/gonic/files/gonic/templates/deployment.yaml
new file mode 100644
index 0000000..0b1ed08
--- /dev/null
+++ b/roles/gonic/files/gonic/templates/deployment.yaml
@@ -0,0 +1,33 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: gonic
+ image: "{{ .Values.image }}:{{ .Values.version }}"
+ volumeMounts:
+ - mountPath: "/data"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: data
+ - mountPath: "/music"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: music
+ - mountPath: "/playlists"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: playlists
+ volumes:
+ - name: "{{ .Chart.Name }}-volume"
+ persistentVolumeClaim:
+ claimName: "{{ .Chart.Name }}-pvc"
diff --git a/roles/gonic/files/gonic/templates/ingress.yaml b/roles/gonic/files/gonic/templates/ingress.yaml
new file mode 100644
index 0000000..aa6a0bd
--- /dev/null
+++ b/roles/gonic/files/gonic/templates/ingress.yaml
@@ -0,0 +1,34 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: gonic
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - music.aadityadhruv.com
+ - music.home
+ secretName: gonic-tls
+ rules:
+ - host: music.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: gonic-service
+ port:
+ number: 80
+ - host: music.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: gonic-service
+ port:
+ number: 80
diff --git a/roles/gonic/files/gonic/templates/pv.yaml b/roles/gonic/files/gonic/templates/pv.yaml
new file mode 100644
index 0000000..869b121
--- /dev/null
+++ b/roles/gonic/files/gonic/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "{{ .Chart.Name }}-pv"
+ labels:
+ app: "{{ .Chart.Name }}-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 100Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/gonic/files/gonic/templates/pvc.yaml b/roles/gonic/files/gonic/templates/pvc.yaml
new file mode 100644
index 0000000..10a5ced
--- /dev/null
+++ b/roles/gonic/files/gonic/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Chart.Name }}-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 100Gi
+ selector:
+ matchLabels:
+ app: "{{ .Chart.Name }}-pv"
diff --git a/roles/gonic/files/gonic/templates/service.yaml b/roles/gonic/files/gonic/templates/service.yaml
new file mode 100644
index 0000000..a9c272f
--- /dev/null
+++ b/roles/gonic/files/gonic/templates/service.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}-service
+spec:
+ type: ClusterIP
+ selector:
+ app: {{ .Chart.Name }}
+ ports:
+ - protocol: TCP
+ port: {{ .Values.port }}
+ targetPort: 80
+ name: webui
+
diff --git a/roles/gonic/tasks/main.yaml b/roles/gonic/tasks/main.yaml
new file mode 100644
index 0000000..1d2daa6
--- /dev/null
+++ b/roles/gonic/tasks/main.yaml
@@ -0,0 +1,17 @@
+---
+- name: Deploy Gonic
+ kubernetes.core.helm:
+ name: gonic
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/gonic/files/gonic"
+ namespace: default
+ state: "{%- if gonic.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ replicas: "{{ gonic.replicas }}"
+ port: "{{ gonic.port }}"
+ image: "{{ gonic.image }}"
+ version: "{{ gonic.version }}"
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ nfs.path }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/jellyfin/defaults/main.yaml b/roles/jellyfin/defaults/main.yaml
new file mode 100644
index 0000000..47cfbc7
--- /dev/null
+++ b/roles/jellyfin/defaults/main.yaml
@@ -0,0 +1,5 @@
+jellyfin:
+ enabled: false
+ port: 8096
+ version: 10.10.0
+ replicas: 1
diff --git a/roles/jellyfin/files/jellyfin/ingress.yaml b/roles/jellyfin/files/jellyfin/ingress.yaml
new file mode 100644
index 0000000..ab148ba
--- /dev/null
+++ b/roles/jellyfin/files/jellyfin/ingress.yaml
@@ -0,0 +1,33 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: jellyfin
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - media.aadityadhruv.com
+ secretName: jellyfin-tls
+ rules:
+ - host: media.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: jellyfin
+ port:
+ number: 8096
+ - host: media.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: jellyfin
+ port:
+ number: 8096
diff --git a/roles/jellyfin/files/jellyfin/pv.yaml b/roles/jellyfin/files/jellyfin/pv.yaml
new file mode 100644
index 0000000..6c7fcb9
--- /dev/null
+++ b/roles/jellyfin/files/jellyfin/pv.yaml
@@ -0,0 +1,34 @@
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: jellyfin-config
+ labels:
+ app: jellyfin-config
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: 192.168.20.5
+ path: /mnt/nfs/k3s/jellyfin/config
+ readOnly: false
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: jellyfin-data
+ labels:
+ app: jellyfin-data
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 100Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: 192.168.20.5
+ path: /mnt/nfs/k3s/jellyfin/data
+ readOnly: false
diff --git a/roles/jellyfin/files/jellyfin/pvc.yaml b/roles/jellyfin/files/jellyfin/pvc.yaml
new file mode 100644
index 0000000..47360a9
--- /dev/null
+++ b/roles/jellyfin/files/jellyfin/pvc.yaml
@@ -0,0 +1,30 @@
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: jellyfin-config-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 2Gi
+ selector:
+ matchLabels:
+ app: jellyfin-config
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: jellyfin-data-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 100Gi
+ selector:
+ matchLabels:
+ app: jellyfin-data
diff --git a/roles/jellyfin/tasks/main.yaml b/roles/jellyfin/tasks/main.yaml
new file mode 100644
index 0000000..c5f471f
--- /dev/null
+++ b/roles/jellyfin/tasks/main.yaml
@@ -0,0 +1,68 @@
+- name: Add Jellyfin remote chart
+ kubernetes.core.helm_repository:
+ name: jellyfin
+ repo_url: https://utkuozdemir.org/helm-charts
+ delegate_to: localhost
+ run_once: true
+
+- name: Create Jellyfin PVs
+ kubernetes.core.k8s:
+ state: "{%- if jellyfin.enabled -%} present {%- else -%} absent {%- endif -%}"
+ src: "{{ lookup('env', 'PWD') }}/roles/jellyfin/files/jellyfin/pv.yaml"
+ namespace: default
+ delegate_to: localhost
+ run_once: true
+- name: Create Jellyfin PVCs
+ kubernetes.core.k8s:
+ state: "{%- if jellyfin.enabled -%} present {%- else -%} absent {%- endif -%}"
+ src: "{{ lookup('env', 'PWD') }}/roles/jellyfin/files/jellyfin/pvc.yaml"
+ namespace: default
+ delegate_to: localhost
+ run_once: true
+- name: Create Jellyfin Ingress
+ kubernetes.core.k8s:
+ state: "{%- if jellyfin.enabled -%} present {%- else -%} absent {%- endif -%}"
+ src: "{{ lookup('env', 'PWD') }}/roles/jellyfin/files/jellyfin/ingress.yaml"
+ namespace: default
+ delegate_to: localhost
+ run_once: true
+
+- name: Get Values Path
+ set_fact:
+ jellyfin_values_path: "{{ lookup('env', 'PWD') }}/roles/jellyfin/files/jellyfin/values.yaml"
+ delegate_to: localhost
+ run_once: true
+
+- name: Get Values
+ set_fact:
+ jellyfin_defaults: "{{ lookup('file', jellyfin_values_path) | from_yaml }}"
+ delegate_to: localhost
+ run_once: true
+
+
+- name: Set User overrides fact
+ set_fact:
+ overrides:
+ port: "{{ jellyfin.port }}"
+ replicaCount: "{{ jellyfin.replicas }}"
+ image:
+ tag: "{{ jellyfin.version }}"
+
+- name: Merge Values with overrides
+ set_fact:
+ jellyfin_values: "{{ jellyfin_defaults | combine(overrides, recursive=True) }}"
+ delegate_to: localhost
+ run_once: true
+
+- debug:
+ var: jellyfin_values
+
+- name: Deploy Jellyfin
+ kubernetes.core.helm:
+ name: jellyfin
+ chart_ref: jellyfin/jellyfin
+ values: "{{ jellyfin_values }}"
+ namespace: default
+ state: "{%- if jellyfin.enabled -%} present {%- else -%} absent {%- endif -%}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/k3s/tasks/main.yaml b/roles/k3s/tasks/main.yaml
new file mode 100644
index 0000000..dd8f25f
--- /dev/null
+++ b/roles/k3s/tasks/main.yaml
@@ -0,0 +1,34 @@
+---
+- name: Setup K3S Master Node
+ ansible.builtin.shell: "curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='server' sh -s - --token {{ servers.k3s.token }} --disable servicelb"
+ when: inventory_hostname in groups['k3s-master']
+ become: true
+
+- name: Setup K3S Agent Nodes
+ shell: "curl -sfL https://get.k3s.io | K3S_URL=https://{{ hostvars[groups['k3s-master'][0]]['ansible_default_ipv4']['address'] }}:6443 sh -s - agent --token {{ servers.k3s.token }} --disable servicelb"
+ when: inventory_hostname in groups['k3s-agent']
+ become: true
+
+- name: Change perms for k3s.yaml
+ file:
+ path: "/etc/rancher/k3s/k3s.yaml"
+ mode: "0755"
+ become: true
+ when: inventory_hostname in groups['k3s-master']
+
+
+- name: copy file over to localhost
+ ansible.builtin.fetch:
+ src: /etc/rancher/k3s/k3s.yaml
+ dest: /home/aaditya/.kube/config
+ flat: yes
+ when: inventory_hostname in groups['k3s-master']
+
+- name: Update IP address of k3s-master in local kube config
+ ansible.builtin.replace:
+ path: /home/aaditya/.kube/config
+ regexp: "127.0.0.1"
+ replace: "{{ hostvars[groups['k3s-master'][0]]['ansible_default_ipv4']['address'] }}"
+ delegate_to: localhost
+ run_once: true
+
diff --git a/roles/metallb/defaults/main.yaml b/roles/metallb/defaults/main.yaml
new file mode 100644
index 0000000..43916f8
--- /dev/null
+++ b/roles/metallb/defaults/main.yaml
@@ -0,0 +1,3 @@
+metallb:
+ enabled: false
+ pool: 192.168.20.100-192.168.20.250
diff --git a/roles/metallb/tasks/main.yaml b/roles/metallb/tasks/main.yaml
new file mode 100644
index 0000000..b484411
--- /dev/null
+++ b/roles/metallb/tasks/main.yaml
@@ -0,0 +1,36 @@
+---
+- name: Create IPAddressPool
+ kubernetes.core.k8s:
+ state: "{{ 'present' if metallb.enabled else 'absent' }}"
+ definition:
+ apiVersion: metallb.io/v1beta1
+ kind: IPAddressPool
+ metadata:
+ name: pool
+ namespace: default
+ spec:
+ addresses:
+ - "{{ metallb.pool }}"
+ delegate_to: localhost
+ run_once: true
+
+- name: Create L2Advertisement
+ kubernetes.core.k8s:
+ state: "{{ 'present' if metallb.enabled else 'absent' }}"
+ definition:
+ apiVersion: metallb.io/v1beta1
+ kind: L2Advertisement
+ metadata:
+ name: metallb
+ namespace: default
+ spec:
+ ipAddressPools:
+ - pool
+ nodeSelectors:
+ - matchLabels:
+ kubernetes.io/hostname: regirock
+ - matchLabels:
+ kubernetes.io/hostname: regice
+
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/monitoring/tasks/main.yaml b/roles/monitoring/tasks/main.yaml
new file mode 100644
index 0000000..27bec57
--- /dev/null
+++ b/roles/monitoring/tasks/main.yaml
@@ -0,0 +1,17 @@
+---
+- name: Add Prometheus remote chart
+ kubernetes.core.helm_repository:
+ name: prometheus
+ repo_url: https://prometheus-community.github.io/helm-charts
+ delegate_to: localhost
+ run_once: true
+
+- name: Deploy prometheus
+ kubernetes.core.helm:
+ name: prometheus
+ chart_ref: prometheus/prometheus
+ namespace: default
+ state: "{%- if monitoring.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/network/defaults/main.yaml b/roles/network/defaults/main.yaml
new file mode 100644
index 0000000..44350c4
--- /dev/null
+++ b/roles/network/defaults/main.yaml
@@ -0,0 +1,2 @@
+network:
+ gateway: 192.168.1.1
diff --git a/roles/network/tasks/dns.yaml b/roles/network/tasks/dns.yaml
new file mode 100644
index 0000000..f80ec45
--- /dev/null
+++ b/roles/network/tasks/dns.yaml
@@ -0,0 +1,14 @@
+---
+- name: Ensure NetworkManager is installed
+ dnf:
+ name: NetworkManager
+ state: latest
+
+ become: true
+- name: Set DNS to Router
+ community.general.nmcli:
+ conn_name: "{{ ansible_default_ipv4.interface }}"
+ state: present
+ dns4:
+ - "{{ network.gateway }}"
+ become: true
diff --git a/roles/network/tasks/main.yaml b/roles/network/tasks/main.yaml
new file mode 100644
index 0000000..626197b
--- /dev/null
+++ b/roles/network/tasks/main.yaml
@@ -0,0 +1,11 @@
+- name: Setup VLANs
+ import_tasks: vlans.yaml
+ when: inventory_hostname in groups["router"] and network.router.enabled
+
+- name: Setup DNS
+ import_tasks: dns.yaml
+ when: inventory_hostname in groups["servers"]
+
+- name: Misc Print
+ import_tasks: misc.yaml
+
diff --git a/roles/network/tasks/misc.yaml b/roles/network/tasks/misc.yaml
new file mode 100644
index 0000000..bf9cb47
--- /dev/null
+++ b/roles/network/tasks/misc.yaml
@@ -0,0 +1,12 @@
+- name: Print Tomato Setup
+ debug:
+ msg: "To complete the rest of the setup, setup the upstream DNS on the router. Also disable DNS rebind protection. Don't forget to add the bridges to the router's DNSMASQ configuration in the form interface=brXX
+ Setup the following iptables on altaria:\n
+ -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
+-A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.2
+-A PREROUTING -d 137.184.95.59/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
+-A PREROUTING -d 137.184.95.59/32 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.2
+-A PREROUTING -d 137.184.95.59/32 -p tcp -m tcp --dport 2222 -j DNAT --to-destination 10.0.0.2:30022
+"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/network/tasks/vlans.yaml b/roles/network/tasks/vlans.yaml
new file mode 100644
index 0000000..f71d1e4
--- /dev/null
+++ b/roles/network/tasks/vlans.yaml
@@ -0,0 +1,39 @@
+- name: Add VLAN configuration
+ ansible.builtin.raw: "robocfg vlan {{ item }} ports '1t 5t'"
+ loop: "{{ network.vlans }}"
+
+- name: Bind VLANs to eth0
+ ansible.builtin.raw: "vconfig add eth0 {{ item }}"
+ loop: "{{ network.vlans }}"
+ ignore_errors: true
+
+- name: Bring VLANs up
+ ansible.builtin.raw: "ip link set dev vlan{{ item }} up"
+ loop: "{{ network.vlans }}"
+
+- name: Create bridges
+ ansible.builtin.raw: "brctl addbr br{{ item }}"
+ loop: "{{ network.vlans }}"
+ ignore_errors: true
+
+- name: Add vlans to bridges
+ ansible.builtin.raw: "brctl addif br{{ item }} vlan{{ item }}"
+ loop: "{{ network.vlans }}"
+ ignore_errors: true
+
+- name: Setup IP Ranges for VLANs
+ ansible.builtin.raw: "ip addr add 192.168.{{ item }}.1/24 dev br{{ item }}"
+ loop: "{{ network.vlans }}"
+ ignore_errors: true
+
+- name: Bring bridges up
+ ansible.builtin.raw: "ip link set dev br{{ item }} up"
+ loop: "{{ network.vlans }}"
+
+- name: Allow INPUT from bridges #This allows packets to reach the router
+ ansible.builtin.raw: "iptables -A INPUT -i br{{ item }} -j ACCEPT"
+ loop: "{{ network.vlans }}"
+
+- name: Allow INPUT from bridges #This allows packets to be forwarded to other interfaces
+ ansible.builtin.raw: "iptables -A FORWARD -i br{{ item }} -j ACCEPT"
+ loop: "{{ network.vlans }}"
diff --git a/roles/network/tasks/vps.yaml b/roles/network/tasks/vps.yaml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/roles/network/tasks/vps.yaml
diff --git a/roles/photos/defaults/main.yaml b/roles/photos/defaults/main.yaml
new file mode 100644
index 0000000..5c85766
--- /dev/null
+++ b/roles/photos/defaults/main.yaml
@@ -0,0 +1,9 @@
+immich:
+ version: v1.119.0
+ postgres:
+ image: tensorchord/pgvecto-rs
+ user: postgres
+ nfs:
+ path: /mnt/nfs/k3s/immich/db
+nfs:
+ path: /mnt/nfs/k3s/immich/data
diff --git a/roles/photos/files/core/Chart.yaml b/roles/photos/files/core/Chart.yaml
new file mode 100644
index 0000000..7cb306b
--- /dev/null
+++ b/roles/photos/files/core/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: immich-core
+description: Core for immich
+type: application
+
+version: 0.1.0
diff --git a/roles/photos/files/core/templates/ingress.yaml b/roles/photos/files/core/templates/ingress.yaml
new file mode 100644
index 0000000..c883185
--- /dev/null
+++ b/roles/photos/files/core/templates/ingress.yaml
@@ -0,0 +1,33 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: immich
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - photos.aadityadhruv.com
+ secretName: immich-tls
+ rules:
+ - host: photos.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: immich-server
+ port:
+ number: 2283
+ - host: photos.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: immich-server
+ port:
+ number: 2283
diff --git a/roles/photos/files/core/templates/pv.yaml b/roles/photos/files/core/templates/pv.yaml
new file mode 100644
index 0000000..cacdcf9
--- /dev/null
+++ b/roles/photos/files/core/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "immich-pv"
+ labels:
+ app: "immich-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 200Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/photos/files/core/templates/pvc.yaml b/roles/photos/files/core/templates/pvc.yaml
new file mode 100644
index 0000000..6ce8f0c
--- /dev/null
+++ b/roles/photos/files/core/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: immich-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 200Gi
+ selector:
+ matchLabels:
+ app: "immich-pv"
diff --git a/roles/photos/files/postgres/Chart.yaml b/roles/photos/files/postgres/Chart.yaml
new file mode 100644
index 0000000..f64d74d
--- /dev/null
+++ b/roles/photos/files/postgres/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: pgvectors
+description: Postgres chart with pgvector extension
+type: application
+
+version: 0.1.0
diff --git a/roles/photos/files/postgres/templates/database.yaml b/roles/photos/files/postgres/templates/database.yaml
new file mode 100644
index 0000000..098a410
--- /dev/null
+++ b/roles/photos/files/postgres/templates/database.yaml
@@ -0,0 +1,37 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "immich-postgres-deployment"
+ labels:
+ app: "immich-db"
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: "immich-db"
+ template:
+ metadata:
+ labels:
+ app: "immich-db"
+ spec:
+ containers:
+ - name: immich-db
+ image: "{{ .Values.image }}:{{ .Values.version }}"
+ env:
+ - name: POSTGRES_USER
+ value: {{ .Values.user }}
+ - name: POSTGRES_DB
+ value: immich
+ - name: POSTGRES_PASSWORD
+ value: {{ .Values.password }}
+ - name: PGDATA
+ value: /var/lib/postgresql/data/_data
+ ports:
+ - containerPort: 5432
+ volumeMounts:
+ - mountPath: "/var/lib/postgresql/data"
+ name: "immich-database-volume"
+ volumes:
+ - name: "immich-database-volume"
+ persistentVolumeClaim:
+ claimName: "immich-db-pvc"
diff --git a/roles/photos/files/postgres/templates/pv.yaml b/roles/photos/files/postgres/templates/pv.yaml
new file mode 100644
index 0000000..14b5aa2
--- /dev/null
+++ b/roles/photos/files/postgres/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "immich-db-pv"
+ labels:
+ app: "immich-db-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 10Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/photos/files/postgres/templates/pvc.yaml b/roles/photos/files/postgres/templates/pvc.yaml
new file mode 100644
index 0000000..4b3aca7
--- /dev/null
+++ b/roles/photos/files/postgres/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: immich-db-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 10Gi
+ selector:
+ matchLabels:
+ app: "immich-db-pv"
diff --git a/roles/photos/files/postgres/templates/service.yaml b/roles/photos/files/postgres/templates/service.yaml
new file mode 100644
index 0000000..8fb9a49
--- /dev/null
+++ b/roles/photos/files/postgres/templates/service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: immich-db-service
+spec:
+ type: ClusterIP
+ selector:
+ app: immich-db
+ ports:
+ - protocol: TCP
+ port: 5432
+ targetPort: 5432
diff --git a/roles/photos/tasks/main.yaml b/roles/photos/tasks/main.yaml
new file mode 100644
index 0000000..1faca34
--- /dev/null
+++ b/roles/photos/tasks/main.yaml
@@ -0,0 +1,60 @@
+- name: Add Immich remote chart
+ kubernetes.core.helm_repository:
+ name: immich
+ repo_url: https://immich-app.github.io/immich-charts
+ delegate_to: localhost
+ run_once: true
+
+- name: Deploy Immich Postgres Chart
+ kubernetes.core.helm:
+ state: "{%- if immich.enabled -%} present {%- else -%} absent {%- endif -%}"
+ name: immich-postgres
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/photos/files/postgres"
+ values:
+ image: "{{ immich.postgres.image }}"
+ version: "{{ immich.postgres.version }}"
+ user: "{{ immich.postgres.user }}"
+ password: "{{ immich.postgres.password }}"
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ immich.postgres.nfs.path }}"
+ namespace: default
+ delegate_to: localhost
+ run_once: true
+
+- name: Deploy Immich Core
+ kubernetes.core.helm:
+ state: "{%- if immich.enabled -%} present {%- else -%} absent {%- endif -%}"
+ name: immich-core
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/photos/files/core"
+ values:
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ nfs.path }}"
+ namespace: default
+ delegate_to: localhost
+ run_once: true
+
+
+- name: Deploy Immich
+ kubernetes.core.helm:
+ state: "{%- if immich.enabled -%} present {%- else -%} absent {%- endif -%}"
+ name: immich
+ chart_ref: immich/immich
+ values:
+ env:
+ DB_USERNAME: "{{ immich.postgres.user }}"
+ DB_PASSWORD: "{{ immich.postgres.password }}"
+ DB_DATABASE_NAME: immich
+ DB_HOSTNAME: immich-db-service
+ image:
+ tag: "{{ immich.version }}"
+ immich:
+ persistence:
+ library:
+ existingClaim: "immich-pvc"
+ redis:
+ enabled: true
+ namespace: default
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/pihole/defaults/main.yaml b/roles/pihole/defaults/main.yaml
new file mode 100644
index 0000000..d31e2f0
--- /dev/null
+++ b/roles/pihole/defaults/main.yaml
@@ -0,0 +1,8 @@
+pihole:
+ enabled: false
+ baremetal: false
+ version: 2025.02.6
+ replicas: 1
+ image: pihole/pihole
+nfs:
+ path: "/mnt/nfs/k3s/pihole"
diff --git a/roles/pihole/files/pihole.service b/roles/pihole/files/pihole.service
new file mode 100644
index 0000000..6d992d0
--- /dev/null
+++ b/roles/pihole/files/pihole.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Manage PiHole
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+User=root
+ExecStart=/usr/local/bin/podman-compose -f /opt/containers/pihole.yaml up -d
+ExecStop=/usr/local/bin/podman-compose -f /opt/containers/pihole.yaml down
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/pihole/files/pihole/.helmignore b/roles/pihole/files/pihole/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/roles/pihole/files/pihole/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/roles/pihole/files/pihole/Chart.yaml b/roles/pihole/files/pihole/Chart.yaml
new file mode 100644
index 0000000..e472ab4
--- /dev/null
+++ b/roles/pihole/files/pihole/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: pihole
+description: PiHole on K8s
+type: application
+
+version: 0.1.0
diff --git a/roles/pihole/files/pihole/templates/deployment.yaml b/roles/pihole/files/pihole/templates/deployment.yaml
new file mode 100644
index 0000000..4fc7faa
--- /dev/null
+++ b/roles/pihole/files/pihole/templates/deployment.yaml
@@ -0,0 +1,37 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: "{{ .Chart.Name }}-deployment"
+ labels:
+ app: {{ .Chart.Name }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ spec:
+ containers:
+ - name: pihole
+ image: "{{ .Values.image }}:{{ .Values.version }}"
+ ports:
+ - containerPort: 53
+ protocol: TCP
+ - containerPort: 53
+ protocol: UDP
+ - containerPort: 80
+ protocol: TCP
+ volumeMounts:
+ - mountPath: "/etc/pihole"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: "pihole"
+ - mountPath: "/etc/dnsmasq.d"
+ name: "{{ .Chart.Name }}-volume"
+ subPath: "dnsmasq"
+ volumes:
+ - name: "{{ .Chart.Name }}-volume"
+ persistentVolumeClaim:
+ claimName: "{{ .Chart.Name }}-pvc"
diff --git a/roles/pihole/files/pihole/templates/ingress.yaml b/roles/pihole/files/pihole/templates/ingress.yaml
new file mode 100644
index 0000000..8e84845
--- /dev/null
+++ b/roles/pihole/files/pihole/templates/ingress.yaml
@@ -0,0 +1,34 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: pihole
+ annotations:
+ cert-manager.io/cluster-issuer: "ca-issuer"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - dns.aadityadhruv.com
+ - dns.home
+ secretName: pihole-tls
+ rules:
+ - host: dns.home
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: pihole-service
+ port:
+ number: 80
+ - host: dns.aadityadhruv.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: pihole-service
+ port:
+ number: 80
diff --git a/roles/pihole/files/pihole/templates/pv.yaml b/roles/pihole/files/pihole/templates/pv.yaml
new file mode 100644
index 0000000..498fbd5
--- /dev/null
+++ b/roles/pihole/files/pihole/templates/pv.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: "{{ .Chart.Name }}-pv"
+ labels:
+ app: "{{ .Chart.Name }}-pv"
+spec:
+ storageClassName: nfs
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ nfs:
+ server: {{ .Values.nfs.server }}
+ path: {{ .Values.nfs.path }}
+ readOnly: false
diff --git a/roles/pihole/files/pihole/templates/pvc.yaml b/roles/pihole/files/pihole/templates/pvc.yaml
new file mode 100644
index 0000000..71b9b85
--- /dev/null
+++ b/roles/pihole/files/pihole/templates/pvc.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Chart.Name }}-pvc
+spec:
+ storageClassName: nfs
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 2Gi
+ selector:
+ matchLabels:
+ app: "{{ .Chart.Name }}-pv"
diff --git a/roles/pihole/files/pihole/templates/service.yaml b/roles/pihole/files/pihole/templates/service.yaml
new file mode 100644
index 0000000..72612c0
--- /dev/null
+++ b/roles/pihole/files/pihole/templates/service.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}-service
+spec:
+ type: LoadBalancer
+ selector:
+ app: {{ .Chart.Name }}
+ ports:
+ - name: dns-tcp
+ port: 53
+ targetPort: 53
+ protocol: TCP
+ - name: dns-udp
+ port: 53
+ targetPort: 53
+ protocol: UDP
+ - name: web
+ port: 80
+ targetPort: 80
+ protocol: TCP
diff --git a/roles/pihole/tasks/k8s.yaml b/roles/pihole/tasks/k8s.yaml
new file mode 100644
index 0000000..a4fcb81
--- /dev/null
+++ b/roles/pihole/tasks/k8s.yaml
@@ -0,0 +1,15 @@
+- name: Deploy PiHole
+ kubernetes.core.helm:
+ name: pihole
+ chart_ref: "{{ lookup('env', 'PWD') }}/roles/pihole/files/pihole"
+ namespace: default
+ state: "{%- if pihole.enabled -%} present {%- else -%} absent {%- endif -%}"
+ values:
+ replicas: "{{ pihole.replicas }}"
+ image: "{{ pihole.image }}"
+ version: "{{ pihole.version }}"
+ nfs:
+ server: "{{ nfs.server }}"
+ path: "{{ nfs.path }}"
+ delegate_to: localhost
+ run_once: true
diff --git a/roles/pihole/tasks/main.yaml b/roles/pihole/tasks/main.yaml
new file mode 100644
index 0000000..7fa1cef
--- /dev/null
+++ b/roles/pihole/tasks/main.yaml
@@ -0,0 +1,10 @@
+---
+- name: Setup PiHole (cluster)
+ import_tasks: k8s.yaml
+ when: not pihole.baremetal
+
+- name: Setup PiHole (baremetal)
+ import_tasks: pihole.yaml
+ when: pihole.enabled and pihole.baremetal and inventory_hostname in group["pi"]
+
+
diff --git a/roles/pihole/tasks/pihole.yaml b/roles/pihole/tasks/pihole.yaml
new file mode 100644
index 0000000..c4b1959
--- /dev/null
+++ b/roles/pihole/tasks/pihole.yaml
@@ -0,0 +1,73 @@
+---
+- name: Ensure podman exists
+ ansible.builtin.dnf:
+ name: podman
+ state: latest
+ become: true
+
+- name: Ensure pip exists
+ ansible.builtin.dnf:
+ name: python3-pip
+ state: latest
+ become: true
+
+- name: Install podman compose via pip
+ pip:
+ name: podman-compose
+ become: true
+
+- name: Create containers directory
+ ansible.builtin.file:
+ path: /opt/containers/
+ state: directory
+ mode: '0755'
+ become: true
+
+- name: Copy compose file to containers directory
+ ansible.builtin.template:
+ src: pihole.yaml.j2
+ dest: /opt/containers/pihole.yaml
+ become: true
+
+- name: Copy pihole service file to systemd directory
+ ansible.builtin.copy:
+ src: pihole.service
+ dest: /etc/systemd/system/
+ become: true
+
+- name: Ensure systemd-resovled is disabled
+ ansible.builtin.systemd_service:
+ enabled: false
+ name: systemd-resolved
+ state: stopped
+ ignore_errors: true
+ become: true
+
+- name: Enable PiHole serivce
+ ansible.builtin.systemd_service:
+ daemon_reload: true
+ enabled: true
+ state: restarted
+ name: pihole
+ become: true
+
+- name: Open DNS Port TCP
+ ansible.posix.firewalld:
+ port: 53/tcp
+ permanent: true
+ state: enabled
+ become: true
+
+- name: Open DNS Port UDP
+ ansible.posix.firewalld:
+ port: 53/udp
+ permanent: true
+ state: enabled
+ become: true
+
+- name: Open Webserver port
+ ansible.posix.firewalld:
+ port: 8000/tcp
+ permanent: true
+ state: enabled
+ become: true
diff --git a/roles/pihole/templates/pihole.yaml.j2 b/roles/pihole/templates/pihole.yaml.j2
new file mode 100644
index 0000000..7e744df
--- /dev/null
+++ b/roles/pihole/templates/pihole.yaml.j2
@@ -0,0 +1,20 @@
+version: "3"
+services:
+ pihole:
+ image: docker.io/pihole/pihole:{{ pihole.tag }}
+ container_name: pihole
+ ports:
+ - "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}:53:53/tcp"
+ - "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}:53:53/udp"
+ - "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}:8000:80/tcp"
+ environment:
+ TZ: 'America/Chicago'
+ WEBPASSWORD: {{ pihole.password }}
+ volumes:
+ - 'pihole:/etc/pihole:Z'
+ - 'pihole_dnsmaq:/etc/dnsmasq.d:Z'
+ restart: unless-stopped
+volumes:
+ pihole:
+ pihole_dnsmaq:
+
diff --git a/roles/system/defaults/main.yaml b/roles/system/defaults/main.yaml
new file mode 100644
index 0000000..2f889ab
--- /dev/null
+++ b/roles/system/defaults/main.yaml
@@ -0,0 +1,18 @@
+servers:
+ base: true
+packages:
+ dnf:
+ - epel-release
+ - htop
+ - fail2ban
+ - git
+ - neovim
+ - nfs-utils
+ - nmap
+ - podman
+ - podman-compose
+ - restic
+ - sqlite
+ - tmux
+ - wireguard-tools
+ - yamllint
diff --git a/roles/system/files/packages/k9s/k9s.spec b/roles/system/files/packages/k9s/k9s.spec
new file mode 100644
index 0000000..ae4297b
--- /dev/null
+++ b/roles/system/files/packages/k9s/k9s.spec
@@ -0,0 +1,37 @@
+Name: k9s
+Version: 0.27.4
+Release: %autorelease
+Summary: A Kubernetes CLI To Manage Your Clusters
+
+License: Apache-2.0
+URL: https://github.com/derailed/k9s
+Source0: https://github.com/derailed/k9s/archive/refs/tags/v%{version}.tar.gz
+
+
+BuildRequires: golang, make, git
+
+
+%description
+K9s provides a terminal UI to interact with your Kubernetes clusters.
+
+
+%global debug_package %{nil}
+%prep
+%autosetup -n k9s-%{version}
+
+
+%build
+make build
+
+
+%install
+mkdir %{buildroot}%{_bindir} -p
+cp ./execs/k9s %{buildroot}%{_bindir}
+
+%files
+%{_bindir}/k9s
+
+
+%changelog
+%autochangelog
+
diff --git a/roles/system/tasks/main.yaml b/roles/system/tasks/main.yaml
new file mode 100644
index 0000000..3e86842
--- /dev/null
+++ b/roles/system/tasks/main.yaml
@@ -0,0 +1,7 @@
+---
+- name: Install required dnf packages
+ dnf:
+ name: "{{ item }}"
+ loop: "{{ packages.dnf }}"
+ when: inventory_hostname in groups['servers'] and servers.base
+ become: true
diff --git a/roles/wireguard/defaults/main.yaml b/roles/wireguard/defaults/main.yaml
new file mode 100644
index 0000000..649825c
--- /dev/null
+++ b/roles/wireguard/defaults/main.yaml
@@ -0,0 +1,2 @@
+wireguard:
+ enabled: false
diff --git a/roles/wireguard/tasks/main.yaml b/roles/wireguard/tasks/main.yaml
new file mode 100644
index 0000000..4bdd7a9
--- /dev/null
+++ b/roles/wireguard/tasks/main.yaml
@@ -0,0 +1,3 @@
+- name: Setup wireguard
+ import_tasks: wireguard.yaml
+ when: wireguard.enabled and inventory_hostname in groups["servers"]
diff --git a/roles/wireguard/tasks/wireguard.yaml b/roles/wireguard/tasks/wireguard.yaml
new file mode 100644
index 0000000..eda00aa
--- /dev/null
+++ b/roles/wireguard/tasks/wireguard.yaml
@@ -0,0 +1,93 @@
+- name: Setup Wireguard on Master Host
+ block:
+
+ - name: Ensure wireguard is present
+ ansible.builtin.dnf:
+ name: wireguard-tools
+ state: latest
+
+ - name: Generate private key
+ ansible.builtin.shell: "wg genkey"
+ register: privatekey
+
+ - name: Set private key variable
+ ansible.builtin.set_fact:
+ privatekey: "{{ privatekey.stdout_lines[0] }}"
+
+ - name: Generate public key
+ ansible.builtin.shell: "echo {{ privatekey }} | wg pubkey"
+ register: publickey
+
+ - name: Set public key variable
+ ansible.builtin.set_fact:
+ publickey: "{{ publickey.stdout_lines[0] }}"
+
+ - name: Create wireguard config file
+ ansible.builtin.template:
+ src: wireguard.master.j2
+ dest: "{{ network.wireguard.path }}/wg0.conf"
+
+ - name: Ensure ansible facts directory exists
+ ansible.builtin.file:
+ path: /etc/ansible/facts.d
+ state: directory
+ mode: 0755
+
+ - name: Add fact about wireguard config to host
+ ansible.builtin.copy:
+ content: '{ "PublicKey": "{{ publickey }}" }'
+ dest: "/etc/ansible/facts.d/wireguard.fact"
+
+ - name: Re-gather facts
+ gather_facts:
+ when: inventory_hostname in groups["cloud"]
+ become: true
+
+- name: Setup Wireguard on Slave Hosts
+ block:
+ - name: Ensure wireguard is present
+ ansible.builtin.dnf:
+ name: wireguard-tools
+ state: latest
+
+ - name: Wait for master node to generate file
+ ansible.builtin.wait_for:
+ host: "{{ groups['cloud'][0] }}"
+ path: /etc/ansible/facts.d/wireguard.fact
+ search_regex: PublicKey
+ delegate_to: "{{ groups['cloud'][0] }}"
+ register: output
+
+ - name: Generate private key
+ ansible.builtin.shell: "wg genkey"
+ register: privatekey
+
+ - name: Set private key variable
+ ansible.builtin.set_fact:
+ privatekey: "{{ privatekey.stdout_lines[0] }}"
+
+ - name: Generate public key
+ ansible.builtin.shell: "echo {{ privatekey }} | wg pubkey"
+ register: publickey
+
+ - name: Set public key variable
+ ansible.builtin.set_fact:
+ publickey: "{{ publickey.stdout_lines[0] }}"
+
+ - name: Setup wireguard ip fact
+ set_fact:
+ wireguard_ip: "10.0.0.{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'].split('.')[3] }}"
+
+ - name: Create wireguard config file
+ ansible.builtin.template:
+ src: wireguard.slave.j2
+ dest: "{{ network.wireguard.path }}/wg0.conf"
+
+ - name: Add host's details to master
+ lineinfile:
+ path: "{{ network.wireguard.path }}/wg0.conf"
+ line: "\n[Peer]\nPublicKey={{ publickey }}\nAllowedIPs={{ wireguard_ip }}\n"
+ delegate_to: "{{ groups['cloud'][0] }}"
+
+ when: inventory_hostname not in groups["cloud"]
+ become: true
diff --git a/roles/wireguard/templates/wireguard.master.j2 b/roles/wireguard/templates/wireguard.master.j2
new file mode 100644
index 0000000..c2ac41c
--- /dev/null
+++ b/roles/wireguard/templates/wireguard.master.j2
@@ -0,0 +1,6 @@
+[Interface]
+Address = 10.0.0.1/24
+PostUp = firewall-cmd --add-masquerade
+PostDown = firewall-cmd --remove-masquerade
+ListenPort = {{ network.wireguard.port }}
+PrivateKey = {{ privatekey }}
diff --git a/roles/wireguard/templates/wireguard.slave.j2 b/roles/wireguard/templates/wireguard.slave.j2
new file mode 100644
index 0000000..b6a01b8
--- /dev/null
+++ b/roles/wireguard/templates/wireguard.slave.j2
@@ -0,0 +1,11 @@
+[Interface]
+Address = {{ wireguard_ip }}/24
+ListenPort = {{ network.wireguard.port }}
+PrivateKey = {{ privatekey }}
+DNS = {{ network.dns }}
+
+[Peer]
+PublicKey = {{ hostvars[groups['cloud'][0]]['ansible_local']['wireguard']['PublicKey'] }}
+AllowedIPs = 0.0.0.0/0
+Endpoint = {{ hostvars[groups['cloud'][0]]['ansible_default_ipv4']['address'] }}:{{ network.wireguard.port }}
+PersistentKeepalive = 15
diff --git a/scripts/backups/backup.sh b/scripts/backups/backup.sh
new file mode 100755
index 0000000..2636c1e
--- /dev/null
+++ b/scripts/backups/backup.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+set -x
+source /etc/backups/backup.env
+
+# Make logs directory
+mkdir -p $BACKUPS_DIR/logs
+touch $BACKUPS_DIR/logs/$DATE.txt
+
+#Starting backup
+echo "-------" $DATE BACKUP START "--------" &>> $BACKUPS_DIR/logs/$DATE.txt
+
+#Restic backup command
+restic $DRY_RUN --verbose -r $RESTIC_REPOSITORY \
+ backup $BACKUP_PATHS \
+ &>> $BACKUPS_DIR/logs/$DATE.txt
+
+echo "-------" $DATE BACKUP PRUNE START "--------" &>> $BACKUPS_DIR/logs/$DATE.txt
+#Prune
+restic -r $RESTIC_REPOSITORY forget \
+ --keep-last $SNAPSHOTS_RETAINED \
+ --keep-weekly $WEEKS_RETAINED \
+ --keep-monthly $MONTHS_RETAINED \
+ --keep-yearly $YEARS_RETAINED $DRY_RUN \
+ --prune \
+ &>> $BACKUPS_DIR/logs/$DATE.txt
+#End backup
+echo "-------" $DATE BACKUP COMPLETE "--------" &>> $BACKUPS_DIR/logs/$DATE.txt
+
+