diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..156f105 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +values-secret.yaml \ No newline at end of file diff --git a/charts/roost/templates/NOTES.txt b/charts/roost/templates/NOTES.txt index 74c90f2..53653ad 100644 --- a/charts/roost/templates/NOTES.txt +++ b/charts/roost/templates/NOTES.txt @@ -1,20 +1,55 @@ # Welcome to the RoostAI Helm Chart! +## Secret Values (values-secret.yaml) + +Sensitive credentials (DB passwords, OAuth secrets, license key, ACM ARN, etc.) +must NOT be committed to git. Store them in a separate file: + + charts/roost/values-secret.yaml ← listed in .gitignore + +Deploy with both files: + helm upgrade --install roost charts/roost \ + -f charts/roost/values.yaml \ + -f charts/roost/values-secret.yaml \ + -n roost --create-namespace + ## Accessing RoostAI -{{- if or (eq .Values.cloudConfig.clusterType "gke") (eq .Values.cloudConfig.clusterType "aks") }} -NOTE: It may take a few minutes for the Ingress Address IP to be available. +{{- if .Values.gateway.enabled }} +NOTE: Gateway API mode is enabled. NGINX Gateway Fabric must be installed in the cluster. + Install it with (use --skip-crds if Gateway API CRDs >= v1.5 are already present): + helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \ + --create-namespace -n nginx-gateway --skip-crds + + It may take a few minutes for the Gateway address to become available. + Watch the gateway status: + kubectl get --namespace {{ .Release.Namespace }} gateway roost-gateway -w + +Get the RoostAI external address: +export SERVICE_IP=$(kubectl get gateway --namespace {{ .Release.Namespace }} roost-gateway \ + -o jsonpath="{.status.addresses[0].value}") +echo "RoostAI URL: http://$SERVICE_IP" + +{{- if eq .Values.cloudConfig.clusterType "local" }} +On Docker Desktop the LoadBalancer is exposed on localhost (127.0.0.1). +Since '{{ .Values.enterprise.domainURL }}' resolves to 127.0.0.1 automatically, +you can open your browser at: http://{{ .Values.enterprise.domainURL }} +{{- end }} +{{- else if or (eq .Values.cloudConfig.clusterType "gke") (eq .Values.cloudConfig.clusterType "aks") }} +NOTE: It may take a few minutes for the Ingress address to be available. You can watch the status by running: 'kubectl get --namespace {{ .Release.Namespace }} ingress -w roost-{{ .Values.cloudConfig.clusterType }}-ingress' Get the roostai loadbalancer external IP by running these commands: -export SERVICE_IP=$(kubectl get ingress --namespace {{ .Release.Namespace }} roost-{{ .Values.cloudConfig.clusterType }}-ingress -o jsonpath="{.status.loadBalancer.ingress[0].ip}") +export SERVICE_IP=$(kubectl get ingress --namespace {{ .Release.Namespace }} roost-{{ .Values.cloudConfig.clusterType }}-ingress -o jsonpath="{.status.loadBalancer.ingress[0].hostname}") {{- else }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. You can watch the status by running: 'kubectl get --namespace {{ .Release.Namespace }} svc -w roost-nginx-svc' Get the roostai loadbalancer external IP by running these commands: -export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} roost-nginx-svc -o jsonpath="{.status.loadBalancer.ingress[0].ip}") +export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} roost-nginx-svc -o jsonpath="{.status.loadBalancer.ingress[0].hostname}") {{- end }} +{{- if not .Values.gateway.enabled }} echo "RoostAI LoadBalancer URL: http://$SERVICE_IP" +{{- end }} ## Mapping the RoostAI LoadBalancer IP to Your Domain @@ -30,4 +65,4 @@ To map this LoadBalancer IP to your domain, follow these steps: 4. Save the DNS record. -5. It may take some time (DNS propagation) for your domain to point to the RoostAI LoadBalancer IP. \ No newline at end of file +5. It may take some time (DNS propagation) for your domain to point to the RoostAI LoadBalancer IP. diff --git a/charts/roost/templates/_helpers.tpl b/charts/roost/templates/_helpers.tpl index fe46e68..8b120b5 100644 --- a/charts/roost/templates/_helpers.tpl +++ b/charts/roost/templates/_helpers.tpl @@ -65,22 +65,28 @@ Create the name of the service account to use Storage Class Name */}} {{- define "cluster.storageClassName" -}} -{{- if eq .Values.cloudConfig.clusterType "aks" }} -storageClassName: roost-sc-azurefile-csi-nfs +{{- if and .Values.storageClass .Values.storageClass }} +storageClassName: {{ .Values.storageClass }} +{{- else if eq .Values.cloudConfig.clusterType "aks" }} +storageClassName: {{ .Values.storageClass }} {{- else if eq .Values.cloudConfig.clusterType "gke" }} storageClassName: standard-rwx {{- else if eq .Values.cloudConfig.clusterType "eks" }} -storageClassName: roost-sc-efs -{{- else }} -# storageClassName: default +storageClassName: {{ .Values.storageClass }} +{{- else if eq .Values.cloudConfig.clusterType "local" }} +storageClassName: {{ .Values.storageClass }} {{- end }} {{- end }} {{/* Roost Nginx Service Type +When Gateway API is enabled the nginx service is always ClusterIP — the Gateway's +LoadBalancer is the external entry point. Legacy mode preserves cloud-specific types. */}} {{- define "nginxService.type" -}} -{{- if or (eq .Values.cloudConfig.clusterType "gke") (eq .Values.cloudConfig.clusterType "aks") }} +{{- if .Values.gateway.enabled }} +type: ClusterIP +{{- else if or (eq .Values.cloudConfig.clusterType "gke") (eq .Values.cloudConfig.clusterType "aks") }} type: ClusterIP {{- else }} type: LoadBalancer diff --git a/charts/roost/templates/roost-ai-code-analyzer.yaml b/charts/roost/templates/roost-ai-code-analyzer.yaml new file mode 100644 index 0000000..69cba9a --- /dev/null +++ b/charts/roost/templates/roost-ai-code-analyzer.yaml @@ -0,0 +1,179 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: roost-ai-code-analyzer-config + namespace: {{ .Release.Namespace }} +data: + DATABASE_URL: 'postgresql://{{ .Values.aiCodeAnalyzer.db.user }}:{{ .Values.aiCodeAnalyzer.db.password }}@ai-code-analyzer-db-svc.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}:5432/{{ .Values.aiCodeAnalyzer.db.database }}' + POSTGRES_DB: '{{ .Values.aiCodeAnalyzer.db.database }}' + POSTGRES_USER: '{{ .Values.aiCodeAnalyzer.db.user }}' + POSTGRES_PASSWORD: '{{ .Values.aiCodeAnalyzer.db.password }}' + +--- +apiVersion: v1 +kind: Service +metadata: + name: ai-code-analyzer-svc + namespace: {{ .Release.Namespace }} +spec: + selector: + app: ai-code-analyzer + ports: + - protocol: TCP + port: 5060 + targetPort: 5060 + +--- +apiVersion: v1 +kind: Service +metadata: + name: ai-code-analyzer-db-svc + namespace: {{ .Release.Namespace }} +spec: + selector: + app: ai-code-analyzer-db + ports: + - protocol: TCP + port: 5432 + targetPort: 5432 + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: ai-code-analyzer-pvc-{{ .Release.Namespace }} + namespace: {{ .Release.Namespace }} +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ .Values.aiCodeAnalyzer.storage.size }} +{{- include "cluster.storageClassName" . | indent 2 }} + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: ai-code-analyzer-db-pvc-{{ .Release.Namespace }} + namespace: {{ .Release.Namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.aiCodeAnalyzer.db.storage.size }} +{{- include "cluster.storageClassName" . | indent 2 }} + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ai-code-analyzer-db + namespace: {{ .Release.Namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: ai-code-analyzer-db + template: + metadata: + labels: + app: ai-code-analyzer-db + spec: + containers: + - name: ai-code-analyzer-db + image: postgres:18-alpine + envFrom: + - configMapRef: + name: roost-ai-code-analyzer-config + env: + - name: PGDATA + value: /var/lib/postgresql/data + ports: + - containerPort: 5432 + volumeMounts: + - mountPath: /var/lib/postgresql/data + name: ai-code-analyzer-db-storage + livenessProbe: + exec: + command: + - pg_isready + - -U + - {{ .Values.aiCodeAnalyzer.db.user }} + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - pg_isready + - -U + - {{ .Values.aiCodeAnalyzer.db.user }} + initialDelaySeconds: 10 + periodSeconds: 5 + imagePullPolicy: Always + volumes: + - name: ai-code-analyzer-db-storage + persistentVolumeClaim: + claimName: ai-code-analyzer-db-pvc-{{ .Release.Namespace }} + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ai-code-analyzer + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.aiCodeAnalyzer.replicas }} + selector: + matchLabels: + app: ai-code-analyzer + template: + metadata: + labels: + app: ai-code-analyzer + annotations: + checksum/config: {{ toYaml (pick .Values "aiCodeAnalyzer") | sha256sum }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + initContainers: + - name: wait-for-db + image: postgres:18-alpine + command: + - sh + - -c + - | + until pg_isready -h ai-code-analyzer-db-svc -p 5432 -U {{ .Values.aiCodeAnalyzer.db.user }}; + do + echo "Waiting for postgres..." + sleep 2 + done + containers: + - name: ai-code-analyzer + image: zbio/ai-io:{{ .Values.aiCodeAnalyzer.imageTag }} + envFrom: + - configMapRef: + name: roost-ai-code-analyzer-config + ports: + - containerPort: 5060 + volumeMounts: + - mountPath: /app/chroma_db + subPath: chroma_db + name: ai-code-analyzer-storage + - mountPath: /app/jobs + subPath: jobs + name: ai-code-analyzer-storage + - mountPath: /app/test_artifacts + subPath: test_artifacts + name: ai-code-analyzer-storage + imagePullPolicy: Always + volumes: + - name: ai-code-analyzer-storage + persistentVolumeClaim: + claimName: ai-code-analyzer-pvc-{{ .Release.Namespace }} + +--- \ No newline at end of file diff --git a/charts/roost/templates/roost-ai-server.yaml b/charts/roost/templates/roost-ai-server.yaml index 53f1e71..63d2a87 100644 --- a/charts/roost/templates/roost-ai-server.yaml +++ b/charts/roost/templates/roost-ai-server.yaml @@ -12,13 +12,13 @@ data: ROOST_VER: '{{ .Values.roostConfig.roostVersion }}' DEPLOYED_IN_K8S: 'true' ROOST_AI_NS: '{{ .Release.Namespace }}' - AI_SERVER_PVC: 'roost-ai-server-pvc' + AI_SERVER_PVC: roost-ai-server-pvc-{{ .Release.Namespace }} --- apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: roost-ai-server-pvc + name: roost-ai-server-pvc-{{ .Release.Namespace }} namespace: {{ .Release.Namespace }} spec: accessModes: @@ -46,14 +46,26 @@ spec: app: roost-ai-server svc_group: roost-backend-svc spec: + securityContext: + runAsNonRoot: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 containers: - name: roost-ai-server image: zbio/roostai-server:{{ .Values.roostConfig.roostVersion }} + # resources: + # requests: + # cpu: "100m" + # memory: "256Mi" + # limits: + # cpu: "500m" + # memory: "512Mi" envFrom: - configMapRef: name: roost-ai-server-config volumeMounts: - - mountPath: /var/tmp/Roost/RoostGPT + - mountPath: /var/tmp/Roost name: roost-ai-server-data ports: - name: ai-server-port @@ -62,7 +74,7 @@ spec: volumes: - name: roost-ai-server-data persistentVolumeClaim: - claimName: roost-ai-server-pvc + claimName: roost-ai-server-pvc-{{ .Release.Namespace }} --- {{- end }} diff --git a/charts/roost/templates/roost-app.yaml b/charts/roost/templates/roost-app.yaml index 5c590e7..adaadd2 100644 --- a/charts/roost/templates/roost-app.yaml +++ b/charts/roost/templates/roost-app.yaml @@ -1,3 +1,6 @@ +{{- $hasTls := or .Values.gateway.tls.enabled (and .Values.acm.enabled .Values.acm.arn ) -}} +{{- $useHttp := and (eq .Values.cloudConfig.clusterType "local") (not $hasTls) -}} +{{- $protocol := ternary "http" "https" $useHttp -}} apiVersion: v1 kind: ConfigMap metadata: @@ -6,17 +9,19 @@ metadata: data: NODE_ENV: 'production' DEFAULT_PORT: '3000' - API_HOST_URL: 'https://{{ .Values.enterprise.domainURL }}/api' - LOGIN_REDIRECT_URL: 'https://{{ .Values.enterprise.domainURL }}/login' + API_HOST_URL: '{{ $protocol }}://{{ .Values.enterprise.domainURL }}/api' + LOGIN_REDIRECT_URL: '{{ $protocol }}://{{ .Values.enterprise.domainURL }}/login' NODE_DOMAIN_OR_IP: '{{ .Values.enterprise.domainURL }}' ROOST_VER: '{{ .Values.roostConfig.roostVersion }}' DB_VER: '{{ .Values.roostConfig.dbVersion }}' + # Auth Config GOOGLE_CLIENT_ID: '{{ .Values.auth.googleClientID }}' GOOGLE_CLIENT_SECRET: '{{ .Values.auth.googleClientSecret }}' AZURE_CLIENT_ID: '{{ .Values.auth.azureClientID }}' AZURE_CLIENT_SECRET: '{{ .Values.auth.azureClientSecret }}' + AZURE_TENANT_ID: '{{ .Values.auth.azureTenantID }}' GITHUB_CLIENT_ID: '{{ .Values.auth.githubClientID }}' GITHUB_CLIENT_SECRET: '{{ .Values.auth.githubClientSecret }}' LINKEDIN_CLIENT_ID: '{{ .Values.auth.linkedinClientID }}' @@ -34,31 +39,36 @@ data: PING_FEDERATE_CLIENT_ID: '{{ .Values.auth.pingFederateClientID }}' PING_FEDERATE_CLIENT_SECRET: '{{ .Values.auth.pingFederateClientSecret }}' + # Client Config ORG_NAME: '{{ .Values.enterprise.orgName }}' ORG_ADMIN_EMAIL: '{{ .Values.enterprise.orgAdminEmail }}' ORG_EMAIL_DOMAIN: '{{ .Values.enterprise.orgEmailDomain }}' - ORG_APP_NAME: '{{ .Values.enterprise.orgName }}' - # ORG_CLUSTER_LAUNCHER_IP: '' - JUMPHOST_SVC: 'roost-jump-svc' - EAAS_SVC: 'roost-backend-svc' - EAAS_SERVER_USERNAME: '' - EAAS_SERVER_KEY_PATH: '' + ORG_APP_NAME: '{{ .Values.enterprise.appName }}' + EAAS_SVC: '{{ if .Values.eaasServerIp }}{{ .Values.eaasServerIp }}{{ else }}roost-backend-svc.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}{{ end }}' + EAAS_SERVER_USERNAME: '{{ .Values.eaasServerUsername }}' + EAAS_SERVER_KEY_PATH: '{{ .Values.eaasServerPemKey }}' + # DB Config DB_HOST_TYPE: '{{ .Values.database.type }}' {{- if .Values.database.integrated }} - {{- if eq .Values.database.type "postgres" }} - DB_HOST: 'roost-postgres-db-svc' + {{- if eq .Values.database.type "postgres" }} + DB_HOST: 'roost-postgres-db-svc.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}' DB_PORT: '5432' DB_USERNAME: 'postgres' DB_PASSWORD: 'Roost#123' DB_SCHEMA_NAME: 'roostio' - {{- else }} - DB_HOST: 'roost-mysql-db-svc' + POSTGRES_PASSWORD: 'Roost#123' + POSTGRES_USER: 'postgres' + POSTGRES_DB: 'roostio' + {{- else }} + DB_HOST: 'roost-mysql-db-svc.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}' DB_PORT: '3306' - DB_USERNAME: 'root' - DB_PASSWORD: 'Roost#123' - DB_SCHEMA_NAME: 'roostio' - {{- end }} + DB_USERNAME: '{{ .Values.database.user }}' + DB_PASSWORD: '{{ .Values.database.password }}' + DB_SCHEMA_NAME: '{{ .Values.database.schema }}' + MYSQL_ROOT_PASSWORD: '{{ .Values.database.rootPassword }}' + MYSQL_DATABASE: '{{ .Values.database.schema }}' + {{- end }} {{- else }} DB_HOST: '{{ .Values.database.host }}' DB_PORT: '{{ .Values.database.port }}' @@ -67,20 +77,18 @@ data: DB_SCHEMA_NAME: '{{ .Values.database.schema }}' {{- end }} + # Email Config EMAIL_SENDER: '{{ .Values.email.sender }}' EMAIL_SENDER_PASS: '{{ .Values.email.senderPass }}' EMAIL_SMTP: '{{ .Values.email.smtp }}' EMAIL_SMTP_PORT: '{{ .Values.email.smtpPort }}' - JWT_SECRET: '{{ .Values.roostConfig.jwtSecret }}' + # Other Config LICENSE_KEY: '{{ .Values.roostConfig.licenseKey }}' - - ENABLE_SALESFORCE: 'false' - USE_IP_ADDRESS: 'false' - USE_ROOST_DEV: 'false' - ECS_MODE: 'true' + JWT_SECRET: '{{ .Values.auth.jwt_secret }}' USE_NO_AUTH: '{{ .Values.auth.noAuth }}' - LOCAL_AUTH_KEY: 'LocalKey/{{ .Values.auth.localKey }}' + USE_AS_ROOST_CLOUD_SERVER: '{{ .Values.roostConfig.useAsRoostCloudServer }}' + ECS_MODE: '{{ .Values.roostConfig.ecs_mode }}' --- apiVersion: v1 @@ -100,7 +108,7 @@ spec: apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: roost-app-pvc + name: roost-app-pvc-{{ .Release.Namespace }} namespace: {{ .Release.Namespace }} spec: accessModes: @@ -117,7 +125,7 @@ metadata: name: roost-app namespace: {{ .Release.Namespace }} spec: - replicas: 1 + replicas: {{ .Values.roostConfig.roostAppReplicas }} selector: matchLabels: app: roost-app @@ -125,10 +133,24 @@ spec: metadata: labels: app: roost-app + annotations: + checksum/config: {{ toYaml (pick .Values "database" "enterprise" "email" "auth" "eaasServerIp" "eaasServerPemKey" "eaasServerUsername" "roostConfig") | sha256sum }} spec: + securityContext: + runAsNonRoot: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 containers: - name: roost-app image: zbio/roost-app:{{ .Values.roostConfig.roostVersion }} + # resources: + # requests: + # cpu: "400m" + # memory: "512Mi" + # limits: + # cpu: "1000m" + # memory: "1Gi" envFrom: - configMapRef: name: roost-app-config @@ -141,7 +163,7 @@ spec: volumes: - name: roost-app-data persistentVolumeClaim: - claimName: roost-app-pvc + claimName: roost-app-pvc-{{ .Release.Namespace }} --- diff --git a/charts/roost/templates/roost-backend-svc.yaml b/charts/roost/templates/roost-backend-svc.yaml index 262644e..94480c3 100644 --- a/charts/roost/templates/roost-backend-svc.yaml +++ b/charts/roost/templates/roost-backend-svc.yaml @@ -11,18 +11,6 @@ spec: protocol: TCP port: 60007 targetPort: ai-server-port -{{- if .Values.roostConfig.enableClusterLauncher }} - - name: roost-launcher - protocol: TCP - port: 60002 - targetPort: launcher-port -{{- end }} -{{- if .Values.roostConfig.enableEaasServer }} - - name: roost-eaas - protocol: TCP - port: 60003 - targetPort: eaas-port -{{- end }} --- diff --git a/charts/roost/templates/roost-eaas.yaml b/charts/roost/templates/roost-eaas.yaml deleted file mode 100644 index 842409e..0000000 --- a/charts/roost/templates/roost-eaas.yaml +++ /dev/null @@ -1,68 +0,0 @@ -{{- if .Values.roostConfig.enableEaasServer }} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: roost-eaas-config - namespace: {{ .Release.Namespace }} -data: - VERBOSE_LEVEL: '{{ .Values.roostConfig.verboseLevel }}' - ENT_SERVER: '{{ .Values.enterprise.domainURL }}' - AUTH_KEY: '{{ .Values.auth.localKey }}' - ROOST_VER: '{{ .Values.roostConfig.roostVersion }}' - DEPLOYED_IN_K8S: 'true' - ROOST_AI_NS: '{{ .Release.Namespace }}' - RELEASE_SERVER_PVC: 'roost-eaas-pvc' - ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: roost-eaas-pvc - namespace: {{ .Release.Namespace }} -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 10Gi -{{- include "cluster.storageClassName" . | indent 2 }} - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: roost-eaas - namespace: {{ .Release.Namespace }} -spec: - replicas: 1 - selector: - matchLabels: - app: roost-eaas - svc_group: roost-backend-svc - template: - metadata: - labels: - app: roost-eaas - svc_group: roost-backend-svc - spec: - containers: - - name: roost-eaas - image: zbio/roost-eaas:{{ .Values.roostConfig.roostVersion }} - envFrom: - - configMapRef: - name: roost-eaas-config - volumeMounts: - - mountPath: /var/tmp/Roost - name: roost-eaas-data - ports: - - name: eaas-port - containerPort: 60003 - imagePullPolicy: Always - volumes: - - name: roost-eaas-data - persistentVolumeClaim: - claimName: roost-eaas-pvc - ---- -{{- end }} diff --git a/charts/roost/templates/roost-jump.yaml b/charts/roost/templates/roost-jump.yaml deleted file mode 100644 index 7ed9cb3..0000000 --- a/charts/roost/templates/roost-jump.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{{- if .Values.roostConfig.enableJumphost }} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: roost-jump-config - namespace: {{ .Release.Namespace }} -data: - JUMPHOST: 'true' - ENT_SERVER: '{{ .Values.enterprise.domainURL }}' - ROOST_LOCAL_KEY: '{{ .Values.auth.localKey }}' - RUN_AS_CONTAINER: 'true' - VERBOSE_LEVEL: '{{ .Values.roostConfig.verboseLevel }}' - ---- -apiVersion: v1 -kind: Service -metadata: - name: roost-jump-svc - namespace: {{ .Release.Namespace }} -spec: - selector: - app: roost-jump - ports: - - protocol: TCP - port: 60001 - targetPort: 60001 - ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: roost-jump-pvc - namespace: {{ .Release.Namespace }} -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 10Gi -{{- include "cluster.storageClassName" . | indent 2 }} - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: roost-jump - namespace: {{ .Release.Namespace }} -spec: - replicas: 1 - selector: - matchLabels: - app: roost-jump - template: - metadata: - labels: - app: roost-jump - spec: - containers: - - name: roost-jump - image: zbio/roost-jump:{{ .Values.roostConfig.roostVersion }} - envFrom: - - configMapRef: - name: roost-jump-config - volumeMounts: - - mountPath: /var/tmp/Roost - name: roost-jump-data - ports: - - containerPort: 60001 - imagePullPolicy: Always - volumes: - - name: roost-jump-data - persistentVolumeClaim: - claimName: roost-jump-pvc - ---- -{{- end }} diff --git a/charts/roost/templates/roost-launcher.yaml b/charts/roost/templates/roost-launcher.yaml deleted file mode 100644 index 088a18f..0000000 --- a/charts/roost/templates/roost-launcher.yaml +++ /dev/null @@ -1,68 +0,0 @@ -{{- if .Values.roostConfig.enableClusterLauncher }} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: roost-launcher-config - namespace: {{ .Release.Namespace }} -data: - APP_NAME: '{{ .Values.enterprise.orgName }}' - ENT_SERVER: '{{ .Values.enterprise.domainURL }}' - AUTH_KEY: '{{ .Values.auth.localKey }}' - CIDR_BLOCK: '' - ROOST_REGION: '' - ROOST_VPC: '' - VERBOSE_LEVEL: '{{ .Values.roostConfig.verboseLevel }}' - ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: roost-launcher-pvc - namespace: {{ .Release.Namespace }} -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 10Gi -{{- include "cluster.storageClassName" . | indent 2 }} - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: roost-launcher - namespace: {{ .Release.Namespace }} -spec: - replicas: 1 - selector: - matchLabels: - app: roost-launcher - svc_group: roost-backend-svc - template: - metadata: - labels: - app: roost-launcher - svc_group: roost-backend-svc - spec: - containers: - - name: roost-launcher - image: zbio/roost-launcher:{{ .Values.roostConfig.roostVersion }} - envFrom: - - configMapRef: - name: roost-launcher-config - volumeMounts: - - mountPath: /var/tmp/Roost - name: roost-launcher-data - ports: - - name: launcher-port - containerPort: 60002 - imagePullPolicy: Always - volumes: - - name: roost-launcher-data - persistentVolumeClaim: - claimName: roost-launcher-pvc - ---- -{{- end }} diff --git a/charts/roost/templates/roost-local-dns.yaml b/charts/roost/templates/roost-local-dns.yaml new file mode 100644 index 0000000..f2a7c12 --- /dev/null +++ b/charts/roost/templates/roost-local-dns.yaml @@ -0,0 +1,66 @@ +{{/* +In-cluster hairpin routing fix for local/Docker Desktop deployments. + +Problem: roost-app pods call http://{{ enterprise.domainURL }}/ which resolves via +CoreDNS to 127.0.0.1 (pod loopback) for .localhost domains — the request never +reaches the NGINX Gateway Fabric LoadBalancer. + +Fix: Exploit CoreDNS search domains. For a domain like "localroost.localhost", +CoreDNS in a pod will search ".svc.cluster.local". If a Service named +"localroost" exists in namespace "localhost", the query +"localroost.localhost.svc.cluster.local" matches and returns a CNAME to the +NGINX Gateway Fabric service — hairpin routing works without patching CoreDNS. + +REQUIREMENT: enterprise.domainURL must be a two-part domain (exactly one dot), +e.g., "localroost.localhost" or "roostai.test". +Multi-dot domains like "dev.roost.ai" are skipped (not applicable for local dev +anyway — use a simple two-part domain for Docker Desktop testing). + +Flow (from inside a pod): + localroost.localhost + → CoreDNS search: localroost.localhost.svc.cluster.local + → matches ExternalName Service "localroost" in namespace "localhost" + → CNAME → nginx-gateway-fabric.nginx-gateway.svc.cluster.local + → NGINX Gateway Fabric port 80 + → Gateway roost-gateway → HTTPRoute roost-route + → roost-nginx-svc:80 → roost-nginx pod + +Only rendered when: + gateway.enabled=true AND clusterType=local AND domainURL has exactly one dot +*/}} + +{{- if and .Values.gateway.enabled (eq .Values.cloudConfig.clusterType "local") }} +{{- $parts := splitList "." .Values.enterprise.domainURL }} +{{- $svcName := first $parts }} +{{- $nsName := join "." (rest $parts) }} +{{- /* Only render when the namespace part is a single DNS label (no dots). */}} +{{- if and $svcName $nsName (not (contains "." $nsName)) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ $nsName }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + helm.sh/chart: roost-local-dns + +--- + +apiVersion: v1 +kind: Service +metadata: + name: {{ $svcName }} + namespace: {{ $nsName }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + helm.sh/chart: roost-local-dns +spec: + type: ExternalName + externalName: {{ .Values.gateway.nginxGatewayService }} + ports: + - port: 80 + protocol: TCP + name: http + +--- +{{- end }} +{{- end }} diff --git a/charts/roost/templates/roost-mysql-db.yaml b/charts/roost/templates/roost-mysql-db.yaml index a0c452d..948ec89 100644 --- a/charts/roost/templates/roost-mysql-db.yaml +++ b/charts/roost/templates/roost-mysql-db.yaml @@ -6,10 +6,14 @@ metadata: name: roost-mysql-db-config namespace: {{ .Release.Namespace }} data: - MYSQL_ROOT_PASSWORD: 'Roost#123' # '{{ .Values.database.password }}' - MYSQL_DATABASE: 'roostio' # '{{ .Values.database.schema }}' - MYSQL_USER: 'roost' # '{{ .Values.database.user }}' - MYSQL_PASSWORD: 'Roost#123' # '{{ .Values.database.password }}' + # MYSQL_ROOT_PASSWORD: 'Roost#123' # '{{ .Values.database.password }}' + # MYSQL_DATABASE: 'roostio' # '{{ .Values.database.schema }}' + # MYSQL_USER: 'roost' # '{{ .Values.database.user }}' + # MYSQL_PASSWORD: 'Roost#123' # '{{ .Values.database.password }}' + MYSQL_ROOT_PASSWORD: "{{ .Values.database.rootPassword }}" + MYSQL_DATABASE: "{{ .Values.database.schema }}" + # MYSQL_USER: "{{ .Values.database.user }}" + MYSQL_PASSWORD: "{{ .Values.database.password }}" --- apiVersion: v1 @@ -25,28 +29,15 @@ spec: port: 3306 targetPort: 3306 ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: roost-mysql-db-pvc - namespace: {{ .Release.Namespace }} -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 10Gi -{{- include "cluster.storageClassName" . | indent 2 }} - --- apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: name: roost-mysql-db namespace: {{ .Release.Namespace }} spec: replicas: 1 + serviceName: roost-mysql-db-svc selector: matchLabels: app: roost-mysql-db @@ -55,26 +46,44 @@ spec: labels: app: roost-mysql-db spec: + securityContext: + fsGroup: 999 # Ensures the mounted volume is readable/writable by MySQL + runAsUser: 999 # Matches the MySQL container user + runAsGroup: 999 containers: - name: roost-mysql-db image: zbio/roostai_mysql_db:{{ .Values.roostConfig.dbVersion }} + # resources: + # requests: + # cpu: "500m" + # memory: "1Gi" + # limits: + # cpu: "1000m" + # memory: "2Gi" envFrom: - configMapRef: name: roost-mysql-db-config volumeMounts: - mountPath: /var/lib/mysql name: roost-mysql-db-data - # subPath: roostai_mysql_data ports: - containerPort: 3306 args: - --bind-address=* - --default-authentication-plugin=mysql_native_password imagePullPolicy: Always - volumes: - - name: roost-mysql-db-data - persistentVolumeClaim: - claimName: roost-mysql-db-pvc + volumeClaimTemplates: + - metadata: + name: roost-mysql-db-data + annotations: + "helm.sh/resource-policy": keep + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.database.storage.size }} + storageClassName: {{ .Values.database.storage.storageClass }} --- {{- end }} diff --git a/charts/roost/templates/roost-nginx.yaml b/charts/roost/templates/roost-nginx.yaml index 424b0a2..a42ed77 100644 --- a/charts/roost/templates/roost-nginx.yaml +++ b/charts/roost/templates/roost-nginx.yaml @@ -11,6 +11,11 @@ data: UI_SERVICE_NAME: roostai-react-app:4200 UI_SERVICE_PORT: '4200' K8S_MODE: 'true' + AI_CODE_ANALYZER_SERVICE_NAME: ai-code-analyzer-svc:5060 + AI_CODE_ANALYZER_SERVICE_PORT: '5060' + AI_CODE_ANALYZER_SUBDOMAIN: 'f{{ .Values.enterprise.domainURL }}' + AI_ANALYZER_DOMAIN: 'f{{ .Values.enterprise.domainURL }}' + MAIN_DOMAIN: '{{ .Values.enterprise.domainURL }}' --- apiVersion: v1 @@ -18,13 +23,19 @@ kind: Service metadata: name: roost-nginx-svc namespace: {{ .Release.Namespace }} -{{- if .Values.acm.enabled }} - annotations: - service.beta.kubernetes.io/aws-load-balancer-ssl-cert: {{ .Values.acm.arn }} -{{- end }} -{{- if eq .Values.cloudConfig.clusterType "gke" }} +{{- if not .Values.gateway.enabled }} +{{- if or (and .Values.acm.enabled .Values.acm.arn) (eq .Values.cloudConfig.clusterType "gke") }} annotations: + {{- if and .Values.acm.enabled .Values.acm.arn }} + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: {{ .Values.acm.arn }} + service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443" + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + {{- end }} + {{- if eq .Values.cloudConfig.clusterType "gke" }} cloud.google.com/neg: '{"ingress": true}' + {{- end }} +{{- end }} {{- end }} spec: {{- include "nginxService.type" . | indent 2 }} @@ -42,6 +53,104 @@ spec: --- +{{- if .Values.gateway.enabled }} + +{{- if .Values.gateway.createGatewayClass }} +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: {{ .Values.gateway.className }} +spec: + controllerName: gateway.nginx.org/nginx-gateway-fabric + +--- +{{- end }} + +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: roost-gateway + namespace: {{ .Release.Namespace }} +spec: + gatewayClassName: {{ .Values.gateway.className }} + +{{- if and .Values.acm.enabled .Values.acm.arn }} + infrastructure: + annotations: + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: {{ .Values.acm.arn | quote }} + service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing" + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443" + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" + service.beta.kubernetes.io/load-balancer-source-ranges: "0.0.0.0/0" + {{- range $key, $val := .Values.gateway.infraAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} +{{- else if .Values.gateway.infraAnnotations }} + infrastructure: + annotations: + {{- range $key, $val := .Values.gateway.infraAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} +{{- end }} + + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + +{{- if and .Values.acm.enabled .Values.acm.arn }} + - name: https + port: 443 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same +{{- end }} +--- + +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: roost-route + namespace: {{ .Release.Namespace }} +spec: + parentRefs: + - name: roost-gateway + namespace: {{ .Release.Namespace }} + hostnames: + - {{ .Values.enterprise.domainURL | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: roost-nginx-svc + port: 80 + +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: roost-ai-code-analyzer-route + namespace: {{ .Release.Namespace }} +spec: + parentRefs: + - name: roost-gateway + namespace: {{ .Release.Namespace }} + hostnames: + - {{ printf "f%s" .Values.enterprise.domainURL | quote }} + rules: + - backendRefs: + - name: roost-nginx-svc + port: 80 +--- + +{{- else }} + {{- if or (eq .Values.cloudConfig.clusterType "gke") (eq .Values.cloudConfig.clusterType "aks") }} {{- if .Values.certificateManager.createNew }} apiVersion: networking.gke.io/v1 @@ -67,12 +176,12 @@ metadata: kubernetes.io/ingress.class: gce {{- end }} {{- if .Values.azureCerts.enabled }} - kubernetes.azure.com/tls-cert-keyvault-uri: {{ .Values.azureCerts.identifier }} + kubernetes.azure.com/tls-cert-keyvault-uri: {{ .Values.azureCerts.identifier }} {{- end }} {{- if .Values.certificateManager.createNew }} networking.gke.io/managed-certificates: roost-gcp-cert {{- else if eq .Values.cloudConfig.clusterType "gke" }} - ingress.gcp.kubernetes.io/pre-shared-cert: {{ .Values.certificateManager.existingCert }} + ingress.gcp.kubernetes.io/pre-shared-cert: {{ .Values.certificateManager.existingCert }} {{- end }} spec: {{- if eq .Values.cloudConfig.clusterType "aks" }} @@ -87,8 +196,12 @@ spec: tls: - secretName: keyvault-roost-{{ .Values.cloudConfig.clusterType }}-ingress {{- end }} + --- {{- end }} + +{{- end }} + apiVersion: apps/v1 kind: Deployment metadata: diff --git a/charts/roost/templates/roost-postgres-db.yaml b/charts/roost/templates/roost-postgres-db.yaml index f1ff2cc..ac12025 100644 --- a/charts/roost/templates/roost-postgres-db.yaml +++ b/charts/roost/templates/roost-postgres-db.yaml @@ -6,9 +6,9 @@ metadata: name: roost-postgres-db-config namespace: {{ .Release.Namespace }} data: - POSTGRES_PASSWORD: 'Roost#123' # '{{ .Values.database.password }}' - POSTGRES_USER: 'postgres' # '{{ .Values.database.user }}' - POSTGRES_DB: 'roostio' # '{{ .Values.database.schema }}' + POSTGRES_PASSWORD: "{{ .Values.database.password }}" + POSTGRES_USER: "{{ .Values.database.user }}" + POSTGRES_DB: "{{ .Values.database.schema }}" --- apiVersion: v1 @@ -24,20 +24,6 @@ spec: port: 5432 targetPort: 5432 ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: roost-postgres-db-pvc - namespace: {{ .Release.Namespace }} -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 10Gi -{{- include "cluster.storageClassName" . | indent 2 }} - --- apiVersion: apps/v1 kind: Deployment @@ -54,6 +40,10 @@ spec: labels: app: roost-postgres-db spec: + securityContext: + fsGroup: 999 + runAsUser: 999 + runAsGroup: 999 containers: - name: roost-postgres-db image: postgres:15.2 # {{ .Values.roostConfig.dbVersion }} @@ -63,14 +53,21 @@ spec: volumeMounts: - mountPath: /var/lib/postgresql/data name: roost-postgres-db-data - # subPath: postgres_data ports: - containerPort: 5432 imagePullPolicy: Always - volumes: - - name: roost-postgres-db-data - persistentVolumeClaim: - claimName: roost-postgres-db-pvc + volumeClaimTemplates: + - metadata: + name: roost-postgres-db-data + annotations: + "helm.sh/resource-policy": keep + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.database.storage.size }} + storageClassName: {{ .Values.database.storage.storageClass }} --- {{- end }} diff --git a/charts/roost/templates/roost-sc.yaml b/charts/roost/templates/roost-sc.yaml index a106e5b..15da5ed 100644 --- a/charts/roost/templates/roost-sc.yaml +++ b/charts/roost/templates/roost-sc.yaml @@ -1,39 +1,48 @@ -{{- if eq .Values.cloudConfig.clusterType "eks" }} +{{- if and (eq .Values.cloudConfig.clusterType "eks") .Values.installClusterResources.storageClass }} apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: - name: roost-sc-efs + name: {{ .Values.storageClass }} provisioner: efs.csi.aws.com parameters: fileSystemId: {{ .Values.cloudConfig.efsFileSystemID }} - provisioner: efs.csi.aws.com - provisioningMode: efs-ap - - directoryPerms: '777' - filePerms: '666' - - uid: '0' - gid: '0' - # gidRangeStart: 1000 - # gidRangeEnd: 2000 - + provisioningMode: efs-ap basePath: /var/tmp/Roost - # Below properties will work in new release of https://github.com/kubernetes-sigs/aws-efs-csi-driver - # subPathPattern: '/${.PVC.name}/${.PVC.namespace}' - ensureUniqueDirectory: 'false' + directoryPerms: "770" + gidRangeStart: "10001" + gidRangeEnd: "20001" + ensureUniqueDirectory: "true" + subPathPattern: "/${.PVC.namespace}-${.PVC.name}" # aws supports only 4 level path. /var/tmp/Roost is already 3 level +reclaimPolicy: Retain +volumeBindingMode: Immediate + +--- +# EBS - used by MySQL +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: {{ .Values.database.storage.storageClass }} +provisioner: ebs.csi.aws.com +parameters: + type: gp3 + fsType: ext4 + encrypted: "true" +reclaimPolicy: Retain +volumeBindingMode: WaitForFirstConsumer +allowVolumeExpansion: true --- {{- end }} -{{- if eq .Values.cloudConfig.clusterType "aks" }} +{{- if and (eq .Values.cloudConfig.clusterType "aks") .Values.installClusterResources.storageClass }} apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: - name: roost-sc-azurefile-csi-nfs + name: {{ .Values.storageClass }} provisioner: file.csi.azure.com parameters: protocol: nfs - # skuName: Standard_LRS # available values: Premium_LRS, Premium_ZRS, Standard_LRS, Standard_GRS, Standard_ZRS, Standard_RAGRS, Standard_RAGZRS + skuName: Premium_LRS # NFS protocol requires Premium tier; options: Premium_LRS, Premium_ZRS, Standard_LRS, Standard_GRS, Standard_ZRS, Standard_RAGRS, Standard_RAGZRS allowVolumeExpansion: true reclaimPolicy: Delete volumeBindingMode: Immediate @@ -42,3 +51,19 @@ mountOptions: --- {{- end}} + +{{- if and (eq .Values.cloudConfig.clusterType "local") .Values.installClusterResources.storageClass }} +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ .Values.storageClass }} +spec: + capacity: + storage: 30Gi + accessModes: + - ReadWriteMany + storageClassName: roost-sc-local + hostPath: + path: {{ .Values.cloudConfig.localStoragePath }} +--- +{{- end}} diff --git a/charts/roost/templates/roost-web.yaml b/charts/roost/templates/roost-web.yaml index aa1e381..a89c04e 100644 --- a/charts/roost/templates/roost-web.yaml +++ b/charts/roost/templates/roost-web.yaml @@ -1,16 +1,20 @@ +{{- $hasTls := or .Values.gateway.tls.enabled (and .Values.acm.enabled .Values.acm.arn) -}} +{{- $useHttp := and (eq .Values.cloudConfig.clusterType "local") (not $hasTls) -}} +{{- $protocol := ternary "http" "https" $useHttp -}} apiVersion: v1 kind: ConfigMap metadata: name: roost-web-config namespace: {{ .Release.Namespace }} data: - REACT_APP_API_HOST: 'https://{{ .Values.enterprise.domainURL }}/api' - REACT_APP_REDIRECT_URI: 'https://{{ .Values.enterprise.domainURL }}/login' + REACT_APP_API_HOST: '{{ $protocol }}://{{ .Values.enterprise.domainURL }}/api' + REACT_APP_REDIRECT_URI: '{{ $protocol }}://{{ .Values.enterprise.domainURL }}/login' REACT_APP_ENTERPRISE_LOGO: '{{ .Values.enterprise.logo }}' - REACT_APP_REMOTE_CONSOLE_PROXY: 'https://{{ .Values.enterprise.domainURL }}' + REACT_APP_REMOTE_CONSOLE_PROXY: '{{ $protocol }}://{{ .Values.enterprise.domainURL }}' REACT_APP_GOOGLE_CLIENT_ID: '{{ .Values.auth.googleClientID }}' REACT_APP_AZURE_CLIENT_ID: '{{ .Values.auth.azureClientID }}' + REACT_APP_AZURE_TENANT_ID: '{{ .Values.auth.azureTenantID }}' REACT_APP_GITHUB_CLIENT_ID: '{{ .Values.auth.githubClientID }}' REACT_APP_LINKEDIN_CLIENT_ID: '{{ .Values.auth.linkedinClientID }}' REACT_APP_OKTA_CLIENT_ISSUER: '{{ .Values.auth.oktaClientIssuer }}' @@ -21,8 +25,9 @@ data: REACT_APP_AUTH0_CLIENT_ID: '{{ .Values.auth.auth0ClientID }}' REACT_APP_PING_FEDERATE_CLIENT_ISSUER: '{{ .Values.auth.pingFederateClientIssuer }}' REACT_APP_PING_FEDERATE_CLIENT_ID: '{{ .Values.auth.pingFederateClientID }}' + REACT_APP_OTP_LOGIN_ENABLED: '{{ .Values.auth.otpLogin }}' - REACT_APP_COOKIE_SECURE: 'true' + REACT_APP_COOKIE_SECURE: '{{ not $useHttp }}' REACT_APP_COOKIE_DOMAIN: '{{ .Values.enterprise.domainURL }}' REACT_APP_ROOST_VER: '{{ .Values.roostConfig.roostVersion }}' @@ -36,6 +41,7 @@ data: {{- end }} REACT_APP_ONLY_ROOSTGPT: '{{ .Values.roostConfig.onlyGPT }}' REACT_APP_NO_AUTH: '{{ .Values.auth.noAuth }}' + REACT_APP_USE_AS_ROOST_CLOUD_SERVER: '{{ .Values.roostConfig.useAsRoostCloudServer }}' --- apiVersion: v1 @@ -67,9 +73,21 @@ spec: labels: app: roost-web spec: + securityContext: + runAsNonRoot: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 containers: - name: roost-web image: zbio/roost-web:{{ .Values.roostConfig.roostVersion }} + # resources: + # requests: + # cpu: 20m + # memory: 64Mi + # limits: + # cpu: 100m + # memory: 128Mi envFrom: - configMapRef: name: roost-web-config diff --git a/charts/roost/values.yaml b/charts/roost/values.yaml index ea52da5..dce581b 100644 --- a/charts/roost/values.yaml +++ b/charts/roost/values.yaml @@ -1,26 +1,72 @@ # Default values for .. # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# +# ─── SECRET VALUES ──────────────────────────────────────────────────────────── +# This file (values.yaml) contains only non-secret defaults and is safe to +# commit to git. +# +# Create a separate file for secrets (e.g. values-secret.yaml) that is listed +# in .gitignore and pass it at deploy time: +# +# helm upgrade --install roost charts/roost \ +# -f charts/roost/values.yaml \ +# -f charts/roost/values-secret.yaml \ +# -n roost --create-namespace +# +# Typical values-secret.yaml contents: +# database: +# password: '' +# rootPassword: '' +# auth: +# localKey: '' +# jwt_secret: '' +# googleClientSecret: '' +# githubClientSecret: '' +# # ... other OAuth secrets +# email: +# senderPass: '' +# roostConfig: +# licenseKey: '' +# acm: +# arn: '' # EKS only +# cloudConfig: +# efsFileSystemID: '' # EKS only +# ────────────────────────────────────────────────────────────────────────────── + +# Kubernetes cluster domain. Override if your cluster uses a non-default domain. +clusterDomain: cluster.local +storageClass: hostpath #Set these values. standard-rwx (GKE), hostpath (Docker Desktop), any custom name for EKS + +installClusterResources: + storageClass: true database: integrated: true # true/false type: mysql # mysql/postgres # Specify, if database.integrated = false + # For integrated MySQL in the same namespace, use: roost-mysql-db-svc..svc.cluster.local host: '' port: 3306 - schema: '' - user: '' + schema: 'roostio' + user: 'root' password: '' + rootPassword: '' + storage: + storageClass: roost-db-sc-ebs + size: 20Gi auth: - noAuth: false # true/false + noAuth: true # true/false + otpLogin: true # true/false googleClientID: '' googleClientSecret: '' azureClientID: '' azureClientSecret: '' + azureTenantID: '' githubClientID: '' githubClientSecret: '' @@ -28,8 +74,8 @@ auth: linkedinClientID: '' linkedinClientSecret: '' - oktaClientIssuer: '' - oktaClientID: '' + oktaClientIssuer: 'https://integrator-9683991.okta.com/oauth2/default' + oktaClientID: '0oa10qvprv5Tg1aqF698' oktaClientSecret: '' azureADFSClientIssuer: '' @@ -40,51 +86,64 @@ auth: auth0ClientID: '' auth0ClientSecret: '' + xauth0ClientIssuer: '' + xauth0ClientID: '' + xauth0ClientSecret: '' + pingFederateClientIssuer: '' pingFederateClientID: '' pingFederateClientSecret: '' # REQUIRED: local auth key for roost, example : 06b5e496f8f53139de7d2cc03b1e71ce localKey: '' + jwt_secret: 'abcdadslkjfla1394cfvbwrjq4584163' enterprise: # logo url logo: https://roost.ai/hubfs/logos/Roost.ai-logo-gold.svg + appName: '' # domain where roostAI will be hosted, example : test.example.com - domainURL: '' + domainURL: 'localroost.localhost' # configure organisation name - don't use spaces orgName: '' # admin email, example suppor@zb.io orgAdminEmail: '' # email domain, example zb.io orgEmailDomain: '' + sslCertificatePath: '' + sslCertificateKeyPath: '' # configure email for email notification support email: sender: '' senderPass: '' + senderPassword: '' smtp: '' - smtpPort: '' + smtpPort: '465' roostConfig: licenseKey: '' # provide license key obtained from roost - jwtSecret: '' # 32-character-secure-long-secret + + roostAppReplicas: 1 # number of roost-app replicas; PVC uses ReadWriteMany to share across replicas enableRoostGPT: true # true/false - enableEaasServer: false # true/false - enableClusterLauncher: false # true/false - enableJumphost: false # true/false onlyGPT: false # true/false + useAsRoostCloudServer: false # true/false # roostVersion and dbVersion can be based on helm chart versioning - roostVersion: 'latest' + roostVersion: 'v1.2.0' dbVersion: 'v1.1.0' - verboseLevel: 2 + verboseLevel: 4 + ecs_mode: true cloudConfig: - clusterType: '' # eks/gke/aks/local + clusterType: 'local' # eks/gke/aks/local efsFileSystemID: '' # Specify only if cloud_provider.type = eks + # GKE note: clusterType=gke requires the Filestore CSI addon enabled on the cluster. + # It creates the 'standard-rwx' StorageClass automatically. Enable via: + # gcloud container clusters update --update-addons=GcpFilestoreCsiDriver=ENABLED + localStoragePath: '/tmp/roost-storage' # hostPath for local clusterType; must exist on the node # provide aws acm arn for certificates for eks acm: @@ -102,3 +161,94 @@ azureCerts: # certificate identifier # https://.vault.azure.net/certificates// identifier: '' + +gateway: + # Enable NGINX Gateway API mode. + # Requires NGINX Gateway Fabric (v2.4+) installed in the cluster. + # + # ── How traffic flows (gateway.enabled: true) ──────────────────────────── + # Internet + # └─► Cloud LoadBalancer (attached to NGF's own Service in nginx-gateway ns) + # └─► NGINX Gateway Fabric pod (reads Gateway + HTTPRoute resources) + # └─► roost-nginx-svc (ClusterIP — never exposed directly) + # └─► roost-nginx pod (reverse proxy → backend / frontend) + # + # Per cloud provider: + # EKS — AWS NLB is created for NGF Service. + # TLS: set acm.enabled=true + acm.arn → chart injects ACM annotation + # onto the Gateway infrastructure block; NLB terminates TLS. + # GKE — Google L4 NLB is created for NGF Service. + # TLS: use cert-manager to provision a K8s Secret, then set + # gateway.tls.enabled=true + gateway.tls.secretName. + # (GKE managed-cert annotations are NOT supported on Gateway resources.) + # AKS — Azure Standard LB is created for NGF Service. + # TLS: same as GKE — cert-manager + gateway.tls.enabled + secretName. + # local — Docker Desktop exposes NGF on 127.0.0.1; no TLS needed. + # ───────────────────────────────────────────────────────────────────────── + # + # Install steps: + # 1. Install Gateway API CRDs (skip if already installed, e.g. Docker Desktop >= 4.27): + # Check: kubectl get crd gatewayclasses.gateway.networking.k8s.io \ + # -o jsonpath='{.metadata.annotations.gateway\.networking\.k8s\.io/bundle-version}' + # Install (only if not present or older than v1.2): + # kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.4.2" | kubectl apply -f - + # kubectl apply --server-side -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.4.2/deploy/crds.yaml + + # 2. Install NGINX Gateway Fabric via Helm: + # # Use --skip-crds if Gateway API CRDs v1.5+ are already installed (avoids downgrade conflict) + # helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --skip-crds + # + # Set to false to use legacy Ingress/LoadBalancer mode (backward-compatible). + enabled: true + + # GatewayClass name — must match the NGINX Gateway Fabric's GatewayClass name. + className: nginx + + # Set true ONLY if you want this chart to create the GatewayClass resource. + # If NGINX Gateway Fabric is already installed cluster-wide it creates its own — leave false. + createGatewayClass: false + + # TLS: reference a Kubernetes Secret containing tls.crt + tls.key. + # Leave disabled for HTTP-only deployments (local dev). + # Use cert-manager to auto-provision the Secret in cloud environments. + tls: + enabled: false + secretName: 'roost-tls-secret' + + # Extra annotations forwarded to the Gateway's infrastructure (underlying LoadBalancer Service). + # EKS+ACM annotations are auto-populated from acm.enabled / acm.arn above. + # Add custom cloud LB annotations here if needed. + infraAnnotations: {} + # Example: + # service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing + + # FQDN of the NGINX Gateway Fabric's traffic service used for in-cluster hairpin routing. + # Format: -nginx-gateway-fabric..svc.cluster.local + # If installed with: helm install ngf ... -n nginx-gateway → use the default below. + nginxGatewayService: 'ngf-nginx-gateway-fabric.nginx-gateway.svc.cluster.local' + + +pvcs: + aiServer: 'local-pvc' + +eaasServerIp: '' +eaasServerPemKey : '' +eaasServerUsername : 'roost' + +aiCodeAnalyzer: + enabled: true + + replicas: 1 + + imageTag: latest + + storage: + size: 20Gi + + db: + database: code_parser + user: postgres + password: '12345678' + + storage: + size: 20Gi \ No newline at end of file diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..8cad85a --- /dev/null +++ b/release.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +helm package charts/roost -d releases + +helm repo index releases --url https://roost-io.github.io/helm/releases \ No newline at end of file diff --git a/releases/index.yaml b/releases/index.yaml new file mode 100644 index 0000000..d1f8a9c --- /dev/null +++ b/releases/index.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +entries: + roost: + - apiVersion: v2 + appVersion: 1.0.0 + created: "2026-05-13T13:43:46.603176+05:30" + description: Roost.ai, an End-to-End Testing platform using Generative AI. + digest: d1626eade9a17698c2cda4e142597315366ae6a568440d8e2a61a855bb7b7f95 + name: roost + type: application + urls: + - https://roost-io.github.io/helm/releases/roost-1.0.0.tgz + version: 1.0.0 +generated: "2026-05-13T13:43:46.601318+05:30" diff --git a/releases/roost-1.0.0.tgz b/releases/roost-1.0.0.tgz new file mode 100644 index 0000000..2e3c35e Binary files /dev/null and b/releases/roost-1.0.0.tgz differ