diff --git a/cluster-autoscaler/cloudprovider/cloud_provider.go b/cluster-autoscaler/cloudprovider/cloud_provider.go index 4da16976d0..85586ff7e5 100644 --- a/cluster-autoscaler/cloudprovider/cloud_provider.go +++ b/cluster-autoscaler/cloudprovider/cloud_provider.go @@ -158,7 +158,7 @@ const ( // ResourceNameCores is string name for cores. It's used by ResourceLimiter. ResourceNameCores = "cpu" // ResourceNameMemory is string name for memory. It's used by ResourceLimiter. - // Memory should always be provided in megabytes. + // Memory should always be provided in bytes. ResourceNameMemory = "memory" ) diff --git a/cluster-autoscaler/cloudprovider/gce/gce_manager.go b/cluster-autoscaler/cloudprovider/gce/gce_manager.go index 1ea991e4dd..2c0302352e 100644 --- a/cluster-autoscaler/cloudprovider/gce/gce_manager.go +++ b/cluster-autoscaler/cloudprovider/gce/gce_manager.go @@ -45,6 +45,7 @@ import ( "k8s.io/autoscaler/cluster-autoscaler/cloudprovider" "k8s.io/autoscaler/cluster-autoscaler/config/dynamic" "k8s.io/autoscaler/cluster-autoscaler/utils/gpu" + "k8s.io/autoscaler/cluster-autoscaler/utils/units" provider_gce "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" ) @@ -1097,12 +1098,12 @@ func (m *gceManagerImpl) fetchResourceLimiter() error { maxLimits[limit.Name] = limit.Maximum } - // GKE API provides memory in GB, but ResourceLimiter expects them in MB + // GKE API provides memory in GB, but ResourceLimiter expects them in bytes if _, found := minLimits[cloudprovider.ResourceNameMemory]; found { - minLimits[cloudprovider.ResourceNameMemory] = minLimits[cloudprovider.ResourceNameMemory] * 1024 + minLimits[cloudprovider.ResourceNameMemory] = minLimits[cloudprovider.ResourceNameMemory] * units.Gigabyte } if _, found := maxLimits[cloudprovider.ResourceNameMemory]; found { - maxLimits[cloudprovider.ResourceNameMemory] = maxLimits[cloudprovider.ResourceNameMemory] * 1024 + maxLimits[cloudprovider.ResourceNameMemory] = maxLimits[cloudprovider.ResourceNameMemory] * units.Gigabyte } resourceLimiter := cloudprovider.NewResourceLimiter(minLimits, maxLimits) diff --git a/cluster-autoscaler/cloudprovider/gce/gce_price_model.go b/cluster-autoscaler/cloudprovider/gce/gce_price_model.go index 3c13cd4c65..2031ec13ce 100644 --- a/cluster-autoscaler/cloudprovider/gce/gce_price_model.go +++ b/cluster-autoscaler/cloudprovider/gce/gce_price_model.go @@ -22,6 +22,7 @@ import ( apiv1 "k8s.io/api/core/v1" "k8s.io/autoscaler/cluster-autoscaler/utils/gpu" + "k8s.io/autoscaler/cluster-autoscaler/utils/units" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" ) @@ -36,7 +37,6 @@ const ( preemptibleDiscount = 0.00698 / 0.033174 gpuPricePerHour = 0.700 - gigabyte = 1024.0 * 1024.0 * 1024.0 preemptibleLabel = "cloud.google.com/gke-preemptible" ) @@ -147,7 +147,7 @@ func getBasePrice(resources apiv1.ResourceList, startTime time.Time, endTime tim cpu := resources[apiv1.ResourceCPU] mem := resources[apiv1.ResourceMemory] price += float64(cpu.MilliValue()) / 1000.0 * cpuPricePerHour * hours - price += float64(mem.Value()) / gigabyte * memoryPricePerHourPerGb * hours + price += float64(mem.Value()) / float64(units.Gigabyte) * memoryPricePerHourPerGb * hours return price } diff --git a/cluster-autoscaler/context/autoscaling_context.go b/cluster-autoscaler/context/autoscaling_context.go index 9d27bc7aba..ed7e48d8e9 100644 --- a/cluster-autoscaler/context/autoscaling_context.go +++ b/cluster-autoscaler/context/autoscaling_context.go @@ -69,9 +69,9 @@ type AutoscalingOptions struct { MaxCoresTotal int64 // MinCoresTotal sets the minimum number of cores in the whole cluster MinCoresTotal int64 - // MaxMemoryTotal sets the maximum memory (in megabytes) in the whole cluster + // MaxMemoryTotal sets the maximum memory (in bytes) in the whole cluster MaxMemoryTotal int64 - // MinMemoryTotal sets the maximum memory (in megabytes) in the whole cluster + // MinMemoryTotal sets the maximum memory (in bytes) in the whole cluster MinMemoryTotal int64 // NodeGroupAutoDiscovery represents one or more definition(s) of node group auto-discovery NodeGroupAutoDiscovery []string diff --git a/cluster-autoscaler/core/scale_down_test.go b/cluster-autoscaler/core/scale_down_test.go index c1e59f09eb..7a73369c58 100644 --- a/cluster-autoscaler/core/scale_down_test.go +++ b/cluster-autoscaler/core/scale_down_test.go @@ -38,6 +38,7 @@ import ( kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes" scheduler_util "k8s.io/autoscaler/cluster-autoscaler/utils/scheduler" . "k8s.io/autoscaler/cluster-autoscaler/utils/test" + "k8s.io/autoscaler/cluster-autoscaler/utils/units" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" @@ -865,7 +866,7 @@ var defaultScaleDownOptions = context.AutoscalingOptions{ MinCoresTotal: 0, MinMemoryTotal: 0, MaxCoresTotal: config.DefaultMaxClusterCores, - MaxMemoryTotal: config.DefaultMaxClusterMemory, + MaxMemoryTotal: config.DefaultMaxClusterMemory * units.Gigabyte, } func TestScaleDownEmptyMultipleNodeGroups(t *testing.T) { @@ -910,7 +911,7 @@ func TestScaleDownEmptyMinCoresLimitHit(t *testing.T) { func TestScaleDownEmptyMinMemoryLimitHit(t *testing.T) { options := defaultScaleDownOptions - options.MinMemoryTotal = 4000 + options.MinMemoryTotal = 4000 * MB config := &scaleTestConfig{ nodes: []nodeConfig{ {"n1", 2000, 1000 * MB, 0, true, "ng1"}, @@ -1310,7 +1311,7 @@ func TestCalculateCoresAndMemoryTotal(t *testing.T) { coresTotal, memoryTotal := calculateCoresAndMemoryTotal(nodes, time.Now()) assert.Equal(t, int64(42), coresTotal) - assert.Equal(t, int64(44000), memoryTotal) + assert.Equal(t, int64(44000*MB), memoryTotal) } func TestFilterOutMasters(t *testing.T) { diff --git a/cluster-autoscaler/core/scale_up_test.go b/cluster-autoscaler/core/scale_up_test.go index fe00bcd25d..5f8f1ea4bb 100644 --- a/cluster-autoscaler/core/scale_up_test.go +++ b/cluster-autoscaler/core/scale_up_test.go @@ -36,6 +36,7 @@ import ( "k8s.io/autoscaler/cluster-autoscaler/simulator" kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes" . "k8s.io/autoscaler/cluster-autoscaler/utils/test" + "k8s.io/autoscaler/cluster-autoscaler/utils/units" apiv1 "k8s.io/api/core/v1" extensionsv1 "k8s.io/api/extensions/v1beta1" @@ -52,7 +53,7 @@ import ( var defaultOptions = context.AutoscalingOptions{ EstimatorName: estimator.BinpackingEstimatorName, MaxCoresTotal: config.DefaultMaxClusterCores, - MaxMemoryTotal: config.DefaultMaxClusterMemory, + MaxMemoryTotal: config.DefaultMaxClusterMemory * units.Gigabyte, MinCoresTotal: 0, MinMemoryTotal: 0, } @@ -106,7 +107,7 @@ const MB = 1024 * 1024 func TestScaleUpMaxMemoryLimitHit(t *testing.T) { options := defaultOptions - options.MaxMemoryTotal = 1300 // set in mb + options.MaxMemoryTotal = 1300 * MB config := &scaleTestConfig{ nodes: []nodeConfig{ {"n1", 2000, 100 * MB, 0, true, "ng1"}, diff --git a/cluster-autoscaler/core/utils.go b/cluster-autoscaler/core/utils.go index 36fcd77f35..d6ec6ae90f 100644 --- a/cluster-autoscaler/core/utils.go +++ b/cluster-autoscaler/core/utils.go @@ -18,7 +18,6 @@ package core import ( "fmt" - "math" "math/rand" "reflect" "time" @@ -488,12 +487,6 @@ func ConfigurePredicateCheckerForLoop(unschedulablePods []*apiv1.Pod, schedulabl } } -// Getting node cores/memory -const ( - // Megabyte is 2^20 bytes. - Megabyte float64 = 1024 * 1024 -) - func getNodeCoresAndMemory(node *apiv1.Node) (int64, int64, error) { cores, err := getNodeResource(node, apiv1.ResourceCPU) if err != nil { @@ -509,8 +502,7 @@ func getNodeCoresAndMemory(node *apiv1.Node) (int64, int64, error) { return 0, 0, fmt.Errorf("Invalid node CPU/memory values - cpu %v, memory %v", cores, memory) } - memoryMb := math.Ceil(float64(memory) / Megabyte) - return cores, int64(memoryMb), nil + return cores, memory, nil } func getNodeResource(node *apiv1.Node, resource apiv1.ResourceName) (int64, error) { diff --git a/cluster-autoscaler/core/utils_test.go b/cluster-autoscaler/core/utils_test.go index 46eace68ae..7af2ac79e3 100644 --- a/cluster-autoscaler/core/utils_test.go +++ b/cluster-autoscaler/core/utils_test.go @@ -599,7 +599,7 @@ func TestGetNodeCoresAndMemory(t *testing.T) { cores, memory, err := getNodeCoresAndMemory(node) assert.NoError(t, err) assert.Equal(t, int64(2), cores) - assert.Equal(t, int64(2048), memory) + assert.Equal(t, int64(2048*MB), memory) node.Status.Capacity = apiv1.ResourceList{} diff --git a/cluster-autoscaler/main.go b/cluster-autoscaler/main.go index c5bd4018f6..b3b6f14d10 100644 --- a/cluster-autoscaler/main.go +++ b/cluster-autoscaler/main.go @@ -40,6 +40,7 @@ import ( "k8s.io/autoscaler/cluster-autoscaler/simulator" "k8s.io/autoscaler/cluster-autoscaler/utils/errors" kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes" + "k8s.io/autoscaler/cluster-autoscaler/utils/units" kube_client "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -143,9 +144,9 @@ func createAutoscalingOptions() context.AutoscalingOptions { if err != nil { glog.Fatalf("Failed to parse flags: %v", err) } - // Convert memory limits to megabytes. - minMemoryTotal = minMemoryTotal * 1024 - maxMemoryTotal = maxMemoryTotal * 1024 + // Convert memory limits to bytes. + minMemoryTotal = minMemoryTotal * units.Gigabyte + maxMemoryTotal = maxMemoryTotal * units.Gigabyte return context.AutoscalingOptions{ CloudConfig: *cloudConfig, diff --git a/cluster-autoscaler/utils/units/units.go b/cluster-autoscaler/utils/units/units.go new file mode 100644 index 0000000000..16a04e183e --- /dev/null +++ b/cluster-autoscaler/utils/units/units.go @@ -0,0 +1,22 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package units + +const ( + // Gigabyte is 2^30 bytes. + Gigabyte = 1024 * 1024 * 1024 +)