Skip to content

Commit df5453e

Browse files
authored
refactor: support direct rule evaluation (#450)
## Issue N/S ## Description Refactor to support direct, in-process evaluation of AWS rules. Required by: - validator-labs/validatorctl#102 Related: - validator-labs/validator-plugin-network#239 --------- Signed-off-by: Tyler Gillson <[email protected]>
1 parent 7931d59 commit df5453e

19 files changed

+168
-159
lines changed

api/v1alpha1/awsvalidator_types.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"strings"
2222

2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+
25+
"github.com/validator-labs/validator-plugin-aws/pkg/constants"
2426
)
2527

2628
// AwsValidatorSpec defines the desired state of AwsValidator
@@ -50,6 +52,11 @@ type AwsValidatorSpec struct {
5052
TagRules []TagRule `json:"tagRules,omitempty" yaml:"tagRules,omitempty"`
5153
}
5254

55+
// PluginCode returns the network validator's plugin code.
56+
func (s AwsValidatorSpec) PluginCode() string {
57+
return constants.PluginCode
58+
}
59+
5360
// ResultCount returns the number of validation results expected for an AwsValidatorSpec.
5461
func (s AwsValidatorSpec) ResultCount() int {
5562
return len(s.AmiRules) + len(s.IamGroupRules) + len(s.IamPolicyRules) + len(s.IamRoleRules) +
@@ -237,6 +244,16 @@ type AwsValidator struct {
237244
Status AwsValidatorStatus `json:"status,omitempty"`
238245
}
239246

247+
// PluginCode returns the AWS validator's plugin code.
248+
func (v AwsValidator) PluginCode() string {
249+
return v.Spec.PluginCode()
250+
}
251+
252+
// ResultCount returns the number of validation results expected for an AwsValidator.
253+
func (v AwsValidator) ResultCount() int {
254+
return v.Spec.ResultCount()
255+
}
256+
240257
//+kubebuilder:object:root=true
241258

242259
// AwsValidatorList contains a list of AwsValidator

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ require (
1818
github.com/onsi/ginkgo/v2 v2.19.1
1919
github.com/onsi/gomega v1.34.1
2020
github.com/pkg/errors v0.9.1
21-
github.com/validator-labs/validator v0.1.0
21+
github.com/validator-labs/validator v0.1.1
2222
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
2323
k8s.io/api v0.30.3
2424
k8s.io/apimachinery v0.30.3
@@ -97,3 +97,5 @@ require (
9797
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
9898
sigs.k8s.io/yaml v1.4.0 // indirect
9999
)
100+
101+
// replace github.com/validator-labs/validator => ../validator

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
190190
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
191191
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
192192
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
193-
github.com/validator-labs/validator v0.1.0 h1:GVekIT5sG+kcyUbT04qb/pURmd9eE6NNKnSR9yJ1sQk=
194-
github.com/validator-labs/validator v0.1.0/go.mod h1:OeJMHGKW3pWGkvKxHLN7HzjelSILJg2k8w3Z9SdML1g=
193+
github.com/validator-labs/validator v0.1.1 h1:BzUWeSAP5eGHX2oOulJWZxXr+Zz6Uh6ZqP5sYudnv3I=
194+
github.com/validator-labs/validator v0.1.1/go.mod h1:to8CMM+LlTcEzbqxVyHND9/uJO2+ORTFk9ovqVOnCU8=
195195
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
196196
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
197197
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=

internal/controller/awsvalidator_controller.go

Lines changed: 7 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,22 @@ package controller
1919

2020
import (
2121
"context"
22-
"fmt"
2322
"os"
2423
"time"
2524

2625
"github.com/go-logr/logr"
2726
"github.com/pkg/errors"
2827
corev1 "k8s.io/api/core/v1"
2928
apierrs "k8s.io/apimachinery/pkg/api/errors"
30-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3129
"k8s.io/apimachinery/pkg/runtime"
3230
ktypes "k8s.io/apimachinery/pkg/types"
3331
"sigs.k8s.io/cluster-api/util/patch"
3432
ctrl "sigs.k8s.io/controller-runtime"
3533
"sigs.k8s.io/controller-runtime/pkg/client"
3634

3735
"github.com/validator-labs/validator-plugin-aws/api/v1alpha1"
38-
"github.com/validator-labs/validator-plugin-aws/internal/aws"
39-
"github.com/validator-labs/validator-plugin-aws/internal/constants"
40-
"github.com/validator-labs/validator-plugin-aws/internal/validators"
41-
"github.com/validator-labs/validator-plugin-aws/internal/validators/ami"
42-
"github.com/validator-labs/validator-plugin-aws/internal/validators/iam"
43-
"github.com/validator-labs/validator-plugin-aws/internal/validators/servicequota"
44-
"github.com/validator-labs/validator-plugin-aws/internal/validators/tag"
36+
"github.com/validator-labs/validator-plugin-aws/pkg/validate"
4537
vapi "github.com/validator-labs/validator/api/v1alpha1"
46-
"github.com/validator-labs/validator/pkg/types"
47-
"github.com/validator-labs/validator/pkg/util"
4838
vres "github.com/validator-labs/validator/pkg/validationresult"
4939
)
5040

@@ -95,16 +85,16 @@ func (r *AwsValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Request
9585
return ctrl.Result{}, err
9686
}
9787
nn := ktypes.NamespacedName{
98-
Name: validationResultName(validator),
88+
Name: vres.Name(validator),
9989
Namespace: req.Namespace,
10090
}
10191
if err := r.Get(ctx, nn, vr); err == nil {
102-
vres.HandleExistingValidationResult(vr, r.Log)
92+
vres.HandleExisting(vr, r.Log)
10393
} else {
10494
if !apierrs.IsNotFound(err) {
10595
l.Error(err, "unexpected error getting ValidationResult")
10696
}
107-
if err := vres.HandleNewValidationResult(ctx, r.Client, p, buildValidationResult(validator), r.Log); err != nil {
97+
if err := vres.HandleNew(ctx, r.Client, p, vres.Build(validator), r.Log); err != nil {
10898
return ctrl.Result{}, err
10999
}
110100
return ctrl.Result{RequeueAfter: time.Millisecond}, nil
@@ -113,111 +103,11 @@ func (r *AwsValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Request
113103
// Always update the expected result count in case the validator's rules have changed
114104
vr.Spec.ExpectedResults = validator.Spec.ResultCount()
115105

116-
resp := types.ValidationResponse{
117-
ValidationRuleResults: make([]*types.ValidationRuleResult, 0, vr.Spec.ExpectedResults),
118-
ValidationRuleErrors: make([]error, 0, vr.Spec.ExpectedResults),
119-
}
120-
121-
// AMI rules
122-
for _, rule := range validator.Spec.AmiRules {
123-
awsAPI, err := aws.NewAPI(validator.Spec.Auth, rule.Region)
124-
if err != nil {
125-
errMsg := "Failed to reconcile AMI rule"
126-
r.Log.V(0).Error(err, errMsg)
127-
vrr := validators.BuildValidationResult(rule.Name, errMsg, constants.ValidationTypeAmi)
128-
resp.AddResult(vrr, err)
129-
continue
130-
}
131-
amiRuleService := ami.NewAmiRuleService(r.Log, awsAPI.EC2)
132-
vrr, err := amiRuleService.ReconcileAmiRule(rule)
133-
if err != nil {
134-
r.Log.V(0).Error(err, "failed to reconcile AMI rule")
135-
}
136-
resp.AddResult(vrr, err)
137-
}
138-
139-
// IAM rules
140-
awsAPI, err := aws.NewAPI(validator.Spec.Auth, validator.Spec.DefaultRegion)
141-
if err != nil {
142-
r.Log.V(0).Error(err, "failed to get AWS client")
143-
} else {
144-
iamRuleService := iam.NewIAMRuleService(r.Log, awsAPI.IAM)
145-
146-
for _, rule := range validator.Spec.IamRoleRules {
147-
vrr, err := iamRuleService.ReconcileIAMRoleRule(rule)
148-
if err != nil {
149-
r.Log.V(0).Error(err, "failed to reconcile IAM role rule")
150-
}
151-
resp.AddResult(vrr, err)
152-
}
153-
for _, rule := range validator.Spec.IamUserRules {
154-
vrr, err := iamRuleService.ReconcileIAMUserRule(rule)
155-
if err != nil {
156-
r.Log.V(0).Error(err, "failed to reconcile IAM user rule")
157-
}
158-
resp.AddResult(vrr, err)
159-
}
160-
for _, rule := range validator.Spec.IamGroupRules {
161-
vrr, err := iamRuleService.ReconcileIAMGroupRule(rule)
162-
if err != nil {
163-
r.Log.V(0).Error(err, "failed to reconcile IAM group rule")
164-
}
165-
resp.AddResult(vrr, err)
166-
}
167-
for _, rule := range validator.Spec.IamPolicyRules {
168-
vrr, err := iamRuleService.ReconcileIAMPolicyRule(rule)
169-
if err != nil {
170-
r.Log.V(0).Error(err, "failed to reconcile IAM policy rule")
171-
}
172-
resp.AddResult(vrr, err)
173-
}
174-
}
175-
176-
// Service Quota rules
177-
for _, rule := range validator.Spec.ServiceQuotaRules {
178-
awsAPI, err := aws.NewAPI(validator.Spec.Auth, rule.Region)
179-
if err != nil {
180-
errMsg := "Failed to reconcile Service Quota rule"
181-
r.Log.V(0).Error(err, errMsg)
182-
vrr := validators.BuildValidationResult(rule.Name, errMsg, constants.ValidationTypeServiceQuota)
183-
resp.AddResult(vrr, err)
184-
continue
185-
}
186-
svcQuotaService := servicequota.NewServiceQuotaRuleService(
187-
r.Log,
188-
awsAPI.EC2,
189-
awsAPI.EFS,
190-
awsAPI.ELB,
191-
awsAPI.ELBV2,
192-
awsAPI.SQ,
193-
)
194-
vrr, err := svcQuotaService.ReconcileServiceQuotaRule(rule)
195-
if err != nil {
196-
r.Log.V(0).Error(err, "failed to reconcile Service Quota rule")
197-
}
198-
resp.AddResult(vrr, err)
199-
}
200-
201-
// Tag rules
202-
for _, rule := range validator.Spec.TagRules {
203-
awsAPI, err := aws.NewAPI(validator.Spec.Auth, rule.Region)
204-
if err != nil {
205-
errMsg := "Failed to reconcile Tag rule"
206-
r.Log.V(0).Error(err, errMsg)
207-
vrr := validators.BuildValidationResult(rule.Name, errMsg, constants.ValidationTypeTag)
208-
resp.AddResult(vrr, err)
209-
continue
210-
}
211-
tagRuleService := tag.NewTagRuleService(r.Log, awsAPI.EC2)
212-
vrr, err := tagRuleService.ReconcileTagRule(rule)
213-
if err != nil {
214-
r.Log.V(0).Error(err, "failed to reconcile Tag rule")
215-
}
216-
resp.AddResult(vrr, err)
217-
}
106+
// Validate the rules
107+
resp := validate.Validate(validator.Spec, r.Log)
218108

219109
// Patch the ValidationResult with the latest ValidationRuleResults
220-
if err := vres.SafeUpdateValidationResult(ctx, p, vr, resp, r.Log); err != nil {
110+
if err := vres.SafeUpdate(ctx, p, vr, resp, r.Log); err != nil {
221111
return ctrl.Result{}, err
222112
}
223113

@@ -250,29 +140,3 @@ func (r *AwsValidatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
250140
For(&v1alpha1.AwsValidator{}).
251141
Complete(r)
252142
}
253-
254-
func buildValidationResult(validator *v1alpha1.AwsValidator) *vapi.ValidationResult {
255-
return &vapi.ValidationResult{
256-
ObjectMeta: metav1.ObjectMeta{
257-
Name: validationResultName(validator),
258-
Namespace: validator.Namespace,
259-
OwnerReferences: []metav1.OwnerReference{
260-
{
261-
APIVersion: validator.APIVersion,
262-
Kind: validator.Kind,
263-
Name: validator.Name,
264-
UID: validator.UID,
265-
Controller: util.Ptr(true),
266-
},
267-
},
268-
},
269-
Spec: vapi.ValidationResultSpec{
270-
Plugin: constants.PluginCode,
271-
ExpectedResults: validator.Spec.ResultCount(),
272-
},
273-
}
274-
}
275-
276-
func validationResultName(validator *v1alpha1.AwsValidator) string {
277-
return fmt.Sprintf("validator-plugin-aws-%s", validator.Name)
278-
}

internal/controller/awsvalidator_controller_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/validator-labs/validator-plugin-aws/api/v1alpha1"
1313
vapi "github.com/validator-labs/validator/api/v1alpha1"
14+
vres "github.com/validator-labs/validator/pkg/validationresult"
1415
//+kubebuilder:scaffold:imports
1516
)
1617

@@ -105,11 +106,11 @@ var _ = Describe("AWSValidator controller", Ordered, func() {
105106

106107
vr := &vapi.ValidationResult{
107108
ObjectMeta: metav1.ObjectMeta{
108-
Name: validationResultName(val),
109+
Name: vres.Name(val),
109110
Namespace: validatorNamespace,
110111
},
111112
}
112-
vrKey := types.NamespacedName{Name: validationResultName(val), Namespace: validatorNamespace}
113+
vrKey := types.NamespacedName{Name: vres.Name(val), Namespace: validatorNamespace}
113114

114115
It("Should create a ValidationResult and update its Status with a failed condition", func() {
115116
By("By creating a new AWSValidator")
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)