Skip to content

Commit

Permalink
[WIP] V2 stack controller (#648)
Browse files Browse the repository at this point in the history
<!--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.
-->

This PR re-implements the Stack controller in terms of the low-level
`Workspace` and `Update` subordinate objects.

Follow-ups:
- git source support w/ polling
- tests for the stack controller
- stack outputs in Stack status (requires an enhancement to the Update
API)
- optimized handling of the stack config in Workspace API

### 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. -->
  • Loading branch information
EronWright authored Sep 6, 2024
1 parent a21e0e4 commit e850d02
Show file tree
Hide file tree
Showing 45 changed files with 5,444 additions and 106 deletions.
1 change: 1 addition & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
],
"env": {
"WORKSPACE_LOCALHOST": "localhost:50051",
"SOURCE_CONTROLLER_LOCALHOST": "localhost:9090",
},
},
{
Expand Down
3 changes: 3 additions & 0 deletions agent/pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ func NewServer(ctx context.Context, ws auto.Workspace, opts *Options) (*Server,
return nil, fmt.Errorf("failed to select stack: %w", err)
}
if opts.SecretsProvider != "" {
// We must always make sure the secret provider is initialized in the workspace
// before we set any configs. Otherwise secret provider will mysteriously reset.
// https://github.com/pulumi/pulumi-kubernetes-operator/issues/135
err = stack.ChangeSecretsProvider(ctx, opts.SecretsProvider, &auto.ChangeSecretsProviderOptions{})
if err != nil {
return nil, fmt.Errorf("failed to set secrets provider: %w", err)
Expand Down
10 changes: 5 additions & 5 deletions operator/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ FROM golang:1.22 AS builder
ARG TARGETOS
ARG TARGETARCH

WORKDIR /workspace
WORKDIR /operator
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
COPY agent/go.mod agent/go.mod
COPY agent/go.sum agent/go.sum
COPY --from=agent /go.mod /agent/go.mod
COPY --from=agent /go.sum /agent/go.sum

# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
Expand All @@ -17,7 +17,7 @@ RUN go mod download
# Copy the go source
COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY agent/ agent/
COPY --from=agent / /agent/
COPY internal/controller/ internal/controller/

# Build
Expand All @@ -31,7 +31,7 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o ma
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static-debian12:debug-nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
COPY --from=builder /operator/manager .
USER 65532:65532

ENTRYPOINT ["/manager"]
4 changes: 2 additions & 2 deletions operator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ run: manifests generate fmt vet ## Run a controller from your host.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .
$(CONTAINER_TOOL) build -t ${IMG} --build-context agent=../agent .

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
Expand Down Expand Up @@ -191,7 +191,7 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -oyaml -f -
$(KUSTOMIZE) build config/default | $(KUBECTL) apply --server-side=true -oyaml -f -

.PHONY: undeploy
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
Expand Down
20 changes: 18 additions & 2 deletions operator/PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
domain: pulumi.com
layout:
- go.kubebuilder.io/v4
multigroup: true
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
Expand All @@ -18,7 +19,7 @@ resources:
domain: pulumi.com
group: auto
kind: Workspace
path: github.com/pulumi/pulumi-kubernetes-operator/operator/api/v1alpha1
path: github.com/pulumi/pulumi-kubernetes-operator/operator/api/auto/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
Expand All @@ -27,6 +28,21 @@ resources:
domain: pulumi.com
group: auto
kind: Update
path: github.com/pulumi/pulumi-kubernetes-operator/operator/api/v1alpha1
path: github.com/pulumi/pulumi-kubernetes-operator/operator/api/auto/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
group: pulumi.com
kind: Stack
path: github.com/pulumi/pulumi-kubernetes-operator/operator/api/pulumi/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
group: pulumi.com
kind: Program
path: github.com/pulumi/pulumi-kubernetes-operator/operator/api/pulumi/v1
version: v1
version: "3"
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ const (
RefreshType UpdateType = "refresh"
)

const (
UpdateConditionTypeComplete = "Complete"
UpdateConditionTypeFailed = "Failed"
UpdateConditionTypeProgressing = "Progressing"
)

// UpdateSpec defines the desired state of Update
type UpdateSpec struct {
// WorkspaceName is the workspace to update.
Expand Down Expand Up @@ -85,6 +91,9 @@ type UpdateStatus struct {
// +optional
Permalink string `json:"permalink,omitempty"`

// +optional
Message string `json:"message,omitempty"`

// Represents the observations of an update's current state.
// Known .status.conditions.type are: "Complete", "Failed", and "Progressing"
// +patchMergeKey=type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ type WorkspaceSpec struct {
// Compute Resources required by this workspace.
// More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
// +optional
Resources corev1.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,8,opt,name=resources"`
Resources corev1.ResourceRequirements `json:"resources,omitempty"`

// PodTemplate defines a PodTemplateSpec for Workspace's pods.
//
// +optional
PodTemplate *corev1.PodTemplateSpec `json:"podTemplate,omitempty"`
PodTemplate *EmbeddedPodTemplateSpec `json:"podTemplate,omitempty"`

// List of stacks to .
// +optional
Expand Down Expand Up @@ -171,6 +171,37 @@ type ConfigValueFrom struct {
Path string `json:"path,omitempty"`
}

// EmbeddedPodTemplateSpec is an embedded version of k8s.io/api/core/v1.PodTemplateSpec.
// It contains a reduced ObjectMeta.
type EmbeddedPodTemplateSpec struct {
// EmbeddedMetadata contains metadata relevant to an embedded resource.
// +optional
Metadata EmbeddedObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// Specification of the desired behavior of the pod.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +optional
Spec *corev1.PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
}

// EmbeddedObjectMeta contains a subset of the fields included in k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta
// Only fields which are relevant to embedded resources are included.
type EmbeddedObjectMeta struct {
// Map of string keys and values that can be used to organize and categorize
// (scope and select) objects. May match selectors of replication controllers
// and services.
// More info: http://kubernetes.io/docs/user-guide/labels
// +optional
Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,11,rep,name=labels"`

// Annotations is an unstructured key value map stored with a resource that may be
// set by external tools to store and retrieve arbitrary metadata. They are not
// queryable and should be preserved when modifying objects.
// More info: http://kubernetes.io/docs/user-guide/annotations
// +optional
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,12,rep,name=annotations"`
}

// WorkspaceStatus defines the observed state of Workspace
type WorkspaceStatus struct {
// observedGeneration represents the .metadata.generation that the status was set based upon.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions operator/api/pulumi/shared/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package shared contains shared schema definitions for different API versions.
// +k8s:deepcopy-gen=package
// +groupName=pulumi.com
package shared
Loading

0 comments on commit e850d02

Please sign in to comment.