From 1deb6741434789fd21211713d3ca3c0fe3be1d8d Mon Sep 17 00:00:00 2001 From: druppelt <44848632+druppelt@users.noreply.github.com> Date: Mon, 16 Sep 2024 19:41:53 +0200 Subject: [PATCH] feat: calc resources for limited simultaneous rollouts with --max-rollouts Introduces the --max-rollouts param, which limits how many simultaneous rollouts are assumed. Refs: #16 --- README.md | 36 ++++++--- cmd/kuota-calc.go | 46 +++++------ internal/calc/calc.go | 89 +++++++++++++++++++++- internal/calc/calc_test.go | 101 +++++++++++++++++++++++++ internal/calc/cronjob.go | 6 +- internal/calc/cronjob_test.go | 8 +- internal/calc/daemonset.go | 5 +- internal/calc/daemonset_test.go | 8 +- internal/calc/deployment.go | 9 ++- internal/calc/deploymentConfig.go | 9 ++- internal/calc/deploymentConfig_test.go | 8 +- internal/calc/deployment_test.go | 8 +- internal/calc/job.go | 5 +- internal/calc/job_test.go | 8 +- internal/calc/pod.go | 5 +- internal/calc/pod_test.go | 8 +- internal/calc/statefulset.go | 6 +- internal/calc/statefulset_test.go | 8 +- 18 files changed, 292 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index b5adcbe..d693616 100644 --- a/README.md +++ b/README.md @@ -12,25 +12,37 @@ Simple utility to calculate the maximum needed resource quota for deployment(s). deployment strategy, replicas and all containers into account, see [supported-resources](https://github.com/druppelt/kuota-calc#supported-k8s-resources) for a list of kubernetes resources which are currently supported by kuota-calc. ## Motivation -In shared environments such as kubernetes it is always a good idea to isolate/constrain different workloads to prevent them from infering each other. Kubernetes provides [Resource Quotas](https://kubernetes.io/docs/concepts/policy/resource-quotas/) to limit compute, storage and object resources of namespaces. +In shared environments such as kubernetes it is always a good idea to isolate/constrain different workloads to prevent them from interfering each other. Kubernetes provides [Resource Quotas](https://kubernetes.io/docs/concepts/policy/resource-quotas/) to limit compute, storage and object resources of namespaces. Calculating the needed compute resources can be a bit challenging (especially with large and complex deployments) because we must respect certain settings/defaults like the deployment strategy, number of replicas and so on. This is where kuota-calc can help you, it calculates the maximum needed resource quota in order to be able to start a deployment of all resources at the same time by respecting deployment strategies, replicas and so on. ## Example +Get a detailed report of all resources, their max required quota and a total. ```bash $ cat examples/deployment.yaml | kuota-calc -detailed -Version Kind Name Replicas Strategy MaxReplicas CPURequest CPULimit MemoryRequest MemoryLimit -apps/v1 Deployment myapp 10 RollingUpdate 11 2750m 5500m 704Mi 2816Mi -apps/v1 StatefulSet myapp 3 RollingUpdate 3 750m 3 6Gi 12Gi +Version Kind Name Replicas Strategy MaxReplicas CPURequest CPULimit MemoryRequest MemoryLimit +apps/v1 Deployment myapp 10 RollingUpdate 13 3250m 6500m 832Mi 3328Mi +apps/v1 StatefulSet myapp 3 RollingUpdate 3 750m 3 6Gi 12Gi + +Table and Total assuming simultaneous rollout of all resources Total -CPU Request: 3500m -CPU Limit: 8500m -Memory Request: 6848Mi -Memory Limit: 15104Mi +CPU Request: 4 +CPU Limit: 9500m +Memory Request: 6976Mi +Memory Limit: 15616Mi ``` -To calc usage for deploymentConfigs, deployments and statefulSets deployed in openshift: +For comparison, here the simultaneous rollout is limited to zero resources, so you get the required quotas to just run, but not deploy the applications. +````bash +$ cat examples/deployment.yaml | kuota-calc --max-rollouts=0 +CPU Request: 3250m +CPU Limit: 8 +Memory Request: 6784Mi +Memory Limit: 14848Mi +```` + +To calc usage for deploymentConfigs, deployments and statefulSets deployed in an openshift cluster: ```bash $ oc get dc,sts,deploy -o json | yq -p=json -o=yaml '.items[] | split_doc' | kuota-calc --detailed Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+ @@ -52,7 +64,7 @@ Pre-compiled statically linked binaries are available on the [releases page](htt kuota-calc can either be used as a kubectl plugin or invoked directly. If you intend to use kuota-calc as a kubectl plugin, simply place the binary anywhere in `$PATH` named `kubectl-kuota_calc` with execute permissions. -For further information, see the offical documentation on kubectl plugins [here](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/). +For further information, see the official documentation on kubectl plugins [here](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/). **currently the kubectl plugin is not released for this fork** @@ -68,3 +80,7 @@ Currently supported: - batch/v1 CronJob - batch/v1 Job - v1 Pod + +## known limitation +- CronJobs: the cron concurrencyPolicy is not considered, a CronJob is treated as a single Pod (#18) +- DaemonSet: neither node count nor UpdateStrategy are considered. Treated as a single Pod. (#21) \ No newline at end of file diff --git a/cmd/kuota-calc.go b/cmd/kuota-calc.go index 35b1959..1d02bd5 100644 --- a/cmd/kuota-calc.go +++ b/cmd/kuota-calc.go @@ -11,7 +11,6 @@ import ( "github.com/druppelt/kuota-calc/internal/calc" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/cli-runtime/pkg/genericclioptions" ) @@ -29,9 +28,10 @@ type KuotaCalcOpts struct { genericclioptions.IOStreams // flags - debug bool - detailed bool - version bool + debug bool + detailed bool + version bool + maxRollouts int // files []string versionInfo *Version @@ -61,6 +61,7 @@ func NewKuotaCalcCmd(version *Version, streams genericclioptions.IOStreams) *cob cmd.Flags().BoolVar(&opts.debug, "debug", false, "enable debug logging") cmd.Flags().BoolVar(&opts.detailed, "detailed", false, "enable detailed output") cmd.Flags().BoolVar(&opts.version, "version", false, "print version and exit") + cmd.Flags().IntVar(&opts.maxRollouts, "max-rollouts", -1, "limit the simultaneous rollout to the n most expensive rollouts per resource") return cmd } @@ -131,10 +132,10 @@ func (opts *KuotaCalcOpts) printDetailed(usage []*calc.ResourceUsage) { u.Details.Replicas, u.Details.Strategy, u.Details.MaxReplicas, - u.Resources.CPUMin.String(), - u.Resources.CPUMax.String(), - u.Resources.MemoryMin.String(), - u.Resources.MemoryMax.String(), + u.RolloutResources.CPUMin.String(), + u.RolloutResources.CPUMax.String(), + u.RolloutResources.MemoryMin.String(), + u.RolloutResources.MemoryMax.String(), ) } @@ -142,30 +143,25 @@ func (opts *KuotaCalcOpts) printDetailed(usage []*calc.ResourceUsage) { _, _ = fmt.Fprintf(opts.Out, "printing detailed resources to tabwriter failed: %v\n", err) } + if opts.maxRollouts > -1 { + _, _ = fmt.Fprintf(opts.Out, "\nTable assuming simultaneous rollout of all resources\n") + _, _ = fmt.Fprintf(opts.Out, "Total assuming simultaneous rollout of %d resources\n", opts.maxRollouts) + } else { + _, _ = fmt.Fprintf(opts.Out, "\nTable and Total assuming simultaneous rollout of all resources\n") + } + _, _ = fmt.Fprintf(opts.Out, "\nTotal\n") opts.printSummary(usage) } func (opts *KuotaCalcOpts) printSummary(usage []*calc.ResourceUsage) { - var ( - cpuMinUsage resource.Quantity - cpuMaxUsage resource.Quantity - memoryMinUsage resource.Quantity - memoryMaxUsage resource.Quantity - ) - - for _, u := range usage { - cpuMinUsage.Add(u.Resources.CPUMin) - cpuMaxUsage.Add(u.Resources.CPUMax) - memoryMinUsage.Add(u.Resources.MemoryMin) - memoryMaxUsage.Add(u.Resources.MemoryMax) - } + totalResources := calc.Total(opts.maxRollouts, usage) _, _ = fmt.Fprintf(opts.Out, "CPU Request: %s\nCPU Limit: %s\nMemory Request: %s\nMemory Limit: %s\n", - cpuMinUsage.String(), - cpuMaxUsage.String(), - memoryMinUsage.String(), - memoryMaxUsage.String(), + totalResources.CPUMin.String(), + totalResources.CPUMax.String(), + totalResources.MemoryMin.String(), + totalResources.MemoryMax.String(), ) } diff --git a/internal/calc/calc.go b/internal/calc/calc.go index 1823f0a..d8a66be 100644 --- a/internal/calc/calc.go +++ b/internal/calc/calc.go @@ -4,6 +4,7 @@ package calc import ( "errors" "fmt" + "slices" openshiftAppsV1 "github.com/openshift/api/apps/v1" openshiftScheme "github.com/openshift/client-go/apps/clientset/versioned/scheme" @@ -45,8 +46,9 @@ func (cErr CalculationError) Unwrap() error { // ResourceUsage summarizes the usage of compute resources for a k8s resource. type ResourceUsage struct { - Resources Resources - Details Details + NormalResources Resources + RolloutResources Resources + Details Details } // Details contains a few details of a k8s resource, which are needed to generate a detailed resource @@ -151,6 +153,89 @@ func maxQuantity(q1, q2 resource.Quantity) resource.Quantity { return q2 } +// diffQuantities is just higher-lower returned as a new Quantity +func diffQuantities(higher, lower *resource.Quantity) resource.Quantity { + q := higher.DeepCopy() + q.Sub(*lower) + + return q +} + +// Total calculates the sum of all usages. maxRollout limits how many simultaneous rollouts are assumed. +// Negative maxRollout value -> unlimited rollouts. +func Total(maxRollout int, usage []*ResourceUsage) Resources { + var ( + cpuMinUsage resource.Quantity + cpuMaxUsage resource.Quantity + memoryMinUsage resource.Quantity + memoryMaxUsage resource.Quantity + ) + + if maxRollout <= -1 { + // unlimited simultaneous rollout, just sum all rollout resources + for _, u := range usage { + cpuMinUsage.Add(u.RolloutResources.CPUMin) + cpuMaxUsage.Add(u.RolloutResources.CPUMax) + memoryMinUsage.Add(u.RolloutResources.MemoryMin) + memoryMaxUsage.Add(u.RolloutResources.MemoryMax) + } + } else { + // limited simultaneous rollout + // first sum the normal resources + // then search for the highest diffs between normal and rollout and add the top `opts.maxRollout` to the sums. + for _, u := range usage { + cpuMinUsage.Add(u.NormalResources.CPUMin) + cpuMaxUsage.Add(u.NormalResources.CPUMax) + memoryMinUsage.Add(u.NormalResources.MemoryMin) + memoryMaxUsage.Add(u.NormalResources.MemoryMax) + } + + var cpuMinDiffs, cpuMaxDiffs, memoryMinDiffs, memoryMaxDiffs []resource.Quantity + + for _, u := range usage { + cpuMinDiffs = append(cpuMinDiffs, diffQuantities(&u.RolloutResources.CPUMin, &u.NormalResources.CPUMin)) + + cpuMaxDiffs = append(cpuMaxDiffs, diffQuantities(&u.RolloutResources.CPUMax, &u.NormalResources.CPUMax)) + + memoryMinDiffs = append(memoryMinDiffs, diffQuantities(&u.RolloutResources.MemoryMin, &u.NormalResources.MemoryMin)) + + memoryMaxDiffs = append(memoryMaxDiffs, diffQuantities(&u.RolloutResources.MemoryMax, &u.NormalResources.MemoryMax)) + } + + compareQuantityDescending := func(a, b resource.Quantity) int { + return a.Cmp(b) * -1 + } + + slices.SortFunc(cpuMinDiffs, compareQuantityDescending) + slices.SortFunc(cpuMaxDiffs, compareQuantityDescending) + slices.SortFunc(memoryMinDiffs, compareQuantityDescending) + slices.SortFunc(memoryMaxDiffs, compareQuantityDescending) + + for i := 0; i < len(cpuMinDiffs) && i < maxRollout; i++ { + cpuMinUsage.Add(cpuMinDiffs[i]) + } + + for i := 0; i < len(cpuMaxDiffs) && i < maxRollout; i++ { + cpuMaxUsage.Add(cpuMaxDiffs[i]) + } + + for i := 0; i < len(memoryMinDiffs) && i < maxRollout; i++ { + memoryMinUsage.Add(memoryMinDiffs[i]) + } + + for i := 0; i < len(memoryMaxDiffs) && i < maxRollout; i++ { + memoryMaxUsage.Add(memoryMaxDiffs[i]) + } + } + + return Resources{ + CPUMin: cpuMinUsage, + CPUMax: cpuMaxUsage, + MemoryMin: memoryMinUsage, + MemoryMax: memoryMaxUsage, + } +} + // ResourceQuotaFromYaml decodes a single yaml document into a k8s object. Then performs a type assertion // on the object and calculates the resource needs of it. // Currently supported: diff --git a/internal/calc/calc_test.go b/internal/calc/calc_test.go index 8caf253..172f973 100644 --- a/internal/calc/calc_test.go +++ b/internal/calc/calc_test.go @@ -734,3 +734,104 @@ func TestResourceQuotaFromYaml(t *testing.T) { func AssertEqualQuantities(r *require.Assertions, expected resource.Quantity, actual resource.Quantity, name string) { r.Conditionf(func() bool { return expected.Equal(actual) }, name+" expected: "+expected.String()+" but was: "+actual.String()) } + +func TestTotal(t *testing.T) { + var tests = []struct { + name string + maxRollout int + usages []*ResourceUsage + expectedResources Resources + }{ + { + name: "two resources, unlimited rollouts", + maxRollout: -1, + usages: []*ResourceUsage{ + { + NormalResources: Resources{ + CPUMin: resource.MustParse("100m"), + CPUMax: resource.MustParse("200m"), + MemoryMin: resource.MustParse("100Mi"), + MemoryMax: resource.MustParse("200Mi"), + }, + RolloutResources: Resources{ + CPUMin: resource.MustParse("200m"), + CPUMax: resource.MustParse("400m"), + MemoryMin: resource.MustParse("200Mi"), + MemoryMax: resource.MustParse("400Mi"), + }, + }, + { + NormalResources: Resources{ + CPUMin: resource.MustParse("50m"), + CPUMax: resource.MustParse("100m"), + MemoryMin: resource.MustParse("50Mi"), + MemoryMax: resource.MustParse("100Mi"), + }, + RolloutResources: Resources{ + CPUMin: resource.MustParse("100m"), + CPUMax: resource.MustParse("200m"), + MemoryMin: resource.MustParse("100Mi"), + MemoryMax: resource.MustParse("200Mi"), + }, + }, + }, + expectedResources: Resources{ + CPUMin: resource.MustParse("300m"), + CPUMax: resource.MustParse("600m"), + MemoryMin: resource.MustParse("300Mi"), + MemoryMax: resource.MustParse("600Mi"), + }, + }, + { + name: "two resources, one rollouts", + maxRollout: 1, + usages: []*ResourceUsage{ + { + NormalResources: Resources{ + CPUMin: resource.MustParse("100m"), + CPUMax: resource.MustParse("200m"), + MemoryMin: resource.MustParse("100Mi"), + MemoryMax: resource.MustParse("200Mi"), + }, + RolloutResources: Resources{ + CPUMin: resource.MustParse("200m"), + CPUMax: resource.MustParse("400m"), + MemoryMin: resource.MustParse("200Mi"), + MemoryMax: resource.MustParse("400Mi"), + }, + }, + { + NormalResources: Resources{ + CPUMin: resource.MustParse("50m"), + CPUMax: resource.MustParse("100m"), + MemoryMin: resource.MustParse("50Mi"), + MemoryMax: resource.MustParse("100Mi"), + }, + RolloutResources: Resources{ + CPUMin: resource.MustParse("100m"), + CPUMax: resource.MustParse("200m"), + MemoryMin: resource.MustParse("100Mi"), + MemoryMax: resource.MustParse("200Mi"), + }, + }, + }, + expectedResources: Resources{ + CPUMin: resource.MustParse("250m"), + CPUMax: resource.MustParse("500m"), + MemoryMin: resource.MustParse("250Mi"), + MemoryMax: resource.MustParse("500Mi"), + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + r := require.New(t) + total := Total(test.maxRollout, test.usages) + AssertEqualQuantities(r, test.expectedResources.CPUMin, total.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.expectedResources.CPUMax, total.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.expectedResources.MemoryMin, total.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.expectedResources.MemoryMax, total.MemoryMax, "memory limit value") + }) + } +} diff --git a/internal/calc/cronjob.go b/internal/calc/cronjob.go index 2287a0a..af3aed1 100644 --- a/internal/calc/cronjob.go +++ b/internal/calc/cronjob.go @@ -3,10 +3,12 @@ package calc import batchV1 "k8s.io/api/batch/v1" func cronjob(cronjob batchV1.CronJob) *ResourceUsage { - podResources := calcPodResources(&cronjob.Spec.JobTemplate.Spec.Template.Spec).MaxResources + podResources := calcPodResources(&cronjob.Spec.JobTemplate.Spec.Template.Spec) resourceUsage := ResourceUsage{ - Resources: podResources, + // TODO should jobs always be considered with their rollout resources? + NormalResources: podResources.Containers, + RolloutResources: podResources.MaxResources, Details: Details{ Version: cronjob.APIVersion, Kind: cronjob.Kind, diff --git a/internal/calc/cronjob_test.go b/internal/calc/cronjob_test.go index 9856cc0..0b78fc5 100644 --- a/internal/calc/cronjob_test.go +++ b/internal/calc/cronjob_test.go @@ -38,10 +38,10 @@ func TestCronJob(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equalf(test.replicas, usage.Details.Replicas, "replicas") r.Equalf(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") r.Equalf(test.strategy, usage.Details.Strategy, "strategy") diff --git a/internal/calc/daemonset.go b/internal/calc/daemonset.go index 9f3c3e0..18ddeec 100644 --- a/internal/calc/daemonset.go +++ b/internal/calc/daemonset.go @@ -5,10 +5,11 @@ import ( ) func daemonSet(dSet appsv1.DaemonSet) *ResourceUsage { - podResources := calcPodResources(&dSet.Spec.Template.Spec).MaxResources + podResources := calcPodResources(&dSet.Spec.Template.Spec) resourceUsage := ResourceUsage{ - Resources: podResources, + NormalResources: podResources.Containers, + RolloutResources: podResources.MaxResources, Details: Details{ Version: dSet.APIVersion, Kind: dSet.Kind, diff --git a/internal/calc/daemonset_test.go b/internal/calc/daemonset_test.go index bb52637..f44645d 100644 --- a/internal/calc/daemonset_test.go +++ b/internal/calc/daemonset_test.go @@ -41,10 +41,10 @@ func TestDaemonSet(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equalf(test.replicas, usage.Details.Replicas, "replicas") r.Equalf(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") r.Equalf(string(test.strategy), usage.Details.Strategy, "strategy") diff --git a/internal/calc/deployment.go b/internal/calc/deployment.go index 25f8a4f..1813810 100644 --- a/internal/calc/deployment.go +++ b/internal/calc/deployment.go @@ -25,7 +25,8 @@ func deployment(deployment appsv1.Deployment) (*ResourceUsage, error) { //nolint if *replicas == 0 { return &ResourceUsage{ - Resources: Resources{}, + NormalResources: Resources{}, + RolloutResources: Resources{}, Details: Details{ Version: deployment.APIVersion, Kind: deployment.Kind, @@ -104,10 +105,12 @@ func deployment(deployment appsv1.Deployment) (*ResourceUsage, error) { //nolint } podResources := calcPodResources(&deployment.Spec.Template.Spec) - newResources := podResources.Containers.MulInt32(*replicas - maxUnavailable).Add(podResources.MaxResources.MulInt32(maxNonReadyPodCount)) + rolloutResources := podResources.Containers.MulInt32(*replicas - maxUnavailable).Add(podResources.MaxResources.MulInt32(maxNonReadyPodCount)) + normalResources := podResources.Containers.MulInt32(*replicas) resourceUsage := ResourceUsage{ - Resources: newResources, + NormalResources: normalResources, + RolloutResources: rolloutResources, Details: Details{ Version: deployment.APIVersion, Kind: deployment.Kind, diff --git a/internal/calc/deploymentConfig.go b/internal/calc/deploymentConfig.go index 1e50dee..d0dd3e4 100644 --- a/internal/calc/deploymentConfig.go +++ b/internal/calc/deploymentConfig.go @@ -25,7 +25,8 @@ func deploymentConfig(deploymentConfig openshiftAppsV1.DeploymentConfig) (*Resou if replicas == 0 { return &ResourceUsage{ - Resources: Resources{}, + NormalResources: Resources{}, + RolloutResources: Resources{}, Details: Details{ Version: deploymentConfig.APIVersion, Kind: deploymentConfig.Kind, @@ -105,10 +106,12 @@ func deploymentConfig(deploymentConfig openshiftAppsV1.DeploymentConfig) (*Resou podResources := calcPodResources(&deploymentConfig.Spec.Template.Spec) strategyResources := ConvertToResources(&deploymentConfig.Spec.Strategy.Resources) - newResources := podResources.Containers.MulInt32(replicas - maxUnavailable).Add(podResources.MaxResources.MulInt32(maxNonReadyPodCount)).Add(strategyResources) + rolloutResources := podResources.Containers.MulInt32(replicas - maxUnavailable).Add(podResources.MaxResources.MulInt32(maxNonReadyPodCount)).Add(strategyResources) + normalResources := podResources.Containers.MulInt32(replicas) resourceUsage := ResourceUsage{ - Resources: newResources, + NormalResources: normalResources, + RolloutResources: rolloutResources, Details: Details{ Version: deploymentConfig.APIVersion, Kind: deploymentConfig.Kind, diff --git a/internal/calc/deploymentConfig_test.go b/internal/calc/deploymentConfig_test.go index e65d972..c5363fd 100644 --- a/internal/calc/deploymentConfig_test.go +++ b/internal/calc/deploymentConfig_test.go @@ -42,10 +42,10 @@ func TestDeploymentConfig(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equal(test.replicas, usage.Details.Replicas, "replicas") r.Equal(string(test.strategy), usage.Details.Strategy, "strategy") r.Equal(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") diff --git a/internal/calc/deployment_test.go b/internal/calc/deployment_test.go index 4f45db2..cc01e7a 100644 --- a/internal/calc/deployment_test.go +++ b/internal/calc/deployment_test.go @@ -107,10 +107,10 @@ func TestDeployment(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equal(test.replicas, usage.Details.Replicas, "replicas") r.Equal(string(test.strategy), usage.Details.Strategy, "strategy") r.Equal(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") diff --git a/internal/calc/job.go b/internal/calc/job.go index 378e1cd..fc472c8 100644 --- a/internal/calc/job.go +++ b/internal/calc/job.go @@ -3,10 +3,11 @@ package calc import batchV1 "k8s.io/api/batch/v1" func job(job batchV1.Job) *ResourceUsage { - podResources := calcPodResources(&job.Spec.Template.Spec).MaxResources + podResources := calcPodResources(&job.Spec.Template.Spec) resourceUsage := ResourceUsage{ - Resources: podResources, + NormalResources: podResources.Containers, + RolloutResources: podResources.MaxResources, Details: Details{ Version: job.APIVersion, Kind: job.Kind, diff --git a/internal/calc/job_test.go b/internal/calc/job_test.go index a7bbcf5..bea68e0 100644 --- a/internal/calc/job_test.go +++ b/internal/calc/job_test.go @@ -38,10 +38,10 @@ func TestJob(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equalf(test.replicas, usage.Details.Replicas, "replicas") r.Equalf(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") r.Equalf(test.strategy, usage.Details.Strategy, "strategy") diff --git a/internal/calc/pod.go b/internal/calc/pod.go index 79f86ac..e28b6b8 100644 --- a/internal/calc/pod.go +++ b/internal/calc/pod.go @@ -3,10 +3,11 @@ package calc import v1 "k8s.io/api/core/v1" func pod(pod v1.Pod) *ResourceUsage { - podResources := calcPodResources(&pod.Spec).MaxResources + podResources := calcPodResources(&pod.Spec) resourceUsage := ResourceUsage{ - Resources: podResources, + NormalResources: podResources.Containers, + RolloutResources: podResources.MaxResources, Details: Details{ Version: pod.APIVersion, Kind: pod.Kind, diff --git a/internal/calc/pod_test.go b/internal/calc/pod_test.go index 43ac76c..bbfd125 100644 --- a/internal/calc/pod_test.go +++ b/internal/calc/pod_test.go @@ -72,10 +72,10 @@ func TestPod(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equalf(test.replicas, usage.Details.Replicas, "replicas") r.Equalf(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") r.Equalf(string(test.strategy), usage.Details.Strategy, "strategy") diff --git a/internal/calc/statefulset.go b/internal/calc/statefulset.go index 59b104e..af586c1 100644 --- a/internal/calc/statefulset.go +++ b/internal/calc/statefulset.go @@ -66,10 +66,12 @@ func statefulSet(s appsv1.StatefulSet) (*ResourceUsage, error) { } podResources := calcPodResources(&s.Spec.Template.Spec) - newResources := podResources.Containers.MulInt32(replicas - maxUnavailable).Add(podResources.MaxResources.MulInt32(maxUnavailable)) + rolloutResources := podResources.Containers.MulInt32(replicas - maxUnavailable).Add(podResources.MaxResources.MulInt32(maxUnavailable)) + normalResources := podResources.Containers.MulInt32(replicas) resourceUsage := ResourceUsage{ - Resources: newResources, + NormalResources: normalResources, + RolloutResources: rolloutResources, Details: Details{ Version: s.APIVersion, Kind: s.Kind, diff --git a/internal/calc/statefulset_test.go b/internal/calc/statefulset_test.go index bc78e67..10e9d55 100644 --- a/internal/calc/statefulset_test.go +++ b/internal/calc/statefulset_test.go @@ -52,10 +52,10 @@ func TestStatefulSet(t *testing.T) { r.NoError(err) r.NotEmpty(usage) - AssertEqualQuantities(r, test.cpuMin, usage.Resources.CPUMin, "cpu request value") - AssertEqualQuantities(r, test.cpuMax, usage.Resources.CPUMax, "cpu limit value") - AssertEqualQuantities(r, test.memoryMin, usage.Resources.MemoryMin, "memory request value") - AssertEqualQuantities(r, test.memoryMax, usage.Resources.MemoryMax, "memory limit value") + AssertEqualQuantities(r, test.cpuMin, usage.RolloutResources.CPUMin, "cpu request value") + AssertEqualQuantities(r, test.cpuMax, usage.RolloutResources.CPUMax, "cpu limit value") + AssertEqualQuantities(r, test.memoryMin, usage.RolloutResources.MemoryMin, "memory request value") + AssertEqualQuantities(r, test.memoryMax, usage.RolloutResources.MemoryMax, "memory limit value") r.Equalf(test.replicas, usage.Details.Replicas, "replicas") r.Equalf(test.maxReplicas, usage.Details.MaxReplicas, "maxReplicas") r.Equalf(string(test.strategy), usage.Details.Strategy, "strategy")