diff --git a/.mcp.json b/.mcp.json index f82e538..9f3f3be 100644 --- a/.mcp.json +++ b/.mcp.json @@ -22,14 +22,6 @@ "pgtuner": { "type": "sse", "url": "http://localhost:8085/sse" - }, - "fetch": { - "type": "sse", - "url": "http://localhost:8082/sse" - }, - "sequentialthinking": { - "type": "sse", - "url": "http://localhost:8083/sse" } } } diff --git a/Makefile b/Makefile index 9479e87..0f27f50 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # Variables REGISTRY ?= ghcr.io/cpfarhood -IMAGE_NAME ?= antigravity +IMAGE_NAME ?= devcontainer IMAGE_TAG ?= latest FULL_IMAGE = $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG) @@ -29,15 +29,15 @@ run: -e HAPPY_EXPERIMENTAL="true" \ -v $(PWD)/home:/home \ -v $(PWD)/workspace:/workspace \ - --name antigravity \ + --name devcontainer \ $(FULL_IMAGE) @echo "Access at http://localhost:5800" # Stop the running container stop: - @echo "Stopping antigravity container..." - docker stop antigravity || true - docker rm antigravity || true + @echo "Stopping devcontainer..." + docker stop devcontainer || true + docker rm devcontainer || true # Clean up local volumes clean: stop @@ -81,7 +81,7 @@ helm-port-forward: # Show help help: - @echo "Antigravity Dev Container Makefile" + @echo "Dev Container Makefile" @echo "" @echo "Usage: make [target]" @echo "" @@ -101,7 +101,7 @@ help: @echo "" @echo "Variables:" @echo " REGISTRY - Docker registry (default: ghcr.io/cpfarhood)" - @echo " IMAGE_NAME - Image name (default: antigravity)" + @echo " IMAGE_NAME - Image name (default: devcontainer)" @echo " IMAGE_TAG - Image tag (default: latest)" @echo " RELEASE_NAME - Helm release name (default: mydev)" @echo " NAMESPACE - Kubernetes namespace (default: default)" diff --git a/chart/templates/NOTES.txt b/chart/templates/NOTES.txt new file mode 100644 index 0000000..fb4c248 --- /dev/null +++ b/chart/templates/NOTES.txt @@ -0,0 +1,31 @@ +Dev Container "{{ .Values.name }}" has been deployed. + +{{- if ne (.Values.ide.type | default "vscode") "none" }} + +Access the IDE: + kubectl port-forward deployment/{{ include "devcontainer.fullname" . }} 5800:5800 -n {{ .Release.Namespace }} + Then open: http://localhost:5800 +{{- end }} + +{{- if .Values.ssh.enabled }} + +SSH access: + kubectl port-forward deployment/{{ include "devcontainer.fullname" . }} 2222:22 -n {{ .Release.Namespace }} + Then: ssh -p 2222 user@localhost +{{- end }} + +Useful commands: + Logs: kubectl logs -f deployment/{{ include "devcontainer.fullname" . }} -n {{ .Release.Namespace }} + Shell: kubectl exec -it deployment/{{ include "devcontainer.fullname" . }} -n {{ .Release.Namespace }} -- bash + +{{- if not (lookup "v1" "Secret" .Release.Namespace (include "devcontainer.envSecretName" .)) }} + +Optional: Create a secret for GITHUB_TOKEN, VNC_PASSWORD, etc: + kubectl create secret generic {{ include "devcontainer.envSecretName" . }} \ + --from-literal=GITHUB_TOKEN=ghp_xxx \ + --from-literal=VNC_PASSWORD=changeme \ + -n {{ .Release.Namespace }} +{{- end }} + +Note: The PVC "{{ include "devcontainer.pvcName" . }}" is protected from deletion on helm uninstall. +To remove it manually: kubectl delete pvc {{ include "devcontainer.pvcName" . }} -n {{ .Release.Namespace }} diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl index ee6a9b0..e9d24bc 100644 --- a/chart/templates/_helpers.tpl +++ b/chart/templates/_helpers.tpl @@ -2,6 +2,9 @@ Resource name prefix: devcontainer-{name} */}} {{- define "devcontainer.fullname" -}} +{{- if not .Values.name }} +{{- fail "values.name is required and must not be empty" }} +{{- end }} {{- printf "devcontainer-%s" .Values.name }} {{- end }} @@ -25,6 +28,18 @@ Common labels {{- define "devcontainer.labels" -}} app: devcontainer instance: {{ .Values.name }} +app.kubernetes.io/name: devcontainer +app.kubernetes.io/instance: {{ .Values.name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +{{- end }} + +{{/* +Selector labels — keep narrow since changing these requires recreating the Deployment +*/}} +{{- define "devcontainer.selectorLabels" -}} +app: devcontainer +instance: {{ .Values.name }} {{- end }} {{/* diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml index 0dc03f6..7a9a0e4 100644 --- a/chart/templates/deployment.yaml +++ b/chart/templates/deployment.yaml @@ -8,7 +8,7 @@ spec: replicas: 1 selector: matchLabels: - {{- include "devcontainer.labels" . | nindent 6 }} + {{- include "devcontainer.selectorLabels" . | nindent 6 }} template: metadata: labels: @@ -23,7 +23,7 @@ spec: {{- if and .Values.ide.type (eq .Values.ide.type "antigravity") }} initContainers: - name: setup-userdata - image: busybox:latest + image: busybox:1.37 command: ['sh', '-c'] args: - | @@ -169,7 +169,7 @@ spec: {{- if .Values.mcp.sidecars.homeassistant.enabled }} - name: homeassistant-mcp image: "{{ .Values.mcp.sidecars.homeassistant.image.repository }}:{{ .Values.mcp.sidecars.homeassistant.image.tag }}" - imagePullPolicy: Always + imagePullPolicy: IfNotPresent command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.homeassistant.port }}"] ports: - name: homeassistant @@ -203,7 +203,7 @@ spec: {{- if .Values.mcp.sidecars.pgtuner.enabled }} - name: pgtuner-mcp image: "{{ .Values.mcp.sidecars.pgtuner.image.repository }}:{{ .Values.mcp.sidecars.pgtuner.image.tag }}" - imagePullPolicy: Always + imagePullPolicy: Always # pgtuner uses `latest` tag (no versioned releases available) command: ["python", "-m", "pgtuner_mcp", "--mode", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"] ports: - name: pgtuner @@ -237,7 +237,7 @@ spec: {{- if .Values.mcp.sidecars.playwright.enabled }} - name: playwright-mcp image: "{{ .Values.mcp.sidecars.playwright.image.repository }}:{{ .Values.mcp.sidecars.playwright.image.tag }}" - imagePullPolicy: Always + imagePullPolicy: IfNotPresent command: ["node"] args: - cli.js diff --git a/chart/templates/pvc.yaml b/chart/templates/pvc.yaml index a57ef1b..b79659a 100644 --- a/chart/templates/pvc.yaml +++ b/chart/templates/pvc.yaml @@ -2,12 +2,16 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ include "devcontainer.pvcName" . }} + annotations: + helm.sh/resource-policy: keep labels: {{- include "devcontainer.labels" . | nindent 4 }} spec: accessModes: - ReadWriteMany + {{- if .Values.storage.className }} storageClassName: {{ .Values.storage.className }} + {{- end }} resources: requests: storage: {{ .Values.storage.size }} diff --git a/chart/values.schema.json b/chart/values.schema.json index 71970ae..1b09df7 100644 --- a/chart/values.schema.json +++ b/chart/values.schema.json @@ -35,7 +35,7 @@ "githubRepo": { "type": "string", "description": "GitHub repository URL to clone", - "pattern": "^https://github\\.com/.+/.+$" + "pattern": "^https?://.+/.+/.+$" }, "ide": { "type": "object", @@ -108,7 +108,7 @@ "description": "Storage class name (must support ReadWriteMany)" } }, - "required": ["size", "className"] + "required": ["size"] }, "resources": { "type": "object", @@ -143,12 +143,10 @@ "properties": { "serverUrl": { "type": "string", - "format": "uri", "description": "Happy Coder server URL" }, "webappUrl": { "type": "string", - "format": "uri", "description": "Happy Coder webapp URL" }, "homeDir": { @@ -161,7 +159,7 @@ "description": "Enable experimental Happy features" } }, - "required": ["serverUrl", "webappUrl", "homeDir", "experimental"] + "required": ["homeDir", "experimental"] }, "mcp": { "type": "object", diff --git a/chart/values.yaml b/chart/values.yaml index bba5a6c..420c37c 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -45,7 +45,7 @@ user: # Storage configuration storage: size: 32Gi - className: ceph-filesystem + className: "" # Empty string uses the cluster's default StorageClass (must support ReadWriteMany) # Resource allocation resources: @@ -70,8 +70,8 @@ clusterAccess: none # Happy Coder AI assistant configuration happy: - serverUrl: "https://happy.farh.net" - webappUrl: "https://happy-coder.farh.net" + serverUrl: "" + webappUrl: "" homeDir: "/config/userdata/.happy" experimental: "true" @@ -115,7 +115,7 @@ mcp: enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN image: repository: ghcr.io/homeassistant-ai/ha-mcp - tag: stable + tag: v6.7.1 port: 8087 resources: requests: @@ -145,7 +145,7 @@ mcp: enabled: true image: repository: mcr.microsoft.com/playwright/mcp - tag: latest + tag: v0.0.68 port: 8086 resources: requests: diff --git a/scripts/cont-init-user.sh b/scripts/cont-init-user.sh index 0963b1d..f4bb39c 100644 --- a/scripts/cont-init-user.sh +++ b/scripts/cont-init-user.sh @@ -2,5 +2,9 @@ # Fix the app user (UID 1000) created by baseimage-gui at runtime. # baseimage-gui sets shell=/sbin/nologin and home=/dev/null, which # prevents VSCode from opening terminals. -usermod -s /bin/bash app -usermod -d /config/userdata app +if id app >/dev/null 2>&1; then + usermod -s /bin/bash app + usermod -d /config/userdata app +else + echo "WARNING: 'app' user not found, skipping usermod" >&2 +fi diff --git a/scripts/init-repo.sh b/scripts/init-repo.sh index 99c3349..077e920 100644 --- a/scripts/init-repo.sh +++ b/scripts/init-repo.sh @@ -22,6 +22,7 @@ if [ -n "$GITHUB_TOKEN" ]; then # Create or update the credentials file CREDENTIALS_FILE="/config/userdata/.git-credentials" + mkdir -p "$(dirname "$CREDENTIALS_FILE")" # Support multiple git hosting providers # GitHub supports both oauth2 and token as username @@ -51,6 +52,7 @@ else # Create an empty credentials file with proper permissions CREDENTIALS_FILE="/config/userdata/.git-credentials" + mkdir -p "$(dirname "$CREDENTIALS_FILE")" touch "$CREDENTIALS_FILE" chmod 600 "$CREDENTIALS_FILE" diff --git a/scripts/startapp.sh b/scripts/startapp.sh index 748fc9c..bfae2e6 100644 --- a/scripts/startapp.sh +++ b/scripts/startapp.sh @@ -34,6 +34,9 @@ case "$IDE" in exec sleep infinity ;; *) + if [ "$IDE" != "vscode" ]; then + echo "WARNING: Unknown IDE value '$IDE', defaulting to VSCode" + fi echo "Opening VSCode in: $WORKSPACE_DIR" exec code --new-window --wait "$WORKSPACE_DIR" ;;