From a895d4cf33bf3ab1682cca35692087b5f7105abb Mon Sep 17 00:00:00 2001 From: Roger Oriol Date: Tue, 3 Feb 2026 23:56:31 +0100 Subject: [PATCH] myorg assistant --- myorg-assistant/configmap.yaml | 22 +++ .../cronjobs/deadline-checker.yaml | 60 ++++++ myorg-assistant/cronjobs/evening-summary.yaml | 60 ++++++ myorg-assistant/cronjobs/git-sync.yaml | 75 ++++++++ .../cronjobs/morning-briefing.yaml | 67 +++++++ .../cronjobs/waiting-followup.yaml | 60 ++++++ myorg-assistant/deploy.sh | 99 ++++++++++ myorg-assistant/deployment.yaml | 176 ++++++++++++++++++ myorg-assistant/ingress.yaml | 26 +++ myorg-assistant/pvc.yaml | 12 ++ myorg-assistant/service.yaml | 16 ++ 11 files changed, 673 insertions(+) create mode 100644 myorg-assistant/configmap.yaml create mode 100644 myorg-assistant/cronjobs/deadline-checker.yaml create mode 100644 myorg-assistant/cronjobs/evening-summary.yaml create mode 100644 myorg-assistant/cronjobs/git-sync.yaml create mode 100644 myorg-assistant/cronjobs/morning-briefing.yaml create mode 100644 myorg-assistant/cronjobs/waiting-followup.yaml create mode 100755 myorg-assistant/deploy.sh create mode 100644 myorg-assistant/deployment.yaml create mode 100644 myorg-assistant/ingress.yaml create mode 100644 myorg-assistant/pvc.yaml create mode 100644 myorg-assistant/service.yaml diff --git a/myorg-assistant/configmap.yaml b/myorg-assistant/configmap.yaml new file mode 100644 index 0000000..be4182a --- /dev/null +++ b/myorg-assistant/configmap.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: myorg-assistant-config + namespace: default +data: + # LiteLLM Configuration + LITELLM_ENDPOINT: "http://litellm-service.default.svc.cluster.local:4000" + LITELLM_MODEL: "claude-sonnet-4-5" + + # Myorg Repository Path + MYORG_REPO_PATH: "/data/myorg" + + # Scheduling + TIMEZONE: "Europe/Madrid" + + # Web Interface + WEB_HOST: "0.0.0.0" + WEB_PORT: "8000" + + # Git Configuration + GIT_BRANCH: "main" diff --git a/myorg-assistant/cronjobs/deadline-checker.yaml b/myorg-assistant/cronjobs/deadline-checker.yaml new file mode 100644 index 0000000..74d43c4 --- /dev/null +++ b/myorg-assistant/cronjobs/deadline-checker.yaml @@ -0,0 +1,60 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: myorg-deadline-checker + namespace: default + labels: + app: myorg-assistant + job: deadline-checker +spec: + # Run every hour + schedule: "0 * * * *" + timeZone: "Europe/Madrid" + successfulJobsHistoryLimit: 2 + failedJobsHistoryLimit: 2 + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + metadata: + labels: + app: myorg-assistant + job: deadline-checker + spec: + restartPolicy: OnFailure + containers: + - name: deadline-checker + image: myorg-assistant:latest + imagePullPolicy: IfNotPresent + command: + - python + - run_job.py + - deadline-checker + env: + - name: MYORG_REPO_PATH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: MYORG_REPO_PATH + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_BOT_TOKEN + - name: DISCORD_CHANNEL_ID + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_CHANNEL_ID + - name: LITELLM_API_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: LITELLM_API_KEY + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + volumes: + - name: myorg-data + persistentVolumeClaim: + claimName: myorg-assistant-pvc diff --git a/myorg-assistant/cronjobs/evening-summary.yaml b/myorg-assistant/cronjobs/evening-summary.yaml new file mode 100644 index 0000000..6eaef63 --- /dev/null +++ b/myorg-assistant/cronjobs/evening-summary.yaml @@ -0,0 +1,60 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: myorg-evening-summary + namespace: default + labels: + app: myorg-assistant + job: evening-summary +spec: + # Run at 8:00 PM every day + schedule: "0 20 * * *" + timeZone: "Europe/Madrid" + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 3 + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + metadata: + labels: + app: myorg-assistant + job: evening-summary + spec: + restartPolicy: OnFailure + containers: + - name: evening-summary + image: myorg-assistant:latest + imagePullPolicy: IfNotPresent + command: + - python + - run_job.py + - evening-summary + env: + - name: MYORG_REPO_PATH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: MYORG_REPO_PATH + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_BOT_TOKEN + - name: DISCORD_CHANNEL_ID + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_CHANNEL_ID + - name: LITELLM_API_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: LITELLM_API_KEY + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + volumes: + - name: myorg-data + persistentVolumeClaim: + claimName: myorg-assistant-pvc diff --git a/myorg-assistant/cronjobs/git-sync.yaml b/myorg-assistant/cronjobs/git-sync.yaml new file mode 100644 index 0000000..5ea7318 --- /dev/null +++ b/myorg-assistant/cronjobs/git-sync.yaml @@ -0,0 +1,75 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: myorg-git-sync + namespace: default + labels: + app: myorg-assistant + job: git-sync +spec: + # Run every 15 minutes + schedule: "*/15 * * * *" + timeZone: "Europe/Madrid" + successfulJobsHistoryLimit: 1 + failedJobsHistoryLimit: 2 + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + metadata: + labels: + app: myorg-assistant + job: git-sync + spec: + restartPolicy: OnFailure + containers: + - name: git-sync + image: myorg-assistant:latest + imagePullPolicy: IfNotPresent + command: + - python + - run_job.py + - git-sync + env: + - name: MYORG_REPO_PATH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: MYORG_REPO_PATH + - name: GIT_BRANCH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: GIT_BRANCH + - name: GIT_REPO_URL + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_REPO_URL + - name: GIT_USERNAME + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_USERNAME + - name: GIT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_TOKEN + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_BOT_TOKEN + - name: LITELLM_API_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: LITELLM_API_KEY + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + volumes: + - name: myorg-data + persistentVolumeClaim: + claimName: myorg-assistant-pvc diff --git a/myorg-assistant/cronjobs/morning-briefing.yaml b/myorg-assistant/cronjobs/morning-briefing.yaml new file mode 100644 index 0000000..7f1576b --- /dev/null +++ b/myorg-assistant/cronjobs/morning-briefing.yaml @@ -0,0 +1,67 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: myorg-morning-briefing + namespace: default + labels: + app: myorg-assistant + job: morning-briefing +spec: + # Run at 8:00 AM every day (adjust for your timezone) + schedule: "0 8 * * *" + timeZone: "Europe/Madrid" + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 3 + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + metadata: + labels: + app: myorg-assistant + job: morning-briefing + spec: + restartPolicy: OnFailure + containers: + - name: morning-briefing + image: myorg-assistant:latest + imagePullPolicy: IfNotPresent + command: + - python + - run_job.py + - morning-briefing + env: + # From ConfigMap + - name: MYORG_REPO_PATH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: MYORG_REPO_PATH + - name: TIMEZONE + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: TIMEZONE + # From Secret + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_BOT_TOKEN + - name: DISCORD_CHANNEL_ID + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_CHANNEL_ID + - name: LITELLM_API_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: LITELLM_API_KEY + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + volumes: + - name: myorg-data + persistentVolumeClaim: + claimName: myorg-assistant-pvc diff --git a/myorg-assistant/cronjobs/waiting-followup.yaml b/myorg-assistant/cronjobs/waiting-followup.yaml new file mode 100644 index 0000000..a2417fa --- /dev/null +++ b/myorg-assistant/cronjobs/waiting-followup.yaml @@ -0,0 +1,60 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: myorg-waiting-followup + namespace: default + labels: + app: myorg-assistant + job: waiting-followup +spec: + # Run every Monday at 9:00 AM + schedule: "0 9 * * 1" + timeZone: "Europe/Madrid" + successfulJobsHistoryLimit: 2 + failedJobsHistoryLimit: 2 + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + metadata: + labels: + app: myorg-assistant + job: waiting-followup + spec: + restartPolicy: OnFailure + containers: + - name: waiting-followup + image: myorg-assistant:latest + imagePullPolicy: IfNotPresent + command: + - python + - run_job.py + - waiting-followup + env: + - name: MYORG_REPO_PATH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: MYORG_REPO_PATH + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_BOT_TOKEN + - name: DISCORD_CHANNEL_ID + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_CHANNEL_ID + - name: LITELLM_API_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: LITELLM_API_KEY + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + volumes: + - name: myorg-data + persistentVolumeClaim: + claimName: myorg-assistant-pvc diff --git a/myorg-assistant/deploy.sh b/myorg-assistant/deploy.sh new file mode 100755 index 0000000..a822c2d --- /dev/null +++ b/myorg-assistant/deploy.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# Deployment script for MyOrg Assistant to k3s + +set -e + +echo "🚀 Deploying MyOrg Assistant to k3s..." + +# Check if kubectl is available +if ! command -v kubectl &> /dev/null; then + echo "❌ kubectl not found. Please install kubectl first." + exit 1 +fi + +# Check if we're connected to the cluster +if ! kubectl cluster-info &> /dev/null; then + echo "❌ Cannot connect to k3s cluster. Please check your kubeconfig." + exit 1 +fi + +echo "✅ Connected to k3s cluster" + +# Build Docker image +echo "" +echo "📦 Building Docker image..." +cd .. +docker build -t myorg-assistant:latest . + +# Load image into k3s (if using k3s) +echo "" +echo "📥 Loading image into k3s..." +if command -v k3s &> /dev/null; then + docker save myorg-assistant:latest | sudo k3s ctr images import - +else + echo "⚠️ k3s command not found, assuming image is already available" +fi + +cd k8s + +# Check if secret exists +if kubectl get secret myorg-assistant-secret &> /dev/null; then + echo "" + echo "✅ Secret already exists" +else + echo "" + echo "⚠️ Secret not found!" + echo "Please create k8s/secret.yaml from k8s/secret.yaml.example and apply it:" + echo " cp secret.yaml.example secret.yaml" + echo " # Edit secret.yaml with your credentials" + echo " kubectl apply -f secret.yaml" + exit 1 +fi + +# Apply manifests +echo "" +echo "📝 Applying Kubernetes manifests..." + +echo " - ConfigMap..." +kubectl apply -f configmap.yaml + +echo " - PersistentVolumeClaim..." +kubectl apply -f pvc.yaml + +echo " - Service..." +kubectl apply -f service.yaml + +echo " - Deployment..." +kubectl apply -f deployment.yaml + +echo " - CronJobs..." +kubectl apply -f cronjobs/ + +# Wait for deployment +echo "" +echo "⏳ Waiting for deployment to be ready..." +kubectl rollout status deployment/myorg-assistant --timeout=300s + +# Show status +echo "" +echo "✅ Deployment complete!" +echo "" +echo "📊 Status:" +kubectl get pods -l app=myorg-assistant +echo "" +kubectl get svc myorg-assistant-service +echo "" + +# Show logs +echo "📋 Recent logs:" +POD_NAME=$(kubectl get pods -l app=myorg-assistant -o jsonpath='{.items[0].metadata.name}') +kubectl logs $POD_NAME --tail=20 + +echo "" +echo "🎉 MyOrg Assistant is now running!" +echo "" +echo "Useful commands:" +echo " View logs: kubectl logs -f $POD_NAME" +echo " Pod shell: kubectl exec -it $POD_NAME -- /bin/bash" +echo " Restart: kubectl rollout restart deployment/myorg-assistant" +echo " Delete: kubectl delete -f k8s/" diff --git a/myorg-assistant/deployment.yaml b/myorg-assistant/deployment.yaml new file mode 100644 index 0000000..10722e1 --- /dev/null +++ b/myorg-assistant/deployment.yaml @@ -0,0 +1,176 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myorg-assistant + namespace: default + labels: + app: myorg-assistant +spec: + replicas: 1 + selector: + matchLabels: + app: myorg-assistant + template: + metadata: + labels: + app: myorg-assistant + spec: + initContainers: + - name: git-clone + image: alpine/git:latest + command: + - sh + - -c + - | + if [ ! -d /data/myorg/.git ]; then + echo "Cloning repository..." + git clone ${GIT_REPO_URL} /data/myorg + cd /data/myorg + git config user.name "${GIT_USERNAME}" + git config user.email "${GIT_USERNAME}@users.noreply.github.com" + git config credential.helper store + echo "https://${GIT_USERNAME}:${GIT_TOKEN}@github.com" > ~/.git-credentials + else + echo "Repository already exists, pulling latest changes..." + cd /data/myorg + git pull + fi + env: + - name: GIT_REPO_URL + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_REPO_URL + - name: GIT_USERNAME + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_USERNAME + - name: GIT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_TOKEN + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + + containers: + - name: myorg-assistant + image: myorg-assistant:latest + imagePullPolicy: IfNotPresent + command: ["./start.sh"] + ports: + - containerPort: 8000 + name: web + protocol: TCP + env: + # From ConfigMap + - name: LITELLM_ENDPOINT + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: LITELLM_ENDPOINT + - name: LITELLM_MODEL + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: LITELLM_MODEL + - name: MYORG_REPO_PATH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: MYORG_REPO_PATH + - name: TIMEZONE + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: TIMEZONE + - name: WEB_HOST + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: WEB_HOST + - name: WEB_PORT + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: WEB_PORT + - name: GIT_BRANCH + valueFrom: + configMapKeyRef: + name: myorg-assistant-config + key: GIT_BRANCH + + # From Secret + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_BOT_TOKEN + - name: DISCORD_CHANNEL_ID + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: DISCORD_CHANNEL_ID + - name: LITELLM_API_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: LITELLM_API_KEY + - name: GIT_REPO_URL + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_REPO_URL + - name: GIT_USERNAME + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_USERNAME + - name: GIT_TOKEN + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: GIT_TOKEN + - name: WEB_SECRET_KEY + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: WEB_SECRET_KEY + - name: WEB_PASSWORD + valueFrom: + secretKeyRef: + name: myorg-assistant-secret + key: WEB_PASSWORD + optional: true + + volumeMounts: + - name: myorg-data + mountPath: /data/myorg + + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + + livenessProbe: + exec: + command: + - sh + - -c + - "ps aux | grep 'python -m src.main bot' | grep -v grep" + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 3 + + volumes: + - name: myorg-data + persistentVolumeClaim: + claimName: myorg-assistant-pvc + + restartPolicy: Always diff --git a/myorg-assistant/ingress.yaml b/myorg-assistant/ingress.yaml new file mode 100644 index 0000000..2b080d3 --- /dev/null +++ b/myorg-assistant/ingress.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: myorg-assistant-ingress + namespace: default + annotations: + kubernetes.io/ingress.class: "traefik" + # Add SSL/TLS annotations if needed + # cert-manager.io/cluster-issuer: "letsencrypt-prod" +spec: + rules: + - host: myorg.yourdomain.com # Replace with your domain + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: myorg-assistant-service + port: + number: 8000 + # Optional: TLS configuration + # tls: + # - hosts: + # - myorg.yourdomain.com + # secretName: myorg-tls-secret diff --git a/myorg-assistant/pvc.yaml b/myorg-assistant/pvc.yaml new file mode 100644 index 0000000..74c071c --- /dev/null +++ b/myorg-assistant/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: myorg-assistant-pvc + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: local-path # Adjust based on your k3s storage class diff --git a/myorg-assistant/service.yaml b/myorg-assistant/service.yaml new file mode 100644 index 0000000..c971879 --- /dev/null +++ b/myorg-assistant/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: myorg-assistant-service + namespace: default + labels: + app: myorg-assistant +spec: + type: ClusterIP + selector: + app: myorg-assistant + ports: + - name: web + port: 8000 + targetPort: 8000 + protocol: TCP