git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server

subrepo:
  subdir:   "metrics-server"
  merged:   "92d8412"
upstream:
  origin:   "https://github.com/kubernetes-incubator/metrics-server.git"
  branch:   "master"
  commit:   "92d8412"
git-subrepo:
  version:  "0.4.0"
  origin:   "???"
  commit:   "???"
diff --git a/metrics-server/pkg/storage/nodemetrics/reststorage.go b/metrics-server/pkg/storage/nodemetrics/reststorage.go
new file mode 100644
index 0000000..909e8bf
--- /dev/null
+++ b/metrics-server/pkg/storage/nodemetrics/reststorage.go
@@ -0,0 +1,149 @@
+// 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
+}
diff --git a/metrics-server/pkg/storage/podmetrics/reststorage.go b/metrics-server/pkg/storage/podmetrics/reststorage.go
new file mode 100644
index 0000000..59edb17
--- /dev/null
+++ b/metrics-server/pkg/storage/podmetrics/reststorage.go
@@ -0,0 +1,168 @@
+// 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 podmetrics
+
+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"
+	apitypes "k8s.io/apimachinery/pkg/types"
+	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
+	"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.PodMetricsProvider
+	podLister     v1listers.PodLister
+}
+
+var _ rest.KindProvider = &MetricStorage{}
+var _ rest.Storage = &MetricStorage{}
+var _ rest.Getter = &MetricStorage{}
+var _ rest.Lister = &MetricStorage{}
+
+func NewStorage(groupResource schema.GroupResource, prov provider.PodMetricsProvider, podLister v1listers.PodLister) *MetricStorage {
+	return &MetricStorage{
+		groupResource: groupResource,
+		prov:          prov,
+		podLister:     podLister,
+	}
+}
+
+// Storage interface
+func (m *MetricStorage) New() runtime.Object {
+	return &metrics.PodMetrics{}
+}
+
+// KindProvider interface
+func (m *MetricStorage) Kind() string {
+	return "PodMetrics"
+}
+
+// Lister interface
+func (m *MetricStorage) NewList() runtime.Object {
+	return &metrics.PodMetricsList{}
+}
+
+// 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
+	}
+	namespace := genericapirequest.NamespaceValue(ctx)
+	pods, err := m.podLister.Pods(namespace).List(labelSelector)
+	if err != nil {
+		errMsg := fmt.Errorf("Error while listing pods for selector %v in namespace %q: %v", labelSelector, namespace, err)
+		glog.Error(errMsg)
+		return &metrics.PodMetricsList{}, errMsg
+	}
+
+	metricsItems, err := m.getPodMetrics(pods...)
+	if err != nil {
+		errMsg := fmt.Errorf("Error while fetching pod metrics for selector %v in namespace %q: %v", labelSelector, namespace, err)
+		glog.Error(errMsg)
+		return &metrics.PodMetricsList{}, errMsg
+	}
+
+	return &metrics.PodMetricsList{Items: metricsItems}, nil
+}
+
+// Getter interface
+func (m *MetricStorage) Get(ctx context.Context, name string, opts *metav1.GetOptions) (runtime.Object, error) {
+	namespace := genericapirequest.NamespaceValue(ctx)
+
+	pod, err := m.podLister.Pods(namespace).Get(name)
+	if err != nil {
+		errMsg := fmt.Errorf("Error while getting pod %v: %v", name, err)
+		glog.Error(errMsg)
+		if errors.IsNotFound(err) {
+			// return not-found errors directly
+			return &metrics.PodMetrics{}, err
+		}
+		return &metrics.PodMetrics{}, errMsg
+	}
+	if pod == nil {
+		return &metrics.PodMetrics{}, errors.NewNotFound(v1.Resource("pods"), fmt.Sprintf("%v/%v", namespace, name))
+	}
+
+	podMetrics, err := m.getPodMetrics(pod)
+	if err == nil && len(podMetrics) == 0 {
+		err = fmt.Errorf("no metrics known for pod \"%s/%s\"", pod.Namespace, pod.Name)
+	}
+	if err != nil {
+		glog.Errorf("unable to fetch pod metrics for pod %s/%s: %v", pod.Namespace, pod.Name, err)
+		return nil, errors.NewNotFound(m.groupResource, fmt.Sprintf("%v/%v", namespace, name))
+	}
+	return &podMetrics[0], nil
+}
+
+func (m *MetricStorage) getPodMetrics(pods ...*v1.Pod) ([]metrics.PodMetrics, error) {
+	namespacedNames := make([]apitypes.NamespacedName, len(pods))
+	for i, pod := range pods {
+		namespacedNames[i] = apitypes.NamespacedName{
+			Name:      pod.Name,
+			Namespace: pod.Namespace,
+		}
+	}
+	timestamps, containerMetrics, err := m.prov.GetContainerMetrics(namespacedNames...)
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]metrics.PodMetrics, 0, len(pods))
+
+	for i, pod := range pods {
+		if pod.Status.Phase != v1.PodRunning {
+			// ignore pod not in Running phase
+			continue
+		}
+		if containerMetrics[i] == nil {
+			glog.Errorf("unable to fetch pod metrics for pod %s/%s: no metrics known for pod", pod.Namespace, pod.Name)
+			continue
+		}
+
+		res = append(res, metrics.PodMetrics{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:              pod.Name,
+				Namespace:         pod.Namespace,
+				CreationTimestamp: metav1.NewTime(time.Now()),
+			},
+			Timestamp:  metav1.NewTime(timestamps[i].Timestamp),
+			Window:     metav1.Duration{Duration: timestamps[i].Window},
+			Containers: containerMetrics[i],
+		})
+	}
+	return res, nil
+}
+
+func (m *MetricStorage) NamespaceScoped() bool {
+	return true
+}