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
10 changes: 8 additions & 2 deletions internal/restResources/restResources.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,18 @@ func (h *handler) Observe(ctx context.Context, mg *unstructured.Unstructured) (c
log.Debug("Updating status", "error", err)
return controller.ExternalObservation{}, err
}
ok, err := isCRUpdated(mg, *body)
res, err := isCRUpdated(mg, *body)
if err != nil {
log.Debug("Checking if CR is updated", "error", err)
return controller.ExternalObservation{}, err
}
if !ok {
if !res.IsEqual {
cond := condition.Unavailable()
if res.Reason != nil {
cond.Reason = fmt.Sprintf("Resource is not up-to-date due to %s - spec value: %s, remote value: %s", res.Reason.Reason, res.Reason.FirstValue, res.Reason.SecondValue)
}

unstructuredtools.SetCondition(mg, cond)
log.Debug("External resource not up-to-date", "kind", mg.GetKind())
return controller.ExternalObservation{
ResourceExists: true,
Expand Down
222 changes: 184 additions & 38 deletions internal/restResources/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,41 @@
}
reqConfiguration.Query[field] = stringVal
} else if callInfo.ReqParams.Body.Contains(field) {
mapBody[field] = value
if mapBody[field] == nil {
mapBody[field] = value
}

Check warning on line 127 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L125-L127

Added lines #L125 - L127 were not covered by tests
}
}
}

// isCRUpdated checks if the CR was updated by comparing the fields in the CR with the response from the API call, if existing cr fields are different from the response, it returns false
func isCRUpdated(mg *unstructured.Unstructured, rm map[string]interface{}) (bool, error) {
func isCRUpdated(mg *unstructured.Unstructured, rm map[string]interface{}) (ComparisonResult, error) {

Check warning on line 133 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L133

Added line #L133 was not covered by tests
m, err := unstructuredtools.GetFieldsFromUnstructured(mg, "spec")
if err != nil {
return false, fmt.Errorf("error getting spec fields: %w", err)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "error getting spec fields",
},
}, fmt.Errorf("error getting spec fields: %w", err)

Check warning on line 141 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L136-L141

Added lines #L136 - L141 were not covered by tests
}

return compareExisting(m, rm), nil
return compareExisting(m, rm)

Check warning on line 144 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L144

Added line #L144 was not covered by tests
}

type Reason struct {
Reason string
FirstValue any
SecondValue any
}

type ComparisonResult struct {
IsEqual bool
Reason *Reason
}

// compareExisting recursively compares fields between two maps and logs differences.
func compareExisting(mg map[string]interface{}, rm map[string]interface{}, path ...string) bool {
func compareExisting(mg map[string]interface{}, rm map[string]interface{}, path ...string) (ComparisonResult, error) {

Check warning on line 159 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L159

Added line #L159 was not covered by tests
for key, value := range mg {
currentPath := append(path, key)
pathStr := fmt.Sprintf("%v", currentPath)
Expand All @@ -148,63 +166,179 @@
continue
}

// fmt.Println("Comparing", pathStr, value, rmValue)

if reflect.TypeOf(value).Kind() != reflect.TypeOf(rmValue).Kind() {
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "types differ",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("types differ at %s - %s is different from %s", pathStr, reflect.TypeOf(value).Kind(), reflect.TypeOf(rmValue).Kind())
}

Check warning on line 180 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L171-L180

Added lines #L171 - L180 were not covered by tests

switch reflect.TypeOf(value).Kind() {
case reflect.Map:
mgMap, ok1 := value.(map[string]interface{})
if !ok1 {
fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
continue
// fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "type assertion failed",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("type assertion failed for map at %s", pathStr)

Check warning on line 194 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L186-L194

Added lines #L186 - L194 were not covered by tests
}
rmMap, ok2 := rmValue.(map[string]interface{})
if !ok2 {
fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
continue
// fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "type assertion failed",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("type assertion failed for map at %s", pathStr)

Check warning on line 206 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L198-L206

Added lines #L198 - L206 were not covered by tests
}
if !compareExisting(mgMap, rmMap, currentPath...) {
fmt.Printf("Values differ at '%s'\n", pathStr)
return false
res, err := compareExisting(mgMap, rmMap, currentPath...)
if err != nil {
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "error comparing maps",
FirstValue: value,
SecondValue: rmValue,
},
}, err
}
if !res.IsEqual {
// fmt.Printf("Values differ at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "values differ",
FirstValue: value,
SecondValue: rmValue,
},
}, nil

Check warning on line 228 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L208-L228

Added lines #L208 - L228 were not covered by tests
}
case reflect.Slice:
valueSlice, ok1 := value.([]interface{})
if !ok1 || reflect.TypeOf(rmValue).Kind() != reflect.Slice {
fmt.Printf("Values are not both slices or type assertion failed at '%s'\n", pathStr)
continue
// fmt.Printf("Values are not both slices or type assertion failed at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "values are not both slices or type assertion failed",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("values are not both slices or type assertion failed at %s", pathStr)

Check warning on line 241 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L233-L241

Added lines #L233 - L241 were not covered by tests
}
rmSlice, ok2 := rmValue.([]interface{})
if !ok2 {
fmt.Printf("Type assertion failed for slice at '%s'\n", pathStr)
continue
// fmt.Printf("Type assertion failed for slice at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "values are not both slices or type assertion failed",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("type assertion failed for slice at %s", pathStr)

Check warning on line 253 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L245-L253

Added lines #L245 - L253 were not covered by tests
}
for i, v := range valueSlice {
if reflect.TypeOf(v).Kind() == reflect.Map {
mgMap, ok1 := v.(map[string]interface{})
if !ok1 {
fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
continue
// fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "type assertion failed",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("type assertion failed for map at %s", pathStr)

Check warning on line 267 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L259-L267

Added lines #L259 - L267 were not covered by tests
}
rmMap, ok2 := rmSlice[i].(map[string]interface{})
if !ok2 {
fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
continue
// fmt.Printf("Type assertion failed for map at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "type assertion failed",
FirstValue: value,
SecondValue: rmValue,
},
}, fmt.Errorf("type assertion failed for map at %s", pathStr)
}
res, err := compareExisting(mgMap, rmMap, currentPath...)
if err != nil {
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "error comparing maps",
FirstValue: value,
SecondValue: rmValue,
},
}, err

Check warning on line 290 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L271-L290

Added lines #L271 - L290 were not covered by tests
}
if !compareExisting(mgMap, rmMap, currentPath...) {
fmt.Printf("Values differ at '%s'\n", pathStr)
return false
if !res.IsEqual {
// fmt.Printf("Values differ at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "values differ",
FirstValue: value,
SecondValue: rmValue,
},
}, nil

Check warning on line 301 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L292-L301

Added lines #L292 - L301 were not covered by tests
}
} else if v != rmSlice[i] {
fmt.Printf("Values differ at '%s'\n", pathStr)
return false
// fmt.Printf("Values differ at '%s'\n", pathStr)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "values differ",
FirstValue: value,
SecondValue: rmValue,
},
}, nil

Check warning on line 312 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L304-L312

Added lines #L304 - L312 were not covered by tests
}
}
default:
if !compareAny(value, rmValue) {
fmt.Printf("Values differ at '%s' %s %s\n", pathStr, value, rmValue)
return false
ok, err := compareAny(value, rmValue)
if err != nil {
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "error comparing values",
FirstValue: value,
SecondValue: rmValue,
},
}, err
}
if !ok {
// fmt.Printf("Values differ at '%s' %s %s\n", pathStr, value, rmValue)
return ComparisonResult{
IsEqual: false,
Reason: &Reason{
Reason: "values differ",
FirstValue: value,
SecondValue: rmValue,
},
}, nil

Check warning on line 336 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L316-L336

Added lines #L316 - L336 were not covered by tests
}
}
}

return true
return ComparisonResult{IsEqual: true}, nil

Check warning on line 341 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L341

Added line #L341 was not covered by tests
}
func numberCaster(value interface{}) int64 {
switch v := value.(type) {
Expand Down Expand Up @@ -237,23 +371,35 @@
}
}

func compareAny(a any, b any) bool {
func compareAny(a any, b any) (bool, error) {

Check warning on line 374 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L374

Added line #L374 was not covered by tests
//if is number compare as number
switch a.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
ia := numberCaster(a)
ib := numberCaster(b)
return ia == ib
return ia == ib, nil

Check warning on line 380 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L380

Added line #L380 was not covered by tests
case string:
sa := a.(string)
sb := b.(string)
return sa == sb
sa, ok := a.(string)
if !ok {
return false, fmt.Errorf("type assertion failed - to string: %v", a)
}
sb, ok := b.(string)
if !ok {
return false, fmt.Errorf("type assertion failed - to string: %v", b)
}
return sa == sb, nil

Check warning on line 390 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L382-L390

Added lines #L382 - L390 were not covered by tests
case bool:
ba := a.(bool)
bb := b.(bool)
return ba == bb
ba, ok := a.(bool)
if !ok {
return false, fmt.Errorf("type assertion failed - to bool: %v", a)
}
bb, ok := b.(bool)
if !ok {
return false, fmt.Errorf("type assertion failed - to bool: %v", b)
}
return ba == bb, nil

Check warning on line 400 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L392-L400

Added lines #L392 - L400 were not covered by tests
default:
return reflect.DeepEqual(a, b)
return reflect.DeepEqual(a, b), nil

Check warning on line 402 in internal/restResources/support.go

View check run for this annotation

Codecov / codecov/patch

internal/restResources/support.go#L402

Added line #L402 was not covered by tests
}
}

Expand Down
Loading