Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94ff1d12e3 | ||
|
|
cc9c3dea88 | ||
|
|
815cd85b9a | ||
|
|
9021eddbc3 | ||
|
|
2adf17c307 | ||
|
|
1add5b5cd7 | ||
|
|
34f10211ab | ||
|
|
02447f2946 | ||
|
|
8799962b1c | ||
|
|
fb80024fa2 | ||
|
|
0f1a788874 | ||
|
|
39df442e60 | ||
|
|
62a451773e | ||
|
|
f196099491 | ||
|
|
66502b8279 | ||
|
|
9018c091fa | ||
|
|
114608af2f | ||
|
|
51a73fb213 |
No files matched your search
@@ -141,6 +141,7 @@ jobs:
|
|||||||
export PATH="$tools_dir:$PATH"
|
export PATH="$tools_dir:$PATH"
|
||||||
ruff check .
|
ruff check .
|
||||||
ruff format --check .
|
ruff format --check .
|
||||||
|
python3 -m unittest discover -s tests -v
|
||||||
|
|
||||||
lint-yaml:
|
lint-yaml:
|
||||||
runs-on: [self-hosted, linux, arch, homelab]
|
runs-on: [self-hosted, linux, arch, homelab]
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ jobs:
|
|||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v "$PWD/renovate/renovate.json:/opt/renovate/renovate.json:ro" \
|
-v "$PWD/renovate/renovate.json:/opt/renovate/renovate.json:ro" \
|
||||||
-e RENOVATE_PLATFORM=gitea \
|
-e RENOVATE_PLATFORM=gitea \
|
||||||
-e RENOVATE_ENDPOINT=https://gitea.forust.xyz/api/v1 \
|
-e RENOVATE_ENDPOINT=https://git.forust.xyz/api/v1 \
|
||||||
-e RENOVATE_TOKEN="$RENOVATE_TOKEN" \
|
-e RENOVATE_TOKEN="$RENOVATE_TOKEN" \
|
||||||
-e RENOVATE_GITHUB_COM_TOKEN="${RENOVATE_GITHUB_COM_TOKEN:-}" \
|
-e RENOVATE_GITHUB_COM_TOKEN="${RENOVATE_GITHUB_COM_TOKEN:-}" \
|
||||||
-e RENOVATE_REPOSITORIES="${RENOVATE_REPOSITORIES:-forust/homelab}" \
|
-e RENOVATE_REPOSITORIES="${RENOVATE_REPOSITORIES:-forust/homelab}" \
|
||||||
|
|||||||
@@ -68,35 +68,6 @@ spec:
|
|||||||
reloader.stakater.com/auto: "true"
|
reloader.stakater.com/auto: "true"
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: netbird
|
|
||||||
image: netbirdio/netbird:0.80.0
|
|
||||||
envFrom:
|
|
||||||
- configMapRef:
|
|
||||||
name: adguard-config
|
|
||||||
env:
|
|
||||||
- name: NB_SETUP_KEY
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: adguard-netbird-secrets
|
|
||||||
key: NB_SETUP_KEY
|
|
||||||
securityContext:
|
|
||||||
capabilities:
|
|
||||||
add:
|
|
||||||
- NET_ADMIN
|
|
||||||
- SYS_ADMIN
|
|
||||||
- SYS_RESOURCE
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "64Mi"
|
|
||||||
cpu: "50m"
|
|
||||||
limits:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "200m"
|
|
||||||
volumeMounts:
|
|
||||||
- name: netbird-state
|
|
||||||
mountPath: /var/lib/netbird
|
|
||||||
- name: dev-tun
|
|
||||||
mountPath: /dev/net/tun
|
|
||||||
- name: adguard
|
- name: adguard
|
||||||
image: adguard/adguardhome:v0.107.79
|
image: adguard/adguardhome:v0.107.79
|
||||||
resources:
|
resources:
|
||||||
@@ -113,6 +84,13 @@ spec:
|
|||||||
name: dns
|
name: dns
|
||||||
- containerPort: 853
|
- containerPort: 853
|
||||||
name: dot
|
name: dot
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: dns
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
successThreshold: 1
|
||||||
|
failureThreshold: 3
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: adguard-data
|
- name: adguard-data
|
||||||
mountPath: /opt/adguardhome/work
|
mountPath: /opt/adguardhome/work
|
||||||
@@ -124,12 +102,6 @@ spec:
|
|||||||
mountPath: /certs
|
mountPath: /certs
|
||||||
readOnly: true
|
readOnly: true
|
||||||
volumes:
|
volumes:
|
||||||
- name: netbird-state
|
|
||||||
emptyDir: {}
|
|
||||||
- name: dev-tun
|
|
||||||
hostPath:
|
|
||||||
path: /dev/net/tun
|
|
||||||
type: CharDevice
|
|
||||||
- name: adguard-data
|
- name: adguard-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: adguard-pvc
|
claimName: adguard-pvc
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: adguard-config
|
|
||||||
namespace: adguard
|
|
||||||
data:
|
|
||||||
NB_MANAGEMENT_URL: "https://nb.forust.xyz"
|
|
||||||
NB_HOSTNAME: "adguard"
|
|
||||||
NB_LOG_LEVEL: "info"
|
|
||||||
NB_DISABLE_DNS: "true"
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: adguard-netbird-secrets
|
|
||||||
namespace: adguard
|
|
||||||
type: Opaque
|
|
||||||
stringData:
|
|
||||||
NB_SETUP_KEY: "REPLACE_ME"
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
EDU_LOGIN=your_edu_login_here
|
KEEPER_LOGIN=your_edu_login_here
|
||||||
EDU_PASSWORD=your_edu_password_here
|
KEEPER_PASSWORD=your_edu_password_here
|
||||||
EDU_URL_LOGIN=https://edu.edu.vn.ua/user/login
|
EDU_URL_BASE=https://edu.edu.vn.ua
|
||||||
EDU_URL_VERIFY=https://edu.edu.vn.ua/course/userlist
|
EDU_URL_LOGIN=/user/login
|
||||||
PHPSESSID_INTERVAL=10
|
EDU_URL_COURSES=/course/userlist
|
||||||
|
KEEPER_INTERVAL=10
|
||||||
USER_AGENT="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36"
|
USER_AGENT="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36"
|
||||||
WEBINAR_URL=https://edu.edu.vn.ua/webinar/useractive
|
EDU_URL_WEBINAR=/webinar/useractive
|
||||||
WEBINAR_CHECK_INTERVAL=60
|
WEBINAR_CHECK_INTERVAL=60
|
||||||
REDIS_HOST=redis
|
REDIS_HOST=redis
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|||||||
@@ -48,17 +48,43 @@ def touch_success_file():
|
|||||||
logger.error(f'Failed to touch success file: {e}')
|
logger.error(f'Failed to touch success file: {e}')
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_session(session, redis_client):
|
||||||
|
"""Publish a verified cookie with a lifetime tied to the refresh interval."""
|
||||||
|
login_response = session.post(
|
||||||
|
URL_LOGIN, data={'login': LOGIN, 'password': PASSWORD}, allow_redirects=True, timeout=(10, 30)
|
||||||
|
)
|
||||||
|
login_response.raise_for_status()
|
||||||
|
verify_response = session.get(URL_VERIFY, allow_redirects=False, timeout=(10, 30))
|
||||||
|
if verify_response.status_code != 200:
|
||||||
|
logger.warning('Session verification failed (HTTP %s)', verify_response.status_code)
|
||||||
|
return False
|
||||||
|
phpsessid = session.cookies.get('PHPSESSID')
|
||||||
|
if not phpsessid:
|
||||||
|
logger.warning('Verified response did not provide a PHPSESSID cookie')
|
||||||
|
return False
|
||||||
|
redis_client.set('EDU_PHPSESSID', phpsessid, ex=INTERVAL * 120)
|
||||||
|
touch_success_file()
|
||||||
|
logger.info('Verified session saved to Redis')
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
if not LOGIN or not PASSWORD:
|
||||||
|
raise ValueError('KEEPER_LOGIN and KEEPER_PASSWORD must be set')
|
||||||
|
if INTERVAL <= 0:
|
||||||
|
raise ValueError('KEEPER_INTERVAL must be a positive number of minutes')
|
||||||
logger.info('Starting Session Keeper Bot')
|
logger.info('Starting Session Keeper Bot')
|
||||||
|
|
||||||
# Connect to Redis
|
# Connect to Redis
|
||||||
try:
|
try:
|
||||||
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
|
redis_client = redis.Redis(
|
||||||
|
host=REDIS_HOST, port=REDIS_PORT, decode_responses=True, socket_connect_timeout=5, socket_timeout=5
|
||||||
|
)
|
||||||
redis_client.ping()
|
redis_client.ping()
|
||||||
logger.info(f'Connected to Redis at {REDIS_HOST}:{REDIS_PORT}')
|
logger.info(f'Connected to Redis at {REDIS_HOST}:{REDIS_PORT}')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Failed to connect to Redis: {e}')
|
logger.error(f'Failed to connect to Redis: {e}')
|
||||||
return
|
raise
|
||||||
|
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
|
|
||||||
@@ -83,44 +109,7 @@ def main():
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
logger.info('Attempting login...')
|
refresh_session(session, redis_client)
|
||||||
|
|
||||||
# Login payload
|
|
||||||
payload = {'login': LOGIN, 'password': PASSWORD}
|
|
||||||
|
|
||||||
# Perform Login
|
|
||||||
# Note: The user request shows a POST to /user/login with form data
|
|
||||||
# We need to make sure we handle the PHPSESSID correctly.
|
|
||||||
# If we already have a PHPSESSID, requests will send it.
|
|
||||||
|
|
||||||
login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True)
|
|
||||||
|
|
||||||
logger.info(f'Login Response Status: {login_response.status_code}')
|
|
||||||
logger.info(f'Cookies after login: {session.cookies.get_dict()}')
|
|
||||||
|
|
||||||
# Verify Session
|
|
||||||
logger.info('Verifying session...')
|
|
||||||
verify_response = session.get(URL_VERIFY, allow_redirects=False)
|
|
||||||
|
|
||||||
logger.info(f'Verify Response Status: {verify_response.status_code}')
|
|
||||||
|
|
||||||
if verify_response.status_code == 200:
|
|
||||||
logger.info('Session verification SUCCESS (200 OK).')
|
|
||||||
touch_success_file()
|
|
||||||
|
|
||||||
# Save PHPSESSID to Redis
|
|
||||||
phpsessid = session.cookies.get('PHPSESSID')
|
|
||||||
if phpsessid:
|
|
||||||
try:
|
|
||||||
redis_client.set('EDU_PHPSESSID', phpsessid)
|
|
||||||
logger.info(f'Saved PHPSESSID to Redis: {phpsessid}')
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f'Failed to save PHPSESSID to Redis: {e}')
|
|
||||||
elif verify_response.status_code == 302:
|
|
||||||
logger.warning('Session verification FAILED (302 Redirect). Session might be invalid.')
|
|
||||||
else:
|
|
||||||
logger.warning(f'Session verification returned unexpected status: {verify_response.status_code}')
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'An error occurred: {e}')
|
logger.error(f'An error occurred: {e}')
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -13,9 +13,12 @@ services:
|
|||||||
- GITEA__database__PASSWD=gitea
|
- GITEA__database__PASSWD=gitea
|
||||||
- GITEA__database__NAME=gitea
|
- GITEA__database__NAME=gitea
|
||||||
# Server
|
# Server
|
||||||
- GITEA__server__ROOT_URL=https://gitea.forust.xyz
|
- GITEA__server__ROOT_URL=https://git.forust.xyz
|
||||||
- GITEA__server__SSH_DOMAIN=gitssh.forust.xyz
|
- GITEA__server__SSH_DOMAIN=gitssh.forust.xyz
|
||||||
- GITEA__server__SSH_PORT=2221
|
- GITEA__server__SSH_PORT=2221
|
||||||
|
# Pin 28.0 defaults explicitly (see k8s/config.yaml for rationale)
|
||||||
|
- GITEA__service__DISABLE_REGISTRATION=true
|
||||||
|
- GITEA__actions__RUN_RETENTION_DAYS=90
|
||||||
# Mailer
|
# Mailer
|
||||||
- GITEA__mailer__ENABLED=true
|
- GITEA__mailer__ENABLED=true
|
||||||
- GITEA__mailer__FROM=${SERVICE_EMAIL}
|
- GITEA__mailer__FROM=${SERVICE_EMAIL}
|
||||||
@@ -34,7 +37,7 @@ services:
|
|||||||
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
|
- "traefik.http.routers.gitea.rule=Host(`git.forust.xyz`) || Host(`gitea.forust.xyz`)"
|
||||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||||
- "traefik.http.routers.gitea.tls.certresolver"
|
- "traefik.http.routers.gitea.tls.certresolver"
|
||||||
# Local Router
|
# Local Router
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ metadata:
|
|||||||
name: gitea-config
|
name: gitea-config
|
||||||
namespace: gitea
|
namespace: gitea
|
||||||
data:
|
data:
|
||||||
GITEA__server__DOMAIN: "gitea.forust.xyz"
|
GITEA__server__ROOT_URL: "https://git.forust.xyz"
|
||||||
GITEA__server__ROOT_URL: "https://gitea.forust.xyz"
|
|
||||||
GITEA__server__SSH_DOMAIN: "gitssh.forust.xyz"
|
GITEA__server__SSH_DOMAIN: "gitssh.forust.xyz"
|
||||||
GITEA__server__SSH_PORT: "2221"
|
GITEA__server__SSH_PORT: "2221"
|
||||||
|
|
||||||
|
GITEA__service__DISABLE_REGISTRATION: "true"
|
||||||
|
|
||||||
|
GITEA__actions__RUN_RETENTION_DAYS: "90"
|
||||||
|
|
||||||
GITEA__database__DB_TYPE: "postgres"
|
GITEA__database__DB_TYPE: "postgres"
|
||||||
GITEA__database__HOST: "postgres.database.svc.cluster.local:5432"
|
GITEA__database__HOST: "postgres.database.svc.cluster.local:5432"
|
||||||
GITEA__database__NAME: "gitea"
|
GITEA__database__NAME: "gitea"
|
||||||
|
|||||||
@@ -177,8 +177,8 @@ data:
|
|||||||
# url: https://gitssh.forust.xyz
|
# url: https://gitssh.forust.xyz
|
||||||
# - title: gcr.forust.xyz
|
# - title: gcr.forust.xyz
|
||||||
# url: https://gcr.forust.xyz/v2/
|
# url: https://gcr.forust.xyz/v2/
|
||||||
- title: gitea.forust.xyz
|
- title: git.forust.xyz
|
||||||
url: https://gitea.forust.xyz
|
url: https://git.forust.xyz
|
||||||
- title: nextcloud.forust.xyz
|
- title: nextcloud.forust.xyz
|
||||||
url: https://nextcloud.forust.xyz
|
url: https://nextcloud.forust.xyz
|
||||||
- title: mc.forust.xyz
|
- title: mc.forust.xyz
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
SECRET_ENCRYPTION_KEY="REPLACE_ME"
|
||||||
|
TZ="Europe/Bratislava"
|
||||||
|
PUID="1000"
|
||||||
|
PGID="1000"
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
services:
|
||||||
|
homarr:
|
||||||
|
container_name: homarr
|
||||||
|
image: ghcr.io/homarr-labs/homarr:v2.1.2
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./appdata:/appdata
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- ./kubeconfig:/app/config/kubeconfig:ro
|
||||||
|
env_file: .env
|
||||||
|
ports:
|
||||||
|
- 80:7575
|
||||||
|
- 81:3000
|
||||||
|
environment:
|
||||||
|
- TZ=${TZ:-Europe/Bratislava}
|
||||||
|
- TURBO_TELEMETRY_DISABLED=1
|
||||||
|
- KUBECONFIG=/app/config/kubeconfig
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
|
||||||
|
|
||||||
|
# Prod Router
|
||||||
|
- "traefik.http.routers.homarr.rule=Host(`homarr.forust.xyz`)"
|
||||||
|
- "traefik.http.routers.homarr.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.homarr.tls.certresolver=letsencrypt"
|
||||||
|
# Local Router
|
||||||
|
- "traefik.http.routers.homarr-local.rule=Host(`homarr.workstation.internal`)"
|
||||||
|
- "traefik.http.routers.homarr-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.homarr-local.tls=true"
|
||||||
|
# Dev Router
|
||||||
|
- "traefik.http.routers.homarr-dev.rule=Host(`homarr.gigaforust.internal`)"
|
||||||
|
- "traefik.http.routers.homarr-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.homarr-dev.tls=true"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: home-prod-tls
|
||||||
|
# namespace: homarr
|
||||||
|
# spec:
|
||||||
|
# secretName: home-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - home.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: internal-wildcard-tls
|
||||||
|
namespace: homarr
|
||||||
|
spec:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
dnsNames:
|
||||||
|
- "*.workstation.internal"
|
||||||
|
- "*.gigaforust.internal"
|
||||||
|
- workstation.internal
|
||||||
|
- gigaforust.internal
|
||||||
|
issuerRef:
|
||||||
|
name: internal-ca
|
||||||
|
kind: ClusterIssuer
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: homarr-config
|
||||||
|
namespace: homarr
|
||||||
|
data:
|
||||||
|
TZ: "Europe/Bratislava"
|
||||||
|
TURBO_TELEMETRY_DISABLED: "1"
|
||||||
|
ENABLE_KUBERNETES: "true"
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: homarr-service
|
||||||
|
namespace: homarr
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: homarr
|
||||||
|
ports:
|
||||||
|
- port: 7575
|
||||||
|
targetPort: 7575
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: homarr-deployment
|
||||||
|
namespace: homarr
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: homarr
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: homarr
|
||||||
|
spec:
|
||||||
|
serviceAccountName: homarr
|
||||||
|
containers:
|
||||||
|
- name: homarr
|
||||||
|
image: ghcr.io/homarr-labs/homarr:v2.1.2
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: homarr-config
|
||||||
|
- secretRef:
|
||||||
|
name: homarr-secrets
|
||||||
|
ports:
|
||||||
|
- containerPort: 7575
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 7575
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 7575
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
volumeMounts:
|
||||||
|
- name: homarr-data
|
||||||
|
mountPath: /appdata
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "250m"
|
||||||
|
memory: "350Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "500m"
|
||||||
|
memory: "700Mi"
|
||||||
|
volumes:
|
||||||
|
- name: homarr-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: homarr-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: homarr-pvc
|
||||||
|
namespace: homarr
|
||||||
|
spec:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
|
volumeMode: Filesystem
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# apiVersion: traefik.io/v1alpha1
|
||||||
|
# kind: IngressRoute
|
||||||
|
# metadata:
|
||||||
|
# name: homarr-prod
|
||||||
|
# namespace: homarr
|
||||||
|
# spec:
|
||||||
|
# entryPoints:
|
||||||
|
# - websecure
|
||||||
|
# routes:
|
||||||
|
# - match: Host(`home.forust.xyz`)
|
||||||
|
# kind: Rule
|
||||||
|
# services:
|
||||||
|
# - name: homarr-service
|
||||||
|
# port: 7575
|
||||||
|
# tls:
|
||||||
|
# secretName: home-prod-tls
|
||||||
|
# ---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: homarr-local
|
||||||
|
namespace: homarr
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`home.workstation.internal`) || Host(`home.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: homarr-service
|
||||||
|
port: 7575
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: homarr
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: homarr
|
||||||
|
namespace: homarr
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: homarr-readonly
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
- services
|
||||||
|
- endpoints
|
||||||
|
- namespaces
|
||||||
|
- nodes
|
||||||
|
- configmaps
|
||||||
|
- persistentvolumeclaims
|
||||||
|
- events
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources:
|
||||||
|
- deployments
|
||||||
|
- statefulsets
|
||||||
|
- daemonsets
|
||||||
|
- replicasets
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["networking.k8s.io"]
|
||||||
|
resources:
|
||||||
|
- ingresses
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["traefik.io"]
|
||||||
|
resources:
|
||||||
|
- ingressroutes
|
||||||
|
- ingressroutetcps
|
||||||
|
- ingressrouteudps
|
||||||
|
- middlewares
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["metrics.k8s.io"]
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
- nodes
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: homarr-readonly
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: homarr-readonly
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: homarr
|
||||||
|
namespace: homarr
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: homarr-secrets
|
||||||
|
namespace: homarr
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
# openssl rand -hex 32
|
||||||
|
SECRET_ENCRYPTION_KEY: "REPLACE_ME"
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
<h2>./projects</h2>
|
<h2>./projects</h2>
|
||||||
<ul class="repo-list">
|
<ul class="repo-list">
|
||||||
<li>
|
<li>
|
||||||
<a href="https://gitea.forust.xyz/forust/gosleep" target="_blank">forust/gosleep</a>
|
<a href="https://git.forust.xyz/forust/gosleep" target="_blank">forust/gosleep</a>
|
||||||
<span class="comment">// linux sleep timer written in rust (originally in go)</span>
|
<span class="comment">// linux sleep timer written in rust (originally in go)</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
n8n:
|
n8n:
|
||||||
image: docker.n8n.io/n8nio/n8n:2.42.2
|
image: docker.n8n.io/n8nio/n8n:2.42.3
|
||||||
container_name: n8n
|
container_name: n8n
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: n8n
|
- name: n8n
|
||||||
image: docker.n8n.io/n8nio/n8n:2.42.2
|
image: docker.n8n.io/n8nio/n8n:2.42.3
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: n8n-config
|
name: n8n-config
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
RENOVATE_ENDPOINT=https://gitea.forust.xyz/api/v1
|
RENOVATE_ENDPOINT=https://git.forust.xyz/api/v1
|
||||||
RENOVATE_TOKEN=
|
RENOVATE_TOKEN=
|
||||||
RENOVATE_REPOSITORIES=forust/homelab
|
RENOVATE_REPOSITORIES=forust/homelab
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
@@ -218,6 +218,34 @@ data:
|
|||||||
"matchUpdateTypes": ["patch"],
|
"matchUpdateTypes": ["patch"],
|
||||||
"groupName": "all patch updates",
|
"groupName": "all patch updates",
|
||||||
"groupSlug": "all-patch"
|
"groupSlug": "all-patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"matchPackageNames": ["python"],
|
||||||
|
"groupName": "python base image",
|
||||||
|
"groupSlug": "python",
|
||||||
|
"automerge": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Rolling/floating tags (streaming stack, nextcloud beta, kubectl latest) - never automerge, every bump is a manual review. Placed last so automerge:false wins over the shared digest/patch rule.",
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"matchPackageNames": [
|
||||||
|
"lscr.io/linuxserver/jellyfin",
|
||||||
|
"lscr.io/linuxserver/qbittorrent",
|
||||||
|
"lscr.io/linuxserver/sonarr",
|
||||||
|
"lscr.io/linuxserver/radarr",
|
||||||
|
"lscr.io/linuxserver/prowlarr",
|
||||||
|
"lscr.io/linuxserver/bazarr",
|
||||||
|
"ghcr.io/seerr-team/seerr",
|
||||||
|
"fallenbagel/jellyseerr",
|
||||||
|
"ghcr.io/lampac-nextgen/lampac",
|
||||||
|
"ghcr.io/nextcloud-releases/all-in-one",
|
||||||
|
"alpine/kubectl"
|
||||||
|
],
|
||||||
|
"groupName": "floating images - manual",
|
||||||
|
"groupSlug": "floating-manual",
|
||||||
|
"automerge": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ spec:
|
|||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
containers:
|
containers:
|
||||||
- name: renovate
|
- name: renovate
|
||||||
image: renovate/renovate:44.132.4
|
image: renovate/renovate:44.136.0
|
||||||
env:
|
env:
|
||||||
- name: RENOVATE_PLATFORM
|
- name: RENOVATE_PLATFORM
|
||||||
value: gitea
|
value: gitea
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ metadata:
|
|||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
stringData:
|
||||||
RENOVATE_TOKEN: ""
|
RENOVATE_TOKEN: ""
|
||||||
RENOVATE_ENDPOINT: "https://gitea.forust.xyz/api/v1"
|
RENOVATE_ENDPOINT: "https://git.forust.xyz/api/v1"
|
||||||
RENOVATE_REPOSITORIES: "forust/homelab"
|
RENOVATE_REPOSITORIES: "forust/homelab"
|
||||||
RENOVATE_GITHUB_COM_TOKEN: ""
|
RENOVATE_GITHUB_COM_TOKEN: ""
|
||||||
@@ -207,6 +207,34 @@
|
|||||||
"matchUpdateTypes": ["patch"],
|
"matchUpdateTypes": ["patch"],
|
||||||
"groupName": "all patch updates",
|
"groupName": "all patch updates",
|
||||||
"groupSlug": "all-patch"
|
"groupSlug": "all-patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"matchPackageNames": ["python"],
|
||||||
|
"groupName": "python base image",
|
||||||
|
"groupSlug": "python",
|
||||||
|
"automerge": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Rolling/floating tags (streaming stack, nextcloud beta, kubectl latest) - never automerge, every bump is a manual review. Placed last so automerge:false wins over the shared digest/patch rule.",
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"matchPackageNames": [
|
||||||
|
"lscr.io/linuxserver/jellyfin",
|
||||||
|
"lscr.io/linuxserver/qbittorrent",
|
||||||
|
"lscr.io/linuxserver/sonarr",
|
||||||
|
"lscr.io/linuxserver/radarr",
|
||||||
|
"lscr.io/linuxserver/prowlarr",
|
||||||
|
"lscr.io/linuxserver/bazarr",
|
||||||
|
"ghcr.io/seerr-team/seerr",
|
||||||
|
"fallenbagel/jellyseerr",
|
||||||
|
"ghcr.io/lampac-nextgen/lampac",
|
||||||
|
"ghcr.io/nextcloud-releases/all-in-one",
|
||||||
|
"alpine/kubectl"
|
||||||
|
],
|
||||||
|
"groupName": "floating images - manual",
|
||||||
|
"groupSlug": "floating-manual",
|
||||||
|
"automerge": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
PUID=1000
|
||||||
|
PGID=1000
|
||||||
|
TZ=Europe/Berlin
|
||||||
Whitespace-only changes.
@@ -0,0 +1,133 @@
|
|||||||
|
services:
|
||||||
|
jellyfin:
|
||||||
|
image: lscr.io/linuxserver/jellyfin:version-12.1ubu2604
|
||||||
|
container_name: jellyfin
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
volumes:
|
||||||
|
- jellyfin-cfg:/config
|
||||||
|
- movies:/media/movies
|
||||||
|
- tv:/media/tv
|
||||||
|
devices:
|
||||||
|
- /dev/dri:/dev/dri
|
||||||
|
ports:
|
||||||
|
- "18096:8096"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
qbittorrent:
|
||||||
|
image: lscr.io/linuxserver/qbittorrent:5.2.4
|
||||||
|
container_name: qbittorrent
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
- WEBUI_PORT=8080
|
||||||
|
volumes:
|
||||||
|
- qbittorrent-cfg:/config
|
||||||
|
- downloads:/downloads
|
||||||
|
ports:
|
||||||
|
- "18180:8080"
|
||||||
|
- "6881:6881"
|
||||||
|
- "6881:6881/udp"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
sonarr:
|
||||||
|
image: lscr.io/linuxserver/sonarr:4.0.20
|
||||||
|
container_name: sonarr
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
volumes:
|
||||||
|
- sonarr-cfg:/config
|
||||||
|
- downloads:/downloads
|
||||||
|
- tv:/tv
|
||||||
|
ports:
|
||||||
|
- "18989:8989"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
radarr:
|
||||||
|
image: lscr.io/linuxserver/radarr:6.4.4
|
||||||
|
container_name: radarr
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
volumes:
|
||||||
|
- radarr-cfg:/config
|
||||||
|
- downloads:/downloads
|
||||||
|
- movies:/movies
|
||||||
|
ports:
|
||||||
|
- "17878:7878"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
prowlarr:
|
||||||
|
image: lscr.io/linuxserver/prowlarr:2.6.5
|
||||||
|
container_name: prowlarr
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
volumes:
|
||||||
|
- prowlarr-cfg:/config
|
||||||
|
ports:
|
||||||
|
- "19696:9696"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
jellyseerr:
|
||||||
|
image: fallenbagel/jellyseerr:latest
|
||||||
|
container_name: jellyseerr
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
volumes:
|
||||||
|
- jellyseerr-cfg:/app/config
|
||||||
|
ports:
|
||||||
|
- "15055:5055"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
bazarr:
|
||||||
|
image: lscr.io/linuxserver/bazarr:1.6.2
|
||||||
|
container_name: bazarr
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID:-1000}
|
||||||
|
- PGID=${PGID:-1000}
|
||||||
|
- TZ=${TZ:-Europe/Berlin}
|
||||||
|
volumes:
|
||||||
|
- bazarr-cfg:/config
|
||||||
|
- movies:/movies
|
||||||
|
- tv:/tv
|
||||||
|
ports:
|
||||||
|
- "16767:6767"
|
||||||
|
networks:
|
||||||
|
- streaming
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
jellyfin-cfg:
|
||||||
|
qbittorrent-cfg:
|
||||||
|
sonarr-cfg:
|
||||||
|
radarr-cfg:
|
||||||
|
prowlarr-cfg:
|
||||||
|
jellyseerr-cfg:
|
||||||
|
bazarr-cfg:
|
||||||
|
downloads:
|
||||||
|
movies:
|
||||||
|
tv:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
streaming:
|
||||||
|
name: streaming
|
||||||
Whitespace-only changes.
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: streaming
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: internal-wildcard-tls
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
dnsNames:
|
||||||
|
- "*.workstation.internal"
|
||||||
|
- "*.gigaforust.internal"
|
||||||
|
- workstation.internal
|
||||||
|
- gigaforust.internal
|
||||||
|
issuerRef:
|
||||||
|
name: internal-ca
|
||||||
|
kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: jellyfin-prod-tls
|
||||||
|
# namespace: streaming
|
||||||
|
# spec:
|
||||||
|
# secretName: jellyfin-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - jellyfin.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: qbittorrent-prod-tls
|
||||||
|
# namespace: streaming
|
||||||
|
# spec:
|
||||||
|
# secretName: qbittorrent-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - qbittorrent.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: sonarr-prod-tls
|
||||||
|
# namespace: streaming
|
||||||
|
# spec:
|
||||||
|
# secretName: sonarr-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - sonarr.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: radarr-prod-tls
|
||||||
|
# namespace: streaming
|
||||||
|
# spec:
|
||||||
|
# secretName: radarr-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - radarr.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: prowlarr-prod-tls
|
||||||
|
# namespace: streaming
|
||||||
|
# spec:
|
||||||
|
# secretName: prowlarr-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - prowlarr.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# ---
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: Certificate
|
||||||
|
# metadata:
|
||||||
|
# name: jellyseerr-prod-tls
|
||||||
|
# namespace: streaming
|
||||||
|
# spec:
|
||||||
|
# secretName: jellyseerr-prod-tls
|
||||||
|
# dnsNames:
|
||||||
|
# - jellyseerr.forust.xyz
|
||||||
|
# issuerRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# kind: ClusterIssuer
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: jellyfin
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 18096
|
||||||
|
targetPort: 18096
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: jellyfin
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: jellyfin
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 18096
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: qbittorrent
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 18180
|
||||||
|
targetPort: 18180
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: qbittorrent
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: qbittorrent
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 18180
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: sonarr
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 18989
|
||||||
|
targetPort: 18989
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: sonarr
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: sonarr
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 18989
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: radarr
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 17878
|
||||||
|
targetPort: 17878
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: radarr
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: radarr
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 17878
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: prowlarr
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 19696
|
||||||
|
targetPort: 19696
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: prowlarr
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: prowlarr
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 19696
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: jellyseerr
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 15055
|
||||||
|
targetPort: 15055
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: jellyseerr
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: jellyseerr
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 15055
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 16767
|
||||||
|
targetPort: 16767
|
||||||
|
---
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
kind: EndpointSlice
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
|
namespace: streaming
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: bazarr
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- port: 16767
|
||||||
|
protocol: TCP
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- "192.168.88.100"
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: jellyfin-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`jellyfin.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: jellyfin
|
||||||
|
port: 18096
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: qbittorrent-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`qbittorrent.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: qbittorrent
|
||||||
|
port: 18180
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: sonarr-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`sonarr.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: sonarr
|
||||||
|
port: 18989
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: radarr-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`radarr.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: radarr
|
||||||
|
port: 17878
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: prowlarr-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`prowlarr.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: prowlarr
|
||||||
|
port: 19696
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: jellyseerr-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`jellyseerr.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: jellyseerr
|
||||||
|
port: 15055
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: bazarr-local
|
||||||
|
namespace: streaming
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`bazarr.workstation.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: bazarr
|
||||||
|
port: 16767
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
termix:
|
termix:
|
||||||
image: ghcr.io/lukegus/termix:2.9.0
|
image: ghcr.io/lukegus/termix:2.9.1
|
||||||
container_name: termix
|
container_name: termix
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: termix
|
- name: termix
|
||||||
image: ghcr.io/lukegus/termix:2.9.0
|
image: ghcr.io/lukegus/termix:2.9.1
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: termix-config
|
name: termix-config
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
"""Session publication checks without Redis, the EDU website, or credentials."""
|
||||||
|
|
||||||
|
import importlib.util
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
SCRIPT = Path(__file__).resolve().parents[1] / 'edu_master/phpsessid-bot/bot.py'
|
||||||
|
spec = importlib.util.spec_from_file_location('session_keeper', SCRIPT)
|
||||||
|
bot = importlib.util.module_from_spec(spec)
|
||||||
|
with patch.dict(sys.modules, {'redis': Mock(), 'requests': Mock()}):
|
||||||
|
spec.loader.exec_module(bot)
|
||||||
|
|
||||||
|
|
||||||
|
class SessionKeeperTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.session = Mock()
|
||||||
|
self.session.get.return_value.status_code = 200
|
||||||
|
self.session.cookies.get.return_value = 'test-cookie'
|
||||||
|
self.redis = Mock()
|
||||||
|
self.touch = patch.object(bot, 'touch_success_file').start()
|
||||||
|
self.addCleanup(patch.stopall)
|
||||||
|
|
||||||
|
def test_verified_cookie_expires_and_is_not_logged(self):
|
||||||
|
with self.assertLogs(bot.logger, level='INFO') as logs:
|
||||||
|
self.assertTrue(bot.refresh_session(self.session, self.redis))
|
||||||
|
self.redis.set.assert_called_once_with('EDU_PHPSESSID', 'test-cookie', ex=bot.INTERVAL * 120)
|
||||||
|
self.touch.assert_called_once()
|
||||||
|
self.assertNotIn('test-cookie', '\n'.join(logs.output))
|
||||||
|
self.assertEqual(self.session.post.call_args.kwargs['timeout'], (10, 30))
|
||||||
|
self.assertEqual(self.session.get.call_args.kwargs['timeout'], (10, 30))
|
||||||
|
|
||||||
|
def test_redirect_does_not_publish(self):
|
||||||
|
self.session.get.return_value.status_code = 302
|
||||||
|
self.assertFalse(bot.refresh_session(self.session, self.redis))
|
||||||
|
self.redis.set.assert_not_called()
|
||||||
|
self.touch.assert_not_called()
|
||||||
|
|
||||||
|
def test_missing_cookie_does_not_mark_success(self):
|
||||||
|
self.session.cookies.get.return_value = None
|
||||||
|
self.assertFalse(bot.refresh_session(self.session, self.redis))
|
||||||
|
self.redis.set.assert_not_called()
|
||||||
|
self.touch.assert_not_called()
|
||||||
|
|
||||||
|
def test_redis_failure_does_not_mark_success(self):
|
||||||
|
self.redis.set.side_effect = OSError('redis unavailable')
|
||||||
|
with self.assertRaises(OSError):
|
||||||
|
bot.refresh_session(self.session, self.redis)
|
||||||
|
self.touch.assert_not_called()
|
||||||
|
|
||||||
|
def test_http_timeout_does_not_publish(self):
|
||||||
|
self.session.post.side_effect = TimeoutError('EDU unavailable')
|
||||||
|
with self.assertRaises(TimeoutError):
|
||||||
|
bot.refresh_session(self.session, self.redis)
|
||||||
|
self.redis.set.assert_not_called()
|
||||||
|
self.touch.assert_not_called()
|
||||||
|
|
||||||
|
def test_missing_credentials_fail_before_network_access(self):
|
||||||
|
with patch.object(bot, 'LOGIN', None), self.assertRaises(ValueError):
|
||||||
|
bot.main()
|
||||||
|
|
||||||
|
def test_nonpositive_interval_fails_before_network_access(self):
|
||||||
|
with (
|
||||||
|
patch.object(bot, 'LOGIN', 'test'),
|
||||||
|
patch.object(bot, 'PASSWORD', 'test'),
|
||||||
|
patch.object(bot, 'INTERVAL', 0),
|
||||||
|
self.assertRaises(ValueError),
|
||||||
|
):
|
||||||
|
bot.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -10,6 +10,8 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`traefik.forust.xyz`)
|
- match: Host(`traefik.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: security-chain@file
|
||||||
services:
|
services:
|
||||||
- name: api@internal
|
- name: api@internal
|
||||||
kind: TraefikService
|
kind: TraefikService
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ ports:
|
|||||||
exposedPort: 8080
|
exposedPort: 8080
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
expose:
|
expose:
|
||||||
default: false
|
default: true
|
||||||
http:
|
http:
|
||||||
aliasHeadersStrategy: delete
|
aliasHeadersStrategy: delete
|
||||||
ssh:
|
ssh:
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PrometheusRule
|
||||||
|
metadata:
|
||||||
|
name: uptime-kuma
|
||||||
|
namespace: uptime-kuma
|
||||||
|
labels:
|
||||||
|
release: prometheus-stack
|
||||||
|
spec:
|
||||||
|
groups:
|
||||||
|
- name: uptime_kuma.monitors
|
||||||
|
rules:
|
||||||
|
- alert: KumaMonitorDown
|
||||||
|
expr: |
|
||||||
|
monitor_status{monitor_type!="group"} == 0
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
annotations:
|
||||||
|
summary: "Uptime Kuma monitor down: {{ $labels.monitor_name }}"
|
||||||
|
description: "Uptime Kuma monitor {{ $labels.monitor_name }} ({{ $labels.monitor_url }}) is down for 5m. Check Uptime Kuma (https://uptime.forust.xyz) and the target service."
|
||||||
|
|
||||||
|
- alert: KumaScrapeDown
|
||||||
|
expr: |
|
||||||
|
absent(monitor_status) == 1
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
annotations:
|
||||||
|
summary: "Uptime Kuma metrics missing"
|
||||||
|
description: "uptime-kuma: no monitor_status series for 10m. Pod may be down, the uk1_ API key may have been rotated without updating uptime-kuma-secrets, or ServiceMonitor/Service broken. All Kuma monitors are unobserved."
|
||||||
|
|
||||||
|
- alert: KumaCertExpiring
|
||||||
|
expr: |
|
||||||
|
monitor_cert_days_remaining < 14
|
||||||
|
for: 1h
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "TLS cert expiring: {{ $labels.monitor_name }} ({{ $value }}d left)"
|
||||||
|
description: "Uptime Kuma monitor {{ $labels.monitor_name }} ({{ $labels.monitor_url }}) reports a TLS certificate with {{ $value }} days remaining. Check cert-manager Certificate for this host."
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: uptime-kuma-secrets
|
||||||
|
namespace: uptime-kuma
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
metrics-username: "uptime-kuma"
|
||||||
|
metrics-password: "REPLACE_ME"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: uptime-kuma
|
||||||
|
namespace: uptime-kuma
|
||||||
|
labels:
|
||||||
|
release: prometheus-stack
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: uptime-kuma
|
||||||
|
endpoints:
|
||||||
|
- port: http
|
||||||
|
path: /metrics
|
||||||
|
interval: 60s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
basicAuth:
|
||||||
|
username:
|
||||||
|
name: uptime-kuma-secrets
|
||||||
|
key: metrics-username
|
||||||
|
password:
|
||||||
|
name: uptime-kuma-secrets
|
||||||
|
key: metrics-password
|
||||||
@@ -3,11 +3,14 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
name: uptime-kuma-service
|
name: uptime-kuma-service
|
||||||
namespace: uptime-kuma
|
namespace: uptime-kuma
|
||||||
|
labels:
|
||||||
|
app: uptime-kuma
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: uptime-kuma
|
app: uptime-kuma
|
||||||
ports:
|
ports:
|
||||||
- port: 3001
|
- port: 3001
|
||||||
|
name: http
|
||||||
targetPort: 3001
|
targetPort: 3001
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
|
|||||||
Reference in new issue
Block a user