@@ -18,9 +18,9 @@ import (
18
18
operatorcommon "github.com/openshift/assisted-service/internal/operators/common"
19
19
"github.com/openshift/assisted-service/internal/usage"
20
20
"github.com/openshift/assisted-service/models"
21
- "github.com/pkg/errors"
22
21
"github.com/sirupsen/logrus"
23
22
"github.com/thoas/go-funk"
23
+ "gorm.io/gorm"
24
24
)
25
25
26
26
type ValidationResult struct {
@@ -72,7 +72,7 @@ func (r *refreshPreprocessor) preprocess(ctx context.Context, c *clusterPreproce
72
72
if c .cluster != nil {
73
73
ignoredValidations , err = common .DeserializeJSONList (c .cluster .IgnoredClusterValidations )
74
74
if err != nil {
75
- return nil , nil , errors . Wrap ( err , fmt .Sprintf ( "Unable to deserialize ignored cluster validations for cluster %s" , string ( * c .cluster .ID )) )
75
+ return nil , nil , fmt .Errorf ( "unable to deserialize ignored cluster validations for cluster %s: %w " , c .cluster .ID . String (), err )
76
76
}
77
77
}
78
78
@@ -102,7 +102,7 @@ func (r *refreshPreprocessor) preprocess(ctx context.Context, c *clusterPreproce
102
102
// dependency, and then we will need to validate that secure boot is disabled.
103
103
err = r .recalculateOperatorDependencies (ctx , c )
104
104
if err != nil {
105
- err = errors . Wrapf ( err , "failed to recalculate operator dependencies for cluster '%s'" , c .clusterId )
105
+ err = fmt . Errorf ( "failed to recalculate operator dependencies for cluster '%s': %w " , c .clusterId , err )
106
106
return nil , nil , err
107
107
}
108
108
@@ -151,72 +151,97 @@ func (r *refreshPreprocessor) preprocess(ctx context.Context, c *clusterPreproce
151
151
func (r * refreshPreprocessor ) recalculateOperatorDependencies (ctx context.Context , c * clusterPreprocessContext ) error {
152
152
// Calculate and save the operators that have been added, updated or deleted:
153
153
operatorsBeforeResolve := c .cluster .MonitoredOperators
154
+
154
155
operatorsAfterResolve , err := r .operatorsAPI .ResolveDependencies (c .cluster , c .cluster .MonitoredOperators )
155
156
if err != nil {
156
- return errors .Wrapf (
157
- err ,
158
- "failed to resolve operator dependencies for cluster '%s'" ,
159
- c .clusterId ,
160
- )
157
+ return fmt .Errorf ("failed to resolve operator dependencies: %w" , err )
161
158
}
159
+
162
160
var addedOperators , updatedOperators , deletedOperators []* models.MonitoredOperator
161
+
163
162
for _ , operatorAfterResolve := range operatorsAfterResolve {
164
163
if operatorAfterResolve .ClusterID == "" {
165
164
operatorAfterResolve .ClusterID = c .clusterId
166
165
}
167
- operatorBeforeREsolve := operatorcommon .GetOperator (operatorsBeforeResolve , operatorAfterResolve .Name )
168
- if operatorBeforeREsolve != nil {
169
- if ! reflect .DeepEqual (operatorAfterResolve , operatorBeforeREsolve ) {
166
+
167
+ operatorBeforeResolve := operatorcommon .GetOperator (operatorsBeforeResolve , operatorAfterResolve .Name )
168
+ if operatorBeforeResolve != nil {
169
+ if ! reflect .DeepEqual (operatorAfterResolve , operatorBeforeResolve ) {
170
170
updatedOperators = append (updatedOperators , operatorAfterResolve )
171
171
}
172
172
} else {
173
173
addedOperators = append (addedOperators , operatorAfterResolve )
174
174
}
175
175
}
176
+
176
177
for _ , operatorBeforeResolve := range operatorsBeforeResolve {
177
178
if ! operatorcommon .HasOperator (operatorsAfterResolve , operatorBeforeResolve .Name ) {
178
179
deletedOperators = append (deletedOperators , operatorBeforeResolve )
179
180
}
180
181
}
181
- for _ , addedOperator := range addedOperators {
182
- err = c .db .Save (addedOperator ).Error
183
- if err != nil {
184
- return errors .Wrapf (
185
- err ,
186
- "failed to add operator '%s' to cluster '%s'" ,
187
- addedOperator .Name , * c .cluster .ID ,
188
- )
189
- }
182
+
183
+ // If nothing changed, nothing needs to be done
184
+ if len (addedOperators ) == 0 && len (deletedOperators ) == 0 && len (updatedOperators ) == 0 {
185
+ return nil
190
186
}
191
- for _ , updatedOperator := range updatedOperators {
192
- err = c .db .Save (updatedOperator ).Error
193
- if err != nil {
194
- return errors .Wrapf (
195
- err ,
196
- "failed to update operator '%s' for cluster '%s'" ,
197
- updatedOperator .Name , * c .cluster .ID ,
198
- )
199
- }
187
+
188
+ // Validate with cluster CPU architecture
189
+ err = r .operatorsAPI .EnsureOperatorPrerequisite (c .cluster , c .cluster .OpenshiftVersion , c .cluster .CPUArchitecture , operatorsAfterResolve )
190
+ if err != nil {
191
+ return fmt .Errorf ("failed to validate operator prerequisite: %w" , err )
200
192
}
201
- for _ , deletedOperator := range deletedOperators {
202
- err = c .db .Delete (deletedOperator ).Error
193
+
194
+ c .cluster .MonitoredOperators = operatorsAfterResolve
195
+
196
+ err = c .db .Transaction (func (tx * gorm.DB ) error {
197
+ for _ , addedOperator := range addedOperators {
198
+ err = tx .Save (addedOperator ).Error
199
+ if err != nil {
200
+ return fmt .Errorf ("failed to add operator '%s': %w" , addedOperator .Name , err )
201
+ }
202
+ }
203
+
204
+ for _ , updatedOperator := range updatedOperators {
205
+ err = tx .Save (updatedOperator ).Error
206
+ if err != nil {
207
+ return fmt .Errorf ("failed to update operator '%s': %w" , updatedOperator .Name , err )
208
+ }
209
+ }
210
+
211
+ for _ , deletedOperator := range deletedOperators {
212
+ err = tx .Delete (deletedOperator ).Error
213
+ if err != nil {
214
+ return fmt .Errorf ("failed to delete operator '%s': %w" , deletedOperator .Name , err )
215
+ }
216
+ }
217
+
218
+ // If any operator has been added or deleted then we need to update the corresponding feature usage
219
+ if len (addedOperators ) > 0 || len (deletedOperators ) > 0 {
220
+ err = r .recalculateOperatorFeatureUsage (c , tx , addedOperators , deletedOperators )
221
+ if err != nil {
222
+ return fmt .Errorf ("failed to recalculate operator feature usage: %w" , err )
223
+ }
224
+ }
225
+
226
+ // If any operator has been added, updated or deleted then we might need to retrigger auto-assign role calculation.
227
+ // This is needed because operators may affect the role assignment logic.
228
+ var resetHostRoles int
229
+ resetHostRoles , err = common .ResetAutoAssignRoles (tx , c .clusterId )
203
230
if err != nil {
204
- return errors .Wrapf (
205
- err ,
206
- "failed to delete operator '%s' from cluster '%s'" ,
207
- deletedOperator .Name ,
208
- c .clusterId ,
209
- )
231
+ return fmt .Errorf ("failed to reset auto assign role: %w" , err )
210
232
}
233
+
234
+ r .log .Infof ("resetting auto-assign roles on cluster %s after operator setup has changed: %d hosts affected" , c .clusterId .String (), resetHostRoles )
235
+
236
+ return nil
237
+ })
238
+
239
+ if err != nil {
240
+ return fmt .Errorf ("transaction to update monitored operators, the associated usage and reset roles failed: %w" , err )
211
241
}
212
- c .cluster .MonitoredOperators = operatorsAfterResolve
213
242
214
- // If any operator has been added or deleted then we need to update the corresponding feature usage:
243
+ // If everything went smoothly, notify about the change
215
244
if len (addedOperators ) > 0 || len (deletedOperators ) > 0 {
216
- err = r .recalculateOperatorFeatureUsage (c , addedOperators , deletedOperators )
217
- if err != nil {
218
- return err
219
- }
220
245
err = r .notifyOperatorFeatureUsageChange (ctx , c , addedOperators , deletedOperators )
221
246
if err != nil {
222
247
return err
@@ -226,37 +251,35 @@ func (r *refreshPreprocessor) recalculateOperatorDependencies(ctx context.Contex
226
251
return nil
227
252
}
228
253
229
- func (r * refreshPreprocessor ) recalculateOperatorFeatureUsage (c * clusterPreprocessContext ,
254
+ func (r * refreshPreprocessor ) recalculateOperatorFeatureUsage (c * clusterPreprocessContext , db * gorm. DB ,
230
255
addedOperators , deletedOperators []* models.MonitoredOperator ) error {
231
256
if r .usageAPI == nil {
232
257
return nil
233
258
}
259
+
234
260
usages , err := usage .Unmarshal (c .cluster .FeatureUsage )
235
261
if err != nil {
236
- return errors .Wrapf (
237
- err ,
238
- "failed to read feature usage from cluster '%s'" ,
239
- c .clusterId ,
240
- )
262
+ return fmt .Errorf ("failed to read feature usage: %w" , err )
241
263
}
264
+
242
265
for _ , addedOperator := range addedOperators {
243
266
featureName := strings .ToUpper (addedOperator .Name )
244
267
r .usageAPI .Add (usages , featureName , nil )
245
268
}
269
+
246
270
for _ , deletedOperator := range deletedOperators {
247
271
featureName := strings .ToUpper (deletedOperator .Name )
248
272
r .usageAPI .Remove (usages , featureName )
249
273
}
274
+
250
275
data , err := json .Marshal (usages )
251
276
if err != nil {
252
- return errors .Wrapf (
253
- err ,
254
- "failed to write feature usage to cluster '%s'" ,
255
- c .clusterId ,
256
- )
277
+ return fmt .Errorf ("failed to write feature usage: %w" , err )
257
278
}
279
+
258
280
c .cluster .FeatureUsage = string (data )
259
- r .usageAPI .Save (c .db , c .clusterId , usages )
281
+ r .usageAPI .Save (db , c .clusterId , usages )
282
+
260
283
return nil
261
284
}
262
285
0 commit comments