Skip to content

Commit 9c7bc7d

Browse files
authored
Merge pull request #129 from datum-cloud/feat/configmap-secret-mounts-federated
Workloads can reference ConfigMaps and Secrets, delivered to every POP cell
2 parents 28508a0 + a8cc43a commit 9c7bc7d

38 files changed

Lines changed: 7685 additions & 131 deletions

api/v1alpha/annotations.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,46 @@ const (
44
AnnotationNamespace = "compute.datumapis.com"
55

66
SSHKeysAnnotation = AnnotationNamespace + "/ssh-keys"
7+
8+
// ExpectedReferencedDataAnnotation is set on a WorkloadDeployment by the
9+
// ReferencedDataController. Its value is a JSON-encoded array of companion
10+
// object names (sorted deterministically) that the cell should expect.
11+
// The cell does a pure set-membership check against labeled companions
12+
// without recomputing names.
13+
//
14+
// Example value: ["configmap.app-config","secret.db-creds"]
15+
ExpectedReferencedDataAnnotation = AnnotationNamespace + "/expected-referenced-data"
16+
17+
// RestartedAtAnnotation may be set on an InstanceTemplateSpec's annotations
18+
// to trigger a rolling restart. The value is an RFC3339 timestamp. Because
19+
// this annotation lives in the template metadata, it is included in the
20+
// template hash and triggers the existing ordered in-place roll.
21+
RestartedAtAnnotation = AnnotationNamespace + "/restartedAt"
22+
23+
// ReferencedDataGateStartAnnotation is stamped on an Instance by the cell
24+
// InstanceReconciler the first time it observes the ReferencedData scheduling
25+
// gate. Its value is an RFC3339 timestamp. Used to compute gate-wait duration
26+
// for the compute_referenced_data_gate_wait_seconds histogram.
27+
ReferencedDataGateStartAnnotation = AnnotationNamespace + "/referenced-data-gate-start"
28+
29+
// ReferencedDataErrorAnnotation is stamped on a WorkloadDeployment by the
30+
// ReferencedDataController when a terminal source error occurs (SourceNotFound,
31+
// SourceUnauthorized, or SourceTooLarge). Its value is a JSON object with
32+
// "reason" and "message" fields carrying the authoritative resolver verdict.
33+
//
34+
// Example value:
35+
// {"reason":"SourceNotFound","message":"ConfigMap \"app-config\" not found in namespace \"default\""}
36+
//
37+
// This annotation bridges the federation boundary: Karmada propagates
38+
// metadata.annotations hub→cell alongside WorkloadDeployment objects, but
39+
// status.conditions do not propagate in that direction. The cell
40+
// InstanceReconciler reads this annotation from the cell WD copy (returned by
41+
// fetchOwnerWorkloadDeployment) and promotes it to the Instance's
42+
// ReferencedDataReady condition so the terminal error is visible at the Instance
43+
// level without requiring a cross-plane condition read.
44+
//
45+
// The annotation is removed when the error resolves (companion materialises /
46+
// ReferencedDataReady flips True), so the absence of the annotation means
47+
// either no error or the error has cleared.
48+
ReferencedDataErrorAnnotation = AnnotationNamespace + "/referenced-data-error"
749
)

api/v1alpha/instance_types.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,16 @@ type SandboxContainer struct {
138138
// so replicate the structure here too.
139139
Env []corev1.EnvVar `json:"env,omitempty"`
140140

141+
// List of sources to populate environment variables in the container.
142+
// The keys defined within a source must be a C_IDENTIFIER. All invalid
143+
// keys will be reported as an event when the container is starting. When a
144+
// key exists in multiple sources, the value associated with the last source
145+
// will take precedence. Values defined by an Env with a duplicate key will
146+
// take precedence.
147+
//
148+
// +kubebuilder:validation:Optional
149+
EnvFrom []EnvFromSource `json:"envFrom,omitempty"`
150+
141151
// The resource requirements for the container, such as CPU, memory, and GPUs.
142152
//
143153
// +kubebuilder:validation:Optional
@@ -156,6 +166,54 @@ type SandboxContainer struct {
156166
Ports []NamedPort `json:"ports,omitempty"`
157167
}
158168

169+
// EnvFromSource represents a source for a set of ConfigMaps or Secrets to be
170+
// used as environment variables in a container.
171+
type EnvFromSource struct {
172+
// An optional identifier to prepend to each key in the referenced
173+
// ConfigMap or Secret. Must be a valid C_IDENTIFIER.
174+
//
175+
// +kubebuilder:validation:Optional
176+
Prefix string `json:"prefix,omitempty"`
177+
178+
// The ConfigMap to select from.
179+
//
180+
// +kubebuilder:validation:Optional
181+
ConfigMapRef *ConfigMapEnvSource `json:"configMapRef,omitempty"`
182+
183+
// The Secret to select from.
184+
//
185+
// +kubebuilder:validation:Optional
186+
SecretRef *SecretEnvSource `json:"secretRef,omitempty"`
187+
}
188+
189+
// ConfigMapEnvSource selects a ConfigMap to populate the environment variables
190+
// of a container.
191+
type ConfigMapEnvSource struct {
192+
// Name of the ConfigMap in the same namespace as the Workload.
193+
//
194+
// +kubebuilder:validation:Required
195+
Name string `json:"name"`
196+
197+
// Specify whether the ConfigMap must be defined.
198+
//
199+
// +kubebuilder:validation:Optional
200+
Optional *bool `json:"optional,omitempty"`
201+
}
202+
203+
// SecretEnvSource selects a Secret to populate the environment variables
204+
// of a container.
205+
type SecretEnvSource struct {
206+
// Name of the Secret in the same namespace as the Workload.
207+
//
208+
// +kubebuilder:validation:Required
209+
Name string `json:"name"`
210+
211+
// Specify whether the Secret must be defined.
212+
//
213+
// +kubebuilder:validation:Optional
214+
Optional *bool `json:"optional,omitempty"`
215+
}
216+
159217
type ContainerResourceRequirements struct {
160218
// Limits describes the maximum amount of compute resources allowed.
161219
//
@@ -414,6 +472,38 @@ const (
414472

415473
// InstanceQuotaGranted indicates whether quota has been allocated for the instance
416474
InstanceQuotaGranted = "QuotaGranted"
475+
476+
// ReferencedDataReady indicates whether all ConfigMaps and Secrets referenced
477+
// by the workload template have been resolved and delivered to the cell.
478+
// This condition is set on both WorkloadDeployment (resolver view) and
479+
// Instance (cell view).
480+
ReferencedDataReady = "ReferencedDataReady"
481+
)
482+
483+
const (
484+
// ReferencedDataReasonResolving indicates the resolver is in the process of
485+
// reading source ConfigMaps/Secrets from the project control plane.
486+
ReferencedDataReasonResolving = "Resolving"
487+
488+
// ReferencedDataReasonAwaitingPropagation indicates the expected companions
489+
// have not yet all arrived on the cell.
490+
ReferencedDataReasonAwaitingPropagation = "AwaitingPropagation"
491+
492+
// ReferencedDataReasonSourceNotFound indicates one or more referenced
493+
// ConfigMaps or Secrets could not be found in the project namespace.
494+
ReferencedDataReasonSourceNotFound = "SourceNotFound"
495+
496+
// ReferencedDataReasonSourceUnauthorized indicates the management identity
497+
// does not have permission to read one or more referenced objects.
498+
ReferencedDataReasonSourceUnauthorized = "SourceUnauthorized"
499+
500+
// ReferencedDataReasonSourceTooLarge indicates one or more referenced objects
501+
// exceed the allowed size limit.
502+
ReferencedDataReasonSourceTooLarge = "SourceTooLarge"
503+
504+
// ReferencedDataReasonReady indicates all referenced data has been resolved
505+
// and is present on the cell.
506+
ReferencedDataReasonReady = "Ready"
417507
)
418508

419509
const (

api/v1alpha/labels.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,13 @@ const (
2323
// PlacementNameLabel carries the placement name from the Workload that drove
2424
// this Instance's deployment, sourced from WorkloadDeploymentSpec.PlacementName.
2525
PlacementNameLabel = LabelNamespace + "/placement-name"
26+
27+
// ReferencedDataLabel is stamped on companion ConfigMaps and Secrets
28+
// materialized by the ReferencedDataController, and on WorkloadDeployments
29+
// that reference external ConfigMaps or Secrets. Used as a label selector
30+
// by the Karmada PropagationPolicy to propagate companions to cells.
31+
ReferencedDataLabel = LabelNamespace + "/referenced-data"
32+
33+
// ReferencedDataLabelValue is the value used for ReferencedDataLabel.
34+
ReferencedDataLabelValue = "true"
2635
)

api/v1alpha/zz_generated.deepcopy.go

Lines changed: 72 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/main.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,12 @@ func main() {
273273
}
274274

275275
if enableCellControllers {
276+
wdOpts := controller.WorkloadDeploymentReconcilerOptions{
277+
EnableReferencedDataGate: serverConfig.FeatureFlags.EnableReferencedDataGate,
278+
}
276279
if err = (&controller.WorkloadDeploymentReconciler{
277280
NetworkingEnabled: features.FeatureGate.Enabled(features.NetworkingIntegration),
278-
}).SetupWithManager(mgr); err != nil {
281+
}).SetupWithManager(mgr, wdOpts); err != nil {
279282
setupLog.Error(err, "unable to create controller", "controller", "WorkloadDeployment")
280283
os.Exit(1)
281284
}
@@ -310,6 +313,29 @@ func main() {
310313
}
311314
runnables = append(runnables, extra...)
312315
}
316+
// ReferencedDataController is a management-plane controller (it reconciles
317+
// WorkloadDeployments on project clusters and materialises companions). Gate
318+
// it to the management controller set so it does not collide with the cell's
319+
// WorkloadDeploymentReconciler.
320+
if enableManagementControllers {
321+
if err = (&controller.ReferencedDataController{}).SetupWithManager(mgr, controller.ReferencedDataControllerOptions{
322+
// ProjectReader is nil for single-cluster mode; the controller falls back
323+
// to a LocalReader. Set this to a *referenceddata.ProjectReader when the
324+
// Milo multicluster mode is active and cross-project reads are required.
325+
Reader: nil,
326+
// FederationClient is set when the federation hub (Karmada) is configured.
327+
// When non-nil, companions are materialised into the downstream
328+
// ns-{project-uid} namespace on the hub so Karmada can propagate them
329+
// to cells alongside the WorkloadDeployment. When nil, companions land
330+
// in the project namespace (single-cluster / dev path).
331+
FederationClient: federationClient,
332+
PerObjectLimitBytes: serverConfig.ReferencedData.PerObjectLimitBytes,
333+
AggregateLimitBytes: serverConfig.ReferencedData.AggregateLimitBytes,
334+
}); err != nil {
335+
setupLog.Error(err, "unable to create controller", "controller", "ReferencedData")
336+
os.Exit(1)
337+
}
338+
}
313339

314340
if serverConfig.WebhookServer != nil {
315341
if err = computev1alphawebhooks.SetupWorkloadWebhookWithManager(mgr); err != nil {

config/base/crd/bases/compute.datumapis.com_instances.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,54 @@ spec:
455455
x-kubernetes-list-map-keys:
456456
- name
457457
x-kubernetes-list-type: map
458+
envFrom:
459+
description: |-
460+
List of sources to populate environment variables in the container.
461+
The keys defined within a source must be a C_IDENTIFIER. All invalid
462+
keys will be reported as an event when the container is starting. When a
463+
key exists in multiple sources, the value associated with the last source
464+
will take precedence. Values defined by an Env with a duplicate key will
465+
take precedence.
466+
items:
467+
description: |-
468+
EnvFromSource represents a source for a set of ConfigMaps or Secrets to be
469+
used as environment variables in a container.
470+
properties:
471+
configMapRef:
472+
description: The ConfigMap to select from.
473+
properties:
474+
name:
475+
description: Name of the ConfigMap in the
476+
same namespace as the Workload.
477+
type: string
478+
optional:
479+
description: Specify whether the ConfigMap
480+
must be defined.
481+
type: boolean
482+
required:
483+
- name
484+
type: object
485+
prefix:
486+
description: |-
487+
An optional identifier to prepend to each key in the referenced
488+
ConfigMap or Secret. Must be a valid C_IDENTIFIER.
489+
type: string
490+
secretRef:
491+
description: The Secret to select from.
492+
properties:
493+
name:
494+
description: Name of the Secret in the same
495+
namespace as the Workload.
496+
type: string
497+
optional:
498+
description: Specify whether the Secret must
499+
be defined.
500+
type: boolean
501+
required:
502+
- name
503+
type: object
504+
type: object
505+
type: array
458506
image:
459507
description: The fully qualified container image name.
460508
type: string

0 commit comments

Comments
 (0)