Skip to content

Commit ecb9858

Browse files
committed
Immutable fields warning
Add a warning condition if an immutable field is modified. This commit allows one to specify immutable fields in generator.yaml.
1 parent ad3bd3d commit ecb9858

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

pkg/generate/config/field.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ type FieldConfig struct {
155155
// IsSecret instructs the code generator that this field should be a
156156
// SecretKeyReference.
157157
IsSecret bool `json:"is_secret"`
158+
// IsImmutable instructs the code generator to add warning conditions
159+
// if user modifies the spec field after resource was created.
160+
IsImmutable bool `json:"is_immutable"`
158161
// From instructs the code generator that the value of the field should
159162
// be retrieved from the specified operation and member path
160163
From *SourceFieldConfig `json:"from,omitempty"`

pkg/model/crd.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,32 @@ func (r *CRD) IsSecretField(path string) bool {
303303
return false
304304
}
305305

306+
// GetImmutableFieldPaths returns list of immutable field paths present in CRD
307+
func (r *CRD) GetImmutableFieldPaths() []string {
308+
fConfigs := r.cfg.ResourceFields(r.Names.Original)
309+
var immutableFields []string
310+
311+
for field, fieldConfig := range fConfigs {
312+
if fieldConfig.IsImmutable {
313+
immutableFields = append(immutableFields, field)
314+
}
315+
}
316+
317+
return immutableFields
318+
}
319+
320+
// HasImmutableFieldChanges helper function that return true if there are any immutable field changes
321+
func (r *CRD) HasImmutableFieldChanges() bool {
322+
fConfigs := r.cfg.ResourceFields(r.Names.Original)
323+
324+
for _, fieldConfig := range fConfigs {
325+
if fieldConfig.IsImmutable {
326+
return true
327+
}
328+
}
329+
return false
330+
}
331+
306332
// SetOutputCustomMethodName returns custom set output operation as *string for
307333
// given operation on custom resource, if specified in generator config
308334
func (r *CRD) SetOutputCustomMethodName(

templates/pkg/resource/sdk.go.tpl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,62 @@ func (rm *resourceManager) terminalAWSError(err error) bool {
273273
return false
274274
{{- end }}
275275
}
276+
277+
{{- if .CRD.HasImmutableFieldChanges }}
278+
// getImmutableFieldChanges returns list of immutable fields from the
279+
func (rm *resourceManager) getImmutableFieldChanges(
280+
delta *ackcompare.Delta,
281+
) []string {
282+
var fields []string;
283+
284+
{{- range $immutableField := .CRD.GetImmutableFieldPaths }}
285+
if delta.DifferentAt("{{$immutableField}}") {
286+
fields = append(fields,"{{$immutableField}}")
287+
}
288+
{{- end }}
289+
290+
return fields
291+
}
292+
// handleImmutableFieldsChangedCondition validates the immutable fields and set appropriate condition
293+
func (rm *resourceManager) handleImmutableFieldsChangedCondition(
294+
r *resource,
295+
delta *ackcompare.Delta,
296+
) *resource {
297+
298+
fields := rm.getImmutableFieldChanges(delta)
299+
ko := r.ko.DeepCopy()
300+
var advisoryCondition *ackv1alpha1.Condition = nil
301+
for _, condition := range ko.Status.Conditions {
302+
if condition.Type == ackv1alpha1.ConditionTypeAdvisory {
303+
advisoryCondition = condition
304+
break
305+
}
306+
}
307+
308+
// Remove the advisory condition if issue is no longer present
309+
if len(fields) == 0 && advisoryCondition != nil{
310+
var newConditions []*ackv1alpha1.Condition
311+
for _, condition := range ko.Status.Conditions {
312+
if condition.Type != ackv1alpha1.ConditionTypeAdvisory {
313+
newConditions = append(newConditions,condition)
314+
}
315+
}
316+
ko.Status.Conditions = newConditions
317+
}
318+
319+
if len(fields) > 0 {
320+
if advisoryCondition == nil {
321+
advisoryCondition = &ackv1alpha1.Condition{
322+
Type: ackv1alpha1.ConditionTypeAdvisory,
323+
}
324+
ko.Status.Conditions = append(ko.Status.Conditions, advisoryCondition)
325+
}
326+
327+
advisoryCondition.Status = corev1.ConditionTrue
328+
message := "Immutable Spec fields have been modified : " + strings.Join(fields, ",")
329+
advisoryCondition.Message = &message
330+
}
331+
332+
return &resource{ko}
333+
}
334+
{{- end }}

templates/pkg/resource/sdk_update.go.tpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ func (rm *resourceManager) sdkUpdate(
3232
if respErr != nil {
3333
return nil, respErr
3434
}
35+
{{- if .CRD.HasImmutableFieldChanges }}
36+
desired = rm.handleImmutableFieldsChangedCondition(desired, delta)
37+
{{- end }}
3538
// Merge in the information we read from the API call above to the copy of
3639
// the original Kubernetes object we passed to the function
3740
ko := desired.ko.DeepCopy()

0 commit comments

Comments
 (0)