Skip to content

Commit 3ee1b27

Browse files
committed
Switch ACK to CEL-Based Immutability and Remove Runtime Checks
1 parent 631aeb1 commit 3ee1b27

File tree

7 files changed

+23
-52
lines changed

7 files changed

+23
-52
lines changed

pkg/config/field.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,9 @@ type FieldConfig struct {
408408
// IsSecret instructs the code generator that this field should be a
409409
// SecretKeyReference.
410410
IsSecret bool `json:"is_secret"`
411-
// IsImmutable instructs the code generator to add advisory conditions
412-
// if user modifies the spec field after resource was created.
411+
// IsImmutable indicates that the field is enforced as immutable at the
412+
// admission layer. The code generator will add kubebuilder:validation:XValidation
413+
// lines to the CRD, preventing changes to this field after it’s set.
413414
IsImmutable bool `json:"is_immutable"`
414415
// From instructs the code generator that the value of the field should
415416
// be retrieved from the specified operation and member path

pkg/model/crd.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -336,33 +336,6 @@ func (r *CRD) IsSecretField(path string) bool {
336336
return false
337337
}
338338

339-
// GetImmutableFieldPaths returns list of immutable field paths present in CRD
340-
func (r *CRD) GetImmutableFieldPaths() []string {
341-
fConfigs := r.cfg.GetFieldConfigs(r.Names.Original)
342-
var immutableFields []string
343-
344-
for field, fieldConfig := range fConfigs {
345-
if fieldConfig.IsImmutable {
346-
immutableFields = append(immutableFields, field)
347-
}
348-
}
349-
350-
// We need a deterministic order to traverse the immutable fields
351-
sort.Strings(immutableFields)
352-
return immutableFields
353-
}
354-
355-
// HasImmutableFieldChanges helper function that return true if there are any immutable field changes
356-
func (r *CRD) HasImmutableFieldChanges() bool {
357-
fConfigs := r.cfg.GetFieldConfigs(r.Names.Original)
358-
for _, fieldConfig := range fConfigs {
359-
if fieldConfig.IsImmutable {
360-
return true
361-
}
362-
}
363-
return false
364-
}
365-
366339
// OmitUnchangedFieldsOnUpdate returns whether the controller needs to omit
367340
// unchanged fields from an update request or not.
368341
func (r *CRD) OmitUnchangedFieldsOnUpdate() bool {

pkg/model/field.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,18 @@ func (f *Field) IsRequired() bool {
188188
)
189189
}
190190

191+
// IsImmutable checks the FieldConfig for the Field and returns true if the
192+
// field is marked as immutable.
193+
//
194+
// If the FieldConfig is nil or IsImmutable is false (or not set), this function
195+
// returns false.
196+
func (f *Field) IsImmutable() bool {
197+
if f.FieldConfig != nil && f.FieldConfig.IsImmutable {
198+
return true
199+
}
200+
return false
201+
}
202+
191203
// GetSetterConfig returns the SetFieldConfig object associated with this field
192204
// and a supplied operation type, or nil if none exists.
193205
func (f *Field) GetSetterConfig(opType OpType) *ackgenconfig.SetFieldConfig {

templates/apis/crd.go.tpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ type {{ .CRD.Kind }}Spec struct {
1919
{{ if $field.GetDocumentation -}}
2020
{{ $field.GetDocumentation }}
2121
{{ end -}}
22+
{{- if $field.IsImmutable }}
23+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set"
24+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.{{ $field.Names.CamelLower }}) || has(self.{{ $field.Names.CamelLower }})",message="Value is required once set"
25+
{{- end }}
2226
{{- if and ($field.IsRequired) (not $field.HasReference) -}}
2327
// +kubebuilder:validation:Required
2428
{{ end -}}

templates/crossplane/apis/crd.go.tpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ type {{ .CRD.Kind }}Parameters struct {
2727
{{- if $field.ShapeRef }}
2828
{{ $field.ShapeRef.Documentation }}
2929
{{- end }}
30+
{{- if $field.IsImmutable }}
31+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set"
32+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.{{ $field.Names.CamelLower }}) || has(self.{{ $field.Names.CamelLower }})",message="Value is required once set"
33+
{{- end }}
3034
{{ if $field.IsRequired }} // +kubebuilder:validation:Required
3135
{{ $field.Names.Camel }} {{ $field.GoType }} `json:"{{ $field.Names.CamelLower }}"`
3236
{{- else }} {{ $field.Names.Camel }} {{ $field.GoType }} `json:"{{ $field.Names.CamelLower }},omitempty"` {{ end }}

templates/pkg/resource/sdk.go.tpl

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -328,23 +328,6 @@ func (rm *resourceManager) terminalAWSError(err error) bool {
328328
{{- end }}
329329
}
330330

331-
{{- if .CRD.HasImmutableFieldChanges }}
332-
// getImmutableFieldChanges returns list of immutable fields from the
333-
func (rm *resourceManager) getImmutableFieldChanges(
334-
delta *ackcompare.Delta,
335-
) []string {
336-
var fields []string;
337-
{{- $prefixConfig := .CRD.Config.PrefixConfig }}
338-
{{- range $immutableField := .CRD.GetImmutableFieldPaths }}
339-
{{- $specPrefix := $prefixConfig.SpecField }}
340-
if delta.DifferentAt("{{ TrimPrefix $specPrefix "." }}.{{$immutableField}}") {
341-
fields = append(fields,"{{$immutableField}}")
342-
}
343-
{{- end }}
344-
345-
return fields
346-
}
347-
{{- end }}
348331
{{- if $hookCode := Hook .CRD "sdk_file_end" }}
349332
{{ $hookCode }}
350333
{{- end }}

templates/pkg/resource/sdk_update.go.tpl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@ func (rm *resourceManager) sdkUpdate(
1010
defer func() {
1111
exit(err)
1212
}()
13-
{{- if .CRD.HasImmutableFieldChanges }}
14-
if immutableFieldChanges := rm.getImmutableFieldChanges(delta); len(immutableFieldChanges) > 0 {
15-
msg := fmt.Sprintf("Immutable Spec fields have been modified: %s", strings.Join(immutableFieldChanges, ","))
16-
return nil, ackerr.NewTerminalError(fmt.Errorf(msg))
17-
}
18-
{{- end }}
1913
{{- if $hookCode := Hook .CRD "sdk_update_pre_build_request" }}
2014
{{ $hookCode }}
2115
{{- end }}

0 commit comments

Comments
 (0)