Skip to content

Commit cbc990d

Browse files
authored
add event to remind no update although CR changed (#377)
* refactor comparable resource assignment * add event to commonservice CR
1 parent fe9f2a1 commit cbc990d

File tree

6 files changed

+98
-16
lines changed

6 files changed

+98
-16
lines changed

controllers/commonservice_controller.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ package controllers
1818

1919
import (
2020
"context"
21+
"fmt"
2122

23+
corev1 "k8s.io/api/core/v1"
2224
"k8s.io/apimachinery/pkg/api/errors"
2325
"k8s.io/apimachinery/pkg/runtime"
2426
"k8s.io/apimachinery/pkg/types"
27+
"k8s.io/client-go/tools/record"
2528
"k8s.io/klog"
2629
ctrl "sigs.k8s.io/controller-runtime"
2730
"sigs.k8s.io/controller-runtime/pkg/builder"
@@ -40,7 +43,8 @@ type CommonServiceReconciler struct {
4043
client.Reader
4144
*deploy.Manager
4245
*bootstrap.Bootstrap
43-
Scheme *runtime.Scheme
46+
Scheme *runtime.Scheme
47+
Recorder record.EventRecorder
4448
}
4549

4650
const (
@@ -64,6 +68,7 @@ func (r *CommonServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
6468
if err := r.handleDelete(); err != nil {
6569
return ctrl.Result{}, err
6670
}
71+
klog.Info("Deleted reconciling CommonService CR successfully")
6772
}
6873
return ctrl.Result{}, client.IgnoreNotFound(err)
6974
}
@@ -117,14 +122,20 @@ func (r *CommonServiceReconciler) ReconcileMasterCR(instance *apiv3.CommonServic
117122
return ctrl.Result{}, client.IgnoreNotFound(err)
118123
}
119124

120-
if err := r.updateOperandConfig(newConfigs); err != nil {
125+
isEqual, err := r.updateOperandConfig(newConfigs)
126+
if err != nil {
121127
if err := r.updatePhase(instance, CRFailed); err != nil {
122128
klog.Error(err)
123129
}
124130
klog.Errorf("Fail to reconcile %s/%s: %v", instance.Namespace, instance.Name, err)
125131
return ctrl.Result{}, err
126132
}
127133

134+
// Create Event if there is no update in OperandConfig after applying current CR
135+
if isEqual {
136+
r.Recorder.Event(instance, corev1.EventTypeNormal, "Noeffect", fmt.Sprintf("No update, resource sizings in the OperandConfig %s/%s are larger than the profile from CommonService CR %s/%s", r.Bootstrap.MasterNamespace, "common-service", instance.Namespace, instance.Name))
137+
}
138+
128139
if err := r.updatePhase(instance, CRSucceeded); err != nil {
129140
klog.Error(err)
130141
return ctrl.Result{}, err
@@ -178,14 +189,20 @@ func (r *CommonServiceReconciler) ReconcileGeneralCR(instance *apiv3.CommonServi
178189
return ctrl.Result{}, err
179190
}
180191

181-
if err = r.updateOperandConfig(newConfigs); err != nil {
192+
isEqual, err := r.updateOperandConfig(newConfigs)
193+
if err != nil {
182194
if err := r.updatePhase(instance, CRFailed); err != nil {
183195
klog.Error(err)
184196
}
185197
klog.Errorf("Fail to reconcile %s/%s: %v", instance.Namespace, instance.Name, err)
186198
return ctrl.Result{}, err
187199
}
188200

201+
// Create Event if there is no update in OperandConfig after applying current CR
202+
if isEqual {
203+
r.Recorder.Event(instance, corev1.EventTypeNormal, "Noeffect", fmt.Sprintf("No update, resource sizings in the OperandConfig %s/%s are larger than the profile from CommonService CR %s/%s", r.Bootstrap.MasterNamespace, "common-service", instance.Namespace, instance.Name))
204+
}
205+
189206
if err := r.updatePhase(instance, CRSucceeded); err != nil {
190207
klog.Errorf("Fail to reconcile %s/%s: %v", instance.Namespace, instance.Name, err)
191208
return ctrl.Result{}, err

controllers/operandconfig.go

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strings"
2424

2525
utilyaml "github.com/ghodss/yaml"
26+
"github.com/mohae/deepcopy"
2627
"k8s.io/apimachinery/pkg/types"
2728
"k8s.io/klog"
2829

@@ -142,13 +143,13 @@ func mergeChangedMap(key string, defaultMap interface{}, changedMap interface{},
142143
if changedMap == nil {
143144
finalMap[key] = defaultMap
144145
} else {
145-
comparableKeys := []string{"replicas", "cpu", "memory"}
146-
for _, comparable := range comparableKeys {
147-
if key == comparable {
148-
finalMap[key], _ = rules.ResourceComparison(defaultMap, changedMap)
149-
} else {
150-
finalMap[key] = changedMap
151-
}
146+
var comparableKeys = map[string]bool{
147+
"replicas": true,
148+
"cpu": true,
149+
"memory": true,
150+
}
151+
if _, ok := comparableKeys[key]; ok {
152+
finalMap[key], _ = rules.ResourceComparison(defaultMap, changedMap)
152153
}
153154
}
154155
}
@@ -209,23 +210,25 @@ func deepMergeTwoMaps(key string, defaultMap interface{}, changedMap interface{}
209210
}
210211
}
211212

212-
func (r *CommonServiceReconciler) updateOperandConfig(newConfigs []interface{}) error {
213+
func (r *CommonServiceReconciler) updateOperandConfig(newConfigs []interface{}) (bool, error) {
213214
opcon := util.NewUnstructured("operator.ibm.com", "OperandConfig", "v1alpha1")
214215
opconKey := types.NamespacedName{
215216
Name: "common-service",
216217
Namespace: r.Bootstrap.MasterNamespace,
217218
}
218219
if err := r.Reader.Get(ctx, opconKey, opcon); err != nil {
219220
klog.Errorf("failed to get OperandConfig %s: %v", opconKey.String(), err)
220-
return err
221+
return true, err
221222
}
222223

224+
// Keep a version of exsiting config for comparasion later
223225
opconServices := opcon.Object["spec"].(map[string]interface{})["services"].([]interface{})
226+
existingOpconServices := deepcopy.Copy(opconServices)
224227

225228
// Convert rules string to slice
226229
ruleSlice, err := convertStringToSlice(rules.ConfigurationRules)
227230
if err != nil {
228-
return err
231+
return true, err
229232
}
230233

231234
for _, opService := range opconServices {
@@ -260,17 +263,32 @@ func (r *CommonServiceReconciler) updateOperandConfig(newConfigs []interface{})
260263
// Checking all the common service CRs to get the minimal size
261264
opconServices, err = r.getMinimalSizes(opconServices, ruleSlice)
262265
if err != nil {
263-
return err
266+
return true, err
267+
}
268+
269+
// Compare to see whether new resource sizing is introduced into opconServices
270+
isEqual := true
271+
for _, opService := range opconServices {
272+
existingOpService := getItemByName(existingOpconServices.([]interface{}), opService.(map[string]interface{})["name"].(string))
273+
for cr, spec := range opService.(map[string]interface{})["spec"].(map[string]interface{}) {
274+
existingCrSpec := existingOpService.(map[string]interface{})["spec"].(map[string]interface{})[cr].(map[string]interface{})
275+
if isEqual = rules.ResourceEqualComparison(existingCrSpec, spec); !isEqual {
276+
break
277+
}
278+
}
279+
if !isEqual {
280+
break
281+
}
264282
}
265283

266284
opcon.Object["spec"].(map[string]interface{})["services"] = opconServices
267285

268286
if err := r.Update(ctx, opcon); err != nil {
269287
klog.Errorf("failed to update OperandConfig %s: %v", opconKey.String(), err)
270-
return err
288+
return true, err
271289
}
272290

273-
return nil
291+
return isEqual, nil
274292
}
275293

276294
func checkCRFromOperandConfig(serviceStatus map[string]interface{}, operatorName, crName string) bool {

controllers/rules/resource_comparison.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,46 @@ func ResourceComparison(resourceA, resourceB interface{}) (interface{}, interfac
6767
return resourceA, resourceA
6868
}
6969
}
70+
71+
func ResourceEqualComparison(resourceA interface{}, resourceB interface{}) bool {
72+
73+
klog.V(2).Infof("Kind of A %s", reflect.TypeOf(resourceA).Kind())
74+
klog.V(2).Infof("Kind of B %s", reflect.TypeOf(resourceB).Kind())
75+
76+
isEqual := true
77+
switch resourceA := resourceA.(type) {
78+
case map[string]interface{}:
79+
if resourceB == nil {
80+
isEqual = false
81+
} else if _, ok := resourceB.(map[string]interface{}); ok { //Check that the changed map value is also a map[string]interface
82+
resourceARef := resourceA
83+
resourceBRef := resourceB.(map[string]interface{})
84+
for newKey := range resourceARef {
85+
isEqual = ResourceEqualComparison(resourceARef[newKey], resourceBRef[newKey])
86+
if !isEqual {
87+
break
88+
}
89+
}
90+
}
91+
return isEqual
92+
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
93+
strA := fmt.Sprintf("%v", resourceA)
94+
strB := fmt.Sprintf("%v", resourceB)
95+
96+
floatA, _ := strconv.ParseFloat(strA, 64)
97+
floatB, _ := strconv.ParseFloat(strB, 64)
98+
if floatA == floatB {
99+
isEqual = true
100+
} else {
101+
isEqual = false
102+
}
103+
return isEqual
104+
default:
105+
if resourceA == resourceB {
106+
isEqual = true
107+
} else {
108+
isEqual = false
109+
}
110+
return isEqual
111+
}
112+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.13
55
require (
66
github.com/IBM/ibm-namespace-scope-operator v1.0.1
77
github.com/ghodss/yaml v1.0.0
8+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
89
github.com/onsi/ginkgo v1.12.1
910
github.com/onsi/gomega v1.10.1
1011
github.com/operator-framework/api v0.3.10

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
253253
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
254254
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
255255
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
256+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
257+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
256258
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
257259
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
258260
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func main() {
123123
Manager: deploy.NewDeployManager(mgr),
124124
Bootstrap: bootstrap.NewBootstrap(mgr),
125125
Scheme: mgr.GetScheme(),
126+
Recorder: mgr.GetEventRecorderFor("commonservice-controller"),
126127
}).SetupWithManager(mgr); err != nil {
127128
klog.Errorf("Unable to create controller CommonService: %v", err)
128129
os.Exit(1)

0 commit comments

Comments
 (0)