mirror of
https://github.com/morten-olsen/homelab-operator.git
synced 2026-02-08 01:36:28 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46e5ccaee8 |
16
.github/workflows/main.yml
vendored
16
.github/workflows/main.yml
vendored
@@ -71,23 +71,9 @@ jobs:
|
||||
environment: release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: create-release
|
||||
uses: release-drafter/release-drafter@v6
|
||||
- uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
config-name: release-drafter-config.yml
|
||||
publish: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||
asset_path: ./operator.yaml
|
||||
asset_name: operator.yaml
|
||||
asset_content_type: application/yaml
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -32,7 +32,3 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
|
||||
/data/
|
||||
|
||||
/cloudflare.yaml
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
3.13
|
||||
@@ -1,6 +1,6 @@
|
||||
FROM node:23-slim
|
||||
FROM node:23-alpine
|
||||
RUN corepack enable
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile --prod
|
||||
COPY . .
|
||||
CMD ["node", "src/index.ts"]
|
||||
CMD ["node", "src/index.ts"]
|
||||
14
Makefile
14
Makefile
@@ -1,14 +0,0 @@
|
||||
.PHONY: dev-recreate dev-destroy server-install
|
||||
|
||||
dev-destroy:
|
||||
colima delete -f
|
||||
|
||||
dev-recreate: dev-destroy
|
||||
colima start --network-address --kubernetes -m 8 --k3s-arg="--disable helm-controller,local-storage,traefik --docker" # --mount ${PWD}/data:/data:w
|
||||
flux install --components="source-controller,helm-controller"
|
||||
|
||||
setup-flux:
|
||||
flux install --components="source-controller,helm-controller"
|
||||
|
||||
server-install:
|
||||
curl -sfL https://get.k3s.io | sh -s - --disable traefik,local-storage,helm-controller
|
||||
282
README.md
282
README.md
@@ -0,0 +1,282 @@
|
||||
# homelab-operator
|
||||
|
||||
A Kubernetes operator designed for homelab environments that simplifies the
|
||||
management of PostgreSQL databases and Kubernetes secrets. Built with TypeScript
|
||||
and designed to run efficiently in resource-constrained environments.
|
||||
|
||||
## Features
|
||||
|
||||
- **PostgreSQL Database Management**: Automatically create and manage PostgreSQL
|
||||
databases and roles
|
||||
- **Secret Management**: Generate and manage Kubernetes secrets with
|
||||
configurable data
|
||||
- **Owner References**: Automatic cleanup when resources are deleted
|
||||
- **Status Tracking**: Comprehensive status conditions and error reporting
|
||||
- **Lightweight**: Minimal resource footprint suitable for homelab environments
|
||||
|
||||
## Architecture
|
||||
|
||||
The operator manages two main Custom Resource Definitions (CRDs):
|
||||
|
||||
### PostgresDatabase
|
||||
|
||||
Manages PostgreSQL databases and their associated roles:
|
||||
|
||||
- Creates a PostgreSQL role with a secure random password
|
||||
- Creates a database owned by that role
|
||||
- Generates a Kubernetes secret containing database credentials
|
||||
- Ensures proper cleanup through owner references
|
||||
|
||||
### SecretRequest
|
||||
|
||||
Generates Kubernetes secrets with configurable data:
|
||||
|
||||
- Supports custom secret names
|
||||
- Configurable data fields with various encodings
|
||||
- Automatic secret lifecycle management
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Kubernetes cluster (1.20+)
|
||||
- PostgreSQL instance accessible from the cluster
|
||||
- Helm 3.x (for chart-based installation)
|
||||
|
||||
### Using Helm Chart
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd homelab-operator
|
||||
```
|
||||
|
||||
2. Install using Helm:
|
||||
|
||||
```bash
|
||||
helm install homelab-operator ./chart \
|
||||
--set-string env.POSTGRES_HOST=<your-postgres-host> \
|
||||
--set-string env.POSTGRES_USER=<admin-user> \
|
||||
--set-string env.POSTGRES_PASSWORD=<admin-password>
|
||||
```
|
||||
|
||||
### Using kubectl
|
||||
|
||||
1. Build and push the Docker image:
|
||||
|
||||
```bash
|
||||
docker build -t your-registry/homelab-operator:latest .
|
||||
docker push your-registry/homelab-operator:latest
|
||||
```
|
||||
|
||||
2. Apply the Kubernetes manifests:
|
||||
|
||||
```bash
|
||||
kubectl apply -f chart/templates/
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The operator is configured through environment variables:
|
||||
|
||||
| Variable | Description | Required | Default |
|
||||
| ------------------- | ---------------------------------------- | -------- | ------- |
|
||||
| `POSTGRES_HOST` | PostgreSQL server hostname | Yes | - |
|
||||
| `POSTGRES_USER` | PostgreSQL admin username | Yes | - |
|
||||
| `POSTGRES_PASSWORD` | PostgreSQL admin password | Yes | - |
|
||||
| `POSTGRES_PORT` | PostgreSQL server port | No | 5432 |
|
||||
| `LOG_LEVEL` | Logging level (debug, info, warn, error) | No | info |
|
||||
|
||||
## Usage
|
||||
|
||||
### PostgreSQL Database
|
||||
|
||||
Create a PostgreSQL database with an associated role:
|
||||
|
||||
```yaml
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: PostgresDatabase
|
||||
metadata:
|
||||
name: my-app-db
|
||||
namespace: my-namespace
|
||||
spec: {}
|
||||
```
|
||||
|
||||
This will create:
|
||||
|
||||
- A PostgreSQL role named `my-app-db`
|
||||
- A PostgreSQL database named `my-namespace_my-app-db` owned by the role
|
||||
- A Kubernetes secret `postgres-database-my-app-db` containing:
|
||||
- `name`: Base64-encoded database name
|
||||
- `user`: Base64-encoded username
|
||||
- `password`: Base64-encoded password
|
||||
|
||||
### Secret Request
|
||||
|
||||
Generate a Kubernetes secret with custom data:
|
||||
|
||||
```yaml
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: SecretRequest
|
||||
metadata:
|
||||
name: my-secret
|
||||
namespace: my-namespace
|
||||
spec:
|
||||
secretName: app-config
|
||||
data:
|
||||
- key: api-key
|
||||
value: "my-api-key"
|
||||
encoding: base64
|
||||
- key: database-url
|
||||
value: "postgresql://user:pass@host:5432/db"
|
||||
- key: random-token
|
||||
length: 32
|
||||
chars: "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
```
|
||||
|
||||
### Accessing Created Resources
|
||||
|
||||
To retrieve database credentials:
|
||||
|
||||
```bash
|
||||
# Get the secret
|
||||
kubectl get secret postgres-database-my-app-db -o jsonpath='{.data.user}' | base64 -d
|
||||
kubectl get secret postgres-database-my-app-db -o jsonpath='{.data.password}' | base64 -d
|
||||
kubectl get secret postgres-database-my-app-db -o jsonpath='{.data.name}' | base64 -d
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Bun](https://bun.sh/) runtime
|
||||
- [pnpm](https://pnpm.io/) package manager
|
||||
- Docker (for building images)
|
||||
- Access to a Kubernetes cluster for testing
|
||||
|
||||
### Setup
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd homelab-operator
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Set up development environment:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your PostgreSQL connection details
|
||||
```
|
||||
|
||||
### Running Locally
|
||||
|
||||
For development, you can run the operator locally against a remote cluster:
|
||||
|
||||
```bash
|
||||
# Ensure kubectl is configured for your development cluster
|
||||
export KUBECONFIG=~/.kube/config
|
||||
|
||||
# Set PostgreSQL connection environment variables
|
||||
export POSTGRES_HOST=localhost
|
||||
export POSTGRES_USER=postgres
|
||||
export POSTGRES_PASSWORD=yourpassword
|
||||
|
||||
# Run the operator
|
||||
bun run src/index.ts
|
||||
```
|
||||
|
||||
### Development with Docker Compose
|
||||
|
||||
A development environment with PostgreSQL is provided:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yaml up -d
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
Build the Docker image:
|
||||
|
||||
```bash
|
||||
docker build -t homelab-operator:latest .
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# Run linting
|
||||
pnpm run test:lint
|
||||
|
||||
# Apply test resources
|
||||
kubectl apply -f test.yaml
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch: `git checkout -b feature/new-feature`
|
||||
3. Make your changes and add tests
|
||||
4. Run linting: `pnpm run test:lint`
|
||||
5. Commit your changes: `git commit -am 'Add new feature'`
|
||||
6. Push to the branch: `git push origin feature/new-feature`
|
||||
7. Submit a pull request
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
├── chart/ # Helm chart for deployment
|
||||
├── src/
|
||||
│ ├── crds/ # Custom Resource Definitions
|
||||
│ │ ├── postgres/ # PostgreSQL database management
|
||||
│ │ └── secrets/ # Secret generation
|
||||
│ ├── custom-resource/ # Base CRD framework
|
||||
│ ├── database/ # Database migrations
|
||||
│ ├── services/ # Core services
|
||||
│ │ ├── config/ # Configuration management
|
||||
│ │ ├── k8s.ts # Kubernetes API client
|
||||
│ │ ├── log/ # Logging service
|
||||
│ │ ├── postgres/ # PostgreSQL service
|
||||
│ │ └── secrets/ # Secret management
|
||||
│ └── utils/ # Utilities and constants
|
||||
├── Dockerfile # Container build configuration
|
||||
└── docker-compose.dev.yaml # Development environment
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the LICENSE file for
|
||||
details.
|
||||
|
||||
## Support
|
||||
|
||||
For support and questions:
|
||||
|
||||
- Create an issue in the GitHub repository
|
||||
- Check existing issues for similar problems
|
||||
- Review the logs using `kubectl logs -l app=homelab-operator`
|
||||
|
||||
## Status Monitoring
|
||||
|
||||
Monitor the operator status:
|
||||
|
||||
```bash
|
||||
# Check operator logs
|
||||
kubectl logs -l app=homelab-operator -f
|
||||
|
||||
# Check CRD status
|
||||
kubectl get postgresdatabases
|
||||
kubectl get secretrequests
|
||||
|
||||
# Describe resources for detailed status
|
||||
kubectl describe postgresdatabase my-app-db
|
||||
kubectl describe secretrequest my-secret
|
||||
```
|
||||
|
||||
14
chart/templates/clusterrole.yaml
Normal file
14
chart/templates/clusterrole.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "homelab-operator.fullname" . }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "watch", "list"]
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs: ["get", "watch", "list", "patch"]
|
||||
- apiGroups: ["apiextensions.k8s.io"]
|
||||
resources: ["customresourcedefinitions"]
|
||||
verbs: ["get", "create", "replace"]
|
||||
@@ -33,14 +33,6 @@ spec:
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data-volumes
|
||||
mountPath: {{ .Values.storage.path }}
|
||||
volumes:
|
||||
- name: data-volumes
|
||||
hostPath:
|
||||
path: {{ .Values.storage.path }}
|
||||
type: DirectoryOrCreate
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
@@ -6,17 +6,11 @@ image:
|
||||
repository: ghcr.io/morten-olsen/homelab-operator
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: main
|
||||
tag: ""
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ''
|
||||
fullnameOverride: ''
|
||||
|
||||
storage:
|
||||
path: /data/volumes
|
||||
reclaimPolicy: Retain
|
||||
allowVolumeExpansion: false
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
@@ -25,7 +19,7 @@ serviceAccount:
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ''
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: audiobookshelf
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
redirectUris:
|
||||
- path: /audiobookshelf/auth/openid/callback
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
matchingMode: strict
|
||||
- path: /audiobookshelf/auth/openid/mobile-redirect
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
matchingMode: strict
|
||||
@@ -1,52 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
|
||||
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
volumeMounts:
|
||||
- mountPath: /config
|
||||
name: config
|
||||
- mountPath: /metadata
|
||||
name: metadata
|
||||
- mountPath: /audiobooks
|
||||
name: audiobooks
|
||||
- mountPath: /podcasts
|
||||
name: podcasts
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-config'
|
||||
- name: metadata
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-metadata'
|
||||
- name: audiobooks
|
||||
persistentVolumeClaim:
|
||||
claimName: books
|
||||
- name: podcasts
|
||||
persistentVolumeClaim:
|
||||
claimName: podcasts
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: ExternalHttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,24 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-config'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
|
||||
---
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-metadata'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,7 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
image:
|
||||
repository: ghcr.io/advplyr/audiobookshelf
|
||||
tag: 2.26.1
|
||||
pullPolicy: IfNotPresent
|
||||
subdomain: audiobookshelf
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: ByteStash
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-headless'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: 5000
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: HttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
redirectUris:
|
||||
- path: /api/auth/oidc/callback
|
||||
subdomain: bytestash
|
||||
matchingMode: strict
|
||||
@@ -1,55 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
serviceName: '{{ .Release.Name }}-headless'
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: ghcr.io/jordan-dalby/bytestash:latest
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
name: http
|
||||
env:
|
||||
- name: ALLOW_NEW_ACCOUNTS
|
||||
value: 'true'
|
||||
- name: DISABLE_INTERNAL_ACCOUNTS
|
||||
value: 'true'
|
||||
- name: OIDC_ENABLED
|
||||
value: 'true'
|
||||
- name: OIDC_DISPLAY_NAME
|
||||
value: OIDC
|
||||
- name: OIDC_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: clientId
|
||||
- name: OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: clientSecret
|
||||
- name: OIDC_ISSUER_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: configuration
|
||||
|
||||
volumeMounts:
|
||||
- mountPath: /data/snippets
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-data'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: ExternalHttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,11 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-data'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 5000
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,3 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
subdomain: bytestash
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: Jellyfin
|
||||
@@ -1 +0,0 @@
|
||||
https://www.authelia.com/integration/openid-connect/clients/jellyfin/
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.environment }}'
|
||||
redirectUris:
|
||||
- path: /sso/OID/redirect/Authentik
|
||||
subdomain: '{{ .Values.globals.subdomain }}'
|
||||
matchingMode: strict
|
||||
@@ -1,11 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-config'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.environment }}'
|
||||
@@ -1,52 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
|
||||
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8096
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
volumeMounts:
|
||||
- mountPath: /config
|
||||
name: config
|
||||
- mountPath: /media/movies
|
||||
name: movies
|
||||
- mountPath: /media/tv-shows
|
||||
name: tvshows
|
||||
- mountPath: /media/music
|
||||
name: music
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-config'
|
||||
- name: movies
|
||||
persistentVolumeClaim:
|
||||
claimName: movies
|
||||
- name: tvshows
|
||||
persistentVolumeClaim:
|
||||
claimName: tvshows
|
||||
- name: music
|
||||
persistentVolumeClaim:
|
||||
claimName: music
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: ExternalHttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8096
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,7 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
image:
|
||||
repository: docker.io/jellyfin/jellyfin
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
subdomain: jellyfin
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: ByteStash
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
redirectUris:
|
||||
- path: /api/auth/oidc/callback
|
||||
subdomain: bytestash
|
||||
matchingMode: strict
|
||||
@@ -1,55 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
serviceName: '{{ .Release.Name }}-headless'
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: ghcr.io/miniflux/miniflux:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
env:
|
||||
- name: ALLOW_NEW_ACCOUNTS
|
||||
value: 'true'
|
||||
- name: DISABLE_INTERNAL_ACCOUNTS
|
||||
value: 'true'
|
||||
- name: OIDC_ENABLED
|
||||
value: 'true'
|
||||
- name: OIDC_DISPLAY_NAME
|
||||
value: OIDC
|
||||
- name: OIDC_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: clientId
|
||||
- name: OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: clientSecret
|
||||
- name: OIDC_ISSUER_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: configuration
|
||||
|
||||
volumeMounts:
|
||||
- mountPath: /data/snippets
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-data'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: ExternalHttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,11 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-data'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,3 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
subdomain: miniflux
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: Jellyfin
|
||||
@@ -1,6 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: PostgresDatabase
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
@@ -1,73 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
|
||||
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 5678
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
volumeMounts:
|
||||
- mountPath: /home/node/.n8n
|
||||
name: data
|
||||
env:
|
||||
- name: TZ
|
||||
value: '{{ .Values.globals.timezone }}'
|
||||
- name: GENERIC_TIMEZONE
|
||||
value: '{{ .Values.globals.timezone }}'
|
||||
- name: N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS
|
||||
value: 'true'
|
||||
- name: N8N_RUNNERS_ENABLED
|
||||
value: 'true'
|
||||
- name: DB_TYPE
|
||||
value: postgresdb
|
||||
- name: DB_POSTGRESDB_DATABASE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-pg-connection'
|
||||
key: database
|
||||
- name: DB_POSTGRESDB_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-pg-connection'
|
||||
key: host
|
||||
- name: DB_POSTGRESDB_PORT
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-pg-connection'
|
||||
key: port
|
||||
- name: DB_POSTGRESDB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-pg-connection'
|
||||
key: user
|
||||
- name: DB_POSTGRESDB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-pg-connection'
|
||||
key: password
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-data'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: ExternalHttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,11 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-data'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 5678
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,8 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
timezone: Europe/Amsterdam
|
||||
image:
|
||||
repository: docker.n8n.io/n8nio/n8n
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
subdomain: n8n
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: ollama
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
redirectUris:
|
||||
- path: /oauth/oidc/callback
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
matchingMode: strict
|
||||
@@ -1,38 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
|
||||
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 11434
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
volumeMounts:
|
||||
- mountPath: /root/.ollama
|
||||
name: data
|
||||
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-data'
|
||||
@@ -1,11 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-data'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 11434
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,7 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
image:
|
||||
repository: ollama/ollama
|
||||
tag: 0.11.8
|
||||
pullPolicy: IfNotPresent
|
||||
subdomain: openwebui
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: openwebui
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
redirectUris:
|
||||
- path: /oauth/oidc/callback
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
matchingMode: strict
|
||||
@@ -1,70 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: '{{ .Release.Name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ .Release.Name }}'
|
||||
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
|
||||
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
volumeMounts:
|
||||
- mountPath: /app/backend/data
|
||||
name: data
|
||||
env:
|
||||
- name: ENABLE_SIGNUP
|
||||
value: 'false'
|
||||
- name: WEBUI_URL # TODO: remove
|
||||
value: https://openwebui.olsen.cloud
|
||||
- name: ENABLE_OAUTH_PERSISTENT_CONFIG
|
||||
value: 'false'
|
||||
- name: ENABLE_OAUTH_SIGNUP
|
||||
value: 'true'
|
||||
- name: OAUTH_MERGE_ACCOUNTS_BY_EMAIL
|
||||
value: 'true'
|
||||
- name: OAUTH_PROVIDER_NAME
|
||||
value: authentik
|
||||
- name: OPENID_PROVIDER_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: configuration
|
||||
- name: OAUTH_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: clientId
|
||||
- name: OAUTH_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: '{{ .Release.Name }}-client'
|
||||
key: clientSecret
|
||||
- name: ENABLE_LOGIN_FORM
|
||||
value: 'false'
|
||||
- name: OPENID_REDIRECT
|
||||
value: https://openwebui.olsen.cloud/oauth/oidc/callback
|
||||
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: '{{ .Release.Name }}-data'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: ExternalHttpService
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
spec:
|
||||
environment: '{{ .Values.globals.environment }}'
|
||||
subdomain: '{{ .Values.subdomain }}'
|
||||
destination:
|
||||
host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,11 +0,0 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}-data'
|
||||
spec:
|
||||
accessModes:
|
||||
- 'ReadWriteOnce'
|
||||
resources:
|
||||
requests:
|
||||
storage: '1Gi'
|
||||
storageClassName: '{{ .Values.globals.environment }}'
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: '{{ .Release.Name }}'
|
||||
labels:
|
||||
app: '{{ .Release.Name }}'
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: '{{ .Release.Name }}'
|
||||
@@ -1,7 +0,0 @@
|
||||
globals:
|
||||
environment: prod
|
||||
image:
|
||||
repository: ghcr.io/open-webui/open-webui
|
||||
tag: main
|
||||
pullPolicy: IfNotPresent
|
||||
subdomain: openwebui
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: {{ include "homelab-operator.fullname" . }}-local-path
|
||||
labels:
|
||||
{{- include "homelab-operator.labels" . | nindent 4 }}
|
||||
provisioner: reuse-local-path-provisioner
|
||||
parameters:
|
||||
# Add any provisioner-specific parameters here
|
||||
reclaimPolicy: {{ .Values.storage.reclaimPolicy | default "Retain" }}
|
||||
allowVolumeExpansion: {{ .Values.storage.allowVolumeExpansion | default false }}
|
||||
volumeBindingMode: {{ .Values.storage.volumeBindingMode | default "WaitForFirstConsumer" }}
|
||||
@@ -1,32 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "homelab-operator.fullname" . }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "watch", "list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["persistentvolumes"]
|
||||
verbs: ["get", "list", "watch", "create", "delete", "patch", "update"]
|
||||
- apiGroups: [""]
|
||||
resources: ["persistentvolumeclaims"]
|
||||
verbs: ["get", "list", "watch", "update", "patch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["persistentvolumeclaims/status"]
|
||||
verbs: ["update", "patch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["events"]
|
||||
verbs: ["create", "patch"]
|
||||
- apiGroups: ["storage.k8s.io"]
|
||||
resources: ["storageclasses"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs: ["get", "watch", "list", "patch", "create", "update", "replace"]
|
||||
- apiGroups: ["apiextensions.k8s.io"]
|
||||
resources: ["customresourcedefinitions"]
|
||||
verbs: ["get", "create", "update", "replace", "patch"]
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: root
|
||||
@@ -1,33 +0,0 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: homelab-apps
|
||||
namespace: '{{ .Values.env }}-argo'
|
||||
spec:
|
||||
generators:
|
||||
- git:
|
||||
repoURL: '{{ .Values.repo }}'
|
||||
revision: '{{ .Values.ref }}'
|
||||
directories:
|
||||
- path: charts/apps/*
|
||||
include: '.*'
|
||||
exclude: '.*.disabled'
|
||||
template:
|
||||
metadata:
|
||||
name: '{{`{{path.basename}}`}}'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: '{{ .Values.repo }}'
|
||||
targetRevision: '{{ .Values.ref }}'
|
||||
path: charts/apps/{{`{{path.basename}}`}}
|
||||
helm:
|
||||
values: |
|
||||
globals: {{ .Values.globals | toYaml | nindent 14 }}
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: '{{ .Values.globals.env }}'
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
@@ -1,21 +0,0 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: homelab-root
|
||||
namespace: '{{ .Values.globals.env }}-argo'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: '{{ .Values.repo }}'
|
||||
targetRevision: '{{ .Values.ref }}'
|
||||
path: charts/root
|
||||
helm:
|
||||
valueFiles:
|
||||
- values.yaml
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: '{{ .Values.globals.env }}-argo'
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
@@ -1,4 +0,0 @@
|
||||
globals:
|
||||
env: prod
|
||||
repo: https://github.com/morten-olsen/homelab-operator.git
|
||||
ref: HEAD
|
||||
@@ -1,3 +0,0 @@
|
||||
apiVersion: v2
|
||||
version: 1.0.0
|
||||
name: Resources
|
||||
@@ -1,28 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: books
|
||||
labels:
|
||||
type: nfs
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: manual-books
|
||||
nfs:
|
||||
path: '{{ .Values.books.path }}'
|
||||
server: '{{ .Values.host }}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: books
|
||||
spec:
|
||||
storageClassName: manual-books
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -1,28 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: movies
|
||||
labels:
|
||||
type: nfs
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: manual-movies
|
||||
nfs:
|
||||
path: '{{ .Values.movies.path }}'
|
||||
server: '{{ .Values.host }}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: movies
|
||||
spec:
|
||||
storageClassName: manual-movies
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -1,28 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: music
|
||||
labels:
|
||||
type: nfs
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: manual-music
|
||||
nfs:
|
||||
path: '{{ .Values.music.path }}'
|
||||
server: '{{ .Values.host }}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: music
|
||||
spec:
|
||||
storageClassName: manual-music
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -1,28 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: podcasts
|
||||
labels:
|
||||
type: nfs
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: manual-podcasts
|
||||
nfs:
|
||||
path: '{{ .Values.podcasts.path }}'
|
||||
server: '{{ .Values.host }}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: podcasts
|
||||
spec:
|
||||
storageClassName: manual-podcasts
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -1,28 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: tvshows
|
||||
labels:
|
||||
type: nfs
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: manual-tvshows
|
||||
nfs:
|
||||
path: '{{ .Values.tvshows.path }}'
|
||||
server: '{{ .Values.host }}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: tvshows
|
||||
spec:
|
||||
storageClassName: manual-tvshows
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -1,11 +0,0 @@
|
||||
host: 192.168.20.106
|
||||
movies:
|
||||
path: /mnt/HDD/Movies
|
||||
tvshows:
|
||||
path: /mnt/HDD/TV-Shows
|
||||
music:
|
||||
path: /mnt/HDD/Music2
|
||||
books:
|
||||
path: /mnt/HDD/Books
|
||||
podcasts:
|
||||
path: /mnt/HDD/Podcasts
|
||||
12
docker-compose.dev.yaml
Normal file
12
docker-compose.dev.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
name: homelab
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17
|
||||
ports:
|
||||
- 5432:5432
|
||||
environment:
|
||||
POSTGRES_USER: $POSTGRES_USER
|
||||
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
volumes:
|
||||
- $PWD/.data/local/postgres:/var/lib/postgresql/data
|
||||
@@ -46,6 +46,6 @@ export default tseslint.config(
|
||||
},
|
||||
...compat.extends('plugin:prettier/recommended'),
|
||||
{
|
||||
ignores: ['**/node_modules/', '**/dist/', '**/.turbo/', '**/generated/', '**/clients/*.types.ts'],
|
||||
ignores: ['**/node_modules/', '**/dist/', '**/.turbo/', '**/generated/'],
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: ServiceEntry
|
||||
metadata:
|
||||
name: dev-authentik-override
|
||||
namespace: dev
|
||||
spec:
|
||||
hosts:
|
||||
- authentik.mortenolsen.nett
|
||||
ports:
|
||||
- number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
- number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
location: MESH_EXTERNAL
|
||||
resolution: STATIC
|
||||
endpoints:
|
||||
- address: 1.1.1.1
|
||||
ports:
|
||||
https: 443
|
||||
http: 80
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: OidcClient
|
||||
metadata:
|
||||
name: test-client
|
||||
spec:
|
||||
environment: dev
|
||||
redirectUris:
|
||||
- url: https://localhost:3000/api/v1/authentik/oauth2/callback
|
||||
matchingMode: strict
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: dev
|
||||
---
|
||||
apiVersion: homelab.mortenolsen.pro/v1
|
||||
kind: Environment
|
||||
metadata:
|
||||
name: prod
|
||||
spec:
|
||||
domain: olsen.cloud
|
||||
networkIp: 192.168.20.180
|
||||
tls:
|
||||
issuer: lets-encrypt-prod
|
||||
@@ -1,39 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: example-pvc
|
||||
namespace: default
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: homelab-operator-local-path
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: example-pod
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: example-container
|
||||
image: alpine
|
||||
command: ["/bin/sh", "-c", "sleep infinity"]
|
||||
volumeMounts:
|
||||
- name: example-volume
|
||||
mountPath: /data
|
||||
resources:
|
||||
limits:
|
||||
memory: 100Mi
|
||||
cpu: "0.1"
|
||||
requests:
|
||||
memory: 50Mi
|
||||
cpu: "0.05"
|
||||
volumes:
|
||||
- name: example-volume
|
||||
persistentVolumeClaim:
|
||||
claimName: example-pvc
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: ServiceEntry
|
||||
metadata:
|
||||
name: test-example-com
|
||||
namespace: dev
|
||||
spec:
|
||||
hosts:
|
||||
- authentik.one.dev.olsen.cloud
|
||||
# (the address field is optional if you use 'resolution: DNS')
|
||||
ports:
|
||||
- number: 80
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
resolution: DNS
|
||||
@@ -1,35 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: homelab
|
||||
|
||||
---
|
||||
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: homelab
|
||||
namespace: homelab
|
||||
spec:
|
||||
interval: 60m
|
||||
url: https://github.com/morten-olsen/homelab-operator
|
||||
ref:
|
||||
branch: main
|
||||
|
||||
---
|
||||
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: operator
|
||||
namespace: homelab
|
||||
spec:
|
||||
releaseName: operator
|
||||
interval: 60m
|
||||
chart:
|
||||
spec:
|
||||
chart: charts/operator
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: homelab
|
||||
namespace: homelab
|
||||
31
package.json
31
package.json
@@ -4,14 +4,15 @@
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"nodemon": "^3.1.10",
|
||||
"@eslint/eslintrc": "3.3.1",
|
||||
"@eslint/js": "9.32.0",
|
||||
"@types/deep-equal": "^1.0.4",
|
||||
"@pnpm/find-workspace-packages": "6.0.9",
|
||||
"eslint": "9.32.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-prettier": "5.5.3",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"prettier": "3.6.2",
|
||||
"typescript": "5.8.3",
|
||||
"typescript-eslint": "8.38.0"
|
||||
@@ -20,37 +21,17 @@
|
||||
"typescript": "^5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@goauthentik/api": "2025.6.3-1751754396",
|
||||
"@kubernetes/client-node": "^1.3.0",
|
||||
"cloudflare": "^4.5.0",
|
||||
"cron": "^4.3.3",
|
||||
"debounce": "^2.2.0",
|
||||
"deep-equal": "^2.2.3",
|
||||
"dotenv": "^17.2.1",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"execa": "^9.6.0",
|
||||
"@sinclair/typebox": "^0.34.38",
|
||||
"knex": "^3.1.0",
|
||||
"p-queue": "^8.1.0",
|
||||
"p-retry": "^6.2.1",
|
||||
"pg": "^8.16.3",
|
||||
"sqlite3": "^5.1.7",
|
||||
"yaml": "^2.8.0",
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"imports": {
|
||||
"#services/*": "./src/services/*",
|
||||
"#resources/*": "./src/resources/*",
|
||||
"#bootstrap/*": "./src/bootstrap/*",
|
||||
"#utils/*": "./src/utils/*"
|
||||
"sqlite3": "^5.1.7"
|
||||
},
|
||||
"packageManager": "pnpm@10.6.0",
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"sqlite3"
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"@kubernetes/client-node": "patches/@kubernetes__client-node.patch"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo 'No tests'",
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
diff --git a/dist/gen/models/ObjectSerializer.js b/dist/gen/models/ObjectSerializer.js
|
||||
index 1d798b6a2d7c059165d1df9fbb77b89a8317ebca..c8bacfdc95be0f0146c6505f89a9372e013afea4 100644
|
||||
--- a/dist/gen/models/ObjectSerializer.js
|
||||
+++ b/dist/gen/models/ObjectSerializer.js
|
||||
@@ -2216,6 +2216,9 @@ export class ObjectSerializer {
|
||||
return transformedData;
|
||||
}
|
||||
else if (type === "Date") {
|
||||
+ if (typeof data === "string") {
|
||||
+ return data;
|
||||
+ }
|
||||
if (format == "date") {
|
||||
let month = data.getMonth() + 1;
|
||||
month = month < 10 ? "0" + month.toString() : month.toString();
|
||||
1638
pnpm-lock.yaml
generated
1638
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
8
postgres-database.ts
Normal file
8
postgres-database.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: 'homelab.mortenolsen.pro/v1';
|
||||
kind: 'PostgresDatabase';
|
||||
name: 'test2';
|
||||
namespace: 'playground';
|
||||
foo: 'bar';
|
||||
foo: 'bar';
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
[project]
|
||||
name = "homelab-operator"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"kubediagrams>=0.5.0",
|
||||
]
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { compile } from 'json-schema-to-typescript';
|
||||
|
||||
import { K8sService } from '../src/services/k8s/k8s.ts';
|
||||
import { Services } from '../src/utils/service.ts';
|
||||
|
||||
const services = new Services();
|
||||
const k8s = services.get(K8sService);
|
||||
|
||||
const manifests = await k8s.extensionsApi.listCustomResourceDefinition();
|
||||
const root = join(import.meta.dirname, '..', 'src', '__generated__', 'resources');
|
||||
|
||||
await mkdir(root, { recursive: true });
|
||||
|
||||
const firstUpsercase = (input: string) => {
|
||||
const [first, ...rest] = input.split('');
|
||||
return [first.toUpperCase(), ...rest].join('');
|
||||
};
|
||||
|
||||
for (const manifest of manifests.items) {
|
||||
for (const version of manifest.spec.versions) {
|
||||
try {
|
||||
const schema = version.schema?.openAPIV3Schema;
|
||||
if (!schema) {
|
||||
continue;
|
||||
}
|
||||
const cleanedSchema = JSON.parse(JSON.stringify(schema));
|
||||
const kind = manifest.spec.names.kind;
|
||||
const typeName = `K8S${kind}${firstUpsercase(version.name)}`;
|
||||
const jsonLocation = join(root, `${typeName}.json`);
|
||||
await writeFile(jsonLocation, JSON.stringify(schema, null, 2));
|
||||
const file = await compile(cleanedSchema, typeName, {
|
||||
declareExternallyReferenced: true,
|
||||
additionalProperties: false,
|
||||
$refOptions: {
|
||||
continueOnError: true,
|
||||
},
|
||||
});
|
||||
const fileLocation = join(root, `${typeName}.ts`);
|
||||
await writeFile(fileLocation, file, 'utf8');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.error(`${manifest.metadata?.name} ${version.name} failed`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
apiVersion: skaffold/v4beta7
|
||||
kind: Config
|
||||
metadata:
|
||||
name: homelab-operator
|
||||
|
||||
build:
|
||||
cluster: {}
|
||||
artifacts:
|
||||
- image: homelaboperator
|
||||
context: .
|
||||
docker:
|
||||
dockerfile: Dockerfile
|
||||
|
||||
manifests:
|
||||
helm:
|
||||
releases:
|
||||
- name: homelab-operator
|
||||
chartPath: charts/operator
|
||||
setValueTemplates:
|
||||
image.repository: '{{.IMAGE_REPO_homelaboperator}}'
|
||||
image.tag: '{{.IMAGE_TAG_homelaboperator}}'
|
||||
|
||||
deploy:
|
||||
# Use kubectl to apply the manifests.
|
||||
kubectl: {}
|
||||
31
src/__generated__/resources/K8SAddonV1.json
generated
31
src/__generated__/resources/K8SAddonV1.json
generated
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"description": "Addon is used to track application of a manifest file on disk. It mostly exists so that the wrangler DesiredSet\nApply controller has an object to track as the owner, and ensure that all created resources are tracked when the\nmanifest is modified or removed.",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Spec provides information about the on-disk manifest backing this resource.",
|
||||
"properties": {
|
||||
"checksum": {
|
||||
"description": "Checksum is the SHA256 checksum of the most recently successfully applied manifest file.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"description": "Source is the Path on disk to the manifest file that this Addon tracks.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
43
src/__generated__/resources/K8SAddonV1.ts
generated
43
src/__generated__/resources/K8SAddonV1.ts
generated
@@ -1,43 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by json-schema-to-typescript.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
||||
* and run json-schema-to-typescript to regenerate this file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Addon is used to track application of a manifest file on disk. It mostly exists so that the wrangler DesiredSet
|
||||
* Apply controller has an object to track as the owner, and ensure that all created resources are tracked when the
|
||||
* manifest is modified or removed.
|
||||
*/
|
||||
export interface K8SAddonV1 {
|
||||
/**
|
||||
* APIVersion defines the versioned schema of this representation of an object.
|
||||
* Servers should convert recognized schemas to the latest internal value, and
|
||||
* may reject unrecognized values.
|
||||
* More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
*/
|
||||
apiVersion?: string;
|
||||
/**
|
||||
* Kind is a string value representing the REST resource this object represents.
|
||||
* Servers may infer this from the endpoint the client submits requests to.
|
||||
* Cannot be updated.
|
||||
* In CamelCase.
|
||||
* More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
*/
|
||||
kind?: string;
|
||||
metadata?: {};
|
||||
/**
|
||||
* Spec provides information about the on-disk manifest backing this resource.
|
||||
*/
|
||||
spec?: {
|
||||
/**
|
||||
* Checksum is the SHA256 checksum of the most recently successfully applied manifest file.
|
||||
*/
|
||||
checksum?: string;
|
||||
/**
|
||||
* Source is the Path on disk to the manifest file that this Addon tracks.
|
||||
*/
|
||||
source?: string;
|
||||
};
|
||||
}
|
||||
376
src/__generated__/resources/K8SAppProjectV1alpha1.json
generated
376
src/__generated__/resources/K8SAppProjectV1alpha1.json
generated
@@ -1,376 +0,0 @@
|
||||
{
|
||||
"description": "AppProject provides a logical grouping of applications, providing controls for:\n* where the apps may deploy to (cluster whitelist)\n* what may be deployed (repository whitelist, resource whitelist/blacklist)\n* who can access these applications (roles, OIDC group claims bindings)\n* and what they can do (RBAC policies)\n* automation access to these roles (JWT tokens)",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"spec": {
|
||||
"description": "AppProjectSpec is the specification of an AppProject",
|
||||
"properties": {
|
||||
"clusterResourceBlacklist": {
|
||||
"description": "ClusterResourceBlacklist contains list of blacklisted cluster level resources",
|
||||
"items": {
|
||||
"description": "GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying\nconcepts during lookup stages without having partially valid types",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"clusterResourceWhitelist": {
|
||||
"description": "ClusterResourceWhitelist contains list of whitelisted cluster level resources",
|
||||
"items": {
|
||||
"description": "GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying\nconcepts during lookup stages without having partially valid types",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"description": {
|
||||
"description": "Description contains optional project description",
|
||||
"type": "string"
|
||||
},
|
||||
"destinationServiceAccounts": {
|
||||
"description": "DestinationServiceAccounts holds information about the service accounts to be impersonated for the application sync operation for each destination.",
|
||||
"items": {
|
||||
"description": "ApplicationDestinationServiceAccount holds information about the service account to be impersonated for the application sync operation.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"defaultServiceAccount",
|
||||
"server"
|
||||
],
|
||||
"properties": {
|
||||
"defaultServiceAccount": {
|
||||
"description": "DefaultServiceAccount to be used for impersonation during the sync operation",
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"description": "Namespace specifies the target namespace for the application's resources.",
|
||||
"type": "string"
|
||||
},
|
||||
"server": {
|
||||
"description": "Server specifies the URL of the target cluster's Kubernetes control plane API.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"destinations": {
|
||||
"description": "Destinations contains list of destinations available for deployment",
|
||||
"items": {
|
||||
"description": "ApplicationDestination holds information about the application's destination",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set.",
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"description": "Namespace specifies the target namespace for the application's resources.\nThe namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace",
|
||||
"type": "string"
|
||||
},
|
||||
"server": {
|
||||
"description": "Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"namespaceResourceBlacklist": {
|
||||
"description": "NamespaceResourceBlacklist contains list of blacklisted namespace level resources",
|
||||
"items": {
|
||||
"description": "GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying\nconcepts during lookup stages without having partially valid types",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"namespaceResourceWhitelist": {
|
||||
"description": "NamespaceResourceWhitelist contains list of whitelisted namespace level resources",
|
||||
"items": {
|
||||
"description": "GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying\nconcepts during lookup stages without having partially valid types",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"orphanedResources": {
|
||||
"description": "OrphanedResources specifies if controller should monitor orphaned resources of apps in this project",
|
||||
"properties": {
|
||||
"ignore": {
|
||||
"description": "Ignore contains a list of resources that are to be excluded from orphaned resources monitoring",
|
||||
"items": {
|
||||
"description": "OrphanedResourceKey is a reference to a resource to be ignored from",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"warn": {
|
||||
"description": "Warn indicates if warning condition should be created for apps which have orphaned resources",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"permitOnlyProjectScopedClusters": {
|
||||
"description": "PermitOnlyProjectScopedClusters determines whether destinations can only reference clusters which are project-scoped",
|
||||
"type": "boolean"
|
||||
},
|
||||
"roles": {
|
||||
"description": "Roles are user defined RBAC roles associated with this project",
|
||||
"items": {
|
||||
"description": "ProjectRole represents a role that has access to a project",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"description": "Description is a description of the role",
|
||||
"type": "string"
|
||||
},
|
||||
"groups": {
|
||||
"description": "Groups are a list of OIDC group claims bound to this role",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"jwtTokens": {
|
||||
"description": "JWTTokens are a list of generated JWT tokens bound to this role",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "JWTToken holds the issuedAt and expiresAt values of a token",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iat"
|
||||
],
|
||||
"properties": {
|
||||
"exp": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"iat": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"description": "Name is a name for this role",
|
||||
"type": "string"
|
||||
},
|
||||
"policies": {
|
||||
"description": "Policies Stores a list of casbin formatted strings that define access policies for the role in the project",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"signatureKeys": {
|
||||
"description": "SignatureKeys contains a list of PGP key IDs that commits in Git must be signed with in order to be allowed for sync",
|
||||
"items": {
|
||||
"description": "SignatureKey is the specification of a key required to verify commit signatures with",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"keyID"
|
||||
],
|
||||
"properties": {
|
||||
"keyID": {
|
||||
"description": "The ID of the key in hexadecimal notation",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"sourceNamespaces": {
|
||||
"description": "SourceNamespaces defines the namespaces application resources are allowed to be created in",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"sourceRepos": {
|
||||
"description": "SourceRepos contains list of repository URLs which can be used for deployment",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"syncWindows": {
|
||||
"description": "SyncWindows controls when syncs can be run for apps in this project",
|
||||
"items": {
|
||||
"description": "SyncWindow contains the kind, time, duration and attributes that are used to assign the syncWindows to apps",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"andOperator": {
|
||||
"description": "UseAndOperator use AND operator for matching applications, namespaces and clusters instead of the default OR operator",
|
||||
"type": "boolean"
|
||||
},
|
||||
"applications": {
|
||||
"description": "Applications contains a list of applications that the window will apply to",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"clusters": {
|
||||
"description": "Clusters contains a list of clusters that the window will apply to",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"duration": {
|
||||
"description": "Duration is the amount of time the sync window will be open",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind defines if the window allows or blocks syncs",
|
||||
"type": "string"
|
||||
},
|
||||
"manualSync": {
|
||||
"description": "ManualSync enables manual syncs when they would otherwise be blocked",
|
||||
"type": "boolean"
|
||||
},
|
||||
"namespaces": {
|
||||
"description": "Namespaces contains a list of namespaces that the window will apply to",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"description": "Schedule is the time the window will begin, specified in cron format",
|
||||
"type": "string"
|
||||
},
|
||||
"timeZone": {
|
||||
"description": "TimeZone of the sync that will be applied to the schedule",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"status": {
|
||||
"description": "AppProjectStatus contains status information for AppProject CRs",
|
||||
"properties": {
|
||||
"jwtTokensByRole": {
|
||||
"additionalProperties": {
|
||||
"description": "JWTTokens represents a list of JWT tokens",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "JWTToken holds the issuedAt and expiresAt values of a token",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iat"
|
||||
],
|
||||
"properties": {
|
||||
"exp": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"iat": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "JWTTokensByRole contains a list of JWT tokens issued for a given role",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata",
|
||||
"spec"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
233
src/__generated__/resources/K8SAppProjectV1alpha1.ts
generated
233
src/__generated__/resources/K8SAppProjectV1alpha1.ts
generated
@@ -1,233 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by json-schema-to-typescript.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
||||
* and run json-schema-to-typescript to regenerate this file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AppProject provides a logical grouping of applications, providing controls for:
|
||||
* * where the apps may deploy to (cluster whitelist)
|
||||
* * what may be deployed (repository whitelist, resource whitelist/blacklist)
|
||||
* * who can access these applications (roles, OIDC group claims bindings)
|
||||
* * and what they can do (RBAC policies)
|
||||
* * automation access to these roles (JWT tokens)
|
||||
*/
|
||||
export interface K8SAppProjectV1Alpha1 {
|
||||
/**
|
||||
* APIVersion defines the versioned schema of this representation of an object.
|
||||
* Servers should convert recognized schemas to the latest internal value, and
|
||||
* may reject unrecognized values.
|
||||
* More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
*/
|
||||
apiVersion?: string;
|
||||
/**
|
||||
* Kind is a string value representing the REST resource this object represents.
|
||||
* Servers may infer this from the endpoint the client submits requests to.
|
||||
* Cannot be updated.
|
||||
* In CamelCase.
|
||||
* More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
*/
|
||||
kind?: string;
|
||||
metadata: {};
|
||||
/**
|
||||
* AppProjectSpec is the specification of an AppProject
|
||||
*/
|
||||
spec: {
|
||||
/**
|
||||
* ClusterResourceBlacklist contains list of blacklisted cluster level resources
|
||||
*/
|
||||
clusterResourceBlacklist?: {
|
||||
group: string;
|
||||
kind: string;
|
||||
}[];
|
||||
/**
|
||||
* ClusterResourceWhitelist contains list of whitelisted cluster level resources
|
||||
*/
|
||||
clusterResourceWhitelist?: {
|
||||
group: string;
|
||||
kind: string;
|
||||
}[];
|
||||
/**
|
||||
* Description contains optional project description
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* DestinationServiceAccounts holds information about the service accounts to be impersonated for the application sync operation for each destination.
|
||||
*/
|
||||
destinationServiceAccounts?: {
|
||||
/**
|
||||
* DefaultServiceAccount to be used for impersonation during the sync operation
|
||||
*/
|
||||
defaultServiceAccount: string;
|
||||
/**
|
||||
* Namespace specifies the target namespace for the application's resources.
|
||||
*/
|
||||
namespace?: string;
|
||||
/**
|
||||
* Server specifies the URL of the target cluster's Kubernetes control plane API.
|
||||
*/
|
||||
server: string;
|
||||
}[];
|
||||
/**
|
||||
* Destinations contains list of destinations available for deployment
|
||||
*/
|
||||
destinations?: {
|
||||
/**
|
||||
* Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set.
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* Namespace specifies the target namespace for the application's resources.
|
||||
* The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace
|
||||
*/
|
||||
namespace?: string;
|
||||
/**
|
||||
* Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set.
|
||||
*/
|
||||
server?: string;
|
||||
}[];
|
||||
/**
|
||||
* NamespaceResourceBlacklist contains list of blacklisted namespace level resources
|
||||
*/
|
||||
namespaceResourceBlacklist?: {
|
||||
group: string;
|
||||
kind: string;
|
||||
}[];
|
||||
/**
|
||||
* NamespaceResourceWhitelist contains list of whitelisted namespace level resources
|
||||
*/
|
||||
namespaceResourceWhitelist?: {
|
||||
group: string;
|
||||
kind: string;
|
||||
}[];
|
||||
/**
|
||||
* OrphanedResources specifies if controller should monitor orphaned resources of apps in this project
|
||||
*/
|
||||
orphanedResources?: {
|
||||
/**
|
||||
* Ignore contains a list of resources that are to be excluded from orphaned resources monitoring
|
||||
*/
|
||||
ignore?: {
|
||||
group?: string;
|
||||
kind?: string;
|
||||
name?: string;
|
||||
}[];
|
||||
/**
|
||||
* Warn indicates if warning condition should be created for apps which have orphaned resources
|
||||
*/
|
||||
warn?: boolean;
|
||||
};
|
||||
/**
|
||||
* PermitOnlyProjectScopedClusters determines whether destinations can only reference clusters which are project-scoped
|
||||
*/
|
||||
permitOnlyProjectScopedClusters?: boolean;
|
||||
/**
|
||||
* Roles are user defined RBAC roles associated with this project
|
||||
*/
|
||||
roles?: {
|
||||
/**
|
||||
* Description is a description of the role
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* Groups are a list of OIDC group claims bound to this role
|
||||
*/
|
||||
groups?: string[];
|
||||
/**
|
||||
* JWTTokens are a list of generated JWT tokens bound to this role
|
||||
*/
|
||||
jwtTokens?: {
|
||||
exp?: number;
|
||||
iat: number;
|
||||
id?: string;
|
||||
}[];
|
||||
/**
|
||||
* Name is a name for this role
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Policies Stores a list of casbin formatted strings that define access policies for the role in the project
|
||||
*/
|
||||
policies?: string[];
|
||||
}[];
|
||||
/**
|
||||
* SignatureKeys contains a list of PGP key IDs that commits in Git must be signed with in order to be allowed for sync
|
||||
*/
|
||||
signatureKeys?: {
|
||||
/**
|
||||
* The ID of the key in hexadecimal notation
|
||||
*/
|
||||
keyID: string;
|
||||
}[];
|
||||
/**
|
||||
* SourceNamespaces defines the namespaces application resources are allowed to be created in
|
||||
*/
|
||||
sourceNamespaces?: string[];
|
||||
/**
|
||||
* SourceRepos contains list of repository URLs which can be used for deployment
|
||||
*/
|
||||
sourceRepos?: string[];
|
||||
/**
|
||||
* SyncWindows controls when syncs can be run for apps in this project
|
||||
*/
|
||||
syncWindows?: {
|
||||
/**
|
||||
* UseAndOperator use AND operator for matching applications, namespaces and clusters instead of the default OR operator
|
||||
*/
|
||||
andOperator?: boolean;
|
||||
/**
|
||||
* Applications contains a list of applications that the window will apply to
|
||||
*/
|
||||
applications?: string[];
|
||||
/**
|
||||
* Clusters contains a list of clusters that the window will apply to
|
||||
*/
|
||||
clusters?: string[];
|
||||
/**
|
||||
* Duration is the amount of time the sync window will be open
|
||||
*/
|
||||
duration?: string;
|
||||
/**
|
||||
* Kind defines if the window allows or blocks syncs
|
||||
*/
|
||||
kind?: string;
|
||||
/**
|
||||
* ManualSync enables manual syncs when they would otherwise be blocked
|
||||
*/
|
||||
manualSync?: boolean;
|
||||
/**
|
||||
* Namespaces contains a list of namespaces that the window will apply to
|
||||
*/
|
||||
namespaces?: string[];
|
||||
/**
|
||||
* Schedule is the time the window will begin, specified in cron format
|
||||
*/
|
||||
schedule?: string;
|
||||
/**
|
||||
* TimeZone of the sync that will be applied to the schedule
|
||||
*/
|
||||
timeZone?: string;
|
||||
}[];
|
||||
};
|
||||
/**
|
||||
* AppProjectStatus contains status information for AppProject CRs
|
||||
*/
|
||||
status?: {
|
||||
/**
|
||||
* JWTTokensByRole contains a list of JWT tokens issued for a given role
|
||||
*/
|
||||
jwtTokensByRole?: {
|
||||
/**
|
||||
* JWTTokens represents a list of JWT tokens
|
||||
*/
|
||||
[k: string]: {
|
||||
items?: {
|
||||
exp?: number;
|
||||
iat: number;
|
||||
id?: string;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
26928
src/__generated__/resources/K8SApplicationSetV1alpha1.json
generated
26928
src/__generated__/resources/K8SApplicationSetV1alpha1.json
generated
File diff suppressed because it is too large
Load Diff
7835
src/__generated__/resources/K8SApplicationSetV1alpha1.ts
generated
7835
src/__generated__/resources/K8SApplicationSetV1alpha1.ts
generated
File diff suppressed because it is too large
Load Diff
6513
src/__generated__/resources/K8SApplicationV1alpha1.json
generated
6513
src/__generated__/resources/K8SApplicationV1alpha1.json
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user