Proto commits in pulumi/pulumi-kubernetes-operator

These 23 commits are when the Protocol Buffers files have changed:

Commit:772b91e
Author:Guinevere Saenger
Committer:GitHub

Run Destroy from state (#1249) ### Proposed changes This pull request introduces a new Source for `pulumi destroy` operations, `projectInfo`. For Destroy operations, Pulumi does not need a program, and the Operator does not need a program source. The only thing Pulumi needs is the project name and runtime. Currently, the Workspace requires a program source to run destroy, which will fail to be provided to the Stack when the program source and the Stack are deleted at the same time. After this this change, when a Stack is being torn down, the Workspace pod receives a stubbed `Pulumi.yaml` with project name and runtime, which the operator agent then uses to destroy all resources in that project. ### Related issues (optional) Closes #1222. Closes https://github.com/pulumi/pulumi-kubernetes-operator/issues/441.

Commit:83f4ad9
Author:Guinevere Saenger
Committer:GitHub

feat: add --run-program support for destroy and refresh (#1171) ## Summary - Adds a `runProgram` field to the Stack CRD that causes `pulumi destroy` and `pulumi refresh` to execute the user's program before operating - Plumbs the field through Update CRD → gRPC proto → agent server → Pulumi Automation API (`optdestroy.RunProgram` / `optrefresh.RunProgram`) - Useful when programs perform setup (network access, credential loading) needed during destroy/refresh Closes #1165 ## Changes **Hand-edited:** - `agent/pkg/proto/agent.proto` — added `run_program` field to `DestroyRequest` and `RefreshRequest` - `agent/pkg/server/server.go` — pass `optdestroy.RunProgram` / `optrefresh.RunProgram` when set - `agent/pkg/server/server_test.go` — added `"with run-program"` test cases for both `TestDestroy` and `TestRefresh` - `operator/api/auto/v1alpha1/update_types.go` — added `RunProgram *bool` to `UpdateSpec` - `operator/api/pulumi/shared/stack_types.go` — added `RunProgram bool` to `StackSpec` - `operator/internal/controller/auto/update_controller.go` — pass `RunProgram` in `Destroy()` and `Refresh()` agent requests - `operator/internal/controller/pulumi/stack_controller.go` — pass `RunProgram` from Stack spec into `newDestroy()` Update CR **Generated** (via `make codegen` + `cd agent && make protoc`): - Proto Go code, CRDs, Helm CRDs, deep copy, apply configs, CRD docs ## Test plan - [x] `TestDestroy/with_run-program` — agent server unit test - [x] `TestRefresh/with_run-program` — agent server unit test - [x] All existing unit tests pass (`make test` from operator/) - [ ] CI 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Commit:03a57ff
Author:Eron Wright

Add drift detection infrastructure for Pulumi Kubernetes Operator This commit implements the foundational infrastructure for drift detection as outlined in issue #1037. Drift detection allows users to monitor when cloud resources diverge from their desired state defined in Stack CRs. ## Changes ### API/CRD Changes: - Add DriftDetectionSpec to configure drift detection schedules - Add DriftDetectionStatus to track last drift check time - Add DriftDetected condition to Stack status - Add previewOnly field to Update CRD for non-destructive refresh ### Protocol Buffer Changes: - Add preview_only field to RefreshRequest message - Regenerate proto code ### Agent Changes: - Update Refresh() to support preview-only mode - Use RunProgram(false) option when preview_only is requested ### Controller Changes: - Add newDriftDetection() helper to create drift detection Updates - Update markStackSucceeded() to handle drift detection results - Parse refresh results to set DriftDetected condition - Emit StackDriftDetected events when drift is found - Update UpdateReconciler to pass preview_only flag to agent ### Code Generation: - Update CRD manifests with new fields - Regenerate deepcopy methods - Update API documentation ## Limitations & Future Work This is foundational infrastructure. Future work needed: - [ ] Add cron-based scheduling logic (currently requires manual trigger) - [ ] Implement auto-remediation workflow - [ ] Wait for upstream Pulumi Automation API support for preview-only refresh - [ ] Add comprehensive tests for drift detection scenarios - [ ] Add example Stack CRs demonstrating drift detection usage Related: #1037 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>

Commit:2411489
Author:Eron Wright
Committer:GitHub

Add structured configuration support with JSON values and ConfigMap references (#1023) ## Summary This PR implements comprehensive structured configuration support for the Pulumi Kubernetes Operator, addressing two long-standing feature requests: - Support for complex configuration values (objects, arrays, booleans, numbers) - [#258](https://github.com/pulumi/pulumi-kubernetes-operator/issues/258) - Reading configuration from ConfigMaps - [#872](https://github.com/pulumi/pulumi-kubernetes-operator/issues/872) The implementation leverages Pulumi CLI's [JSON configuration support](https://github.com/pulumi/pulumi/pull/19427) (v3.202.0+) and extends both the Stack and Workspace APIs to naturally represent structured values using Kubernetes' native JSON type support. ## Key Features ### 1. Structured Configuration Values - **Stack API**: `config` field now accepts objects, arrays, numbers, and booleans directly in YAML - **Workspace API**: `ConfigItem.Value` field supports structured values naturally - Uses `apiextensionsv1.JSON` for natural Kubernetes representation - Fully backwards compatible with existing string-only configurations ### 2. ConfigMap References - New `configRef` field in Stack API for loading config from ConfigMaps - Supports both string and JSON-parsed values via `json: true` flag - Parallel to existing `secretsRef` functionality ### 3. Version Detection & Safety - Automatic Pulumi CLI version detection via new `PulumiVersion` RPC - Stack enters "Stalled" condition if CLI version < v3.202.0 when using structured config - Clear error messages guide users to upgrade ## API Changes ### Stack API ```yaml apiVersion: pulumi.com/v1 kind: Stack spec: # Structured values in config (NEW) config: simpleKey: "string" dbConfig: host: "localhost" port: 5432 regions: ["us-west-2", "us-east-1"] maxConns: 100 enableSSL: true # ConfigMap references (NEW) configRef: appSettings: name: app-config key: settings.json json: true ``` ### Workspace API ```yaml apiVersion: auto.pulumi.com/v1alpha1 kind: Workspace spec: stacks: - name: dev config: # Structured object value (NEW) - key: myapp:database value: host: "localhost" port: 5432 # JSON from environment or file (NEW) - key: myapp:features valueFrom: env: FEATURE_FLAGS json: true ``` ## Implementation Details ### Architecture Changes 1. **Agent Proto**: Extended `ConfigItem` to use `google.protobuf.Value` for structured values, added `PulumiVersion` RPC 2. **Agent Server**: Enhanced `SetAllConfig` to build JSON documents and use Pulumi automation API's `SetAllConfigJson` 3. **Workspace Controller**: Queries Pulumi version on pod ready, translates structured values to protobuf 4. **Stack Controller**: Version validation, ConfigMap resolution, structured config translation ### Key Technical Decisions - **Replace Semantics**: Structured values replace entire objects (no merge/patch support) - **No Structured Secrets**: Limitation of Pulumi CLI - secrets must be strings only - **No Path Support**: `path: true` incompatible with structured values (validation enforced by CLI) - **Version Gating**: Clear errors when CLI doesn't support JSON config ## Backwards Compatibility ✅ **Fully backwards compatible** - Existing string configs work unchanged (JSON encoding handles strings transparently) - No manifest changes required for existing Stacks or Workspaces - New features are opt-in via structured values or `json: true` flags ## Testing ### Unit Tests - Agent config unmarshaling with JSON values - Workspace controller config translation - Version detection and comparison logic ### E2E Tests - Structured config from inline values - Structured config from ConfigMaps - Version compatibility validation - Mixed string and structured configs ### Examples - Comprehensive examples in `examples/structured-config/` - Both Stack and Workspace API patterns - ConfigMap integration examples ## Migration Guide _TODO: Helm does not automatically upgrade CRDs, please confirm and suggest a solution._ Users can adopt structured configuration incrementally: 1. **String configs continue working**: No changes needed 2. **Add structured values**: Simply use YAML objects/arrays in `config` 3. **Use ConfigMaps**: Add `configRef` entries as needed 4. **Workspace users**: Replace string values with structured YAML naturally ## Dependencies - Pulumi SDK v3.202.0+ ## Test Plan - [x] Unit tests pass for all new functionality - [x] E2E tests validate structured config scenarios - [x] Version detection works correctly - [x] Backwards compatibility verified - [x] Example manifests tested ## Related Issues - Closes #258 - Support for complex configuration values - Closes #872 - ConfigMap support for configuration - Related to #575 - Earlier prototype work --- Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>

The documentation is generated from this commit.

Commit:82a5d3f
Author:Eron Wright
Committer:Eron Wright

Implement Agent Server changes for structured configuration This commit implements the agent server enhancements required to support structured (JSON) configuration values in the Pulumi Kubernetes Operator. Changes: - Added PulumiVersion RPC to agent.proto to retrieve Pulumi CLI version - Implemented PulumiVersion method in agent server - Enhanced SetAllConfig to detect and handle JSON configuration values - Added unmarshalConfigItemsJson function to build JSON config documents - Added hasJsonValue helper to detect structured values - Added validation for path and json flag incompatibility - Added debug logging for JSON configuration values - Regenerated protobuf files The implementation includes TODOs for features that depend on upcoming Pulumi Go SDK automation API updates (SetAllConfigJsonWithOptions and ConfigValue.Object field). Related to #575 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>

The documentation is generated from this commit.

Commit:196fa42
Author:Eron Wright
Committer:Eron Wright

Implement Workspace API changes for structured configuration Changes to support structured configuration values (objects, arrays, numbers, booleans) in the Workspace CRD using apiextensionsv1.JSON: - Updated ConfigItem.Value from *string to *apiextensionsv1.JSON with proper kubebuilder tags - Added JSON field to ConfigValueFrom to indicate JSON parsing - Added PulumiVersion field to WorkspaceStatus for version detection - Updated agent proto to support JSON flag in ConfigValueFrom - Modified marshalConfigItem to convert JSON to protobuf Value - Updated stack controller to handle JSON type conversions - Regenerated CRDs, DeepCopy methods, and protobuf code This validates apiextensionsv1.JSON as an effective type for configuration values, enabling natural representation of structured data in Kubernetes resources. Related to #575 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>

Commit:9e5e3ad
Author:Eron Wright

Implement Agent Server changes for structured configuration This commit implements the agent server enhancements required to support structured (JSON) configuration values in the Pulumi Kubernetes Operator. Changes: - Added PulumiVersion RPC to agent.proto to retrieve Pulumi CLI version - Implemented PulumiVersion method in agent server - Enhanced SetAllConfig to detect and handle JSON configuration values - Added unmarshalConfigItemsJson function to build JSON config documents - Added hasJsonValue helper to detect structured values - Added validation for path and json flag incompatibility - Added debug logging for JSON configuration values - Regenerated protobuf files The implementation includes TODOs for features that depend on upcoming Pulumi Go SDK automation API updates (SetAllConfigJsonWithOptions and ConfigValue.Object field). Related to #575 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>

The documentation is generated from this commit.

Commit:e4eeb69
Author:Eron Wright

Implement Workspace API changes for structured configuration Changes to support structured configuration values (objects, arrays, numbers, booleans) in the Workspace CRD using apiextensionsv1.JSON: - Updated ConfigItem.Value from *string to *apiextensionsv1.JSON with proper kubebuilder tags - Added JSON field to ConfigValueFrom to indicate JSON parsing - Added PulumiVersion field to WorkspaceStatus for version detection - Updated agent proto to support JSON flag in ConfigValueFrom - Modified marshalConfigItem to convert JSON to protobuf Value - Updated stack controller to handle JSON type conversions - Regenerated CRDs, DeepCopy methods, and protobuf code This validates apiextensionsv1.JSON as an effective type for configuration values, enabling natural representation of structured data in Kubernetes resources. Related to #575 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>

Commit:2a3889f
Author:Eron Wright
Committer:GitHub

Support for ESC environments in the `Stack` resource (#924) <!--Thanks for your contribution. See [CONTRIBUTING](CONTRIBUTING.md) for Pulumi's contribution guidelines. Help us merge your changes more quickly by adding more details such as labels, milestones, and reviewers.--> ### Proposed changes <!--Give us a brief description of what you've done and what it solves. --> Adds support for importing ESC environments into your `Stack` object or `Workspace`. For example, a Stack definition that includes `environment`: ```yaml apiVersion: pulumi.com/v1 kind: Stack metadata: name: example namespace: default spec: stack: example environment: - default/my-environment ``` Will result in a Pulumi stack configuration file (`Pulumi.example.yaml`) with an `environment` block: ```yaml environment: - default/my-environment ``` Note that not all backends support the use of environments, and the workspace will (repeatedly) fail to initialize in such situations. ### Related issues (optional) <!--Refer to related PRs or issues: #1234, or 'Fixes #1234' or 'Closes #1234'. Or link to full URLs to issues or pull requests in other GitHub repositories. --> Closes #814

Commit:43cd638
Author:Ramon Quitales
Committer:GitHub

feat: report status when stack is locked (#807) ### Proposed changes - **Surfaces Locked Stack Errors:** - The agent server now returns a structured response instead of an error when the Pulumi CLI returns a `409` (Conflict) error. - Clients can now determine if a stack is locked without parsing error streams. - Introduced a new boolean response field, `isStackLocked`, for easy client-side detection. - **Improves Stack CR Status Updates:** - The error message from `UpdateCR.status.message` is now correctly propagated to `StackCR.status.lastUpdate.message`. - Ensures locked stack errors are surfaced in the Stack CR's status subresource. #### Example Stack CR Status Block ``` status: conditions: - lastTransitionTime: "2025-02-06T00:11:09Z" message: reconciliation is in progress reason: NotReadyInProgress status: "False" type: Ready - lastTransitionTime: "2025-02-06T00:11:09Z" message: 4 update failure(s) reason: RetryingAfterFailure status: "True" type: Reconciling lastUpdate: failures: 4 generation: 4 lastAttemptedCommit: sha256:f335a9e0bc445b0dbe3187371f56017bcdd66e23b68c6eda54910eeb48d5e3a0 lastResyncTime: "2025-02-06T00:26:33Z" lastSuccessfulCommit: sha256:f335a9e0bc445b0dbe3187371f56017bcdd66e23b68c6eda54910eeb48d5e3a0 message: Another update is currently in progress name: nginx-stack-194d8a6b139 state: failed type: up observedGeneration: 4 outputs: availableReplicas: 1 ``` #### Example Update CR Status Block ``` status: conditions: - lastTransitionTime: "2025-02-06T00:26:33Z" message: "" observedGeneration: 1 reason: Complete status: "False" type: Progressing - lastTransitionTime: "2025-02-06T00:26:33Z" message: Another update is currently in progress observedGeneration: 1 reason: StackLocked status: "True" type: Failed - lastTransitionTime: "2025-02-06T00:26:33Z" message: "" observedGeneration: 1 reason: Updated status: "True" type: Complete endTime: "1970-01-01T00:00:00Z" message: Another update is currently in progress observedGeneration: 1 startTime: "1970-01-01T00:00:00Z" ``` ### Testing - Added envtests to validate that statuses are correctly surfaced. - Manually validated on a GKE cluster. ### Related Issues Fixes: #806 Fixes: #736

Commit:6b9e71f
Author:Bryce Lampe
Committer:GitHub

[v2] Set config all at once (#718) We currently issue one `SetAllConfig` RPC for each user-specified config. This is slow but it has important correctness guarantees: 1. The order we apply config matters -- if the user specifies `foo: foo` followed by `foo: bar`, the net result must always be `foo: bar`. 2. The Pulumi CLI (and therefore Automation API) only allows specifying `--path` on an all-or-nothing basis. This is bad for us because we potentially have a blend of path and non-path keys. Ideally we would be able to supply all of our configs to the automation API in a single call, and in the case where _all_ of our config keys are path-like (or all are not path-like) we actually can do that because we no longer have limitation (2). This PR makes that possible in the general case by transforming our config keys in a way that allows us to treat them as if they are all path-like. In particular: * The agent's `SetAllConfig` handler is modified to take a list of configs instead of a map in order to preserve config order. The top-level `path` param is also removed and handled on a per-key basis. * While resolving configs, we escape any non-path keys so subsequent path parsing treats them as verbatim. For example `foo.bar` gets escaped as `["foo.bar"]`. * We can then supply all of our keys at once to Automation API with `Path: true`. * If there are no configs to set then the operator doesn't invoke `SetAllConfig`. Fixes https://github.com/pulumi/pulumi-kubernetes-operator/issues/650

Commit:7ce746c
Author:Bryce Lampe
Committer:GitHub

[v2] Consolidate go.mod (#686) * Consolidate `{operator,agent}/go.mod` under a root `go.mod`. * Rewrite imports to use v2 path. * Remove `/test` -- these were still referring to v1 code and can be revived in a followup if we want to keep any of them. * Move Dockerfile to repo root and fix image build. Fixes https://github.com/pulumi/pulumi-kubernetes-operator/issues/687. --------- Co-authored-by: Eron Wright <eron@pulumi.com>

Commit:a3d2072
Author:Bryce Lampe
Committer:GitHub

[v2] Capture stack outputs (#676) This returns stack outputs from the agent and records them in a secret. Scrubbed outputs are also stored in the Stack's status, as we do in v1. * `OutputValue` is returned from the agent and contains raw JSON-encoded bytes for the output. * Each `Update` owns a corresponding `-stack-outputs` secret. * The secret includes a `pulumi.com/secrets` annotation with a list of sensitive fields, and the Stack API uses this to scrub outputs for the Stack's status.

Commit:5b5d8a7
Author:Eron Wright
Committer:GitHub

[pkov2] agent RPC server (#624) <!--Thanks for your contribution. See [CONTRIBUTING](CONTRIBUTING.md) for Pulumi's contribution guidelines. Help us merge your changes more quickly by adding more details such as labels, milestones, and reviewers.--> ### Proposed changes **Epic Link**: https://github.com/pulumi/pulumi-kubernetes-operator/issues/606 **Demo Video Link**: https://pulumi.slack.com/archives/C07DQSV84DC/p1722636430008649 Implements an agent consisting of two commands: - `init` - fetches a flux source into the given directory, intended for use in an init container. - `serve` - starts an RPC server providing an automation API to perform stack updates over the given workspace. ### Overview The RPC server assumes that the project source code has been checked out to a local working directory, called the "workspace" directory. This generally corresponds to a sub-directory within a git repository, e.g. [examples/random-yaml](https://github.com/pulumi/examples/tree/master/random-yaml). At startup, the server opens the workspace using [auto.NewLocalWorkspace](https://github.com/pulumi/pulumi/blob/5651750bb254f73da5ef0fa503818c5a38755ea8/sdk/go/auto/local_workspace.go#L848). All RPC operations are applied to this same workspace, usually one-at-a-time. Some operations cause state changes, e.g. stack selection, that may affect subsequent operations. Some operations produce `PreconditionFailed` if a stack hasn't been selected. At startup, the server optionally runs `pulumi install` to install dependencies and plugins for the project, based on https://github.com/pulumi/pulumi/pull/16782. Note that PKOv1 has some code to install plugins, now believed to be obsolete (see [discussion](https://github.com/pulumi/pulumi/pull/16782#issuecomment-2259286745)). The supported operations are: - `WhoAmI` - returns current user info. - `Install` - runs `pulumi install` in the workspace. - `SelectStack` - select (and optionally create) a stack, for use in subsequent operations. - `Info` - a summary of the current stack. - `SetAllConfig` - set multiple configuration values on the current stack, based on literals, environment variables, and file references. It is expected that the server's pod would have ConfigMaps and Secrets mounted accordingly. - `Preview` runs the preview operation for the current stack. - `Up` runs the up operation for the current stack. - `Destroy` runs the destroy operation for the current stack. - `Refresh` runs the refresh operation for the current stack. The deployment operations have streaming responses, consisting of a series of engine events and a final result. The agent uses zap for logging, because it supports structured logging, implements `io.Writer` to capture Pulumi console output, and integrates well with grpc-go. ### Follow-ups - [x] Write RPC server tests - [ ] Rename 'init' to 'fetch' for clarity - [ ] lock the workspace during an operation? Or rely on locking within the Pulumi CLI? ### Related issues (optional) <!--Refer to related PRs or issues: #1234, or 'Fixes #1234' or 'Closes #1234'. Or link to full URLs to issues or pull requests in other GitHub repositories. --> Closes #610 #611

Commit:4db006e
Author:Eron Wright

SetAllConfig

Commit:e4dffb9
Author:Eron Wright

SelectStack

Commit:859acfd
Author:Eron Wright

installation support

Commit:10e23ba
Author:Eron Wright

zap logging

Commit:1f41a08
Author:Eron Wright

init containers

Commit:2024c9a
Author:Eron Wright

preview event stream

Commit:af2e5cb
Author:Eron Wright

preview, cancelation

Commit:55aadd4
Author:Eron Wright

deployable

Commit:f1984b9
Author:Eron Wright

proto 1