Skip to content

Commit fdf44c3

Browse files
committed
refactor: use valid8or validationresult helpers
1 parent f3132d7 commit fdf44c3

10 files changed

Lines changed: 50 additions & 196 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/go-logr/logr v1.2.4
99
github.com/onsi/ginkgo/v2 v2.9.5
1010
github.com/onsi/gomega v1.27.7
11-
github.com/spectrocloud-labs/valid8or v0.0.0-20230825153231-57f7e708100e
11+
github.com/spectrocloud-labs/valid8or v0.0.4
1212
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
1313
k8s.io/api v0.27.2
1414
k8s.io/apimachinery v0.27.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
143143
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
144144
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
145145
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
146-
github.com/spectrocloud-labs/valid8or v0.0.0-20230825153231-57f7e708100e h1:pnBEWlOAbBrmGnVybAUGbX3wBRv1jsQyLQwG0XgRhec=
147-
github.com/spectrocloud-labs/valid8or v0.0.0-20230825153231-57f7e708100e/go.mod h1:d2uYGVs/uB0FnyTBup6EL94SQ27bLE0gejLkr3akqvQ=
146+
github.com/spectrocloud-labs/valid8or v0.0.4 h1:b+iVsKTxyh0fWLDlL5wXtn4uBFzEA3htXZhXfml+Hg8=
147+
github.com/spectrocloud-labs/valid8or v0.0.4/go.mod h1:ckTAUUaqfm25gg4TnNSiNbDClxnAn74uqyLkxl+Ufpo=
148148
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
149149
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
150150
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=

internal/constants/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package constants
22

33
const (
4-
ValidationRulePrefix string = "validation"
4+
PluginCode string = "AWS"
55

66
ValidationTypeIAMRolePolicy string = "aws-iam-role-policy"
77
ValidationTypeIAMUserPolicy string = "aws-iam-user-policy"

internal/controller/awsvalidator_controller.go

Lines changed: 16 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package controller
1919
import (
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
190178
func (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-
}

internal/types/types.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package types
22

3-
import valid8orv1alpha1 "github.com/spectrocloud-labs/valid8or/api/v1alpha1"
4-
53
// UsageResult describes the maximum usage for an arbitrary category
64
type UsageResult struct {
75
Description string
@@ -23,9 +21,3 @@ func (u UsageMap) Max() *UsageResult {
2321
}
2422
return &UsageResult{Description: maxUsageKey, MaxUsage: maxUsage}
2523
}
26-
27-
// ValidationResult is the result of the execution of a validation rule by a validator
28-
type ValidationResult struct {
29-
Condition *valid8orv1alpha1.ValidationCondition
30-
State *valid8orv1alpha1.ValidationState
31-
}

internal/utils/aws/aws.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/aws/aws-sdk-go/service/iam"
1111
"github.com/aws/aws-sdk-go/service/servicequotas"
1212

13-
"github.com/spectrocloud-labs/valid8or-plugin-aws/internal/utils/ptr"
13+
"github.com/spectrocloud-labs/valid8or/pkg/util/ptr"
1414
)
1515

1616
// IAMService creates an AWS IAM service object for a specific session

internal/utils/ptr/ptr.go

Lines changed: 0 additions & 5 deletions
This file was deleted.

internal/validators/iam/iam_validator.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import (
1515

1616
"github.com/spectrocloud-labs/valid8or-plugin-aws/api/v1alpha1"
1717
"github.com/spectrocloud-labs/valid8or-plugin-aws/internal/constants"
18-
"github.com/spectrocloud-labs/valid8or-plugin-aws/internal/types"
1918
"github.com/spectrocloud-labs/valid8or-plugin-aws/internal/utils/aws"
20-
"github.com/spectrocloud-labs/valid8or-plugin-aws/internal/utils/ptr"
2119
str_utils "github.com/spectrocloud-labs/valid8or-plugin-aws/internal/utils/strings"
22-
valid8orv1alpha1 "github.com/spectrocloud-labs/valid8or/api/v1alpha1"
20+
v8or "github.com/spectrocloud-labs/valid8or/api/v1alpha1"
21+
v8orconstants "github.com/spectrocloud-labs/valid8or/pkg/constants"
22+
"github.com/spectrocloud-labs/valid8or/pkg/types"
23+
"github.com/spectrocloud-labs/valid8or/pkg/util/ptr"
2324
)
2425

2526
type iamAction struct {
@@ -230,10 +231,10 @@ func (s *IAMRuleService) getPolicyDocument(policyArn *string, context []string)
230231

231232
// buildValidationResult builds a default ValidationResult for a given validation type
232233
func buildValidationResult(rule iamRule, validationType string) *types.ValidationResult {
233-
state := valid8orv1alpha1.ValidationSucceeded
234-
latestCondition := valid8orv1alpha1.DefaultValidationCondition()
234+
state := v8or.ValidationSucceeded
235+
latestCondition := v8or.DefaultValidationCondition()
235236
latestCondition.Message = fmt.Sprintf("All required %s permissions were found", validationType)
236-
latestCondition.ValidationRule = fmt.Sprintf("%s-%s", constants.ValidationRulePrefix, rule.Name())
237+
latestCondition.ValidationRule = fmt.Sprintf("%s-%s", v8orconstants.ValidationRulePrefix, rule.Name())
237238
latestCondition.ValidationType = validationType
238239
return &types.ValidationResult{Condition: &latestCondition, State: &state}
239240
}
@@ -362,7 +363,7 @@ func computeFailures(rule iamRule, permissions map[string]*permission, vr *types
362363
failures = append(failures, failureMsg)
363364
}
364365
if len(failures) > 0 {
365-
vr.State = ptr.Ptr(valid8orv1alpha1.ValidationFailed)
366+
vr.State = ptr.Ptr(v8or.ValidationFailed)
366367
vr.Condition.Failures = failures
367368
vr.Condition.Message = "One or more required IAM permissions was not found, or a condition was not met"
368369
vr.Condition.Status = corev1.ConditionFalse

0 commit comments

Comments
 (0)