Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion api/v1alpha1/deco_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package v1alpha1

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// DecoSpec defines the desired state of a Deco workload.
type DecoSpec struct {
Expand Down Expand Up @@ -82,6 +85,15 @@ type DecoSpecBuild struct {
// +optional
// +kubebuilder:validation:Minimum=0
TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty"`

// NodeSelector constrains the build Job pods to nodes matching all the specified labels.
// Use this to target a specific node pool (e.g. cloud.google.com/gke-nodepool: build-pool).
// +optional
NodeSelector map[string]string `json:"nodeSelector,omitempty"`

// Tolerations are applied to the build Job pods, allowing them to be scheduled on tainted nodes.
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
}

// DecoSpecBuildSource identifies the code revision to build.
Expand Down
15 changes: 15 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

7 changes: 7 additions & 0 deletions chart/templates/clusterrole-operator-manager-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- apiGroups:
- batch
resources:
Expand Down
47 changes: 47 additions & 0 deletions chart/templates/customresourcedefinition-decos.deco.sites.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ spec:
- name
type: object
type: array
nodeSelector:
additionalProperties:
type: string
description: |-
NodeSelector constrains the build Job pods to nodes matching all the specified labels.
Use this to target a specific node pool (e.g. cloud.google.com/gke-nodepool: build-pool).
type: object
secrets:
description: |-
Secrets are K8s Secrets whose keys are mounted as environment variables in the build Job.
Expand Down Expand Up @@ -118,6 +125,46 @@ spec:
required:
- commitSha
type: object
tolerations:
description: Tolerations are applied to the build Job pods, allowing
them to be scheduled on tainted nodes.
items:
description: |-
The pod this Toleration is attached to tolerates any taint that matches
the triple <key,value,effect> using the matching operator <operator>.
properties:
effect:
description: |-
Effect indicates the taint effect to match. Empty means match all taint effects.
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
type: string
key:
description: |-
Key is the taint key that the toleration applies to. Empty means match all taint keys.
If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
type: string
tolerationSeconds:
description: |-
TolerationSeconds represents the period of time the toleration (which must be
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
it is not set, which means tolerate the taint forever (do not evict). Zero and
negative values will be treated as 0 (evict immediately) by the system.
format: int64
type: integer
value:
description: |-
Value is the taint value the toleration matches to.
If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
type: object
type: array
ttlSecondsAfterFinished:
description: |-
TTLSecondsAfterFinished controls how long the Job is kept after completion.
Expand Down
36 changes: 23 additions & 13 deletions chart/templates/deployment-operator-controller-manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ spec:
command:
- /manager
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
{{- if or (and .Values.github (or .Values.github.token .Values.github.existingSecret)) (and .Values.valkey (get .Values.valkey "sentinelUrls")) .Values.cfworkers.existingSecret .Values.cfworkers.builderImage .Values.cfworkers.artifactsBucket .Values.s3.existingSecret .Values.s3.region .Values.s3.logsBucket }}
{{- if or (and .Values.github (or .Values.github.token .Values.github.existingSecret)) (and .Values.valkey (get .Values.valkey "sentinelUrls")) .Values.cfworkers.existingSecret .Values.cfworkers.builderImage .Values.cfworkers.artifactsBucket .Values.s3.region .Values.s3.logsBucket .Values.s3.stateBucket .Values.build.serviceAccount .Values.build.roleArn .Values.build.nodeSelector .Values.build.tolerations }}
env:
{{- if and .Values.github .Values.github.existingSecret }}
- name: GITHUB_TOKEN
Expand Down Expand Up @@ -84,18 +84,6 @@ spec:
{{- end }}
{{- end }}
{{- with .Values.s3 }}
{{- if .existingSecret }}
- name: S3_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .existingSecret | quote }}
key: s3-access-key-id
- name: S3_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ .existingSecret | quote }}
key: s3-secret-access-key
{{- end }}
{{- if .region }}
- name: S3_REGION
value: {{ .region | quote }}
Expand All @@ -104,6 +92,28 @@ spec:
- name: S3_LOGS_BUCKET
value: {{ .logsBucket | quote }}
{{- end }}
{{- if .stateBucket }}
- name: S3_STATE_BUCKET
value: {{ .stateBucket | quote }}
{{- end }}
{{- end }}
{{- with .Values.build }}
{{- if .serviceAccount }}
- name: BUILD_SERVICE_ACCOUNT
value: {{ .serviceAccount | quote }}
{{- end }}
{{- if .roleArn }}
- name: BUILD_ROLE_ARN
value: {{ .roleArn | quote }}
{{- end }}
{{- if .nodeSelector }}
- name: BUILD_NODE_SELECTOR
value: {{ .nodeSelector | toJson | quote }}
{{- end }}
{{- if .tolerations }}
- name: BUILD_TOLERATIONS
value: {{ .tolerations | toJson | quote }}
{{- end }}
{{- end }}
{{- end }}
livenessProbe:
Expand Down
11 changes: 9 additions & 2 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,18 @@ cfworkers:
builderImage: "" # Builder container image (repository:tag)
artifactsBucket: "" # S3 bucket for build artifacts (cfworkers-specific)

# S3 credentials and config — shared across all build platforms
# S3 config — shared across all build platforms (credentials via Pod Identity)
s3:
existingSecret: "" # Secret with s3-access-key-id, s3-secret-access-key
region: "" # AWS region (e.g. us-east-1)
logsBucket: "" # S3 bucket for build logs
stateBucket: "" # S3 bucket for site state

# Build job config — shared across all build platforms
build:
serviceAccount: "" # K8s ServiceAccount for builder pods (IRSA)
roleArn: "" # IAM role ARN for IRSA annotation on the ServiceAccount
nodeSelector: {} # Default nodeSelector for build pods (overridable per-site via spec.build.nodeSelector)
tolerations: [] # Default tolerations for build pods (overridable per-site via spec.build.tolerations)

# Name overrides
nameOverride: ""
Expand Down
11 changes: 8 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,15 @@ func main() {
registry := build.NewBuilderRegistry()
registry.Register("cloudflare-worker", build.NewCloudflareFactory(build.CfWorkersConfigFromEnv()))

builderSAAnnotations := map[string]string{}
if roleArn := os.Getenv("BUILD_ROLE_ARN"); roleArn != "" {
builderSAAnnotations["eks.amazonaws.com/role-arn"] = roleArn
}
if err := (&controller.DecoReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Builder: registry,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Builder: registry,
BuilderSAAnnotations: builderSAAnnotations,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Deco")
os.Exit(1)
Expand Down
47 changes: 47 additions & 0 deletions config/crd/bases/deco.sites_decos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ spec:
- name
type: object
type: array
nodeSelector:
additionalProperties:
type: string
description: |-
NodeSelector constrains the build Job pods to nodes matching all the specified labels.
Use this to target a specific node pool (e.g. cloud.google.com/gke-nodepool: build-pool).
type: object
secrets:
description: |-
Secrets are K8s Secrets whose keys are mounted as environment variables in the build Job.
Expand Down Expand Up @@ -119,6 +126,46 @@ spec:
required:
- commitSha
type: object
tolerations:
description: Tolerations are applied to the build Job pods, allowing
them to be scheduled on tainted nodes.
items:
description: |-
The pod this Toleration is attached to tolerates any taint that matches
the triple <key,value,effect> using the matching operator <operator>.
properties:
effect:
description: |-
Effect indicates the taint effect to match. Empty means match all taint effects.
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
type: string
key:
description: |-
Key is the taint key that the toleration applies to. Empty means match all taint keys.
If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
type: string
tolerationSeconds:
description: |-
TolerationSeconds represents the period of time the toleration (which must be
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
it is not set, which means tolerate the taint forever (do not evict). Zero and
negative values will be treated as 0 (evict immediately) by the system.
format: int64
type: integer
value:
description: |-
Value is the taint value the toleration matches to.
If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
type: object
type: array
ttlSecondsAfterFinished:
description: |-
TTLSecondsAfterFinished controls how long the Job is kept after completion.
Expand Down
7 changes: 7 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- apiGroups:
- batch
resources:
Expand Down
40 changes: 25 additions & 15 deletions hack/helm-generator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func addEnvVarsToDeployment(templatesDir string) error {
contentStr := string(content)

// Find the image line and add env vars after it
envBlock := ` {{- if or (and .Values.github (or .Values.github.token .Values.github.existingSecret)) (and .Values.valkey (get .Values.valkey "sentinelUrls")) .Values.cfworkers.existingSecret .Values.cfworkers.builderImage .Values.cfworkers.artifactsBucket .Values.s3.existingSecret .Values.s3.region .Values.s3.logsBucket }}
envBlock := ` {{- if or (and .Values.github (or .Values.github.token .Values.github.existingSecret)) (and .Values.valkey (get .Values.valkey "sentinelUrls")) .Values.cfworkers.existingSecret .Values.cfworkers.builderImage .Values.cfworkers.artifactsBucket .Values.s3.region .Values.s3.logsBucket .Values.s3.stateBucket .Values.build.serviceAccount .Values.build.roleArn .Values.build.nodeSelector .Values.build.tolerations }}
env:
{{- if and .Values.github .Values.github.existingSecret }}
- name: GITHUB_TOKEN
Expand Down Expand Up @@ -241,18 +241,6 @@ func addEnvVarsToDeployment(templatesDir string) error {
{{- end }}
{{- end }}
{{- with .Values.s3 }}
{{- if .existingSecret }}
- name: S3_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .existingSecret | quote }}
key: s3-access-key-id
- name: S3_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ .existingSecret | quote }}
key: s3-secret-access-key
{{- end }}
{{- if .region }}
- name: S3_REGION
value: {{ .region | quote }}
Expand All @@ -261,11 +249,33 @@ func addEnvVarsToDeployment(templatesDir string) error {
- name: S3_LOGS_BUCKET
value: {{ .logsBucket | quote }}
{{- end }}
{{- if .stateBucket }}
- name: S3_STATE_BUCKET
value: {{ .stateBucket | quote }}
{{- end }}
{{- end }}
{{- with .Values.build }}
{{- if .serviceAccount }}
- name: BUILD_SERVICE_ACCOUNT
value: {{ .serviceAccount | quote }}
{{- end }}
{{- if .roleArn }}
- name: BUILD_ROLE_ARN
value: {{ .roleArn | quote }}
{{- end }}
{{- if .nodeSelector }}
- name: BUILD_NODE_SELECTOR
value: {{ .nodeSelector | toJson | quote }}
{{- end }}
{{- if .tolerations }}
- name: BUILD_TOLERATIONS
value: {{ .tolerations | toJson | quote }}
{{- end }}
{{- end }}
{{- end }}`

re := regexp.MustCompile(`(?m)( image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}")`)
contentStr = re.ReplaceAllString(contentStr, "$1\n"+envBlock)
imageLine := ` image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"`
contentStr = strings.Replace(contentStr, imageLine, imageLine+"\n"+envBlock, 1)

return os.WriteFile(deploymentFile, []byte(contentStr), 0644)
}
Loading
Loading