| // 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 nodemetrics |
| |
| import ( |
| "context" |
| "fmt" |
| "time" |
| |
| "github.com/golang/glog" |
| |
| "github.com/kubernetes-incubator/metrics-server/pkg/provider" |
| "k8s.io/api/core/v1" |
| "k8s.io/apimachinery/pkg/api/errors" |
| metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| "k8s.io/apimachinery/pkg/labels" |
| "k8s.io/apimachinery/pkg/runtime" |
| "k8s.io/apimachinery/pkg/runtime/schema" |
| "k8s.io/apiserver/pkg/registry/rest" |
| v1listers "k8s.io/client-go/listers/core/v1" |
| "k8s.io/metrics/pkg/apis/metrics" |
| _ "k8s.io/metrics/pkg/apis/metrics/install" |
| ) |
| |
| type MetricStorage struct { |
| groupResource schema.GroupResource |
| prov provider.NodeMetricsProvider |
| nodeLister v1listers.NodeLister |
| } |
| |
| var _ rest.KindProvider = &MetricStorage{} |
| var _ rest.Storage = &MetricStorage{} |
| var _ rest.Getter = &MetricStorage{} |
| var _ rest.Lister = &MetricStorage{} |
| var _ rest.Scoper = &MetricStorage{} |
| |
| func NewStorage(groupResource schema.GroupResource, prov provider.NodeMetricsProvider, nodeLister v1listers.NodeLister) *MetricStorage { |
| return &MetricStorage{ |
| groupResource: groupResource, |
| prov: prov, |
| nodeLister: nodeLister, |
| } |
| } |
| |
| // Storage interface |
| func (m *MetricStorage) New() runtime.Object { |
| return &metrics.NodeMetrics{} |
| } |
| |
| // KindProvider interface |
| func (m *MetricStorage) Kind() string { |
| return "NodeMetrics" |
| } |
| |
| // Lister interface |
| func (m *MetricStorage) NewList() runtime.Object { |
| return &metrics.NodeMetricsList{} |
| } |
| |
| // Lister interface |
| func (m *MetricStorage) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { |
| labelSelector := labels.Everything() |
| if options != nil && options.LabelSelector != nil { |
| labelSelector = options.LabelSelector |
| } |
| nodes, err := m.nodeLister.ListWithPredicate(func(node *v1.Node) bool { |
| if labelSelector.Empty() { |
| return true |
| } |
| return labelSelector.Matches(labels.Set(node.Labels)) |
| }) |
| if err != nil { |
| errMsg := fmt.Errorf("Error while listing nodes for selector %v: %v", labelSelector, err) |
| glog.Error(errMsg) |
| return &metrics.NodeMetricsList{}, errMsg |
| } |
| |
| names := make([]string, len(nodes)) |
| for i, node := range nodes { |
| names[i] = node.Name |
| } |
| |
| metricsItems, err := m.getNodeMetrics(names...) |
| if err != nil { |
| errMsg := fmt.Errorf("Error while fetching node metrics for selector %v: %v", labelSelector, err) |
| glog.Error(errMsg) |
| return &metrics.NodeMetricsList{}, errMsg |
| } |
| |
| return &metrics.NodeMetricsList{Items: metricsItems}, nil |
| } |
| |
| func (m *MetricStorage) Get(ctx context.Context, name string, opts *metav1.GetOptions) (runtime.Object, error) { |
| nodeMetrics, err := m.getNodeMetrics(name) |
| if err == nil && len(nodeMetrics) == 0 { |
| err = fmt.Errorf("no metrics known for node %q", name) |
| } |
| if err != nil { |
| glog.Errorf("unable to fetch node metrics for node %q: %v", name, err) |
| return nil, errors.NewNotFound(m.groupResource, name) |
| } |
| |
| return &nodeMetrics[0], nil |
| } |
| |
| func (m *MetricStorage) getNodeMetrics(names ...string) ([]metrics.NodeMetrics, error) { |
| timestamps, usages, err := m.prov.GetNodeMetrics(names...) |
| if err != nil { |
| return nil, err |
| } |
| |
| res := make([]metrics.NodeMetrics, 0, len(names)) |
| |
| for i, name := range names { |
| if usages[i] == nil { |
| glog.Errorf("unable to fetch node metrics for node %q: no metrics known for node", name) |
| |
| continue |
| } |
| res = append(res, metrics.NodeMetrics{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: name, |
| CreationTimestamp: metav1.NewTime(time.Now()), |
| }, |
| Timestamp: metav1.NewTime(timestamps[i].Timestamp), |
| Window: metav1.Duration{Duration: timestamps[i].Window}, |
| Usage: usages[i], |
| }) |
| } |
| |
| return res, nil |
| } |
| |
| func (m *MetricStorage) NamespaceScoped() bool { |
| return false |
| } |