From bb8fa0b838aa9ae26aaa4c8a076c7b75897fa825 Mon Sep 17 00:00:00 2001 From: Patrick Lee Scott Date: Mon, 21 Sep 2026 15:53:50 -0500 Subject: [PATCH] feat: add CelldStack dev mode spec.dev runs celld dev instead of a bucket-backed fleet node. It forces one replica and ignores aws, azurite, and bucket. Needs a celld chart release that implements values.dev. --- .github/workflows/on-pr.yaml | 1 + .github/workflows/on-push-main.yaml | 1 + Makefile | 1 + README.md | 14 ++++++++ apis/celldstacks/definition.yaml | 35 +++++++++++++++++-- examples/celldstacks/dev.yaml | 10 ++++++ functions/render/000-state-init.yaml.gotmpl | 28 +++++++++++++-- .../render/200-helm-release-celld.yaml.gotmpl | 1 + tests/test-render/main.k | 35 +++++++++++++++++++ 9 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 examples/celldstacks/dev.yaml diff --git a/.github/workflows/on-pr.yaml b/.github/workflows/on-pr.yaml index 4cb4fb2..dcd60b1 100644 --- a/.github/workflows/on-pr.yaml +++ b/.github/workflows/on-pr.yaml @@ -34,6 +34,7 @@ jobs: { "example": "examples/celldstacks/minimal.yaml" }, { "example": "examples/celldstacks/standard.yaml" }, { "example": "examples/celldstacks/azurite.yaml" }, + { "example": "examples/celldstacks/dev.yaml" }, { "example": "examples/celldstacks/aws.yaml" }, { "example": "examples/celldstacks/aws-local.yaml" } ] diff --git a/.github/workflows/on-push-main.yaml b/.github/workflows/on-push-main.yaml index 76165f3..6d76a55 100644 --- a/.github/workflows/on-push-main.yaml +++ b/.github/workflows/on-push-main.yaml @@ -29,6 +29,7 @@ jobs: { "example": "examples/celldstacks/minimal.yaml" }, { "example": "examples/celldstacks/standard.yaml" }, { "example": "examples/celldstacks/azurite.yaml" }, + { "example": "examples/celldstacks/dev.yaml" }, { "example": "examples/celldstacks/aws.yaml" }, { "example": "examples/celldstacks/aws-local.yaml" } ] diff --git a/Makefile b/Makefile index a286bda..05b11db 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ EXAMPLES := \ examples/celldstacks/minimal.yaml:: \ examples/celldstacks/standard.yaml:: \ examples/celldstacks/azurite.yaml:: \ + examples/celldstacks/dev.yaml:: \ examples/celldstacks/aws.yaml:: \ examples/celldstacks/aws-local.yaml:: diff --git a/README.md b/README.md index a4f171c..ec6d600 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,18 @@ spec: This installs one celld node in namespace `celld`. For local, enable Azurite. For AWS, enable `spec.aws` so the stack creates a bucket and binds the celld ServiceAccount with EKS Pod Identity. +```yaml +spec: + clusterName: my-cluster + dev: + enabled: true + hostPath: /var/celld/worker +``` + +`dev.enabled` runs `celld dev` against a local object store. It does not create a bucket. `hostPath` must be visible on the node. This needs a celld chart release that understands `values.dev` (newer than 0.4.0). + +Azurite remains the bucket-emulator path: + ```yaml spec: clusterName: my-cluster @@ -78,6 +90,8 @@ Not applicable. This stack installs a Helm release; it does not adopt cloud reso | `endpoint` | string | — | S3-compatible endpoint | | `region` | string | `us-east-2` | Object-storage region | | `credentials.existingSecret` | string | — | Secret with AWS_* keys (R2 / BYO). Unused when `aws.enabled` | +| `dev.enabled` | boolean | `false` | Run `celld dev` (local store, one project). Ignores bucket, aws, and azurite. Needs a chart release that implements `values.dev` | +| `dev.hostPath` | string | — | Node path of a Wrangler project. Empty uses the chart placeholder and disables watch | | `azurite.enabled` | boolean | `false` | Deploy in-cluster Azurite and point celld at `az://celld` (local/dev only) | | `azurite.container` | string | `celld` | Blob container name | | `aws.enabled` | boolean | `false` | Create S3 bucket and point celld at `s3://` | diff --git a/apis/celldstacks/definition.yaml b/apis/celldstacks/definition.yaml index eed4f3c..d7ce3e9 100644 --- a/apis/celldstacks/definition.yaml +++ b/apis/celldstacks/definition.yaml @@ -123,8 +123,39 @@ spec: existingSecret: description: Name of a Secret in the celld namespace with AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (and optional AWS_SESSION_TOKEN). For S3-compatible stores (R2) or BYO keys. type: string + dev: + description: Run celld dev (local object store, one Wrangler project) instead of a bucket-backed fleet node. Ignores bucket, aws, and azurite. Requires a celld chart that implements values.dev. + type: object + properties: + enabled: + description: When true, the chart runs `celld dev` on one replica. + type: boolean + default: false + hostPath: + description: Node path of a Wrangler project. Must be visible on the kubelet (kind extraMounts). Empty uses the chart placeholder worker and disables watch. + type: string + mountPath: + description: Mount path inside the pod. Defaults to /workspace. + type: string + default: /workspace + port: + description: Worker listener port. Defaults to 8080. + type: integer + default: 8080 + logs: + description: Pass --logs. Defaults to true. + type: boolean + default: true + watch: + description: Watch the project and rebuild. Forced off when hostPath is empty. + type: boolean + default: true + clean: + description: Pass --clean to delete .celld/dev before start. + type: boolean + default: false azurite: - description: Deploy in-cluster Azurite and point celld at it. Local/dev only — not a production fleet store. + description: Deploy in-cluster Azurite and point celld at it. Local/dev only — not a production fleet store. Ignored when dev.enabled is true. type: object properties: enabled: @@ -148,7 +179,7 @@ spec: storageClassName: type: string aws: - description: Provision an S3 bucket and grant the celld pod access. On EKS, Pod Identity is the default. Locally, disable podIdentity and reuse hops `local aws` credentials. Ignored when azurite.enabled is true. + description: Provision an S3 bucket and grant the celld pod access. On EKS, Pod Identity is the default. Locally, disable podIdentity and reuse hops `local aws` credentials. Ignored when azurite.enabled or dev.enabled is true. type: object properties: enabled: diff --git a/examples/celldstacks/dev.yaml b/examples/celldstacks/dev.yaml new file mode 100644 index 0000000..504da75 --- /dev/null +++ b/examples/celldstacks/dev.yaml @@ -0,0 +1,10 @@ +apiVersion: hops.ops.com.ai/v1alpha1 +kind: CelldStack +metadata: + name: celld + namespace: default +spec: + clusterName: my-cluster + dev: + enabled: true + hostPath: /var/celld/worker diff --git a/functions/render/000-state-init.yaml.gotmpl b/functions/render/000-state-init.yaml.gotmpl index bc6f3e5..c327909 100644 --- a/functions/render/000-state-init.yaml.gotmpl +++ b/functions/render/000-state-init.yaml.gotmpl @@ -48,6 +48,15 @@ {{- $imageTag := $image.tag | default "0.4.0" }} {{- $persistence := $spec.persistence | default dict }} {{- $credentials := $spec.credentials | default dict }} +{{- $dev := $spec.dev | default dict }} +{{- $devEnabled := false }} +{{- if hasKey $dev "enabled" }}{{- $devEnabled = $dev.enabled }}{{- end }} +{{- $devLogs := true }} +{{- if hasKey $dev "logs" }}{{- $devLogs = $dev.logs }}{{- end }} +{{- $devWatch := true }} +{{- if hasKey $dev "watch" }}{{- $devWatch = $dev.watch }}{{- end }} +{{- $devClean := false }} +{{- if hasKey $dev "clean" }}{{- $devClean = $dev.clean }}{{- end }} {{- $azurite := $spec.azurite | default dict }} {{- $azuriteEnabled := false }} {{- if hasKey $azurite "enabled" }}{{- $azuriteEnabled = $azurite.enabled }}{{- end }} @@ -58,9 +67,13 @@ {{- $aws := $spec.aws | default dict }} {{- $awsEnabled := false }} {{- if hasKey $aws "enabled" }}{{- $awsEnabled = $aws.enabled }}{{- end }} -{{- if $azuriteEnabled }} +{{- if or $azuriteEnabled $devEnabled }} {{- $awsEnabled = false }} {{- end }} +{{- if $devEnabled }} + {{- $azuriteEnabled = false }} + {{- $replicaCount = 1 }} +{{- end }} {{- $awsForceDestroy := true }} {{- if hasKey $aws "forceDestroy" }}{{- $awsForceDestroy = $aws.forceDestroy }}{{- end }} {{- $awsRegion := $aws.region | default ($spec.region | default "us-east-2") }} @@ -84,7 +97,9 @@ {{- $awsCredsLocalName = printf "%s-aws" $releaseName }} {{- end }} {{- $bucket := $spec.bucket | default "" }} -{{- if $azuriteEnabled }} +{{- if $devEnabled }} + {{- $bucket = "" }} +{{- else if $azuriteEnabled }} {{- $bucket = printf "az://%s" $azuriteContainer }} {{- else if $awsEnabled }} {{- $bucket = printf "s3://%s" $awsBucketName }} @@ -146,6 +161,15 @@ "localName" $awsCredsLocalName ) ) + "dev" (dict + "enabled" $devEnabled + "hostPath" ($dev.hostPath | default "") + "mountPath" ($dev.mountPath | default "/workspace") + "port" ($dev.port | default 8080) + "logs" $devLogs + "watch" $devWatch + "clean" $devClean + ) "azurite" (dict "enabled" $azuriteEnabled "container" $azuriteContainer diff --git a/functions/render/200-helm-release-celld.yaml.gotmpl b/functions/render/200-helm-release-celld.yaml.gotmpl index 37550cc..fe5226d 100644 --- a/functions/render/200-helm-release-celld.yaml.gotmpl +++ b/functions/render/200-helm-release-celld.yaml.gotmpl @@ -20,6 +20,7 @@ "name" $state.serviceAccount.name ) "persistence" $state.persistence + "dev" $state.dev "azurite" $state.azurite "bootstrapPlaceholder" $state.aws.enabled }} diff --git a/tests/test-render/main.k b/tests/test-render/main.k index da8c549..168b418 100644 --- a/tests/test-render/main.k +++ b/tests/test-render/main.k @@ -307,6 +307,41 @@ _items = [ } } + # ========================================================================== + # Test 9b: dev.enabled runs celld dev and does not configure a fleet bucket. + # ========================================================================== + metav1alpha1.CompositionTest { + metadata.name = "dev-enabled-skips-bucket" + spec = { + compositionPath = "apis/celldstacks/composition.yaml" + xrdPath = "apis/celldstacks/definition.yaml" + timeoutSeconds = 60 + validate = False + xr = stacksv1alpha1.CelldStack { + metadata.name = "dev-test" + spec = { + clusterName = "my-cluster" + dev = {enabled = True, hostPath = "/var/celld/worker"} + azurite = {enabled = True} + aws = {enabled = True} + } + } + assertResources = [ + { + apiVersion = "helm.m.crossplane.io/v1beta1" + kind = "Release" + metadata.name = "dev-test" + spec.forProvider.values = { + replicaCount = 1 + dev = {enabled = True, hostPath = "/var/celld/worker"} + azurite = {enabled = False} + celld = {bucket = ""} + } + } + ] + } + } + # ========================================================================== # Test 10: aws.enabled renders an S3 bucket and PodIdentity, not IAM users. # ==========================================================================