Skip to content

Commit 740330f

Browse files
authored
Add metrice client show (#82)
1 parent dae439f commit 740330f

File tree

5 files changed

+239
-36
lines changed

5 files changed

+239
-36
lines changed

go.mod

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,13 @@ require (
3232
gorm.io/driver/mysql v1.4.1
3333
gorm.io/gorm v1.24.0
3434
k8s.io/api v0.23.5
35-
k8s.io/apiextensions-apiserver v0.23.5 // indirect
3635
k8s.io/apimachinery v0.23.5
3736
k8s.io/cli-runtime v0.23.5
3837
k8s.io/client-go v0.23.5
3938
k8s.io/component-base v0.23.5
4039
k8s.io/controller-manager v0.23.5
4140
k8s.io/cri-api v0.23.1
42-
k8s.io/heapster v1.5.4 // indirect
43-
k8s.io/klog v1.0.0 // indirect
4441
k8s.io/klog/v2 v2.30.0
4542
k8s.io/kubectl v0.23.5
46-
k8s.io/kubernetes v1.13.0
4743
k8s.io/metrics v0.23.5
4844
)

go.sum

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
120120
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
121121
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
122122
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
123-
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
124123
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
125124
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
126125
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -342,7 +341,6 @@ github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5O
342341
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
343342
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
344343
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
345-
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
346344
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
347345
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
348346
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
@@ -488,7 +486,6 @@ github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+
488486
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
489487
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
490488
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
491-
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
492489
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
493490
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
494491
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -528,8 +525,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
528525
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
529526
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
530527
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
531-
github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
532-
github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
533528
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
534529
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
535530
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -868,7 +863,6 @@ github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1
868863
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
869864
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
870865
github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
871-
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
872866
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
873867
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
874868
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
@@ -1594,7 +1588,6 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
15941588
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
15951589
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
15961590
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
1597-
google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
15981591
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
15991592
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
16001593
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -1730,8 +1723,6 @@ k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
17301723
k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
17311724
k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA=
17321725
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
1733-
k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI=
1734-
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
17351726
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
17361727
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
17371728
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
@@ -1775,10 +1766,6 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
17751766
k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
17761767
k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
17771768
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
1778-
k8s.io/heapster v1.5.4 h1:lH2GCZdqRmUKDoyqRgiXbRmIcevaPYTvkguOuYUl8gQ=
1779-
k8s.io/heapster v1.5.4/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM=
1780-
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
1781-
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
17821769
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
17831770
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
17841771
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
@@ -1795,7 +1782,6 @@ k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKb
17951782
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
17961783
k8s.io/kubectl v0.23.5 h1:DmDULqCaF4qstj0Im143XmncvqWtJxHzK8IrW2BzlU0=
17971784
k8s.io/kubectl v0.23.5/go.mod h1:lLgw7cVY8xbd7o637vOXPca/w6HC205KsPCRDYRCxwE=
1798-
k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8=
17991785
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
18001786
k8s.io/metrics v0.23.5 h1:u+3oGwdUWr30LT2v6MHdSJQ4Pbht9s0cVIWyuY5nf9c=
18011787
k8s.io/metrics v0.23.5/go.mod h1:WNAtV2a5BYbmDS8+7jSqYYV6E3efuGTpIwJ8PTD1wgs=

practise/k8s-practise/clients.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,8 @@ func main() {
9393
// 5. scaleClient
9494
// 直接调整副本数
9595
// https://github.com/caoyingjunz/go-learning/blob/master/practise/k8s-practise/scale.go
96+
97+
// 6. metricClient
98+
// 获取资源的 metric
99+
// https://github.com/caoyingjunz/go-learning/blob/master/practise/k8s-practise/metrics.go
96100
}

practise/k8s-practise/metrics-demo.go renamed to practise/k8s-practise/metrics.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,58 +4,59 @@ import (
44
"context"
55
"fmt"
66

7-
v1 "k8s.io/api/core/v1"
7+
"k8s.io/api/core/v1"
88
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
99
cacheddiscovery "k8s.io/client-go/discovery/cached"
1010
"k8s.io/client-go/kubernetes"
1111
"k8s.io/client-go/restmapper"
12-
"k8s.io/client-go/tools/clientcmd"
1312
"k8s.io/controller-manager/pkg/clientbuilder"
14-
"k8s.io/kubernetes/pkg/controller/podautoscaler/metrics"
1513
resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1"
14+
1615
"k8s.io/metrics/pkg/client/custom_metrics"
1716
"k8s.io/metrics/pkg/client/external_metrics"
17+
18+
"go-learning/practise/k8s-practise/app"
19+
"go-learning/practise/k8s-practise/metrics"
1820
)
1921

2022
func main() {
21-
clientConfig, err := clientcmd.BuildConfigFromFlags("", "/Users/caoyuan/.kube/config")
23+
config, err := app.BuildClientConfig("")
2224
if err != nil {
2325
panic(err)
2426
}
25-
hpaClient, err := kubernetes.NewForConfig(clientConfig)
27+
clientSet, err := kubernetes.NewForConfig(config)
2628
if err != nil {
2729
panic(err)
2830
}
2931

3032
rootClientBuilder := clientbuilder.SimpleControllerClientBuilder{
31-
ClientConfig: clientConfig,
33+
ClientConfig: config,
3234
}
3335
discoveryClient := rootClientBuilder.DiscoveryClientOrDie("controller-discovery")
3436
cachedClient := cacheddiscovery.NewMemCacheClient(discoveryClient)
35-
restMapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedClient)
37+
mapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedClient)
38+
39+
apiVersionsGetter := custom_metrics.NewAvailableAPIsGetter(clientSet.Discovery())
3640

37-
apiVersionsGetter := custom_metrics.NewAvailableAPIsGetter(hpaClient.Discovery())
3841
metricsClient := metrics.NewRESTMetricsClient(
39-
resourceclient.NewForConfigOrDie(clientConfig),
40-
custom_metrics.NewForConfig(clientConfig, restMapper, apiVersionsGetter),
41-
external_metrics.NewForConfigOrDie(clientConfig),
42+
resourceclient.NewForConfigOrDie(config),
43+
custom_metrics.NewForConfig(config, mapper, apiVersionsGetter),
44+
external_metrics.NewForConfigOrDie(config),
4245
)
4346

44-
d, err := hpaClient.AppsV1().Deployments("default").Get(context.TODO(), "test1", metav1.GetOptions{})
47+
deploy, err := clientSet.AppsV1().Deployments("default").Get(context.TODO(), "nginx", metav1.GetOptions{})
4548
if err != nil {
4649
panic(err)
4750
}
48-
49-
selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
51+
selector, _ := metav1.LabelSelectorAsSelector(deploy.Spec.Selector)
5052
// 获取 metrice cpu
51-
podMetricsInfo, time, err := metricsClient.GetResourceMetric(v1.ResourceMemory, "default", selector)
53+
podMetricsInfo, time, err := metricsClient.GetResourceMetric(v1.ResourceCPU, "default", selector)
5254
if err != nil {
5355
panic(err)
5456
}
5557

5658
fmt.Println("time", time)
57-
for podName, podMetric := range podMetricsInfo {
58-
fmt.Println("podName", podName)
59-
fmt.Println("podMetric", podMetric)
59+
for name, metric := range podMetricsInfo {
60+
fmt.Println("name", name, "metric", metric)
6061
}
6162
}
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package metrics
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"time"
23+
24+
autoscaling "k8s.io/api/autoscaling/v2beta2"
25+
"k8s.io/api/core/v1"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/labels"
28+
"k8s.io/apimachinery/pkg/runtime/schema"
29+
customapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2"
30+
resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1"
31+
customclient "k8s.io/metrics/pkg/client/custom_metrics"
32+
externalclient "k8s.io/metrics/pkg/client/external_metrics"
33+
)
34+
35+
const (
36+
metricServerDefaultMetricWindow = time.Minute
37+
)
38+
39+
func NewRESTMetricsClient(resourceClient resourceclient.PodMetricsesGetter, customClient customclient.CustomMetricsClient, externalClient externalclient.ExternalMetricsClient) MetricsClient {
40+
return &restMetricsClient{
41+
&resourceMetricsClient{resourceClient},
42+
&customMetricsClient{customClient},
43+
&externalMetricsClient{externalClient},
44+
}
45+
}
46+
47+
// restMetricsClient is a client which supports fetching
48+
// metrics from both the resource metrics API and the
49+
// custom metrics API.
50+
type restMetricsClient struct {
51+
*resourceMetricsClient
52+
*customMetricsClient
53+
*externalMetricsClient
54+
}
55+
56+
// PodMetric contains pod metric value (the metric values are expected to be the metric as a milli-value)
57+
type PodMetric struct {
58+
Timestamp time.Time
59+
Window time.Duration
60+
Value int64
61+
}
62+
63+
// resourceMetricsClient implements the resource-metrics-related parts of MetricsClient,
64+
// using data from the resource metrics API.
65+
type resourceMetricsClient struct {
66+
client resourceclient.PodMetricsesGetter
67+
}
68+
69+
// PodMetricsInfo contains pod metrics as a map from pod names to PodMetricsInfo
70+
type PodMetricsInfo map[string]PodMetric
71+
72+
// MetricsClient knows how to query a remote interface to retrieve container-level
73+
// resource metrics as well as pod-level arbitrary metrics
74+
type MetricsClient interface {
75+
// GetResourceMetric gets the given resource metric (and an associated oldest timestamp)
76+
// for all pods matching the specified selector in the given namespace
77+
GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error)
78+
79+
// GetRawMetric gets the given metric (and an associated oldest timestamp)
80+
// for all pods matching the specified selector in the given namespace
81+
GetRawMetric(metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (PodMetricsInfo, time.Time, error)
82+
83+
// GetObjectMetric gets the given metric (and an associated timestamp) for the given
84+
// object in the given namespace
85+
GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (int64, time.Time, error)
86+
87+
// GetExternalMetric gets all the values of a given external metric
88+
// that match the specified selector.
89+
GetExternalMetric(metricName string, namespace string, selector labels.Selector) ([]int64, time.Time, error)
90+
}
91+
92+
// GetResourceMetric gets the given resource metric (and an associated oldest timestamp)
93+
// for all pods matching the specified selector in the given namespace
94+
func (c *resourceMetricsClient) GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) {
95+
metrics, err := c.client.PodMetricses(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()})
96+
if err != nil {
97+
return nil, time.Time{}, fmt.Errorf("unable to fetch metrics from resource metrics API: %v", err)
98+
}
99+
100+
if len(metrics.Items) == 0 {
101+
return nil, time.Time{}, fmt.Errorf("no metrics returned from resource metrics API")
102+
}
103+
104+
res := make(PodMetricsInfo, len(metrics.Items))
105+
106+
for _, m := range metrics.Items {
107+
podSum := int64(0)
108+
missing := len(m.Containers) == 0
109+
for _, c := range m.Containers {
110+
resValue, found := c.Usage[v1.ResourceName(resource)]
111+
if !found {
112+
missing = true
113+
break // containers loop
114+
}
115+
podSum += resValue.MilliValue()
116+
}
117+
118+
if !missing {
119+
res[m.Name] = PodMetric{
120+
Timestamp: m.Timestamp.Time,
121+
Window: m.Window.Duration,
122+
Value: int64(podSum),
123+
}
124+
}
125+
}
126+
127+
timestamp := metrics.Items[0].Timestamp.Time
128+
129+
return res, timestamp, nil
130+
}
131+
132+
// customMetricsClient implements the custom-metrics-related parts of MetricsClient,
133+
// using data from the custom metrics API.
134+
type customMetricsClient struct {
135+
client customclient.CustomMetricsClient
136+
}
137+
138+
// GetRawMetric gets the given metric (and an associated oldest timestamp)
139+
// for all pods matching the specified selector in the given namespace
140+
func (c *customMetricsClient) GetRawMetric(metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (PodMetricsInfo, time.Time, error) {
141+
metrics, err := c.client.NamespacedMetrics(namespace).GetForObjects(schema.GroupKind{Kind: "Pod"}, selector, metricName, metricSelector)
142+
if err != nil {
143+
return nil, time.Time{}, fmt.Errorf("unable to fetch metrics from custom metrics API: %v", err)
144+
}
145+
146+
if len(metrics.Items) == 0 {
147+
return nil, time.Time{}, fmt.Errorf("no metrics returned from custom metrics API")
148+
}
149+
150+
res := make(PodMetricsInfo, len(metrics.Items))
151+
for _, m := range metrics.Items {
152+
window := metricServerDefaultMetricWindow
153+
if m.WindowSeconds != nil {
154+
window = time.Duration(*m.WindowSeconds) * time.Second
155+
}
156+
res[m.DescribedObject.Name] = PodMetric{
157+
Timestamp: m.Timestamp.Time,
158+
Window: window,
159+
Value: int64(m.Value.MilliValue()),
160+
}
161+
162+
m.Value.MilliValue()
163+
}
164+
165+
timestamp := metrics.Items[0].Timestamp.Time
166+
167+
return res, timestamp, nil
168+
}
169+
170+
// GetObjectMetric gets the given metric (and an associated timestamp) for the given
171+
// object in the given namespace
172+
func (c *customMetricsClient) GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (int64, time.Time, error) {
173+
gvk := schema.FromAPIVersionAndKind(objectRef.APIVersion, objectRef.Kind)
174+
var metricValue *customapi.MetricValue
175+
var err error
176+
if gvk.Kind == "Namespace" && gvk.Group == "" {
177+
// handle namespace separately
178+
// NB: we ignore namespace name here, since CrossVersionObjectReference isn't
179+
// supposed to allow you to escape your namespace
180+
metricValue, err = c.client.RootScopedMetrics().GetForObject(gvk.GroupKind(), namespace, metricName, metricSelector)
181+
} else {
182+
metricValue, err = c.client.NamespacedMetrics(namespace).GetForObject(gvk.GroupKind(), objectRef.Name, metricName, metricSelector)
183+
}
184+
185+
if err != nil {
186+
return 0, time.Time{}, fmt.Errorf("unable to fetch metrics from custom metrics API: %v", err)
187+
}
188+
189+
return metricValue.Value.MilliValue(), metricValue.Timestamp.Time, nil
190+
}
191+
192+
// externalMetricsClient implenets the external metrics related parts of MetricsClient,
193+
// using data from the external metrics API.
194+
type externalMetricsClient struct {
195+
client externalclient.ExternalMetricsClient
196+
}
197+
198+
// GetExternalMetric gets all the values of a given external metric
199+
// that match the specified selector.
200+
func (c *externalMetricsClient) GetExternalMetric(metricName, namespace string, selector labels.Selector) ([]int64, time.Time, error) {
201+
metrics, err := c.client.NamespacedMetrics(namespace).List(metricName, selector)
202+
if err != nil {
203+
return []int64{}, time.Time{}, fmt.Errorf("unable to fetch metrics from external metrics API: %v", err)
204+
}
205+
206+
if len(metrics.Items) == 0 {
207+
return nil, time.Time{}, fmt.Errorf("no metrics returned from external metrics API")
208+
}
209+
210+
res := make([]int64, 0)
211+
for _, m := range metrics.Items {
212+
res = append(res, m.Value.MilliValue())
213+
}
214+
timestamp := metrics.Items[0].Timestamp.Time
215+
return res, timestamp, nil
216+
}

0 commit comments

Comments
 (0)