Commit 1b78799b authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #25768 from piosz/metrics-api-hpa

Automatic merge from submit-queue Use Metrics API in HPA
parents 52707ac7 26ad8278
{ {
"ImportPath": "k8s.io/kubernetes", "ImportPath": "k8s.io/kubernetes",
"GoVersion": "go1.6", "GoVersion": "go1.6",
"GodepVersion": "v67", "GodepVersion": "v69",
"Packages": [ "Packages": [
"github.com/ugorji/go/codec/codecgen", "github.com/ugorji/go/codec/codecgen",
"github.com/onsi/ginkgo/ginkgo", "github.com/onsi/ginkgo/ginkgo",
...@@ -2125,8 +2125,13 @@ ...@@ -2125,8 +2125,13 @@
}, },
{ {
"ImportPath": "k8s.io/heapster/metrics/api/v1/types", "ImportPath": "k8s.io/heapster/metrics/api/v1/types",
"Comment": "v1.1.0-beta1-15-gde510e4", "Comment": "v1.1.0-beta2",
"Rev": "de510e4bdcdea96722b5bde19ff0b7a142939485" "Rev": "9cb18ac0ceb193eb530a1fe339355c94ea454d85"
},
{
"ImportPath": "k8s.io/heapster/metrics/apis/metrics/v1alpha1",
"Comment": "v1.1.0-beta2",
"Rev": "9cb18ac0ceb193eb530a1fe339355c94ea454d85"
} }
] ]
} }
...@@ -28,6 +28,7 @@ import ( ...@@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
_ "k8s.io/kubernetes/pkg/apimachinery/registered" _ "k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
...@@ -41,6 +42,7 @@ import ( ...@@ -41,6 +42,7 @@ import (
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
heapster "k8s.io/heapster/metrics/api/v1/types" heapster "k8s.io/heapster/metrics/api/v1/types"
metrics_api "k8s.io/heapster/metrics/apis/metrics/v1alpha1"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -85,6 +87,7 @@ type testCase struct { ...@@ -85,6 +87,7 @@ type testCase struct {
statusUpdated bool statusUpdated bool
eventCreated bool eventCreated bool
verifyEvents bool verifyEvents bool
useMetricsApi bool
// Channel with names of HPA objects which we have reconciled. // Channel with names of HPA objects which we have reconciled.
processed chan string processed chan string
...@@ -278,16 +281,47 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset { ...@@ -278,16 +281,47 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
tc.Lock() tc.Lock()
defer tc.Unlock() defer tc.Unlock()
timestamp := time.Now() var heapsterRawMemResponse []byte
metrics := heapster.MetricResultList{}
for _, level := range tc.reportedLevels { if tc.useMetricsApi {
metric := heapster.MetricResult{ metrics := []*metrics_api.PodMetrics{}
Metrics: []heapster.MetricPoint{{timestamp, level, nil}}, for i, cpu := range tc.reportedLevels {
LatestTimestamp: timestamp, podMetric := &metrics_api.PodMetrics{
ObjectMeta: v1.ObjectMeta{
Name: fmt.Sprintf("%s-%d", podNamePrefix, i),
Namespace: namespace,
},
Timestamp: unversioned.Time{Time: time.Now()},
Containers: []metrics_api.ContainerMetrics{
{
Name: "container",
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(
int64(cpu),
resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(
int64(1024*1024),
resource.BinarySI),
},
},
},
}
metrics = append(metrics, podMetric)
} }
metrics.Items = append(metrics.Items, metric) heapsterRawMemResponse, _ = json.Marshal(&metrics)
} else {
timestamp := time.Now()
metrics := heapster.MetricResultList{}
for _, level := range tc.reportedLevels {
metric := heapster.MetricResult{
Metrics: []heapster.MetricPoint{{timestamp, level, nil}},
LatestTimestamp: timestamp,
}
metrics.Items = append(metrics.Items, metric)
}
heapsterRawMemResponse, _ = json.Marshal(&metrics)
} }
heapsterRawMemResponse, _ := json.Marshal(&metrics)
return true, newFakeResponseWrapper(heapsterRawMemResponse), nil return true, newFakeResponseWrapper(heapsterRawMemResponse), nil
}) })
...@@ -417,6 +451,7 @@ func TestDefaultScaleUpRC(t *testing.T) { ...@@ -417,6 +451,7 @@ func TestDefaultScaleUpRC(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{900, 950, 950, 1000}, reportedLevels: []uint64{900, 950, 950, 1000},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -430,6 +465,7 @@ func TestDefaultScaleUpDeployment(t *testing.T) { ...@@ -430,6 +465,7 @@ func TestDefaultScaleUpDeployment(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{900, 950, 950, 1000}, reportedLevels: []uint64{900, 950, 950, 1000},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
resource: &fakeResource{ resource: &fakeResource{
name: "test-dep", name: "test-dep",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
...@@ -448,6 +484,7 @@ func TestDefaultScaleUpReplicaSet(t *testing.T) { ...@@ -448,6 +484,7 @@ func TestDefaultScaleUpReplicaSet(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{900, 950, 950, 1000}, reportedLevels: []uint64{900, 950, 950, 1000},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
resource: &fakeResource{ resource: &fakeResource{
name: "test-replicaset", name: "test-replicaset",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
...@@ -467,6 +504,7 @@ func TestScaleUp(t *testing.T) { ...@@ -467,6 +504,7 @@ func TestScaleUp(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{300, 500, 700}, reportedLevels: []uint64{300, 500, 700},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -481,6 +519,7 @@ func TestScaleUpDeployment(t *testing.T) { ...@@ -481,6 +519,7 @@ func TestScaleUpDeployment(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{300, 500, 700}, reportedLevels: []uint64{300, 500, 700},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
resource: &fakeResource{ resource: &fakeResource{
name: "test-dep", name: "test-dep",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
...@@ -500,6 +539,7 @@ func TestScaleUpReplicaSet(t *testing.T) { ...@@ -500,6 +539,7 @@ func TestScaleUpReplicaSet(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{300, 500, 700}, reportedLevels: []uint64{300, 500, 700},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
resource: &fakeResource{ resource: &fakeResource{
name: "test-replicaset", name: "test-replicaset",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
...@@ -537,6 +577,7 @@ func TestDefaultScaleDown(t *testing.T) { ...@@ -537,6 +577,7 @@ func TestDefaultScaleDown(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{400, 500, 600, 700, 800}, reportedLevels: []uint64{400, 500, 600, 700, 800},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -551,6 +592,7 @@ func TestScaleDown(t *testing.T) { ...@@ -551,6 +592,7 @@ func TestScaleDown(t *testing.T) {
verifyCPUCurrent: true, verifyCPUCurrent: true,
reportedLevels: []uint64{100, 300, 500, 250, 250}, reportedLevels: []uint64{100, 300, 500, 250, 250},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -582,6 +624,7 @@ func TestTolerance(t *testing.T) { ...@@ -582,6 +624,7 @@ func TestTolerance(t *testing.T) {
CPUTarget: 100, CPUTarget: 100,
reportedLevels: []uint64{1010, 1030, 1020}, reportedLevels: []uint64{1010, 1030, 1020},
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")}, reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -612,6 +655,7 @@ func TestMinReplicas(t *testing.T) { ...@@ -612,6 +655,7 @@ func TestMinReplicas(t *testing.T) {
CPUTarget: 90, CPUTarget: 90,
reportedLevels: []uint64{10, 95, 10}, reportedLevels: []uint64{10, 95, 10},
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")}, reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -625,6 +669,7 @@ func TestZeroReplicas(t *testing.T) { ...@@ -625,6 +669,7 @@ func TestZeroReplicas(t *testing.T) {
CPUTarget: 90, CPUTarget: 90,
reportedLevels: []uint64{}, reportedLevels: []uint64{},
reportedCPURequests: []resource.Quantity{}, reportedCPURequests: []resource.Quantity{},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -638,6 +683,7 @@ func TestTooFewReplicas(t *testing.T) { ...@@ -638,6 +683,7 @@ func TestTooFewReplicas(t *testing.T) {
CPUTarget: 90, CPUTarget: 90,
reportedLevels: []uint64{}, reportedLevels: []uint64{},
reportedCPURequests: []resource.Quantity{}, reportedCPURequests: []resource.Quantity{},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -651,6 +697,7 @@ func TestTooManyReplicas(t *testing.T) { ...@@ -651,6 +697,7 @@ func TestTooManyReplicas(t *testing.T) {
CPUTarget: 90, CPUTarget: 90,
reportedLevels: []uint64{}, reportedLevels: []uint64{},
reportedCPURequests: []resource.Quantity{}, reportedCPURequests: []resource.Quantity{},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -664,6 +711,7 @@ func TestMaxReplicas(t *testing.T) { ...@@ -664,6 +711,7 @@ func TestMaxReplicas(t *testing.T) {
CPUTarget: 90, CPUTarget: 90,
reportedLevels: []uint64{8000, 9500, 1000}, reportedLevels: []uint64{8000, 9500, 1000},
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")}, reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -677,6 +725,7 @@ func TestSuperfluousMetrics(t *testing.T) { ...@@ -677,6 +725,7 @@ func TestSuperfluousMetrics(t *testing.T) {
CPUTarget: 100, CPUTarget: 100,
reportedLevels: []uint64{4000, 9500, 3000, 7000, 3200, 2000}, reportedLevels: []uint64{4000, 9500, 3000, 7000, 3200, 2000},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -690,6 +739,7 @@ func TestMissingMetrics(t *testing.T) { ...@@ -690,6 +739,7 @@ func TestMissingMetrics(t *testing.T) {
CPUTarget: 100, CPUTarget: 100,
reportedLevels: []uint64{400, 95}, reportedLevels: []uint64{400, 95},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -703,6 +753,7 @@ func TestEmptyMetrics(t *testing.T) { ...@@ -703,6 +753,7 @@ func TestEmptyMetrics(t *testing.T) {
CPUTarget: 100, CPUTarget: 100,
reportedLevels: []uint64{}, reportedLevels: []uint64{},
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -715,6 +766,7 @@ func TestEmptyCPURequest(t *testing.T) { ...@@ -715,6 +766,7 @@ func TestEmptyCPURequest(t *testing.T) {
desiredReplicas: 1, desiredReplicas: 1,
CPUTarget: 100, CPUTarget: 100,
reportedLevels: []uint64{200}, reportedLevels: []uint64{200},
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -729,6 +781,7 @@ func TestEventCreated(t *testing.T) { ...@@ -729,6 +781,7 @@ func TestEventCreated(t *testing.T) {
reportedLevels: []uint64{200}, reportedLevels: []uint64{200},
reportedCPURequests: []resource.Quantity{resource.MustParse("0.2")}, reportedCPURequests: []resource.Quantity{resource.MustParse("0.2")},
verifyEvents: true, verifyEvents: true,
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -743,6 +796,7 @@ func TestEventNotCreated(t *testing.T) { ...@@ -743,6 +796,7 @@ func TestEventNotCreated(t *testing.T) {
reportedLevels: []uint64{200, 200}, reportedLevels: []uint64{200, 200},
reportedCPURequests: []resource.Quantity{resource.MustParse("0.4"), resource.MustParse("0.4")}, reportedCPURequests: []resource.Quantity{resource.MustParse("0.4"), resource.MustParse("0.4")},
verifyEvents: true, verifyEvents: true,
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
} }
...@@ -801,6 +855,7 @@ func TestComputedToleranceAlgImplementation(t *testing.T) { ...@@ -801,6 +855,7 @@ func TestComputedToleranceAlgImplementation(t *testing.T) {
resource.MustParse(fmt.Sprint(perPodRequested) + "m"), resource.MustParse(fmt.Sprint(perPodRequested) + "m"),
resource.MustParse(fmt.Sprint(perPodRequested) + "m"), resource.MustParse(fmt.Sprint(perPodRequested) + "m"),
}, },
useMetricsApi: true,
} }
tc.runTest(t) tc.runTest(t)
......
...@@ -24,10 +24,12 @@ import ( ...@@ -24,10 +24,12 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
heapster "k8s.io/heapster/metrics/api/v1/types" heapster "k8s.io/heapster/metrics/api/v1/types"
metrics_api "k8s.io/heapster/metrics/apis/metrics/v1alpha1"
) )
const ( const (
...@@ -83,8 +85,6 @@ var averageFunction = func(metrics heapster.MetricResultList) (intAndFloat, int, ...@@ -83,8 +85,6 @@ var averageFunction = func(metrics heapster.MetricResultList) (intAndFloat, int,
return result, count, timestamp return result, count, timestamp
} }
var heapsterCpuUsageMetricDefinition = metricDefinition{"cpu-usage", averageFunction}
func getHeapsterCustomMetricDefinition(metricName string) metricDefinition { func getHeapsterCustomMetricDefinition(metricName string) metricDefinition {
return metricDefinition{"custom/" + metricName, averageFunction} return metricDefinition{"custom/" + metricName, averageFunction}
} }
...@@ -118,7 +118,7 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st ...@@ -118,7 +118,7 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st
if err != nil { if err != nil {
return 0, 0, time.Time{}, fmt.Errorf("failed to get pod list: %v", err) return 0, 0, time.Time{}, fmt.Errorf("failed to get pod list: %v", err)
} }
podNames := []string{} podNames := map[string]struct{}{}
requestSum := int64(0) requestSum := int64(0)
missing := false missing := false
for _, pod := range podList.Items { for _, pod := range podList.Items {
...@@ -127,7 +127,7 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st ...@@ -127,7 +127,7 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st
continue continue
} }
podNames = append(podNames, pod.Name) podNames[pod.Name] = struct{}{}
for _, container := range pod.Spec.Containers { for _, container := range pod.Spec.Containers {
if containerRequest, ok := container.Resources.Requests[api.ResourceCPU]; ok { if containerRequest, ok := container.Resources.Requests[api.ResourceCPU]; ok {
requestSum += containerRequest.MilliValue() requestSum += containerRequest.MilliValue()
...@@ -145,11 +145,52 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st ...@@ -145,11 +145,52 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st
glog.V(4).Infof("%s %s - sum of CPU requested: %d", namespace, selector, requestSum) glog.V(4).Infof("%s %s - sum of CPU requested: %d", namespace, selector, requestSum)
requestAvg := requestSum / int64(len(podList.Items)) requestAvg := requestSum / int64(len(podList.Items))
// Consumption is already averaged and in millis. // Consumption is already averaged and in millis.
consumption, timestamp, err := h.getForPods(heapsterCpuUsageMetricDefinition, namespace, podNames) consumption, timestamp, err := h.getCpuUtilizationForPods(namespace, selector, podNames)
if err != nil { if err != nil {
return 0, 0, time.Time{}, err return 0, 0, time.Time{}, err
} }
return consumption.intValue, requestAvg, timestamp, nil return consumption, requestAvg, timestamp, nil
}
func (h *HeapsterMetricsClient) getCpuUtilizationForPods(namespace string, selector labels.Selector, podNames map[string]struct{}) (int64, time.Time, error) {
metricPath := fmt.Sprintf("/apis/metrics/v1alpha1/namespaces/%s/pods", namespace)
params := map[string]string{"labelSelector": selector.String()}
resultRaw, err := h.client.Core().Services(h.heapsterNamespace).
ProxyGet(h.heapsterScheme, h.heapsterService, h.heapsterPort, metricPath, params).
DoRaw()
if err != nil {
return 0, time.Time{}, fmt.Errorf("failed to get pods metrics: %v", err)
}
glog.V(4).Infof("Heapster metrics result: %s", string(resultRaw))
metrics := make([]metrics_api.PodMetrics, 0)
err = json.Unmarshal(resultRaw, &metrics)
if err != nil {
return 0, time.Time{}, fmt.Errorf("failed to unmarshall heapster response: %v", err)
}
if len(metrics) != len(podNames) {
return 0, time.Time{}, fmt.Errorf("metrics obtained for %d/%d of pods", len(metrics), len(podNames))
}
sum := int64(0)
for _, m := range metrics {
if _, found := podNames[m.Name]; found {
for _, c := range m.Containers {
cpu, found := c.Usage[v1.ResourceCPU]
if !found {
return 0, time.Time{}, fmt.Errorf("no cpu for container %v in pod %v/%v", c.Name, namespace, m.Name)
}
sum += cpu.MilliValue()
}
} else {
return 0, time.Time{}, fmt.Errorf("not expected metrics for pod %v/%v", namespace, m.Name)
}
}
return sum / int64(len(metrics)), metrics[0].Timestamp.Time, nil
} }
// GetCustomMetric returns the average value of the given custom metric from the // GetCustomMetric returns the average value of the given custom metric from the
...@@ -174,14 +215,14 @@ func (h *HeapsterMetricsClient) GetCustomMetric(customMetricName string, namespa ...@@ -174,14 +215,14 @@ func (h *HeapsterMetricsClient) GetCustomMetric(customMetricName string, namespa
return nil, time.Time{}, fmt.Errorf("no running pods") return nil, time.Time{}, fmt.Errorf("no running pods")
} }
value, timestamp, err := h.getForPods(metricSpec, namespace, podNames) value, timestamp, err := h.getCustomMetricForPods(metricSpec, namespace, podNames)
if err != nil { if err != nil {
return nil, time.Time{}, err return nil, time.Time{}, err
} }
return &value.floatValue, timestamp, nil return &value.floatValue, timestamp, nil
} }
func (h *HeapsterMetricsClient) getForPods(metricSpec metricDefinition, namespace string, podNames []string) (*intAndFloat, time.Time, error) { func (h *HeapsterMetricsClient) getCustomMetricForPods(metricSpec metricDefinition, namespace string, podNames []string) (*intAndFloat, time.Time, error) {
now := time.Now() now := time.Now()
......
// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 v1alpha1
import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
)
// resource usage metrics of a node.
type NodeMetrics struct {
unversioned.TypeMeta `json:",inline"`
v1.ObjectMeta `json:"metadata,omitempty"`
// The following fields define time interval from which metrics were
// collected from the interval [Timestamp-Window, Timestamp].
Timestamp unversioned.Time `json:"timestamp"`
Window unversioned.Duration `json:"window"`
// The memory usage is the memory working set.
Usage v1.ResourceList `json:"usage"`
}
// resource usage metrics of a pod.
type PodMetrics struct {
unversioned.TypeMeta `json:",inline"`
v1.ObjectMeta `json:"metadata,omitempty"`
// The following fields define time interval from which metrics were
// collected from the interval [Timestamp-Window, Timestamp].
Timestamp unversioned.Time `json:"timestamp"`
Window unversioned.Duration `json:"window"`
// Metrics for all containers are collected within the same time window.
Containers []ContainerMetrics `json:"containers"`
}
// resource usage metrics of a container.
type ContainerMetrics struct {
// Container name corresponding to the one from pod.spec.containers.
Name string `json:"name"`
// The memory usage is the memory working set.
Usage v1.ResourceList `json:"usage"`
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment