Skip to content

Commit

Permalink
OCM-2858 | feat: Move clusternode validations to shared library
Browse files Browse the repository at this point in the history
  • Loading branch information
nirarg committed Jul 20, 2023
1 parent c5b470b commit a8d0967
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 0 deletions.
89 changes: 89 additions & 0 deletions pkg/validations/cluster_node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package validations

import (
"fmt"
)

const (
SingleAZCount = 1
MultiAZCount = 3
)

// MinReplicasValidator is responsible for verifying whether the minReplicas value adheres to specific rules:
//
// * The minReplicas value must be a positive number.
// * If multiple availability zones are used, the Cluster must have a minimum of 3 compute nodes and the total count of nodes must be a multiple of 3.
// * If a single availability zone is used, the Cluster must include at least 2 compute nodes.
// * For Hosted clusters, the number of compute nodes must be a multiple of the number of private subnets.
func MinReplicasValidator(minReplicas int, multiAZ bool, isHostedCP bool, privateSubnetsCount int) error {
if minReplicas < 0 {
return fmt.Errorf("The value for the number of cluster nodes must be non-negative")
}
if isHostedCP {
// This value should be validated in a previous step when checking the subnets
if privateSubnetsCount < 1 {
return fmt.Errorf("Hosted clusters require at least a private subnet")
}

if minReplicas%privateSubnetsCount != 0 {
return fmt.Errorf("Hosted clusters require that the number of compute nodes be a multiple of "+
"the number of private subnets %d, instead received: %d", privateSubnetsCount, minReplicas)
}
return nil
}

if multiAZ {
if minReplicas < 3 {
return fmt.Errorf("Multi AZ cluster requires at least 3 compute nodes")
}
if minReplicas%3 != 0 {
return fmt.Errorf("Multi AZ clusters require that the number of compute nodes be a multiple of 3")
}
} else if minReplicas < 2 {
return fmt.Errorf("Cluster requires at least 2 compute nodes")
}
return nil
}

// MaxReplicasValidator is responsible for verifying whether the maxReplicas value adheres to specific rules:
//
// * The maxReplicas value must be at least equal to minReplicas.
// * If multiple availability zones are used, the number of compute nodes must be a multiple of 3.
// * For Hosted clusters, the number of compute nodes must be a multiple of the number of private subnets.
//
// The assumtion here is that minReplicas was already validated
func MaxReplicasValidator(minReplicas int, maxReplicas int, multiAZ bool, isHostedCP bool, privateSubnetsCount int) error {
if minReplicas > maxReplicas {
return fmt.Errorf("max-replicas must be greater or equal to min-replicas")
}

if isHostedCP {
if maxReplicas%privateSubnetsCount != 0 {
return fmt.Errorf("Hosted clusters require that the number of compute nodes be a multiple of "+
"the number of private subnets %d, instead received: %d", privateSubnetsCount, maxReplicas)
}
return nil
}

if multiAZ && maxReplicas%3 != 0 {
return fmt.Errorf("Multi AZ clusters require that the number of compute nodes be a multiple of 3")
}
return nil
}

// ValidateAvailabilityZonesCount is responsible for verifying whether the number of availability zones adheres to specific rules:
//
// * The number of availability zones for a multi AZ cluster should be 3.
// * The number of availability zones for a single AZ cluster should be 1.
func ValidateAvailabilityZonesCount(multiAZ bool, availabilityZonesCount int) error {
if multiAZ && availabilityZonesCount != MultiAZCount {
return fmt.Errorf("The number of availability zones for a multi AZ cluster should be %d, "+
"instead received: %d", MultiAZCount, availabilityZonesCount)
}
if !multiAZ && availabilityZonesCount != SingleAZCount {
return fmt.Errorf("The number of availability zones for a single AZ cluster should be %d, "+
"instead received: %d", SingleAZCount, availabilityZonesCount)
}

return nil
}
116 changes: 116 additions & 0 deletions pkg/validations/cluster_node_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package validations

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Cluster Node Validations", func() {
Context("MinReplicasValidator", func() {
It("minReplicas negative (failure)", func() {
err := MinReplicasValidator(-1, false, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("The value for the number of cluster nodes must be non-negative"))
})
It("hostedCP privateSubnetsCount zero (failure)", func() {
err := MinReplicasValidator(1, false, true, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Hosted clusters require at least a private subnet"))
})
It("hostedCP compute nodes not multiple of private subnets (failure)", func() {
err := MinReplicasValidator(3, false, true, 2)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Hosted clusters require that the number of compute nodes be a multiple of " +
"the number of private subnets 2, instead received: 3"))
})
It("MultipleAZ minReplicas smaller than 3 (failure)", func() {
err := MinReplicasValidator(2, true, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Multi AZ cluster requires at least 3 compute nodes"))
})
It("MultipleAZ minReplicas not multiple of 3 (failure)", func() {
err := MinReplicasValidator(4, true, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Multi AZ clusters require that the number of compute nodes be a multiple of 3"))
})
It("minReplicas zero (failure)", func() {
err := MinReplicasValidator(0, false, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Cluster requires at least 2 compute nodes"))
})
It("not MultipleAZ minReplicas smaller than 2 (failure)", func() {
err := MinReplicasValidator(1, false, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Cluster requires at least 2 compute nodes"))
})
It("MultipleAZ minReplicas multiple of 3 (success)", func() {
err := MinReplicasValidator(3, true, false, 0)
Expect(err).NotTo(HaveOccurred())
})
It("not MultipleAZ minReplicas 2 (success)", func() {
err := MinReplicasValidator(2, false, false, 0)
Expect(err).NotTo(HaveOccurred())
})
It("hostedCP compute nodes multiple of private subnets (success)", func() {
err := MinReplicasValidator(4, false, true, 2)
Expect(err).NotTo(HaveOccurred())
})
It("Not hostedCP compute nodes count is 3 (success)", func() {
err := MinReplicasValidator(3, true, false, 0)
Expect(err).NotTo(HaveOccurred())
})

})
Context("MaxReplicasValidator", func() {
It("maxReplicas smaller than minReplicas (failure)", func() {
err := MaxReplicasValidator(4, 3, false, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("max-replicas must be greater or equal to min-replicas"))
})
It("hostedCP compute nodes not multiple of private subnets (failure)", func() {
err := MaxReplicasValidator(2, 3, false, true, 2)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Hosted clusters require that the number of compute nodes be a multiple of " +
"the number of private subnets 2, instead received: 3"))
})
It("hostedCP compute nodes multiple of private subnets (success)", func() {
err := MaxReplicasValidator(2, 4, false, true, 2)
Expect(err).NotTo(HaveOccurred())
})
It("MultipleAZ maxReplicas not multiple of 3 (failure)", func() {
err := MaxReplicasValidator(3, 4, true, false, 0)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Multi AZ clusters require that the number of compute nodes be a multiple of 3"))
})
It("MultipleAZ maxReplicas multiple of 3 (success)", func() {
err := MaxReplicasValidator(3, 6, true, false, 0)
Expect(err).NotTo(HaveOccurred())
})
It("Not MultipleAZ and not hostedCP maxReplicas bigger than minReplicas (success)", func() {
err := MaxReplicasValidator(2, 5, false, false, 0)
Expect(err).NotTo(HaveOccurred())
})
})
Context("ValidateAvailabilityZonesCount", func() {
It("Not MultipleAZ (success)", func() {
err := ValidateAvailabilityZonesCount(false, 1)
Expect(err).NotTo(HaveOccurred())
})
It("Not MultipleAZ (failure)", func() {
err := ValidateAvailabilityZonesCount(false, 2)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("The number of availability zones for " +
"a single AZ cluster should be 1, instead received: 2"))
})
It("MultipleAZ (success)", func() {
err := ValidateAvailabilityZonesCount(true, 3)
Expect(err).NotTo(HaveOccurred())
})
It("MultipleAZ (failure)", func() {
err := ValidateAvailabilityZonesCount(true, 2)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("The number of availability zones for " +
"a multi AZ cluster should be 3, instead received: 2"))
})
})
})
31 changes: 31 additions & 0 deletions pkg/validations/validations_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package validations

import (
"fmt"
"os"
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestValidations(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Validations Suite")
}

func TestMain(m *testing.M) {
// call flag.Parse() here if TestMain uses flags
rc := m.Run()

// rc 0 means we've passed,
// and CoverMode will be non empty if run with -cover
if rc == 0 && testing.CoverMode() != "" {
c := testing.Coverage()
if c < 1 {
fmt.Println("Tests passed but coverage failed at", c)
rc = -1
}
}
os.Exit(rc)
}

0 comments on commit a8d0967

Please sign in to comment.