From 928cbabafec755b72c2cead9af6d94bcf60e8873 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 2 Oct 2024 15:34:18 -0700 Subject: [PATCH 01/14] bugfix for fileserver --- operator/cmd/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator/cmd/main.go b/operator/cmd/main.go index 8b9faa14..4f47223a 100644 --- a/operator/cmd/main.go +++ b/operator/cmd/main.go @@ -86,7 +86,7 @@ func main() { "If set, HTTP/2 will be enabled for the metrics and webhook servers") flag.StringVar(&programFSAddr, "program-fs-addr", envOrDefault("PROGRAM_FS_ADDR", ":9090"), "The address the static file server binds to.") - flag.StringVar(&programFSAdvAddr, "program-fs-adv-addr", envOrDefault("PROGRAM_FS_ADV_ADDR", ""), + flag.StringVar(&programFSAdvAddr, "program-fs-adv-addr", envOrDefault("PROGRAM_FS_ADV_ADDR", "localhost:9090"), "The advertised address of the static file server.") opts := zap.Options{ Development: true, From c24b6637a007bde7e6d49d70c544a5a2e0d97831 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 2 Oct 2024 15:37:53 -0700 Subject: [PATCH 02/14] use tini for pulumi container --- Dockerfile | 7 +++++++ .../controller/auto/workspace_controller.go | 17 ++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index b0b3c857..9231bc59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,10 @@ # Build a base image with modules cached. FROM --platform=${BUILDPLATFORM} golang:1.23 AS base +ARG TARGETARCH + +# Install tini to reap zombie processes. +ENV TINI_VERSION v0.19.0 +ADD --chmod=755 https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-${TARGETARCH} /tini COPY /go.mod go.mod COPY /go.sum go.sum @@ -37,6 +42,8 @@ RUN --mount=type=cache,target=${GOCACHE} \ # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details FROM gcr.io/distroless/static-debian12:debug-nonroot + +COPY --from=base /tini /tini COPY --from=op-builder /manager /manager COPY --from=agent-builder /agent /agent USER 65532:65532 diff --git a/operator/internal/controller/auto/workspace_controller.go b/operator/internal/controller/auto/workspace_controller.go index fd2b593a..f317b015 100644 --- a/operator/internal/controller/auto/workspace_controller.go +++ b/operator/internal/controller/auto/workspace_controller.go @@ -22,6 +22,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "os" "strconv" "time" @@ -346,13 +347,15 @@ func labelsForStatefulSet(w *autov1alpha1.Workspace) map[string]string { } func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sourceSpec) (*appsv1.StatefulSet, error) { - // TODO: get from environment - workspaceAgentImage := "pulumi/pulumi-kubernetes-operator:" + version.Version + image := os.Getenv("AGENT_IMAGE") + if image == "" { + image = "pulumi/pulumi-kubernetes-operator:" + version.Version + } labels := labelsForStatefulSet(w) command := []string{ - "/share/agent", "serve", + "/share/tini", "/share/agent", "--", "serve", "--workspace", "/share/workspace", "--skip-install", } @@ -390,7 +393,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour InitContainers: []corev1.Container{ { Name: "bootstrap", - Image: workspaceAgentImage, + Image: image, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: []corev1.VolumeMount{ { @@ -398,7 +401,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour MountPath: WorkspaceShareMountPath, }, }, - Command: []string{"cp", "/agent", "/share/agent"}, + Command: []string{"cp", "/agent", "/tini", "/share/"}, }, }, Containers: []corev1.Container{ @@ -498,7 +501,7 @@ ln -s /share/source/$GIT_DIR /share/workspace container := corev1.Container{ Name: "fetch", - Image: workspaceAgentImage, + Image: image, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: []corev1.VolumeMount{ { @@ -519,7 +522,7 @@ ln -s /share/source/$FLUX_DIR /share/workspace ` container := corev1.Container{ Name: "fetch", - Image: workspaceAgentImage, + Image: image, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: []corev1.VolumeMount{ { From 14764ef51ff372c1e57d871deae2c91b9a3bd01e Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 2 Oct 2024 16:03:50 -0700 Subject: [PATCH 03/14] use tini for all containers --- Dockerfile | 3 ++- deploy/helm/pulumi-operator/templates/deployment.yaml | 3 +-- deploy/yaml/install.yaml | 3 +-- operator/config/manager/manager.yaml | 5 ++--- operator/internal/controller/auto/workspace_controller.go | 8 ++++---- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9231bc59..3f65ca7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,4 +48,5 @@ COPY --from=op-builder /manager /manager COPY --from=agent-builder /agent /agent USER 65532:65532 -ENTRYPOINT ["/manager"] +ENTRYPOINT ["/tini", "--"] +CMD ["/manager"] diff --git a/deploy/helm/pulumi-operator/templates/deployment.yaml b/deploy/helm/pulumi-operator/templates/deployment.yaml index e01e5be7..d4512618 100644 --- a/deploy/helm/pulumi-operator/templates/deployment.yaml +++ b/deploy/helm/pulumi-operator/templates/deployment.yaml @@ -33,9 +33,8 @@ spec: {{- toYaml .Values.extraSidecars | nindent 8 }} {{- end}} - name: manager - command: - - /manager args: + - /manager - --leader-elect - --health-probe-bind-address=:8081 - --metrics-bind-address=:8383 diff --git a/deploy/yaml/install.yaml b/deploy/yaml/install.yaml index e5694d5f..127b2bec 100644 --- a/deploy/yaml/install.yaml +++ b/deploy/yaml/install.yaml @@ -28388,14 +28388,13 @@ spec: spec: containers: - args: + - /manager - --leader-elect - --health-probe-bind-address=:8081 - --metrics-bind-address=:8383 - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local - --zap-log-level=error - --zap-time-encoding=iso8601 - command: - - /manager env: - name: POD_NAMESPACE valueFrom: diff --git a/operator/config/manager/manager.yaml b/operator/config/manager/manager.yaml index 02a416c1..78eaac76 100644 --- a/operator/config/manager/manager.yaml +++ b/operator/config/manager/manager.yaml @@ -33,14 +33,14 @@ spec: runAsUser: 65532 runAsGroup: 65532 containers: - - command: - - /manager + - name: manager env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace args: + - /manager - --leader-elect - --health-probe-bind-address=:8081 - --metrics-bind-address=:8383 @@ -56,7 +56,6 @@ spec: protocol: TCP image: controller:latest imagePullPolicy: IfNotPresent - name: manager securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/operator/internal/controller/auto/workspace_controller.go b/operator/internal/controller/auto/workspace_controller.go index f317b015..15e81ceb 100644 --- a/operator/internal/controller/auto/workspace_controller.go +++ b/operator/internal/controller/auto/workspace_controller.go @@ -401,7 +401,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour MountPath: WorkspaceShareMountPath, }, }, - Command: []string{"cp", "/agent", "/tini", "/share/"}, + Args: []string{"cp", "/agent", "/tini", "/share/"}, }, }, Containers: []corev1.Container{ @@ -509,8 +509,8 @@ ln -s /share/source/$GIT_DIR /share/workspace MountPath: WorkspaceShareMountPath, }, }, - Env: env, - Command: []string{"sh", "-c", script}, + Env: env, + Args: []string{"sh", "-c", script}, } statefulset.Spec.Template.Spec.InitContainers = append(statefulset.Spec.Template.Spec.InitContainers, container) } @@ -544,7 +544,7 @@ ln -s /share/source/$FLUX_DIR /share/workspace Value: source.Flux.Dir, }, }, - Command: []string{"sh", "-c", script}, + Args: []string{"sh", "-c", script}, } statefulset.Spec.Template.Spec.InitContainers = append(statefulset.Spec.Template.Spec.InitContainers, container) } From fda689802cabae306206b16578c728db0c639be3 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 2 Oct 2024 16:23:02 -0700 Subject: [PATCH 04/14] use workspace dir as working dir --- operator/internal/controller/auto/workspace_controller.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/operator/internal/controller/auto/workspace_controller.go b/operator/internal/controller/auto/workspace_controller.go index 15e81ceb..c5fb8c25 100644 --- a/operator/internal/controller/auto/workspace_controller.go +++ b/operator/internal/controller/auto/workspace_controller.go @@ -422,9 +422,10 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour ContainerPort: WorkspaceGrpcPort, }, }, - Env: w.Spec.Env, - EnvFrom: w.Spec.EnvFrom, - Command: command, + Env: w.Spec.Env, + EnvFrom: w.Spec.EnvFrom, + Command: command, + WorkingDir: "/share/workspace", }, }, Volumes: []corev1.Volume{ From 72c9eb0086b565f22acecdf63b536224cb75daba Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Wed, 2 Oct 2024 17:41:21 -0700 Subject: [PATCH 05/14] set agent memory limit --- agent/cmd/serve.go | 11 ++++++++ .../controller/auto/workspace_controller.go | 28 ++++++++++++++----- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/agent/cmd/serve.go b/agent/cmd/serve.go index fd72a2df..8a1a13fd 100644 --- a/agent/cmd/serve.go +++ b/agent/cmd/serve.go @@ -22,6 +22,7 @@ import ( "os" "os/signal" "path/filepath" + "runtime/debug" "syscall" "github.com/pulumi/pulumi-kubernetes-operator/v2/agent/pkg/server" @@ -30,6 +31,7 @@ import ( "github.com/spf13/cobra" "go.uber.org/zap" "go.uber.org/zap/zapio" + "k8s.io/apimachinery/pkg/api/resource" ) var ( @@ -52,6 +54,15 @@ var serveCmd = &cobra.Command{ log.Infow("Pulumi Kubernetes Agent", "version", version.Version) log.Debugw("executing serve command", "WorkDir", _workDir) + // limit the agent's memory usage to the configured quantity (e.g. 64Mi) + if limit, ok := os.LookupEnv("AGENT_MEMLIMIT"); ok { + val := resource.MustParse(limit) + if !val.IsZero() { + log.Debugf("setting memory limit to %s", limit) + debug.SetMemoryLimit(val.Value()) + } + } + // open the workspace using auto api workspaceOpts := []auto.LocalWorkspaceOption{} workDir, err := filepath.EvalSymlinks(_workDir) // resolve the true location of the workspace diff --git a/operator/internal/controller/auto/workspace_controller.go b/operator/internal/controller/auto/workspace_controller.go index c5fb8c25..2bdb3cef 100644 --- a/operator/internal/controller/auto/workspace_controller.go +++ b/operator/internal/controller/auto/workspace_controller.go @@ -318,11 +318,11 @@ func (r *WorkspaceReconciler) SetupWithManager(mgr ctrl.Manager) error { } const ( - FieldManager = "pulumi-kubernetes-operator" - WorkspaceContainerName = "server" - WorkspaceShareVolumeName = "share" - WorkspaceShareMountPath = "/share" - WorkspaceGrpcPort = 50051 + FieldManager = "pulumi-kubernetes-operator" + WorkspacePulumiContainerName = "pulumi" + WorkspaceShareVolumeName = "share" + WorkspaceShareMountPath = "/share" + WorkspaceGrpcPort = 50051 ) func nameForStatefulSet(w *autov1alpha1.Workspace) string { @@ -360,6 +360,20 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour "--skip-install", } + env := w.Spec.Env + + // limit the memory usage to the reserved amount + // https://github.com/pulumi/pulumi-kubernetes-operator/issues/698 + env = append(env, corev1.EnvVar{ + Name: "AGENT_MEMLIMIT", + ValueFrom: &corev1.EnvVarSource{ + ResourceFieldRef: &corev1.ResourceFieldSelector{ + ContainerName: WorkspacePulumiContainerName, + Resource: "requests.memory", + }, + }, + }) + statefulset := &appsv1.StatefulSet{ TypeMeta: metav1.TypeMeta{ Kind: "StatefulSet", @@ -406,7 +420,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour }, Containers: []corev1.Container{ { - Name: "pulumi", + Name: WorkspacePulumiContainerName, Image: getDefaultSSImage(w.Spec.Image, w.Spec.SecurityProfile), ImagePullPolicy: w.Spec.ImagePullPolicy, Resources: w.Spec.Resources, @@ -422,7 +436,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour ContainerPort: WorkspaceGrpcPort, }, }, - Env: w.Spec.Env, + Env: env, EnvFrom: w.Spec.EnvFrom, Command: command, WorkingDir: "/share/workspace", From c48402c2d2b7a8d216e6f7fa5cfdc512753f5fe0 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Fri, 4 Oct 2024 13:11:40 -0700 Subject: [PATCH 06/14] default workspace resources --- operator/Makefile | 2 +- operator/api/auto/v1alpha1/workspace_types.go | 5 - operator/config/webhook/manifests.yaml | 52 ++++++ .../controller/auto/workspace_controller.go | 33 ++-- .../auto/workspace_controller_test.go | 25 ++- .../auto/v1alpha1/workspace_webhook.go | 148 ++++++++++++++++++ 6 files changed, 234 insertions(+), 31 deletions(-) create mode 100644 operator/config/webhook/manifests.yaml create mode 100644 operator/internal/webhook/auto/v1alpha1/workspace_webhook.go diff --git a/operator/Makefile b/operator/Makefile index 620228a0..65d68a9b 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -183,7 +183,7 @@ endif .PHONY: install install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | $(KUBECTL) apply --server-side=true -f - + $(KUSTOMIZE) build config/crd | $(KUBECTL) apply --server-side=true --force-conflicts -f - .PHONY: uninstall uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. diff --git a/operator/api/auto/v1alpha1/workspace_types.go b/operator/api/auto/v1alpha1/workspace_types.go index 4a81069f..33a3ee66 100644 --- a/operator/api/auto/v1alpha1/workspace_types.go +++ b/operator/api/auto/v1alpha1/workspace_types.go @@ -34,11 +34,6 @@ const ( SecurityProfileBaseline SecurityProfile = "baseline" // SecurityProfileRestricted applies the restricted security profile. SecurityProfileRestricted SecurityProfile = "restricted" - - // SecurityProfileBaselineDefaultImage is the default image used when the security profile is 'baseline'. - SecurityProfileBaselineDefaultImage = "pulumi/pulumi:latest" - // SecurityProfileRestrictedDefaultImage is the default image used when the security profile is 'restricted'. - SecurityProfileRestrictedDefaultImage = "pulumi/pulumi:latest-nonroot" ) // WorkspaceSpec defines the desired state of Workspace diff --git a/operator/config/webhook/manifests.yaml b/operator/config/webhook/manifests.yaml new file mode 100644 index 00000000..a61d9ef6 --- /dev/null +++ b/operator/config/webhook/manifests.yaml @@ -0,0 +1,52 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: mutating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-auto-pulumi-com-v1alpha1-workspace + failurePolicy: Fail + name: mworkspace-v1alpha1.kb.io + rules: + - apiGroups: + - auto.pulumi.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - workspaces + sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-auto-pulumi-com-v1alpha1-workspace + failurePolicy: Fail + name: vworkspace-v1alpha1.kb.io + rules: + - apiGroups: + - auto.pulumi.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - workspaces + sideEffects: None diff --git a/operator/internal/controller/auto/workspace_controller.go b/operator/internal/controller/auto/workspace_controller.go index 2bdb3cef..6b7d53ce 100644 --- a/operator/internal/controller/auto/workspace_controller.go +++ b/operator/internal/controller/auto/workspace_controller.go @@ -28,6 +28,7 @@ import ( agentpb "github.com/pulumi/pulumi-kubernetes-operator/v2/agent/pkg/proto" autov1alpha1 "github.com/pulumi/pulumi-kubernetes-operator/v2/operator/api/auto/v1alpha1" + autov1alpha1webhook "github.com/pulumi/pulumi-kubernetes-operator/v2/operator/internal/webhook/auto/v1alpha1" "github.com/pulumi/pulumi-kubernetes-operator/v2/operator/version" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -84,6 +85,14 @@ func (r *WorkspaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, client.IgnoreNotFound(err) } + // apply defaults to the workspace spec + // future: use a mutating webhook to apply defaults + defaulter := autov1alpha1webhook.WorkspaceCustomDefaulter{} + err = defaulter.Default(ctx, w) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to apply defaults: %w", err) + } + ready := meta.FindStatusCondition(w.Status.Conditions, WorkspaceConditionTypeReady) if ready == nil { ready = &metav1.Condition{ @@ -362,6 +371,8 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour env := w.Spec.Env + // resources := resourcesForStatefulSet(w) + // limit the memory usage to the reserved amount // https://github.com/pulumi/pulumi-kubernetes-operator/issues/698 env = append(env, corev1.EnvVar{ @@ -421,7 +432,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour Containers: []corev1.Container{ { Name: WorkspacePulumiContainerName, - Image: getDefaultSSImage(w.Spec.Image, w.Spec.SecurityProfile), + Image: w.Spec.Image, ImagePullPolicy: w.Spec.ImagePullPolicy, Resources: w.Spec.Resources, VolumeMounts: []corev1.VolumeMount{ @@ -692,23 +703,3 @@ func mergePodTemplateSpec(_ context.Context, base *corev1.PodTemplateSpec, patch return patchResult, nil } - -// getDefaultSSImage returns the default image for the StatefulSet container based on the security profile. -// If the user had provided an image, then that image is returned instead. -func getDefaultSSImage(image string, securityProfile autov1alpha1.SecurityProfile) string { - if image != "" { - return image - } - - switch securityProfile { - case autov1alpha1.SecurityProfileRestricted: - return autov1alpha1.SecurityProfileRestrictedDefaultImage - case autov1alpha1.SecurityProfileBaseline: - return autov1alpha1.SecurityProfileBaselineDefaultImage - default: - // This should not happen, since the securityProfile has a default value. - // If for some reason it is empty, then we should default to the baseline image - // since we can't tell if the container can run in a restricted environment. - return autov1alpha1.SecurityProfileBaselineDefaultImage - } -} diff --git a/operator/internal/controller/auto/workspace_controller_test.go b/operator/internal/controller/auto/workspace_controller_test.go index 36229c95..88532e6e 100644 --- a/operator/internal/controller/auto/workspace_controller_test.go +++ b/operator/internal/controller/auto/workspace_controller_test.go @@ -199,7 +199,7 @@ var _ = Describe("Workspace Controller", func() { _, err := reconcileF(ctx) Expect(err).NotTo(HaveOccurred()) container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi") - Expect(container.Env).To(Equal(obj.Spec.Env)) + Expect(container.Env).To(ContainElements(obj.Spec.Env)) }) }) }) @@ -215,16 +215,33 @@ var _ = Describe("Workspace Controller", func() { _, err := reconcileF(ctx) Expect(err).NotTo(HaveOccurred()) container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi") - Expect(container.EnvFrom).To(Equal(obj.Spec.EnvFrom)) + Expect(container.EnvFrom).To(ContainElements(obj.Spec.EnvFrom)) }) }) }) Describe("spec.resources", func() { - When("resources are set", func() { + When("requests are not set", func() { + BeforeEach(func(ctx context.Context) { + obj.Spec.Resources = corev1.ResourceRequirements{} + }) + It("configures the resources of the pulumi container", func(ctx context.Context) { + _, err := reconcileF(ctx) + Expect(err).NotTo(HaveOccurred()) + container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi") + Expect(container.Resources).To(Equal(corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("64Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + }, + })) + }) + }) + + When("requests are set", func() { BeforeEach(func(ctx context.Context) { obj.Spec.Resources = corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ + Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("1"), corev1.ResourceMemory: resource.MustParse("1Gi"), }, diff --git a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go new file mode 100644 index 00000000..4efd7d8b --- /dev/null +++ b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go @@ -0,0 +1,148 @@ +/* +Copyright 2024 The Kubernetes authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + autov1alpha1 "github.com/pulumi/pulumi-kubernetes-operator/v2/operator/api/auto/v1alpha1" +) + +const ( + // SecurityProfileBaselineDefaultImage is the default image used when the security profile is 'baseline'. + SecurityProfileBaselineDefaultImage = "pulumi/pulumi:latest" + // SecurityProfileRestrictedDefaultImage is the default image used when the security profile is 'restricted'. + SecurityProfileRestrictedDefaultImage = "pulumi/pulumi:latest-nonroot" +) + +// nolint:unused + +// SetupWorkspaceWebhookWithManager registers the webhook for Workspace in the manager. +func SetupWorkspaceWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr).For(&autov1alpha1.Workspace{}). + WithValidator(&WorkspaceCustomValidator{}). + WithDefaulter(&WorkspaceCustomDefaulter{}). + Complete() +} + +// +kubebuilder:webhook:path=/mutate-auto-pulumi-com-v1alpha1-workspace,mutating=true,failurePolicy=fail,sideEffects=None,groups=auto.pulumi.com,resources=workspaces,verbs=create;update,versions=v1alpha1,name=mworkspace-v1alpha1.kb.io,admissionReviewVersions=v1 + +// WorkspaceCustomDefaulter struct is responsible for setting default values on the custom resource of the +// Kind Workspace when those are created or updated. +// +// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods, +// as it is used only for temporary operations and does not need to be deeply copied. +type WorkspaceCustomDefaulter struct { + // TODO(user): Add more fields as needed for defaulting +} + +var _ webhook.CustomDefaulter = &WorkspaceCustomDefaulter{} + +// Default implements webhook.CustomDefaulter so a webhook will be registered for the Kind Workspace. +func (d *WorkspaceCustomDefaulter) Default(ctx context.Context, obj runtime.Object) error { + w, ok := obj.(*autov1alpha1.Workspace) + if !ok { + return fmt.Errorf("expected an Workspace object but got %T", obj) + } + + if w.Spec.SecurityProfile == "" { + w.Spec.SecurityProfile = autov1alpha1.SecurityProfileRestricted + } + + if w.Spec.Image == "" { + switch w.Spec.SecurityProfile { + case autov1alpha1.SecurityProfileRestricted: + w.Spec.Image = SecurityProfileRestrictedDefaultImage + default: + case autov1alpha1.SecurityProfileBaseline: + w.Spec.Image = SecurityProfileBaselineDefaultImage + } + } + + // default resource requirements here are designed to provide a "burst"-style workspace. + if w.Spec.Resources.Requests == nil { + w.Spec.Resources.Requests = corev1.ResourceList{} + } + if w.Spec.Resources.Requests.Memory().IsZero() { + w.Spec.Resources.Requests[corev1.ResourceMemory] = resource.MustParse("64Mi") + } + if w.Spec.Resources.Requests.Cpu().IsZero() { + w.Spec.Resources.Requests[corev1.ResourceCPU] = resource.MustParse("100m") + } + + return nil +} + +// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. +// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here. +// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook. +// +kubebuilder:webhook:path=/validate-auto-pulumi-com-v1alpha1-workspace,mutating=false,failurePolicy=fail,sideEffects=None,groups=auto.pulumi.com,resources=workspaces,verbs=create;update,versions=v1alpha1,name=vworkspace-v1alpha1.kb.io,admissionReviewVersions=v1 + +// WorkspaceCustomValidator struct is responsible for validating the Workspace resource +// when it is created, updated, or deleted. +// +// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods, +// as this struct is used only for temporary operations and does not need to be deeply copied. +type WorkspaceCustomValidator struct { + //TODO(user): Add more fields as needed for validation +} + +var _ webhook.CustomValidator = &WorkspaceCustomValidator{} + +// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type Workspace. +func (v *WorkspaceCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + _, ok := obj.(*autov1alpha1.Workspace) + if !ok { + return nil, fmt.Errorf("expected a Workspace object but got %T", obj) + } + + // TODO(user): fill in your validation logic upon object creation. + + return nil, nil +} + +// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type Workspace. +func (v *WorkspaceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + _, ok := newObj.(*autov1alpha1.Workspace) + if !ok { + return nil, fmt.Errorf("expected a Workspace object for the newObj but got %T", newObj) + } + + // TODO(user): fill in your validation logic upon object update. + + return nil, nil +} + +// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type Workspace. +func (v *WorkspaceCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + _, ok := obj.(*autov1alpha1.Workspace) + if !ok { + return nil, fmt.Errorf("expected a Workspace object but got %T", obj) + } + + // TODO(user): fill in your validation logic upon object deletion. + + return nil, nil +} From 796f41c793e407e65261edbfc1bce43eb06d712e Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Fri, 4 Oct 2024 13:45:42 -0700 Subject: [PATCH 07/14] remove webhook scaffolding --- operator/config/webhook/manifests.yaml | 52 -------------- .../controller/auto/workspace_controller.go | 2 - .../auto/v1alpha1/workspace_webhook.go | 71 ++----------------- 3 files changed, 7 insertions(+), 118 deletions(-) delete mode 100644 operator/config/webhook/manifests.yaml diff --git a/operator/config/webhook/manifests.yaml b/operator/config/webhook/manifests.yaml deleted file mode 100644 index a61d9ef6..00000000 --- a/operator/config/webhook/manifests.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration -metadata: - name: mutating-webhook-configuration -webhooks: -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /mutate-auto-pulumi-com-v1alpha1-workspace - failurePolicy: Fail - name: mworkspace-v1alpha1.kb.io - rules: - - apiGroups: - - auto.pulumi.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - workspaces - sideEffects: None ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: validating-webhook-configuration -webhooks: -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /validate-auto-pulumi-com-v1alpha1-workspace - failurePolicy: Fail - name: vworkspace-v1alpha1.kb.io - rules: - - apiGroups: - - auto.pulumi.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - workspaces - sideEffects: None diff --git a/operator/internal/controller/auto/workspace_controller.go b/operator/internal/controller/auto/workspace_controller.go index 6b7d53ce..f83de2eb 100644 --- a/operator/internal/controller/auto/workspace_controller.go +++ b/operator/internal/controller/auto/workspace_controller.go @@ -371,8 +371,6 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour env := w.Spec.Env - // resources := resourcesForStatefulSet(w) - // limit the memory usage to the reserved amount // https://github.com/pulumi/pulumi-kubernetes-operator/issues/698 env = append(env, corev1.EnvVar{ diff --git a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go index 4efd7d8b..af7e38d7 100644 --- a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go +++ b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go @@ -23,9 +23,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/webhook" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" autov1alpha1 "github.com/pulumi/pulumi-kubernetes-operator/v2/operator/api/auto/v1alpha1" ) @@ -37,17 +35,14 @@ const ( SecurityProfileRestrictedDefaultImage = "pulumi/pulumi:latest-nonroot" ) -// nolint:unused +// // SetupWorkspaceWebhookWithManager registers the webhook for Workspace in the manager. +// func SetupWorkspaceWebhookWithManager(mgr ctrl.Manager) error { +// return ctrl.NewWebhookManagedBy(mgr).For(&autov1alpha1.Workspace{}). +// WithDefaulter(&WorkspaceCustomDefaulter{}). +// Complete() +// } -// SetupWorkspaceWebhookWithManager registers the webhook for Workspace in the manager. -func SetupWorkspaceWebhookWithManager(mgr ctrl.Manager) error { - return ctrl.NewWebhookManagedBy(mgr).For(&autov1alpha1.Workspace{}). - WithValidator(&WorkspaceCustomValidator{}). - WithDefaulter(&WorkspaceCustomDefaulter{}). - Complete() -} - -// +kubebuilder:webhook:path=/mutate-auto-pulumi-com-v1alpha1-workspace,mutating=true,failurePolicy=fail,sideEffects=None,groups=auto.pulumi.com,resources=workspaces,verbs=create;update,versions=v1alpha1,name=mworkspace-v1alpha1.kb.io,admissionReviewVersions=v1 +//// +kubebuilder:webhook:path=/mutate-auto-pulumi-com-v1alpha1-workspace,mutating=true,failurePolicy=fail,sideEffects=None,groups=auto.pulumi.com,resources=workspaces,verbs=create;update,versions=v1alpha1,name=mworkspace-v1alpha1.kb.io,admissionReviewVersions=v1 // WorkspaceCustomDefaulter struct is responsible for setting default values on the custom resource of the // Kind Workspace when those are created or updated. @@ -94,55 +89,3 @@ func (d *WorkspaceCustomDefaulter) Default(ctx context.Context, obj runtime.Obje return nil } - -// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. -// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here. -// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook. -// +kubebuilder:webhook:path=/validate-auto-pulumi-com-v1alpha1-workspace,mutating=false,failurePolicy=fail,sideEffects=None,groups=auto.pulumi.com,resources=workspaces,verbs=create;update,versions=v1alpha1,name=vworkspace-v1alpha1.kb.io,admissionReviewVersions=v1 - -// WorkspaceCustomValidator struct is responsible for validating the Workspace resource -// when it is created, updated, or deleted. -// -// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods, -// as this struct is used only for temporary operations and does not need to be deeply copied. -type WorkspaceCustomValidator struct { - //TODO(user): Add more fields as needed for validation -} - -var _ webhook.CustomValidator = &WorkspaceCustomValidator{} - -// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type Workspace. -func (v *WorkspaceCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - _, ok := obj.(*autov1alpha1.Workspace) - if !ok { - return nil, fmt.Errorf("expected a Workspace object but got %T", obj) - } - - // TODO(user): fill in your validation logic upon object creation. - - return nil, nil -} - -// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type Workspace. -func (v *WorkspaceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - _, ok := newObj.(*autov1alpha1.Workspace) - if !ok { - return nil, fmt.Errorf("expected a Workspace object for the newObj but got %T", newObj) - } - - // TODO(user): fill in your validation logic upon object update. - - return nil, nil -} - -// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type Workspace. -func (v *WorkspaceCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - _, ok := obj.(*autov1alpha1.Workspace) - if !ok { - return nil, fmt.Errorf("expected a Workspace object but got %T", obj) - } - - // TODO(user): fill in your validation logic upon object deletion. - - return nil, nil -} From f4f2f9a0dc1826bcb0788ba1d9d8e2838681fce6 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Fri, 4 Oct 2024 14:22:24 -0700 Subject: [PATCH 08/14] linting --- Dockerfile | 2 +- operator/internal/webhook/auto/v1alpha1/workspace_webhook.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3f65ca7f..e3f824bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM --platform=${BUILDPLATFORM} golang:1.23 AS base ARG TARGETARCH # Install tini to reap zombie processes. -ENV TINI_VERSION v0.19.0 +ENV TINI_VERSION=v0.19.0 ADD --chmod=755 https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-${TARGETARCH} /tini COPY /go.mod go.mod diff --git a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go index af7e38d7..5c773975 100644 --- a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go +++ b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go @@ -76,7 +76,7 @@ func (d *WorkspaceCustomDefaulter) Default(ctx context.Context, obj runtime.Obje } } - // default resource requirements here are designed to provide a "burst"-style workspace. + // default resource requirements here are designed to provide a "burstable" workspace. if w.Spec.Resources.Requests == nil { w.Spec.Resources.Requests = corev1.ResourceList{} } From ac134bd656465d1af9e750e13c4f595341d1b797 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 7 Oct 2024 13:12:03 -0700 Subject: [PATCH 09/14] fix copyright --- operator/internal/webhook/auto/v1alpha1/workspace_webhook.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go index 5c773975..593268b8 100644 --- a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go +++ b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go @@ -1,11 +1,11 @@ /* -Copyright 2024 The Kubernetes authors. +Copyright 2024. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, From ecb323c85645ccc8726f4ac61fcdde0141d9ef50 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 7 Oct 2024 13:23:34 -0700 Subject: [PATCH 10/14] remove unnecessary code --- operator/internal/webhook/auto/v1alpha1/workspace_webhook.go | 1 - 1 file changed, 1 deletion(-) diff --git a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go index 593268b8..7b66becc 100644 --- a/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go +++ b/operator/internal/webhook/auto/v1alpha1/workspace_webhook.go @@ -70,7 +70,6 @@ func (d *WorkspaceCustomDefaulter) Default(ctx context.Context, obj runtime.Obje switch w.Spec.SecurityProfile { case autov1alpha1.SecurityProfileRestricted: w.Spec.Image = SecurityProfileRestrictedDefaultImage - default: case autov1alpha1.SecurityProfileBaseline: w.Spec.Image = SecurityProfileBaselineDefaultImage } From ea811b68b807756b8c132d39cfbfebde16212448 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 7 Oct 2024 13:26:28 -0700 Subject: [PATCH 11/14] Update API docs for securityProfile --- deploy/crds/auto.pulumi.com_workspaces.yaml | 8 +++++-- deploy/crds/pulumi.com_stacks.yaml | 16 +++++++++---- .../crds/auto.pulumi.com_workspaces.yaml | 8 +++++-- .../crds/pulumi.com_stacks.yaml | 16 +++++++++---- deploy/yaml/install.yaml | 24 ++++++++++++++----- operator/api/auto/v1alpha1/workspace_types.go | 6 ++++- .../crd/bases/auto.pulumi.com_workspaces.yaml | 8 +++++-- .../config/crd/bases/pulumi.com_stacks.yaml | 16 +++++++++---- 8 files changed, 77 insertions(+), 25 deletions(-) diff --git a/deploy/crds/auto.pulumi.com_workspaces.yaml b/deploy/crds/auto.pulumi.com_workspaces.yaml index 303a898c..df9453d2 100644 --- a/deploy/crds/auto.pulumi.com_workspaces.yaml +++ b/deploy/crds/auto.pulumi.com_workspaces.yaml @@ -8413,8 +8413,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to the workspace, - 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default diff --git a/deploy/crds/pulumi.com_stacks.yaml b/deploy/crds/pulumi.com_stacks.yaml index 3549fe59..841d8cfd 100644 --- a/deploy/crds/pulumi.com_stacks.yaml +++ b/deploy/crds/pulumi.com_stacks.yaml @@ -9334,8 +9334,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default @@ -18871,8 +18875,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default diff --git a/deploy/helm/pulumi-operator/crds/auto.pulumi.com_workspaces.yaml b/deploy/helm/pulumi-operator/crds/auto.pulumi.com_workspaces.yaml index 303a898c..df9453d2 100644 --- a/deploy/helm/pulumi-operator/crds/auto.pulumi.com_workspaces.yaml +++ b/deploy/helm/pulumi-operator/crds/auto.pulumi.com_workspaces.yaml @@ -8413,8 +8413,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to the workspace, - 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default diff --git a/deploy/helm/pulumi-operator/crds/pulumi.com_stacks.yaml b/deploy/helm/pulumi-operator/crds/pulumi.com_stacks.yaml index 3549fe59..841d8cfd 100644 --- a/deploy/helm/pulumi-operator/crds/pulumi.com_stacks.yaml +++ b/deploy/helm/pulumi-operator/crds/pulumi.com_stacks.yaml @@ -9334,8 +9334,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default @@ -18871,8 +18875,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default diff --git a/deploy/yaml/install.yaml b/deploy/yaml/install.yaml index 127b2bec..5a274c0d 100644 --- a/deploy/yaml/install.yaml +++ b/deploy/yaml/install.yaml @@ -9569,8 +9569,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default @@ -19106,8 +19110,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default @@ -27868,8 +27876,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to the workspace, - 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default diff --git a/operator/api/auto/v1alpha1/workspace_types.go b/operator/api/auto/v1alpha1/workspace_types.go index 33a3ee66..e50a5040 100644 --- a/operator/api/auto/v1alpha1/workspace_types.go +++ b/operator/api/auto/v1alpha1/workspace_types.go @@ -42,7 +42,11 @@ type WorkspaceSpec struct { // +kubebuilder:default="default" ServiceAccountName string `json:"serviceAccountName,omitempty"` - // SecurityProfile applies a security profile to the workspace, 'restricted' by default. + // SecurityProfile applies a security profile to the workspace. + // The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + // the Restricted policy of the Pod Security Standards. + // The baseline profile runs the pod as the root user and with a security context that conforms with + // the Baseline policy of the Pod Security Standards. // +kubebuilder:default="restricted" // +optional SecurityProfile SecurityProfile `json:"securityProfile,omitempty"` diff --git a/operator/config/crd/bases/auto.pulumi.com_workspaces.yaml b/operator/config/crd/bases/auto.pulumi.com_workspaces.yaml index 303a898c..df9453d2 100644 --- a/operator/config/crd/bases/auto.pulumi.com_workspaces.yaml +++ b/operator/config/crd/bases/auto.pulumi.com_workspaces.yaml @@ -8413,8 +8413,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to the workspace, - 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default diff --git a/operator/config/crd/bases/pulumi.com_stacks.yaml b/operator/config/crd/bases/pulumi.com_stacks.yaml index 3549fe59..841d8cfd 100644 --- a/operator/config/crd/bases/pulumi.com_stacks.yaml +++ b/operator/config/crd/bases/pulumi.com_stacks.yaml @@ -9334,8 +9334,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default @@ -18871,8 +18875,12 @@ spec: type: object securityProfile: default: restricted - description: SecurityProfile applies a security profile to - the workspace, 'restricted' by default. + description: |- + SecurityProfile applies a security profile to the workspace. + The restricted profile (default) runs the pod as a non-root user and with a security context that conforms with + the Restricted policy of the Pod Security Standards. + The baseline profile runs the pod as the root user and with a security context that conforms with + the Baseline policy of the Pod Security Standards. type: string serviceAccountName: default: default From 800870426981ae0e5f3af574f365d92dc6d373ab Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 7 Oct 2024 13:45:16 -0700 Subject: [PATCH 12/14] fix for make run --- operator/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator/Makefile b/operator/Makefile index 65d68a9b..c9ad6416 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -145,7 +145,7 @@ build: manifests generate fmt vet ## Build manager binary. .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - go run ./cmd/main.go --program-fs-adv-addr=localhost:9090 + WORKSPACE_LOCALHOST=localhost:50051 SOURCE_CONTROLLER_LOCALHOST=localhost:9090 go run ./cmd/main.go # If you wish to build the manager image targeting other platforms you can use the --platform flag. # (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. From d5d708cfe2b9056f2796cd1eea439477f2561f02 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 7 Oct 2024 14:09:38 -0700 Subject: [PATCH 13/14] add port to advertised address --- deploy/helm/pulumi-operator/templates/deployment.yaml | 2 +- deploy/yaml/install.yaml | 2 +- operator/cmd/main.go | 5 ++++- operator/config/manager/manager.yaml | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/deploy/helm/pulumi-operator/templates/deployment.yaml b/deploy/helm/pulumi-operator/templates/deployment.yaml index d4512618..c055fd95 100644 --- a/deploy/helm/pulumi-operator/templates/deployment.yaml +++ b/deploy/helm/pulumi-operator/templates/deployment.yaml @@ -38,7 +38,7 @@ spec: - --leader-elect - --health-probe-bind-address=:8081 - --metrics-bind-address=:8383 - - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local + - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local:80 - --zap-log-level={{ .Values.controller.logLevel }} - --zap-time-encoding=iso8601 env: diff --git a/deploy/yaml/install.yaml b/deploy/yaml/install.yaml index 5a274c0d..4d38710a 100644 --- a/deploy/yaml/install.yaml +++ b/deploy/yaml/install.yaml @@ -28404,7 +28404,7 @@ spec: - --leader-elect - --health-probe-bind-address=:8081 - --metrics-bind-address=:8383 - - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local + - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local:80 - --zap-log-level=error - --zap-time-encoding=iso8601 env: diff --git a/operator/cmd/main.go b/operator/cmd/main.go index 4f47223a..a9fd4f3f 100644 --- a/operator/cmd/main.go +++ b/operator/cmd/main.go @@ -86,7 +86,7 @@ func main() { "If set, HTTP/2 will be enabled for the metrics and webhook servers") flag.StringVar(&programFSAddr, "program-fs-addr", envOrDefault("PROGRAM_FS_ADDR", ":9090"), "The address the static file server binds to.") - flag.StringVar(&programFSAdvAddr, "program-fs-adv-addr", envOrDefault("PROGRAM_FS_ADV_ADDR", "localhost:9090"), + flag.StringVar(&programFSAdvAddr, "program-fs-adv-addr", envOrDefault("PROGRAM_FS_ADV_ADDR", ""), "The advertised address of the static file server.") opts := zap.Options{ Development: true, @@ -150,6 +150,9 @@ func main() { // Create a new ProgramHandler to handle Program objects. Both the ProgramReconciler and the file server need to // access the ProgramHandler, so it is created here and passed to both. + if programFSAdvAddr == "" { + programFSAdvAddr = determineAdvAddr(programFSAddr) + } pHandler := newProgramHandler(mgr.GetClient(), programFSAdvAddr) if err = (&autocontroller.WorkspaceReconciler{ diff --git a/operator/config/manager/manager.yaml b/operator/config/manager/manager.yaml index 78eaac76..d72b2532 100644 --- a/operator/config/manager/manager.yaml +++ b/operator/config/manager/manager.yaml @@ -44,7 +44,7 @@ spec: - --leader-elect - --health-probe-bind-address=:8081 - --metrics-bind-address=:8383 - - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local + - --program-fs-adv-addr=pulumi-kubernetes-operator.$(POD_NAMESPACE).svc.cluster.local:80 - --zap-log-level=error - --zap-time-encoding=iso8601 ports: From 2fb59f1fdd2289eeed2e138caa99ef4f9a144058 Mon Sep 17 00:00:00 2001 From: Eron Wright Date: Mon, 7 Oct 2024 14:15:21 -0700 Subject: [PATCH 14/14] bugfix for advertised address --- operator/cmd/main.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/operator/cmd/main.go b/operator/cmd/main.go index a9fd4f3f..0f2be5e0 100644 --- a/operator/cmd/main.go +++ b/operator/cmd/main.go @@ -27,7 +27,6 @@ import ( // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" - "sigs.k8s.io/controller-runtime/pkg/client" sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2" @@ -153,7 +152,7 @@ func main() { if programFSAdvAddr == "" { programFSAdvAddr = determineAdvAddr(programFSAddr) } - pHandler := newProgramHandler(mgr.GetClient(), programFSAdvAddr) + pHandler := pulumicontroller.NewProgramHandler(mgr.GetClient(), programFSAdvAddr) if err = (&autocontroller.WorkspaceReconciler{ Client: mgr.GetClient(), @@ -249,14 +248,6 @@ func (fs pFileserver) Start(ctx context.Context) error { } } -func newProgramHandler(k8sClient client.Client, advAddr string) *pulumicontroller.ProgramHandler { - if advAddr == "" { - advAddr = determineAdvAddr(advAddr) - } - - return pulumicontroller.NewProgramHandler(k8sClient, advAddr) -} - func determineAdvAddr(addr string) string { host, port, err := net.SplitHostPort(addr) if err != nil {