Skip to content

Commit

Permalink
feat: implement resource rules validation (#105)
Browse files Browse the repository at this point in the history
also style changes:
- update return order to match convention
- remove named imports

## Issue
Resolves #86 

## Description
Adds functionality for validating resource availability.

also style changes:
- update return order to match convention
- remove named imports

---------

Signed-off-by: Artur Shad Nik <[email protected]>
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tyler Gillson <[email protected]>
  • Loading branch information
arturshadnik and TylerGillson authored Jul 26, 2024
1 parent ae3eb42 commit 1b428e1
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 56 deletions.
12 changes: 6 additions & 6 deletions api/v1alpha1/maasvalidator_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,26 @@ type UpstreamDNSRule struct {
type ResourceAvailabilityRule struct {
// Unique name for the rule
Name string `json:"name" yaml:"name"`
// The availability zone to validate
AZ string `json:"az" yaml:"az"`
// The list of resources to validate
Resources []Resource `json:"resources" yaml:"resources"`
}

// Resource defines a compute resource
type Resource struct {
// Availability Zone
AZ string `json:"az" yaml:"az"`
// Minimum desired number of machines
NumMachines int `json:"numMachines" yaml:"numMachines"`
// Minimum CPU cores per machine
NumCPU int `json:"numCPU" yaml:"numCPU"`
// Minimum RAM per machine in GB
NumRAM int `json:"numRAM" yaml:"numRAM"`
RAM int `json:"ram" yaml:"ram"`
// Minimum Disk space per machine in GB
NumDisk int `json:"numDisk" yaml:"numDisk"`
Disk int `json:"disk" yaml:"disk"`
// Optional machine pool
Pool string `json:"pool,omitempty" yaml:"pool,omitempty"`
// Optional machine labels
Labels []string `json:"labels,omitempty" yaml:"labels,omitempty"`
// Optional machine tags
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
}

// MaasValidatorStatus defines the observed state of MaasValidator
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ spec:
description: ResourceAvailabilityRule provides rules for validating
resource availability
properties:
az:
description: The availability zone to validate
type: string
name:
description: Unique name for the rule
type: string
Expand All @@ -132,38 +135,35 @@ spec:
items:
description: Resource defines a compute resource
properties:
az:
description: Availability Zone
type: string
labels:
description: Optional machine labels
items:
type: string
type: array
disk:
description: Minimum Disk space per machine in GB
type: integer
numCPU:
description: Minimum CPU cores per machine
type: integer
numDisk:
description: Minimum Disk space per machine in GB
type: integer
numMachines:
description: Minimum desired number of machines
type: integer
numRAM:
description: Minimum RAM per machine in GB
type: integer
pool:
description: Optional machine pool
type: string
ram:
description: Minimum RAM per machine in GB
type: integer
tags:
description: Optional machine tags
items:
type: string
type: array
required:
- az
- disk
- numCPU
- numDisk
- numMachines
- numRAM
- ram
type: object
type: array
required:
- az
- name
- resources
type: object
Expand Down
34 changes: 17 additions & 17 deletions config/crd/bases/validation.spectrocloud.labs_maasvalidators.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ spec:
description: ResourceAvailabilityRule provides rules for validating
resource availability
properties:
az:
description: The availability zone to validate
type: string
name:
description: Unique name for the rule
type: string
Expand All @@ -132,38 +135,35 @@ spec:
items:
description: Resource defines a compute resource
properties:
az:
description: Availability Zone
type: string
labels:
description: Optional machine labels
items:
type: string
type: array
disk:
description: Minimum Disk space per machine in GB
type: integer
numCPU:
description: Minimum CPU cores per machine
type: integer
numDisk:
description: Minimum Disk space per machine in GB
type: integer
numMachines:
description: Minimum desired number of machines
type: integer
numRAM:
description: Minimum RAM per machine in GB
type: integer
pool:
description: Optional machine pool
type: string
ram:
description: Minimum RAM per machine in GB
type: integer
tags:
description: Optional machine tags
items:
type: string
type: array
required:
- az
- disk
- numCPU
- numDisk
- numMachines
- numRAM
- ram
type: object
type: array
required:
- az
- name
- resources
type: object
Expand Down
33 changes: 33 additions & 0 deletions config/samples/maasvalidator-resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: validation.spectrocloud.labs/v1alpha1
kind: MaasValidator
metadata:
name: maasvalidator-sample-resources
spec:
host: "http://maas.sc:5240/MAAS"
auth:
# You have to specify credentials secret
secretName: maas-credentials
token: "foo" # reads token from cluster secret
resourceAvailabilityRules:
- name: "AZ1 Rule 1" # expect pass
az: "az1"
resources:
- numMachines: 1
numCPU: 16
ram: 16
disk: 100
- name: "AZ3 Rule 1" # expect fail
az: "az3"
resources:
- numMachines: 1
numCPU: 24
ram: 32
disk: 100
- numMachines: 3
numCPU: 16
ram: 16
disk: 100
- numMachines: 1
numCPU: 64
ram: 64
disk: 1000
15 changes: 14 additions & 1 deletion internal/controller/maasvalidator_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/validator-labs/validator-plugin-maas/internal/constants"
dnsval "github.com/validator-labs/validator-plugin-maas/internal/validators/dns"
osval "github.com/validator-labs/validator-plugin-maas/internal/validators/os"
resval "github.com/validator-labs/validator-plugin-maas/internal/validators/res"
vapi "github.com/validator-labs/validator/api/v1alpha1"
"github.com/validator-labs/validator/pkg/types"
"github.com/validator-labs/validator/pkg/util"
Expand Down Expand Up @@ -120,6 +121,7 @@ func (r *MaasValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Reques

imageRulesService := osval.NewImageRulesService(r.Log, maasClient.BootResources)
upstreamDNSRulesService := dnsval.NewUpstreamDNSRulesService(r.Log, maasClient.MAASServer)
resourceRulesService := resval.NewResourceRulesService(r.Log, maasClient.Machines)

// MAAS Instance image rules
for _, rule := range validator.Spec.ImageRules {
Expand All @@ -132,13 +134,24 @@ func (r *MaasValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Reques

// MAAS Instance upstream DNS rules
for _, rule := range validator.Spec.UpstreamDNSRules {
vrr, err := upstreamDNSRulesService.ReconcileMaasInstanceUpstreamDNSRules(rule)
vrr, err := upstreamDNSRulesService.ReconcileMaasInstanceUpstreamDNSRule(rule)
if err != nil {
r.Log.V(0).Error(err, "failed to reconcile MAAS upstream DNS rule")
}
resp.AddResult(vrr, err)
}

seenAZ := make(map[string]bool, 0)
// MAAS Instance resource availability rules
for _, rule := range validator.Spec.ResourceAvailabilityRules {
vrr, err := resourceRulesService.ReconcileMaasInstanceResourceRule(rule, seenAZ)
if err != nil {
r.Log.V(0).Error(err, "failed to reconcile MAAS resource rule")
}
resp.AddResult(vrr, err)
seenAZ[rule.AZ] = true
}

// Patch the ValidationResult with the latest ValidationRuleResults
if err := vres.SafeUpdateValidationResult(ctx, p, vr, resp, r.Log); err != nil {
return ctrl.Result{}, err
Expand Down
25 changes: 21 additions & 4 deletions internal/controller/maasvalidator_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ type MockUDNSRulesService struct {
api.MAASServer
}

type MockMachinesService struct {
api.Machines
}

func (b *MockBootResourcesService) Get(params *entity.BootResourcesReadParams) ([]entity.BootResource, error) {
return []entity.BootResource{
{
Expand All @@ -41,6 +45,20 @@ func (u *MockUDNSRulesService) Get(string) ([]byte, error) {
return []byte("8.8.8.8"), nil
}

func (m *MockMachinesService) Get(params *entity.MachinesParams) ([]entity.Machine, error) {
return []entity.Machine{
{
Hostname: "maas.sc",
CPUCount: 24,
Memory: 128 * 1024,
Storage: 1024 * 1000,
Zone: entity.Zone{Name: "az1"},
Pool: entity.ResourcePool{Name: "pool1"},
TagNames: []string{"foo", "bar"},
},
}, nil
}

var _ = Describe("MaaSValidator controller", Ordered, func() {

BeforeEach(func() {
Expand All @@ -53,6 +71,7 @@ var _ = Describe("MaaSValidator controller", Ordered, func() {
c := &maasclient.Client{}
c.BootResources = &MockBootResourcesService{}
c.MAASServer = &MockUDNSRulesService{}
c.Machines = &MockMachinesService{}
return c, nil
}
})
Expand Down Expand Up @@ -81,15 +100,13 @@ var _ = Describe("MaaSValidator controller", Ordered, func() {
{Name: "Upstream DNS", NumDNSServers: 1},
},
ResourceAvailabilityRules: []v1alpha1.ResourceAvailabilityRule{
{Name: "az1 2 machines", Resources: []v1alpha1.Resource{
{AZ: "az1", NumMachines: 2, NumCPU: 2, NumDisk: 20, NumRAM: 4},
{Name: "az1 2 machines", AZ: "az1", Resources: []v1alpha1.Resource{
{NumMachines: 2, NumCPU: 2, Disk: 20, RAM: 4},
}},
},
},
}

//secret := &corev1.Secret{}

vr := &vapi.ValidationResult{}
vrKey := types.NamespacedName{Name: validationResultName(val), Namespace: validatorNamespace}

Expand Down
4 changes: 2 additions & 2 deletions internal/validators/dns/upstream_dns_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func NewUpstreamDNSRulesService(log logr.Logger, api api.MAASServer) *UpstreamDN
}
}

// ReconcileMaasInstanceUpstreamDNSRules reconciles a MAAS instance upstream DNS rule
func (s *UpstreamDNSRulesService) ReconcileMaasInstanceUpstreamDNSRules(rule v1alpha1.UpstreamDNSRule) (*types.ValidationRuleResult, error) {
// ReconcileMaasInstanceUpstreamDNSRule reconciles a MAAS instance upstream DNS rule
func (s *UpstreamDNSRulesService) ReconcileMaasInstanceUpstreamDNSRule(rule v1alpha1.UpstreamDNSRule) (*types.ValidationRuleResult, error) {

vr := utils.BuildValidationResult(rule.Name, constants.ValidationTypeUDNS)

Expand Down
2 changes: 1 addition & 1 deletion internal/validators/dns/upstream_dns_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestReconcileMaasInstanceImageRule(t *testing.T) {
var errors []string

for _, rule := range tc.upstreamDNSRules {
vr, _ := tc.ruleService.ReconcileMaasInstanceUpstreamDNSRules(rule)
vr, _ := tc.ruleService.ReconcileMaasInstanceUpstreamDNSRule(rule)
details = append(details, vr.Condition.Details...)
errors = append(errors, vr.Condition.Failures...)
}
Expand Down
12 changes: 6 additions & 6 deletions internal/validators/os/os_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (s *ImageRulesService) ReconcileMaasInstanceImageRule(rule v1alpha1.ImageRu

vr := utils.BuildValidationResult(rule.Name, constants.ValidationTypeImage)

errs, details := s.findBootResources(rule)
details, errs := s.findBootResources(rule)

utils.UpdateResult(vr, errs, constants.ErrImageNotFound, details...)

Expand All @@ -57,13 +57,13 @@ func convertBootResourceToOSImage(images []entity.BootResource) []v1alpha1.Image
}

// findBootResources checks if a list of Images is a subset of a list of BootResources
func (s *ImageRulesService) findBootResources(rule v1alpha1.ImageRule) (errs []error, details []string) {
errs = make([]error, 0)
details = make([]string, 0)
func (s *ImageRulesService) findBootResources(rule v1alpha1.ImageRule) ([]string, []error) {
details := make([]string, 0)
errs := make([]error, 0)

images, err := s.api.Get(&entity.BootResourcesReadParams{})
if err != nil {
return errs, details
return details, errs
}
converted := convertBootResourceToOSImage(images)
convertedSet := mapset.NewSet(converted...)
Expand All @@ -79,5 +79,5 @@ func (s *ImageRulesService) findBootResources(rule v1alpha1.ImageRule) (errs []e
for img := range intersectionSet.Iterator().C {
details = append(details, fmt.Sprintf("OS image %s with arch %s was found", img.Name, img.Architecture))
}
return errs, details
return details, errs
}
Loading

0 comments on commit 1b428e1

Please sign in to comment.