diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 1f8fe203f..d2180384c 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -227,6 +227,10 @@ func (c *Cluster) Create() error { c.setStatus(acidv1.ClusterStatusCreating) + if err = c.validateResources(&c.Spec); err != nil { + return fmt.Errorf("unsufficient ressources: %v", err) + } + for _, role := range []PostgresRole{Master, Replica} { if c.Endpoints[role] != nil { @@ -491,6 +495,53 @@ func compareResourcesAssumeFirstNotNil(a *v1.ResourceRequirements, b *v1.Resourc } +func (c *Cluster) validateResources(spec *acidv1.PostgresSpec) error { + + const ( + cpuMinimum = "256m" + memoryMinimum = "256Mi" + storageMinimum = "1Gi" + ) + + var ( + isSmaller bool + err error + ) + + cpuLimit := spec.Resources.ResourceLimits.CPU + if cpuLimit != "" { + isSmaller, err = util.IsSmallerQuantity(cpuLimit, cpuMinimum) + if err != nil { + return fmt.Errorf("error validating CPU limit: %v", err) + } + if isSmaller { + return fmt.Errorf("defined CPU limit %s is below required minimum %s to properly run postgresql resource", cpuLimit, cpuMinimum) + } + } + + memoryLimit := spec.Resources.ResourceLimits.Memory + if memoryLimit != "" { + isSmaller, err = util.IsSmallerQuantity(memoryLimit, memoryMinimum) + if err != nil { + return fmt.Errorf("error validating memory limit: %v", err) + } + if isSmaller { + return fmt.Errorf("defined memory limit %s is below required minimum %s to properly run postgresql resource", memoryLimit, memoryMinimum) + } + } + + storageSize := spec.Volume.Size + isSmaller, err = util.IsSmallerQuantity(storageSize, storageMinimum) + if err != nil { + return fmt.Errorf("error validating volume size: %v", err) + } + if isSmaller { + return fmt.Errorf("defined volume size %s is below required minimum %s to properly run postgresql resource", storageSize, storageMinimum) + } + + return nil +} + // Update changes Kubernetes objects according to the new specification. Unlike the sync case, the missing object // (i.e. service) is treated as an error // logical backup cron jobs are an exception: a user-initiated Update can enable a logical backup job diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index d5cc4ce39..765550fa9 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -740,7 +740,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef limit = c.OpConfig.DefaultMemoryLimit } - isSmaller, err := util.RequestIsSmallerThanLimit(request, limit) + isSmaller, err := util.IsSmallerQuantity(request, limit) if err != nil { return nil, err } @@ -767,7 +767,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef limit = c.OpConfig.DefaultMemoryLimit } - isSmaller, err := util.RequestIsSmallerThanLimit(sidecarRequest, sidecarLimit) + isSmaller, err := util.IsSmallerQuantity(sidecarRequest, sidecarLimit) if err != nil { return nil, err } diff --git a/pkg/util/util.go b/pkg/util/util.go index a8ef460db..ad6de14a2 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -141,17 +141,17 @@ func Coalesce(val, defaultVal string) string { return val } -// RequestIsSmallerThanLimit : ... -func RequestIsSmallerThanLimit(requestStr, limitStr string) (bool, error) { +// IsSmallerQuantity : checks if first resource is of a smaller quantity than the second +func IsSmallerQuantity(requestStr, limitStr string) (bool, error) { request, err := resource.ParseQuantity(requestStr) if err != nil { - return false, fmt.Errorf("could not parse memory request %v : %v", requestStr, err) + return false, fmt.Errorf("could not parse request %v : %v", requestStr, err) } limit, err2 := resource.ParseQuantity(limitStr) if err2 != nil { - return false, fmt.Errorf("could not parse memory limit %v : %v", limitStr, err2) + return false, fmt.Errorf("could not parse limit %v : %v", limitStr, err2) } return request.Cmp(limit) == -1, nil diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index a34e57e23..1f65dc54e 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -69,7 +69,7 @@ var substringMatch = []struct { {regexp.MustCompile(`aaaa (\d+) bbbb`), "aaaa 123 bbbb", nil}, } -var requestIsSmallerThanLimitTests = []struct { +var requestIsSmallerQuantityTests = []struct { request string limit string out bool @@ -155,9 +155,9 @@ func TestMapContains(t *testing.T) { } } -func TestRequestIsSmallerThanLimit(t *testing.T) { - for _, tt := range requestIsSmallerThanLimitTests { - res, err := RequestIsSmallerThanLimit(tt.request, tt.limit) +func TestIsSmallerQuantity(t *testing.T) { + for _, tt := range requestIsSmallerQuantityTests { + res, err := IsSmallerQuantity(tt.request, tt.limit) if err != nil { t.Errorf("RequestIsSmallerThanLimit returned unexpected error: %#v", err) }