@@ -19,7 +19,6 @@ package controller
1919import (
2020 "context"
2121 "fmt"
22- "strings"
2322 "time"
2423
2524 "github.com/aws/aws-sdk-go/aws"
@@ -28,21 +27,20 @@ import (
2827 "github.com/go-logr/logr"
2928 corev1 "k8s.io/api/core/v1"
3029 apierrs "k8s.io/apimachinery/pkg/api/errors"
31- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3230 "k8s.io/apimachinery/pkg/runtime"
33- k8stypes "k8s.io/apimachinery/pkg/types"
31+ ktypes "k8s.io/apimachinery/pkg/types"
3432 ctrl "sigs.k8s.io/controller-runtime"
3533 "sigs.k8s.io/controller-runtime/pkg/client"
3634 "sigs.k8s.io/controller-runtime/pkg/reconcile"
3735
3836 "github.com/spectrocloud-labs/valid8or-plugin-aws/api/v1alpha1"
3937 "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/constants"
40- "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/types"
41- "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/utils/ptr"
4238 "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/validators/iam"
4339 "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/validators/servicequota"
4440 "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/validators/tag"
45- valid8orv1alpha1 "github.com/spectrocloud-labs/valid8or/api/v1alpha1"
41+ v8or "github.com/spectrocloud-labs/valid8or/api/v1alpha1"
42+ "github.com/spectrocloud-labs/valid8or/pkg/types"
43+ v8ores "github.com/spectrocloud-labs/valid8or/pkg/validationresult"
4644)
4745
4846// AwsValidatorReconciler reconciles a AwsValidator object
@@ -52,16 +50,6 @@ type AwsValidatorReconciler struct {
5250 Scheme * runtime.Scheme
5351}
5452
55- // monotonicBool starts off false and remains true permanently if updated to true
56- type monotonicBool struct {
57- ok bool
58- }
59-
60- // Update updates the status of a monotonic bool. If the monotonic bool is already true, Update() is a noop.
61- func (m * monotonicBool ) Update (ok bool ) {
62- m .ok = ok || m .ok
63- }
64-
6553//+kubebuilder:rbac:groups=validation.spectrocloud.labs,resources=awsvalidators,verbs=get;list;watch;create;update;patch;delete
6654//+kubebuilder:rbac:groups=validation.spectrocloud.labs,resources=awsvalidators/status,verbs=get;update;patch
6755//+kubebuilder:rbac:groups=validation.spectrocloud.labs,resources=awsvalidators/finalizers,verbs=update
@@ -105,56 +93,56 @@ func (r *AwsValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Request
10593 tagRuleService := tag .NewTagRuleService (r .Log , session )
10694
10795 // Get the active validator's validation result
108- vr := & valid8orv1alpha1 .ValidationResult {}
109- nn := k8stypes .NamespacedName {
96+ vr := & v8or .ValidationResult {}
97+ nn := ktypes .NamespacedName {
11098 Name : fmt .Sprintf ("valid8or-plugin-aws-%s" , validator .Name ),
11199 Namespace : req .Namespace ,
112100 }
113101 if err := r .Get (ctx , nn , vr ); err == nil {
114- res , err := r . handleExistingValidationResult (nn , vr )
102+ res , err := v8ores . HandleExistingValidationResult (nn , vr , r . Log )
115103 if res != nil {
116104 return * res , err
117105 }
118106 } else {
119107 if ! apierrs .IsNotFound (err ) {
120108 r .Log .V (0 ).Error (err , "unexpected error getting ValidationResult" , "name" , nn .Name , "namespace" , nn .Namespace )
121109 }
122- res , err := r . handleNewValidationResult ( nn , vr )
110+ res , err := v8ores . HandleNewValidationResult ( r . Client , constants . PluginCode , nn , vr , r . Log )
123111 if res != nil {
124112 return * res , err
125113 }
126114 }
127115
128- failed := & monotonicBool {}
116+ failed := & types. MonotonicBool {}
129117
130118 // IAM rules
131119 for _ , rule := range validator .Spec .IamRoleRules {
132120 validationResult , err := iamRuleService .ReconcileIAMRoleRule (nn , rule )
133121 if err != nil {
134122 r .Log .V (0 ).Error (err , "failed to reconcile IAM role rule" )
135123 }
136- r . safeUpdateValidationResult ( nn , validationResult , failed , err )
124+ v8ores . SafeUpdateValidationResult ( r . Client , nn , validationResult , failed , err , r . Log )
137125 }
138126 for _ , rule := range validator .Spec .IamUserRules {
139127 validationResult , err := iamRuleService .ReconcileIAMUserRule (nn , rule )
140128 if err != nil {
141129 r .Log .V (0 ).Error (err , "failed to reconcile IAM user rule" )
142130 }
143- r . safeUpdateValidationResult ( nn , validationResult , failed , err )
131+ v8ores . SafeUpdateValidationResult ( r . Client , nn , validationResult , failed , err , r . Log )
144132 }
145133 for _ , rule := range validator .Spec .IamGroupRules {
146134 validationResult , err := iamRuleService .ReconcileIAMGroupRule (nn , rule )
147135 if err != nil {
148136 r .Log .V (0 ).Error (err , "failed to reconcile IAM group rule" )
149137 }
150- r . safeUpdateValidationResult ( nn , validationResult , failed , err )
138+ v8ores . SafeUpdateValidationResult ( r . Client , nn , validationResult , failed , err , r . Log )
151139 }
152140 for _ , rule := range validator .Spec .IamPolicyRules {
153141 validationResult , err := iamRuleService .ReconcileIAMPolicyRule (nn , rule )
154142 if err != nil {
155143 r .Log .V (0 ).Error (err , "failed to reconcile IAM policy rule" )
156144 }
157- r . safeUpdateValidationResult ( nn , validationResult , failed , err )
145+ v8ores . SafeUpdateValidationResult ( r . Client , nn , validationResult , failed , err , r . Log )
158146 }
159147
160148 // Service Quota rules
@@ -163,7 +151,7 @@ func (r *AwsValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Request
163151 if err != nil {
164152 r .Log .V (0 ).Error (err , "failed to reconcile Service Quota rule" )
165153 }
166- r . safeUpdateValidationResult ( nn , validationResult , failed , err )
154+ v8ores . SafeUpdateValidationResult ( r . Client , nn , validationResult , failed , err , r . Log )
167155 }
168156
169157 // Tag rules
@@ -172,7 +160,7 @@ func (r *AwsValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Request
172160 if err != nil {
173161 r .Log .V (0 ).Error (err , "failed to reconcile Tag rule" )
174162 }
175- r . safeUpdateValidationResult ( nn , validationResult , failed , err )
163+ v8ores . SafeUpdateValidationResult ( r . Client , nn , validationResult , failed , err , r . Log )
176164 }
177165
178166 r .Log .V (0 ).Info ("Requeuing for re-validation in two minutes." , "name" , req .Name , "namespace" , req .Namespace )
@@ -189,7 +177,7 @@ func (r *AwsValidatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
189177// secretKeyAuth creates AWS credentials from a secret containing an access key id and secret access key
190178func (r * AwsValidatorReconciler ) secretKeyAuth (req ctrl.Request , validator * v1alpha1.AwsValidator ) (* credentials.Credentials , * reconcile.Result ) {
191179 authSecret := & corev1.Secret {}
192- nn := k8stypes .NamespacedName {Name : validator .Spec .Auth .SecretName , Namespace : req .Namespace }
180+ nn := ktypes .NamespacedName {Name : validator .Spec .Auth .SecretName , Namespace : req .Namespace }
193181
194182 if err := r .Get (context .Background (), nn , authSecret ); err != nil {
195183 if apierrs .IsNotFound (err ) {
@@ -217,128 +205,3 @@ func (r *AwsValidatorReconciler) secretKeyAuth(req ctrl.Request, validator *v1al
217205
218206 return credentials .NewStaticCredentials (string (id ), string (secretKey ), "" ), nil
219207}
220-
221- // handleExistingValidationResult processes a preexisting validation result for the active validator
222- func (r * AwsValidatorReconciler ) handleExistingValidationResult (nn k8stypes.NamespacedName , vr * valid8orv1alpha1.ValidationResult ) (* ctrl.Result , error ) {
223- switch vr .Status .State {
224-
225- case valid8orv1alpha1 .ValidationInProgress :
226- // validations are only left in progress if an unexpected error occurred
227- r .Log .V (0 ).Info ("Previous validation failed with unexpected error" , "name" , nn .Name , "namespace" , nn .Namespace )
228-
229- case valid8orv1alpha1 .ValidationFailed :
230- // log validation failure, but continue and retry
231- cs := getInvalidConditions (vr .Status .Conditions )
232- if len (cs ) > 0 {
233- for _ , c := range cs {
234- r .Log .V (0 ).Info (
235- "Validation failed. Retrying." , "name" , nn .Name , "namespace" , nn .Namespace ,
236- "validation" , c .ValidationRule , "error" , c .Message , "details" , c .Details , "failures" , c .Failures ,
237- )
238- }
239- }
240-
241- case valid8orv1alpha1 .ValidationSucceeded :
242- // log validation success, continue to re-validate
243- r .Log .V (0 ).Info ("Previous validation succeeded. Re-validating." , "name" , nn .Name , "namespace" , nn .Namespace )
244- }
245-
246- return nil , nil
247- }
248-
249- // handleNewValidationResult creates a new validation result for the active validator
250- func (r * AwsValidatorReconciler ) handleNewValidationResult (nn k8stypes.NamespacedName , vr * valid8orv1alpha1.ValidationResult ) (* ctrl.Result , error ) {
251-
252- // Create the ValidationResult
253- vr .ObjectMeta = metav1.ObjectMeta {
254- Name : nn .Name ,
255- Namespace : nn .Namespace ,
256- }
257- vr .Spec = valid8orv1alpha1.ValidationResultSpec {
258- Plugin : "AWS" ,
259- }
260- if err := r .Client .Create (context .Background (), vr , & client.CreateOptions {}); err != nil {
261- r .Log .V (0 ).Error (err , "failed to create ValidationResult" , "name" , nn .Name , "namespace" , nn .Namespace )
262- return & ctrl.Result {}, err
263- }
264-
265- // Update the ValidationResult's status
266- vr .Status = valid8orv1alpha1.ValidationResultStatus {
267- State : valid8orv1alpha1 .ValidationInProgress ,
268- }
269- if err := r .Status ().Update (context .Background (), vr ); err != nil {
270- r .Log .V (0 ).Error (err , "failed to update ValidationResult status" , "name" , nn .Name , "namespace" , nn .Namespace )
271- return & ctrl.Result {}, err
272- }
273-
274- return nil , nil
275- }
276-
277- // safeUpdateValidationResult updates the overall validation result, ensuring that the overall validation status remains failed if a single rule fails
278- func (r * AwsValidatorReconciler ) safeUpdateValidationResult (nn k8stypes.NamespacedName , validationResult * types.ValidationResult , failed * monotonicBool , err error ) {
279- if err != nil {
280- validationResult .State = ptr .Ptr (valid8orv1alpha1 .ValidationFailed )
281- validationResult .Condition .Status = corev1 .ConditionFalse
282- validationResult .Condition .Message = "Validation failed with an unexpected error"
283- validationResult .Condition .Failures = append (validationResult .Condition .Failures , err .Error ())
284- }
285-
286- didFail := * validationResult .State == valid8orv1alpha1 .ValidationFailed
287- failed .Update (didFail )
288- if failed .ok && ! didFail {
289- validationResult .State = ptr .Ptr (valid8orv1alpha1 .ValidationFailed )
290- }
291-
292- if err := r .updateValidationResult (nn , * validationResult ); err != nil {
293- r .Log .V (0 ).Error (err , "failed to update ValidationResult" )
294- }
295- }
296-
297- // updateValidationResult updates the ValidationResult for the active validation rule
298- func (r * AwsValidatorReconciler ) updateValidationResult (nn k8stypes.NamespacedName , res types.ValidationResult ) error {
299- vr := & valid8orv1alpha1.ValidationResult {}
300- if err := r .Get (context .Background (), nn , vr ); err != nil {
301- return fmt .Errorf ("failed to get ValidationResult %s in namespace %s: %v" , nn .Name , nn .Namespace , err )
302- }
303- vr .Status .State = * res .State
304-
305- idx := getConditionIndexByValidationRule (vr .Status .Conditions , res .Condition .ValidationRule )
306- if idx == - 1 {
307- vr .Status .Conditions = append (vr .Status .Conditions , * res .Condition )
308- } else {
309- vr .Status .Conditions [idx ] = * res .Condition
310- }
311-
312- if err := r .Status ().Update (context .Background (), vr ); err != nil {
313- r .Log .V (0 ).Error (err , "failed to update ValidationResult" )
314- return err
315- }
316- r .Log .V (0 ).Info (
317- "Updated ValidationResult" , "state" , res .State , "reason" , res .Condition .ValidationRule ,
318- "message" , res .Condition .Message , "details" , res .Condition .Details ,
319- "failures" , res .Condition .Failures , "time" , res .Condition .LastValidationTime ,
320- )
321-
322- return nil
323- }
324-
325- // getInvalidConditions filters a ValidationCondition array and returns all conditions corresponding to a failed validation
326- func getInvalidConditions (conditions []valid8orv1alpha1.ValidationCondition ) []valid8orv1alpha1.ValidationCondition {
327- invalidConditions := make ([]valid8orv1alpha1.ValidationCondition , 0 )
328- for _ , c := range conditions {
329- if strings .HasPrefix (c .ValidationRule , constants .ValidationRulePrefix ) && c .Status == corev1 .ConditionFalse {
330- invalidConditions = append (invalidConditions , c )
331- }
332- }
333- return invalidConditions
334- }
335-
336- // getConditionIndexByValidationRule retrieves the index of a condition from a ValidationCondition array matching a specific reason
337- func getConditionIndexByValidationRule (conditions []valid8orv1alpha1.ValidationCondition , validationRule string ) int {
338- for i , c := range conditions {
339- if c .ValidationRule == validationRule {
340- return i
341- }
342- }
343- return - 1
344- }
0 commit comments