blob: 909e8bf4d11cb8297ddf4e650a0c3f16cd7e3ae9 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// Copyright 2018 The Kubernetes Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package nodemetrics
16
17import (
18 "context"
19 "fmt"
20 "time"
21
22 "github.com/golang/glog"
23
24 "github.com/kubernetes-incubator/metrics-server/pkg/provider"
25 "k8s.io/api/core/v1"
26 "k8s.io/apimachinery/pkg/api/errors"
27 metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/labels"
30 "k8s.io/apimachinery/pkg/runtime"
31 "k8s.io/apimachinery/pkg/runtime/schema"
32 "k8s.io/apiserver/pkg/registry/rest"
33 v1listers "k8s.io/client-go/listers/core/v1"
34 "k8s.io/metrics/pkg/apis/metrics"
35 _ "k8s.io/metrics/pkg/apis/metrics/install"
36)
37
38type MetricStorage struct {
39 groupResource schema.GroupResource
40 prov provider.NodeMetricsProvider
41 nodeLister v1listers.NodeLister
42}
43
44var _ rest.KindProvider = &MetricStorage{}
45var _ rest.Storage = &MetricStorage{}
46var _ rest.Getter = &MetricStorage{}
47var _ rest.Lister = &MetricStorage{}
48var _ rest.Scoper = &MetricStorage{}
49
50func NewStorage(groupResource schema.GroupResource, prov provider.NodeMetricsProvider, nodeLister v1listers.NodeLister) *MetricStorage {
51 return &MetricStorage{
52 groupResource: groupResource,
53 prov: prov,
54 nodeLister: nodeLister,
55 }
56}
57
58// Storage interface
59func (m *MetricStorage) New() runtime.Object {
60 return &metrics.NodeMetrics{}
61}
62
63// KindProvider interface
64func (m *MetricStorage) Kind() string {
65 return "NodeMetrics"
66}
67
68// Lister interface
69func (m *MetricStorage) NewList() runtime.Object {
70 return &metrics.NodeMetricsList{}
71}
72
73// Lister interface
74func (m *MetricStorage) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
75 labelSelector := labels.Everything()
76 if options != nil && options.LabelSelector != nil {
77 labelSelector = options.LabelSelector
78 }
79 nodes, err := m.nodeLister.ListWithPredicate(func(node *v1.Node) bool {
80 if labelSelector.Empty() {
81 return true
82 }
83 return labelSelector.Matches(labels.Set(node.Labels))
84 })
85 if err != nil {
86 errMsg := fmt.Errorf("Error while listing nodes for selector %v: %v", labelSelector, err)
87 glog.Error(errMsg)
88 return &metrics.NodeMetricsList{}, errMsg
89 }
90
91 names := make([]string, len(nodes))
92 for i, node := range nodes {
93 names[i] = node.Name
94 }
95
96 metricsItems, err := m.getNodeMetrics(names...)
97 if err != nil {
98 errMsg := fmt.Errorf("Error while fetching node metrics for selector %v: %v", labelSelector, err)
99 glog.Error(errMsg)
100 return &metrics.NodeMetricsList{}, errMsg
101 }
102
103 return &metrics.NodeMetricsList{Items: metricsItems}, nil
104}
105
106func (m *MetricStorage) Get(ctx context.Context, name string, opts *metav1.GetOptions) (runtime.Object, error) {
107 nodeMetrics, err := m.getNodeMetrics(name)
108 if err == nil && len(nodeMetrics) == 0 {
109 err = fmt.Errorf("no metrics known for node %q", name)
110 }
111 if err != nil {
112 glog.Errorf("unable to fetch node metrics for node %q: %v", name, err)
113 return nil, errors.NewNotFound(m.groupResource, name)
114 }
115
116 return &nodeMetrics[0], nil
117}
118
119func (m *MetricStorage) getNodeMetrics(names ...string) ([]metrics.NodeMetrics, error) {
120 timestamps, usages, err := m.prov.GetNodeMetrics(names...)
121 if err != nil {
122 return nil, err
123 }
124
125 res := make([]metrics.NodeMetrics, 0, len(names))
126
127 for i, name := range names {
128 if usages[i] == nil {
129 glog.Errorf("unable to fetch node metrics for node %q: no metrics known for node", name)
130
131 continue
132 }
133 res = append(res, metrics.NodeMetrics{
134 ObjectMeta: metav1.ObjectMeta{
135 Name: name,
136 CreationTimestamp: metav1.NewTime(time.Now()),
137 },
138 Timestamp: metav1.NewTime(timestamps[i].Timestamp),
139 Window: metav1.Duration{Duration: timestamps[i].Window},
140 Usage: usages[i],
141 })
142 }
143
144 return res, nil
145}
146
147func (m *MetricStorage) NamespaceScoped() bool {
148 return false
149}