diff --git a/hack/.golint_failures b/hack/.golint_failures index 1cec2f3c51..038a4c68fb 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -398,7 +398,6 @@ pkg/volume/vsphere_volume plugin/pkg/admission/antiaffinity plugin/pkg/admission/eventratelimit/apis/eventratelimit plugin/pkg/admission/eventratelimit/apis/eventratelimit/v1alpha1 -plugin/pkg/admission/initialresources plugin/pkg/admission/limitranger plugin/pkg/admission/noderestriction plugin/pkg/admission/podnodeselector diff --git a/pkg/kubeapiserver/options/BUILD b/pkg/kubeapiserver/options/BUILD index 66f79c613b..a8099f6291 100644 --- a/pkg/kubeapiserver/options/BUILD +++ b/pkg/kubeapiserver/options/BUILD @@ -37,7 +37,6 @@ go_library( "//plugin/pkg/admission/extendedresourcetoleration:go_default_library", "//plugin/pkg/admission/gc:go_default_library", "//plugin/pkg/admission/imagepolicy:go_default_library", - "//plugin/pkg/admission/initialresources:go_default_library", "//plugin/pkg/admission/limitranger:go_default_library", "//plugin/pkg/admission/namespace/autoprovision:go_default_library", "//plugin/pkg/admission/namespace/exists:go_default_library", diff --git a/pkg/kubeapiserver/options/plugins.go b/pkg/kubeapiserver/options/plugins.go index f718a7db2b..a17c3584ae 100644 --- a/pkg/kubeapiserver/options/plugins.go +++ b/pkg/kubeapiserver/options/plugins.go @@ -34,7 +34,6 @@ import ( "k8s.io/kubernetes/plugin/pkg/admission/extendedresourcetoleration" "k8s.io/kubernetes/plugin/pkg/admission/gc" "k8s.io/kubernetes/plugin/pkg/admission/imagepolicy" - "k8s.io/kubernetes/plugin/pkg/admission/initialresources" "k8s.io/kubernetes/plugin/pkg/admission/limitranger" "k8s.io/kubernetes/plugin/pkg/admission/namespace/autoprovision" "k8s.io/kubernetes/plugin/pkg/admission/namespace/exists" @@ -68,7 +67,6 @@ var AllOrderedPlugins = []string{ exists.PluginName, // NamespaceExists scdeny.PluginName, // SecurityContextDeny antiaffinity.PluginName, // LimitPodHardAntiAffinityTopology - initialresources.PluginName, // InitialResources podpreset.PluginName, // PodPreset limitranger.PluginName, // LimitRanger serviceaccount.PluginName, // ServiceAccount @@ -109,7 +107,6 @@ func RegisterAllAdmissionPlugins(plugins *admission.Plugins) { extendedresourcetoleration.Register(plugins) gc.Register(plugins) imagepolicy.Register(plugins) - initialresources.Register(plugins) limitranger.Register(plugins) autoprovision.Register(plugins) exists.Register(plugins) diff --git a/plugin/BUILD b/plugin/BUILD index e0af06e389..caf1b3baf6 100644 --- a/plugin/BUILD +++ b/plugin/BUILD @@ -21,7 +21,6 @@ filegroup( "//plugin/pkg/admission/extendedresourcetoleration:all-srcs", "//plugin/pkg/admission/gc:all-srcs", "//plugin/pkg/admission/imagepolicy:all-srcs", - "//plugin/pkg/admission/initialresources:all-srcs", "//plugin/pkg/admission/limitranger:all-srcs", "//plugin/pkg/admission/namespace/autoprovision:all-srcs", "//plugin/pkg/admission/namespace/exists:all-srcs", diff --git a/plugin/pkg/admission/initialresources/BUILD b/plugin/pkg/admission/initialresources/BUILD deleted file mode 100644 index 243409ddb5..0000000000 --- a/plugin/pkg/admission/initialresources/BUILD +++ /dev/null @@ -1,70 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_library( - name = "go_default_library", - srcs = [ - "admission.go", - "data_source.go", - "gcm.go", - "hawkular.go", - "influxdb.go", - ], - importpath = "k8s.io/kubernetes/plugin/pkg/admission/initialresources", - deps = [ - "//pkg/apis/core:go_default_library", - "//vendor/cloud.google.com/go/compute/metadata:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/hawkular/hawkular-client-go/metrics:go_default_library", - "//vendor/github.com/influxdata/influxdb/client:go_default_library", - "//vendor/golang.org/x/oauth2:go_default_library", - "//vendor/golang.org/x/oauth2/google:go_default_library", - "//vendor/google.golang.org/api/cloudmonitoring/v2beta2:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", - "//vendor/k8s.io/client-go/rest:go_default_library", - "//vendor/k8s.io/client-go/tools/clientcmd:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "admission_test.go", - "data_source_test.go", - "gcm_test.go", - "hawkular_test.go", - "influxdb_test.go", - ], - embed = [":go_default_library"], - deps = [ - "//pkg/apis/core:go_default_library", - "//vendor/github.com/stretchr/testify/require:go_default_library", - "//vendor/golang.org/x/oauth2:go_default_library", - "//vendor/golang.org/x/oauth2/google:go_default_library", - "//vendor/google.golang.org/api/cloudmonitoring/v2beta2:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/plugin/pkg/admission/initialresources/admission.go b/plugin/pkg/admission/initialresources/admission.go deleted file mode 100644 index 4f1c9ecfa6..0000000000 --- a/plugin/pkg/admission/initialresources/admission.go +++ /dev/null @@ -1,220 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - "flag" - "fmt" - "io" - "sort" - "strings" - "time" - - "github.com/golang/glog" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/apiserver/pkg/admission" - api "k8s.io/kubernetes/pkg/apis/core" -) - -var ( - source = flag.String("ir-data-source", "influxdb", "Data source used by InitialResources. Supported options: influxdb, gcm.") - percentile = flag.Int64("ir-percentile", 90, "Which percentile of samples should InitialResources use when estimating resources. For experiment purposes.") - nsOnly = flag.Bool("ir-namespace-only", false, "Whether the estimation should be made only based on data from the same namespace.") -) - -const ( - initialResourcesAnnotation = "kubernetes.io/initial-resources" - samplesThreshold = 30 - week = 7 * 24 * time.Hour - month = 30 * 24 * time.Hour - // PluginName indicates name of admission plugin. - PluginName = "InitialResources" -) - -// Register registers a plugin -// WARNING: this feature is experimental and will definitely change. -func Register(plugins *admission.Plugins) { - plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) { - // TODO: remove the usage of flags in favor of reading versioned configuration - s, err := newDataSource(*source) - if err != nil { - return nil, err - } - return newInitialResources(s, *percentile, *nsOnly), nil - }) -} - -type InitialResources struct { - *admission.Handler - source dataSource - percentile int64 - nsOnly bool -} - -var _ admission.MutationInterface = &InitialResources{} - -func newInitialResources(source dataSource, percentile int64, nsOnly bool) *InitialResources { - return &InitialResources{ - Handler: admission.NewHandler(admission.Create), - source: source, - percentile: percentile, - nsOnly: nsOnly, - } -} - -// Admit makes an admission decision based on the request attributes -func (ir InitialResources) Admit(a admission.Attributes) (err error) { - // Ignore all calls to subresources or resources other than pods. - if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") { - return nil - } - pod, ok := a.GetObject().(*api.Pod) - if !ok { - return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted") - } - - ir.estimateAndFillResourcesIfNotSet(pod) - return nil -} - -// The method veryfies whether resources should be set for the given pod and -// if there is estimation available the method fills Request field. -func (ir InitialResources) estimateAndFillResourcesIfNotSet(pod *api.Pod) { - var annotations []string - for i := range pod.Spec.InitContainers { - annotations = append(annotations, ir.estimateContainer(pod, &pod.Spec.InitContainers[i], "init container")...) - } - for i := range pod.Spec.Containers { - annotations = append(annotations, ir.estimateContainer(pod, &pod.Spec.Containers[i], "container")...) - } - if len(annotations) > 0 { - if pod.ObjectMeta.Annotations == nil { - pod.ObjectMeta.Annotations = make(map[string]string) - } - val := "Initial Resources plugin set: " + strings.Join(annotations, "; ") - pod.ObjectMeta.Annotations[initialResourcesAnnotation] = val - } -} - -func (ir InitialResources) estimateContainer(pod *api.Pod, c *api.Container, message string) []string { - var annotations []string - req := c.Resources.Requests - cpu := ir.getEstimationIfNeeded(api.ResourceCPU, c, pod.ObjectMeta.Namespace) - mem := ir.getEstimationIfNeeded(api.ResourceMemory, c, pod.ObjectMeta.Namespace) - // If Requests doesn't exits and an estimation was made, create Requests. - if req == nil && (cpu != nil || mem != nil) { - c.Resources.Requests = api.ResourceList{} - req = c.Resources.Requests - } - setRes := []string{} - if cpu != nil { - glog.Infof("CPU estimation for %s %v in pod %v/%v is %v", message, c.Name, pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, cpu.String()) - setRes = append(setRes, string(api.ResourceCPU)) - req[api.ResourceCPU] = *cpu - } - if mem != nil { - glog.Infof("Memory estimation for %s %v in pod %v/%v is %v", message, c.Name, pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, mem.String()) - setRes = append(setRes, string(api.ResourceMemory)) - req[api.ResourceMemory] = *mem - } - if len(setRes) > 0 { - sort.Strings(setRes) - a := strings.Join(setRes, ", ") + fmt.Sprintf(" request for %s %s", message, c.Name) - annotations = append(annotations, a) - } - return annotations -} - -// getEstimationIfNeeded estimates compute resource for container if its corresponding -// Request(min amount) and Limit(max amount) both are not specified. -func (ir InitialResources) getEstimationIfNeeded(kind api.ResourceName, c *api.Container, ns string) *resource.Quantity { - requests := c.Resources.Requests - limits := c.Resources.Limits - var quantity *resource.Quantity - var err error - if _, requestFound := requests[kind]; !requestFound { - if _, limitFound := limits[kind]; !limitFound { - quantity, err = ir.getEstimation(kind, c, ns) - if err != nil { - glog.Errorf("Error while trying to estimate resources: %v", err) - } - } - } - return quantity -} -func (ir InitialResources) getEstimation(kind api.ResourceName, c *api.Container, ns string) (*resource.Quantity, error) { - end := time.Now() - start := end.Add(-week) - var usage, samples int64 - var err error - - // Historical data from last 7 days for the same image:tag within the same namespace. - if usage, samples, err = ir.source.GetUsagePercentile(kind, ir.percentile, c.Image, ns, true, start, end); err != nil { - return nil, err - } - if samples < samplesThreshold { - // Historical data from last 30 days for the same image:tag within the same namespace. - start := end.Add(-month) - if usage, samples, err = ir.source.GetUsagePercentile(kind, ir.percentile, c.Image, ns, true, start, end); err != nil { - return nil, err - } - } - - // If we are allowed to estimate only based on data from the same namespace. - if ir.nsOnly { - if samples < samplesThreshold { - // Historical data from last 30 days for the same image within the same namespace. - start := end.Add(-month) - image := strings.Split(c.Image, ":")[0] - if usage, samples, err = ir.source.GetUsagePercentile(kind, ir.percentile, image, ns, false, start, end); err != nil { - return nil, err - } - } - } else { - if samples < samplesThreshold { - // Historical data from last 7 days for the same image:tag within all namespaces. - start := end.Add(-week) - if usage, samples, err = ir.source.GetUsagePercentile(kind, ir.percentile, c.Image, "", true, start, end); err != nil { - return nil, err - } - } - if samples < samplesThreshold { - // Historical data from last 30 days for the same image:tag within all namespaces. - start := end.Add(-month) - if usage, samples, err = ir.source.GetUsagePercentile(kind, ir.percentile, c.Image, "", true, start, end); err != nil { - return nil, err - } - } - if samples < samplesThreshold { - // Historical data from last 30 days for the same image within all namespaces. - start := end.Add(-month) - image := strings.Split(c.Image, ":")[0] - if usage, samples, err = ir.source.GetUsagePercentile(kind, ir.percentile, image, "", false, start, end); err != nil { - return nil, err - } - } - } - - if samples > 0 && kind == api.ResourceCPU { - return resource.NewMilliQuantity(usage, resource.DecimalSI), nil - } - if samples > 0 && kind == api.ResourceMemory { - return resource.NewQuantity(usage, resource.DecimalSI), nil - } - return nil, nil -} diff --git a/plugin/pkg/admission/initialresources/admission_test.go b/plugin/pkg/admission/initialresources/admission_test.go deleted file mode 100644 index a265fd93a0..0000000000 --- a/plugin/pkg/admission/initialresources/admission_test.go +++ /dev/null @@ -1,300 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - "errors" - "testing" - "time" - - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apiserver/pkg/admission" - api "k8s.io/kubernetes/pkg/apis/core" -) - -type fakeSource struct { - f func(kind api.ResourceName, perc int64, image, namespace string, exactMatch bool, start, end time.Time) (int64, int64, error) -} - -func (s *fakeSource) GetUsagePercentile(kind api.ResourceName, perc int64, image, namespace string, exactMatch bool, start, end time.Time) (usage int64, samples int64, err error) { - return s.f(kind, perc, image, namespace, exactMatch, start, end) -} - -func parseReq(cpu, mem string) api.ResourceList { - if cpu == "" && mem == "" { - return nil - } - req := api.ResourceList{} - if cpu != "" { - req[api.ResourceCPU] = resource.MustParse(cpu) - } - if mem != "" { - req[api.ResourceMemory] = resource.MustParse(mem) - } - return req -} - -func addContainer(pod *api.Pod, name, image string, request api.ResourceList) { - pod.Spec.Containers = append(pod.Spec.Containers, api.Container{ - Name: name, - Image: image, - Resources: api.ResourceRequirements{Requests: request}, - }) -} - -func createPod(name string, image string, request api.ResourceList) *api.Pod { - pod := &api.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-ns"}, - Spec: api.PodSpec{}, - } - pod.Spec.Containers = []api.Container{} - addContainer(pod, "i0", image, request) - pod.Spec.InitContainers = pod.Spec.Containers - pod.Spec.Containers = []api.Container{} - addContainer(pod, "c0", image, request) - return pod -} - -func getPods() []*api.Pod { - return []*api.Pod{ - createPod("p0", "image:v0", parseReq("", "")), - createPod("p1", "image:v1", parseReq("", "300")), - createPod("p2", "image:v2", parseReq("300m", "")), - createPod("p3", "image:v3", parseReq("300m", "300")), - } -} - -func verifyContainer(t *testing.T, c *api.Container, cpu, mem int64) { - req := c.Resources.Requests - if req.Cpu().MilliValue() != cpu { - t.Errorf("Wrong CPU request for container %v. Expected %v, got %v.", c.Name, cpu, req.Cpu().MilliValue()) - } - if req.Memory().Value() != mem { - t.Errorf("Wrong memory request for container %v. Expected %v, got %v.", c.Name, mem, req.Memory().Value()) - } -} - -func verifyPod(t *testing.T, pod *api.Pod, cpu, mem int64) { - verifyContainer(t, &pod.Spec.Containers[0], cpu, mem) - verifyContainer(t, &pod.Spec.InitContainers[0], cpu, mem) -} - -func verifyAnnotation(t *testing.T, pod *api.Pod, expected string) { - a, ok := pod.ObjectMeta.Annotations[initialResourcesAnnotation] - if !ok { - t.Errorf("No annotation but expected %v", expected) - } - if a != expected { - t.Errorf("Wrong annotation set by Initial Resources: got %v, expected %v", a, expected) - } -} - -func expectNoAnnotation(t *testing.T, pod *api.Pod) { - if a, ok := pod.ObjectMeta.Annotations[initialResourcesAnnotation]; ok { - t.Errorf("Expected no annotation but got %v", a) - } -} - -func admit(t *testing.T, ir admission.MutationInterface, pods []*api.Pod) { - for i := range pods { - p := pods[i] - - podKind := api.Kind("Pod").WithVersion("version") - podRes := api.Resource("pods").WithVersion("version") - attrs := admission.NewAttributesRecord(p, nil, podKind, "test", p.ObjectMeta.Name, podRes, "", admission.Create, nil) - if err := ir.Admit(attrs); err != nil { - t.Error(err) - } - } -} - -func testAdminScenarios(t *testing.T, ir admission.MutationInterface, p *api.Pod) { - podKind := api.Kind("Pod").WithVersion("version") - podRes := api.Resource("pods").WithVersion("version") - - var tests = []struct { - attrs admission.Attributes - expectError bool - }{ - { - admission.NewAttributesRecord(p, nil, podKind, "test", p.ObjectMeta.Name, podRes, "foo", admission.Create, nil), - false, - }, - { - admission.NewAttributesRecord(&api.ReplicationController{}, nil, podKind, "test", "", podRes, "", admission.Create, nil), - true, - }, - } - - for _, test := range tests { - err := ir.Admit(test.attrs) - if err != nil && test.expectError == false { - t.Error(err) - } else if err == nil && test.expectError == true { - t.Error("Error expected for Admit but received none") - } - } -} - -func performTest(t *testing.T, ir admission.MutationInterface) { - pods := getPods() - admit(t, ir, pods) - testAdminScenarios(t, ir, pods[0]) - - verifyPod(t, pods[0], 100, 100) - verifyPod(t, pods[1], 100, 300) - verifyPod(t, pods[2], 300, 100) - verifyPod(t, pods[3], 300, 300) - - verifyAnnotation(t, pods[0], "Initial Resources plugin set: cpu, memory request for init container i0; cpu, memory request for container c0") - verifyAnnotation(t, pods[1], "Initial Resources plugin set: cpu request for init container i0") - verifyAnnotation(t, pods[2], "Initial Resources plugin set: memory request for init container i0") - expectNoAnnotation(t, pods[3]) -} - -func TestEstimateReturnsErrorFromSource(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, start, end time.Time) (int64, int64, error) { - return 0, 0, errors.New("Example error") - } - ir := newInitialResources(&fakeSource{f: f}, 90, false) - admit(t, ir, getPods()) -} - -func TestEstimationBasedOnTheSameImageSameNamespace7d(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, start, end time.Time) (int64, int64, error) { - if exactMatch && end.Sub(start) == week && ns == "test-ns" { - return 100, 120, nil - } - return 200, 120, nil - } - performTest(t, newInitialResources(&fakeSource{f: f}, 90, false)) -} - -func TestEstimationBasedOnTheSameImageSameNamespace30d(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, start, end time.Time) (int64, int64, error) { - if exactMatch && end.Sub(start) == week && ns == "test-ns" { - return 200, 20, nil - } - if exactMatch && end.Sub(start) == month && ns == "test-ns" { - return 100, 120, nil - } - return 200, 120, nil - } - performTest(t, newInitialResources(&fakeSource{f: f}, 90, false)) -} - -func TestEstimationBasedOnTheSameImageAllNamespaces7d(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, start, end time.Time) (int64, int64, error) { - if exactMatch && ns == "test-ns" { - return 200, 20, nil - } - if exactMatch && end.Sub(start) == week && ns == "" { - return 100, 120, nil - } - return 200, 120, nil - } - performTest(t, newInitialResources(&fakeSource{f: f}, 90, false)) -} - -func TestEstimationBasedOnTheSameImageAllNamespaces30d(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, start, end time.Time) (int64, int64, error) { - if exactMatch && ns == "test-ns" { - return 200, 20, nil - } - if exactMatch && end.Sub(start) == week && ns == "" { - return 200, 20, nil - } - if exactMatch && end.Sub(start) == month && ns == "" { - return 100, 120, nil - } - return 200, 120, nil - } - performTest(t, newInitialResources(&fakeSource{f: f}, 90, false)) -} - -func TestEstimationBasedOnOtherImages(t *testing.T) { - f := func(_ api.ResourceName, _ int64, image, ns string, exactMatch bool, _, _ time.Time) (int64, int64, error) { - if image == "image" && !exactMatch && ns == "" { - return 100, 5, nil - } - return 200, 20, nil - } - performTest(t, newInitialResources(&fakeSource{f: f}, 90, false)) -} - -func TestNoData(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, _ bool, _, _ time.Time) (int64, int64, error) { - return 200, 0, nil - } - ir := newInitialResources(&fakeSource{f: f}, 90, false) - - pods := []*api.Pod{ - createPod("p0", "image:v0", parseReq("", "")), - } - admit(t, ir, pods) - - if pods[0].Spec.Containers[0].Resources.Requests != nil { - t.Errorf("Unexpected resource estimation") - } - - expectNoAnnotation(t, pods[0]) -} - -func TestManyContainers(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, _, _ time.Time) (int64, int64, error) { - if exactMatch { - return 100, 120, nil - } - return 200, 30, nil - } - ir := newInitialResources(&fakeSource{f: f}, 90, false) - - pod := createPod("p", "image:v0", parseReq("", "")) - addContainer(pod, "c1", "image:v1", parseReq("", "300")) - addContainer(pod, "c2", "image:v2", parseReq("300m", "")) - addContainer(pod, "c3", "image:v3", parseReq("300m", "300")) - admit(t, ir, []*api.Pod{pod}) - - verifyContainer(t, &pod.Spec.Containers[0], 100, 100) - verifyContainer(t, &pod.Spec.Containers[1], 100, 300) - verifyContainer(t, &pod.Spec.Containers[2], 300, 100) - verifyContainer(t, &pod.Spec.Containers[3], 300, 300) - - verifyAnnotation(t, pod, "Initial Resources plugin set: cpu, memory request for init container i0; cpu, memory request for container c0; cpu request for container c1; memory request for container c2") -} - -func TestNamespaceAware(t *testing.T) { - f := func(_ api.ResourceName, _ int64, _, ns string, exactMatch bool, start, end time.Time) (int64, int64, error) { - if ns == "test-ns" { - return 200, 0, nil - } - return 200, 120, nil - } - ir := newInitialResources(&fakeSource{f: f}, 90, true) - - pods := []*api.Pod{ - createPod("p0", "image:v0", parseReq("", "")), - } - admit(t, ir, pods) - - if pods[0].Spec.Containers[0].Resources.Requests != nil { - t.Errorf("Unexpected resource estimation") - } - - expectNoAnnotation(t, pods[0]) -} diff --git a/plugin/pkg/admission/initialresources/data_source.go b/plugin/pkg/admission/initialresources/data_source.go deleted file mode 100644 index a25f5ee800..0000000000 --- a/plugin/pkg/admission/initialresources/data_source.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - "flag" - "fmt" - api "k8s.io/kubernetes/pkg/apis/core" - "time" -) - -var ( - influxdbHost = flag.String("ir-influxdb-host", "localhost:8080/api/v1/namespaces/kube-system/services/monitoring-influxdb:api/proxy", "Address of InfluxDB which contains metrics required by InitialResources") - user = flag.String("ir-user", "root", "User used for connecting to InfluxDB") - // TODO: figure out how to better pass password here - password = flag.String("ir-password", "root", "Password used for connecting to InfluxDB") - db = flag.String("ir-dbname", "k8s", "InfluxDB database name which contains metrics required by InitialResources") - hawkularConfig = flag.String("ir-hawkular", "", "Hawkular configuration URL") -) - -// WARNING: If you are planning to add another implementation of dataSource interface please bear in mind, -// that dataSource will be moved to Heapster some time in the future and possibly rewritten. -type dataSource interface { - // Returns th of sample values which represent usage of for containers running , - // within time range (start, end), number of samples considered and error if occurred. - // If then take only samples that concern the same image (both name and take are the same), - // otherwise consider also samples with the same image a possibly different tag. - GetUsagePercentile(kind api.ResourceName, perc int64, image, namespace string, exactMatch bool, start, end time.Time) (usage int64, samples int64, err error) -} - -func newDataSource(kind string) (dataSource, error) { - if kind == "influxdb" { - return newInfluxdbSource(*influxdbHost, *user, *password, *db) - } - if kind == "gcm" { - return newGcmSource() - } - if kind == "hawkular" { - return newHawkularSource(*hawkularConfig) - } - return nil, fmt.Errorf("unknown data source %v", kind) -} diff --git a/plugin/pkg/admission/initialresources/data_source_test.go b/plugin/pkg/admission/initialresources/data_source_test.go deleted file mode 100644 index 08b21b24db..0000000000 --- a/plugin/pkg/admission/initialresources/data_source_test.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2017 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 initialresources - -import "testing" - -func TestInfluxDBDataSource(t *testing.T) { - ds, _ := newDataSource("influxdb") - if _, ok := ds.(*influxdbSource); !ok { - t.Errorf("newDataSource did not return valid InfluxDB type") - } -} - -func TestGCMDataSource(t *testing.T) { - // No ProjectID set - newDataSource("gcm") -} - -func TestHawkularDataSource(t *testing.T) { - ds, _ := newDataSource("hawkular") - if _, ok := ds.(*hawkularSource); !ok { - t.Errorf("newDataSource did not return valid hawkularSource type") - } -} - -func TestNoDataSourceFound(t *testing.T) { - ds, err := newDataSource("") - if ds != nil || err == nil { - t.Errorf("newDataSource found for empty input") - } -} diff --git a/plugin/pkg/admission/initialresources/gcm.go b/plugin/pkg/admission/initialresources/gcm.go deleted file mode 100644 index fbe64b5dba..0000000000 --- a/plugin/pkg/admission/initialresources/gcm.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - api "k8s.io/kubernetes/pkg/apis/core" - "math" - "sort" - "time" - - gce "cloud.google.com/go/compute/metadata" - "golang.org/x/oauth2" - "golang.org/x/oauth2/google" - gcm "google.golang.org/api/cloudmonitoring/v2beta2" -) - -const ( - kubePrefix = "custom.cloudmonitoring.googleapis.com/kubernetes.io/" - cpuMetricName = kubePrefix + "cpu/usage_rate" - memMetricName = kubePrefix + "memory/usage" - labelImage = kubePrefix + "label/container_base_image" - labelNs = kubePrefix + "label/pod_namespace" -) - -type gcmSource struct { - project string - gcmService *gcm.Service -} - -func newGcmSource() (dataSource, error) { - // Detect project ID - projectId, err := gce.ProjectID() - if err != nil { - return nil, err - } - - // Create Google Cloud Monitoring service. - client := oauth2.NewClient(oauth2.NoContext, google.ComputeTokenSource("")) - s, err := gcm.New(client) - if err != nil { - return nil, err - } - - return &gcmSource{ - project: projectId, - gcmService: s, - }, nil -} - -func (s *gcmSource) query(metric, oldest, youngest string, labels []string, pageToken string) (*gcm.ListTimeseriesResponse, error) { - req := s.gcmService.Timeseries.List(s.project, metric, youngest, nil). - Oldest(oldest). - Aggregator("mean"). - Window("1m") - for _, l := range labels { - req = req.Labels(l) - } - if pageToken != "" { - req = req.PageToken(pageToken) - } - return req.Do() -} - -func retrieveRawSamples(res *gcm.ListTimeseriesResponse, output *[]int) { - for _, ts := range res.Timeseries { - for _, p := range ts.Points { - *output = append(*output, int(*p.DoubleValue)) - } - } -} - -func (s *gcmSource) GetUsagePercentile(kind api.ResourceName, perc int64, image, namespace string, exactMatch bool, start, end time.Time) (int64, int64, error) { - var metric string - if kind == api.ResourceCPU { - metric = cpuMetricName - } else if kind == api.ResourceMemory { - metric = memMetricName - } - - var labels []string - if exactMatch { - labels = append(labels, labelImage+"=="+image) - } else { - labels = append(labels, labelImage+"=~"+image+".*") - } - if namespace != "" { - labels = append(labels, labelNs+"=="+namespace) - } - - oldest := start.Format(time.RFC3339) - youngest := end.Format(time.RFC3339) - - rawSamples := make([]int, 0) - pageToken := "" - for { - res, err := s.query(metric, oldest, youngest, labels, pageToken) - if err != nil { - return 0, 0, err - } - - retrieveRawSamples(res, &rawSamples) - - pageToken = res.NextPageToken - if pageToken == "" { - break - } - } - - count := len(rawSamples) - if count == 0 { - return 0, 0, nil - } - sort.Ints(rawSamples) - usageIndex := int64(math.Ceil(float64(count)*9/10)) - 1 - usage := rawSamples[usageIndex] - - return int64(usage), int64(count), nil -} diff --git a/plugin/pkg/admission/initialresources/gcm_test.go b/plugin/pkg/admission/initialresources/gcm_test.go deleted file mode 100644 index b03960bb35..0000000000 --- a/plugin/pkg/admission/initialresources/gcm_test.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2017 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 initialresources - -import ( - "testing" - "time" - - "golang.org/x/oauth2" - "golang.org/x/oauth2/google" - gcm "google.golang.org/api/cloudmonitoring/v2beta2" - api "k8s.io/kubernetes/pkg/apis/core" -) - -func TestGCMReturnsErrorIfClientCannotConnect(t *testing.T) { - client := oauth2.NewClient(oauth2.NoContext, google.ComputeTokenSource("")) - service, _ := gcm.New(client) - source := &gcmSource{ - project: "", - gcmService: service, - } - - _, _, err := source.GetUsagePercentile(api.ResourceCPU, 90, "", "", true, time.Now(), time.Now()) - if err == nil { - t.Errorf("Expected error from GCM") - } - - _, _, err = source.GetUsagePercentile(api.ResourceMemory, 90, "", "foo", false, time.Now(), time.Now()) - if err == nil { - t.Errorf("Expected error from GCM") - } -} diff --git a/plugin/pkg/admission/initialresources/hawkular.go b/plugin/pkg/admission/initialresources/hawkular.go deleted file mode 100644 index 1f5aaea424..0000000000 --- a/plugin/pkg/admission/initialresources/hawkular.go +++ /dev/null @@ -1,223 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/golang/glog" - "github.com/hawkular/hawkular-client-go/metrics" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - api "k8s.io/kubernetes/pkg/apis/core" - - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -type hawkularSource struct { - client *metrics.Client - uri *url.URL - useNamespace bool - modifiers []metrics.Modifier -} - -const ( - containerImageTag string = "container_base_image" - descriptorTag string = "descriptor_name" - separator string = "/" - - defaultServiceAccountFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" -) - -// heapsterName gets the equivalent MetricDescriptor.Name used in the Heapster -func heapsterName(kind api.ResourceName) string { - switch kind { - case api.ResourceCPU: - return "cpu/usage" - case api.ResourceMemory: - return "memory/usage" - default: - return "" - } -} - -// tagQuery creates tagFilter query for Hawkular -func tagQuery(kind api.ResourceName, image string, exactMatch bool) map[string]string { - q := make(map[string]string) - - // Add here the descriptor_tag.. - q[descriptorTag] = heapsterName(kind) - - if exactMatch { - q[containerImageTag] = image - } else { - split := strings.Index(image, "@") - if split < 0 { - split = strings.Index(image, ":") - } - q[containerImageTag] = fmt.Sprintf("%s:*", image[:split]) - } - - return q -} - -// dataSource API - -func (hs *hawkularSource) GetUsagePercentile(kind api.ResourceName, perc int64, image, namespace string, exactMatch bool, start, end time.Time) (int64, int64, error) { - q := tagQuery(kind, image, exactMatch) - - m := make([]metrics.Modifier, len(hs.modifiers), 2+len(hs.modifiers)) - copy(m, hs.modifiers) - - if namespace != metav1.NamespaceAll { - m = append(m, metrics.Tenant(namespace)) - } - - p := float64(perc) - m = append(m, metrics.Filters(metrics.TagsFilter(q), metrics.BucketsFilter(1), metrics.StartTimeFilter(start), metrics.EndTimeFilter(end), metrics.PercentilesFilter([]float64{p}))) - - bp, err := hs.client.ReadBuckets(metrics.Counter, m...) - if err != nil { - return 0, 0, err - } - - if len(bp) > 0 && len(bp[0].Percentiles) > 0 { - return int64(bp[0].Percentiles[0].Value), int64(bp[0].Samples), nil - } - return 0, 0, nil -} - -// newHawkularSource creates a new Hawkular Source. The uri follows the scheme from Heapster -func newHawkularSource(uri string) (dataSource, error) { - u, err := url.Parse(uri) - if err != nil { - return nil, err - } - - d := &hawkularSource{ - uri: u, - } - if err = d.init(); err != nil { - return nil, err - } - return d, nil -} - -// init initializes the Hawkular dataSource. Almost equal to the Heapster initialization -func (hs *hawkularSource) init() error { - hs.modifiers = make([]metrics.Modifier, 0) - p := metrics.Parameters{ - Tenant: "heapster", // This data is stored by the heapster - for no-namespace hits - Url: hs.uri.String(), - } - - opts := hs.uri.Query() - - if v, found := opts["tenant"]; found { - p.Tenant = v[0] - } - - if v, found := opts["useServiceAccount"]; found { - if b, _ := strconv.ParseBool(v[0]); b { - accountFile := defaultServiceAccountFile - if file, f := opts["serviceAccountFile"]; f { - accountFile = file[0] - } - - // If a readable service account token exists, then use it - if contents, err := ioutil.ReadFile(accountFile); err == nil { - p.Token = string(contents) - } else { - glog.Errorf("Could not read contents of %s, no token authentication is used\n", defaultServiceAccountFile) - } - } - } - - // Authentication / Authorization parameters - tC := &tls.Config{} - - if v, found := opts["auth"]; found { - if _, f := opts["caCert"]; f { - return fmt.Errorf("both auth and caCert files provided, combination is not supported") - } - if len(v[0]) > 0 { - // Authfile - kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&clientcmd.ClientConfigLoadingRules{ - ExplicitPath: v[0]}, - &clientcmd.ConfigOverrides{}).ClientConfig() - if err != nil { - return err - } - tC, err = restclient.TLSConfigFor(kubeConfig) - if err != nil { - return err - } - } - } - - if u, found := opts["user"]; found { - if _, wrong := opts["useServiceAccount"]; wrong { - return fmt.Errorf("if user and password are used, serviceAccount cannot be used") - } - if p, f := opts["pass"]; f { - hs.modifiers = append(hs.modifiers, func(req *http.Request) error { - req.SetBasicAuth(u[0], p[0]) - return nil - }) - } - } - - if v, found := opts["caCert"]; found { - caCert, err := ioutil.ReadFile(v[0]) - if err != nil { - return err - } - - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - - tC.RootCAs = caCertPool - } - - if v, found := opts["insecure"]; found { - insecure, err := strconv.ParseBool(v[0]) - if err != nil { - return err - } - tC.InsecureSkipVerify = insecure - } - - p.TLSConfig = tC - - c, err := metrics.NewHawkularClient(p) - if err != nil { - return err - } - - hs.client = c - - glog.Infof("Initialised Hawkular Source with parameters %v", p) - return nil -} diff --git a/plugin/pkg/admission/initialresources/hawkular_test.go b/plugin/pkg/admission/initialresources/hawkular_test.go deleted file mode 100644 index 306728f0ba..0000000000 --- a/plugin/pkg/admission/initialresources/hawkular_test.go +++ /dev/null @@ -1,142 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - "fmt" - api "k8s.io/kubernetes/pkg/apis/core" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "testing" - "time" - - assert "github.com/stretchr/testify/require" -) - -const ( - testImageName string = "hawkular/hawkular-metrics" - testImageVersion string = "latest" - testImageSHA string = "b727ece3780cdd30e9a86226e520f26bcc396071ed7a86b7ef6684bb93a9f717" - testPartialMatch string = "hawkular/hawkular-metrics:*" -) - -func testImageWithVersion() string { - return fmt.Sprintf("%s:%s", testImageName, testImageVersion) -} - -func testImageWithReference() string { - return fmt.Sprintf("%s@sha256:%s", testImageName, testImageSHA) -} - -func TestTaqQuery(t *testing.T) { - kind := api.ResourceCPU - tQ := tagQuery(kind, testImageWithVersion(), false) - - assert.Equal(t, 2, len(tQ)) - assert.Equal(t, testPartialMatch, tQ[containerImageTag]) - assert.Equal(t, "cpu/usage", tQ[descriptorTag]) - - tQe := tagQuery(kind, testImageWithVersion(), true) - assert.Equal(t, 2, len(tQe)) - assert.Equal(t, testImageWithVersion(), tQe[containerImageTag]) - assert.Equal(t, "cpu/usage", tQe[descriptorTag]) - - tQr := tagQuery(kind, testImageWithReference(), false) - assert.Equal(t, 2, len(tQe)) - assert.Equal(t, testPartialMatch, tQr[containerImageTag]) - assert.Equal(t, "cpu/usage", tQr[descriptorTag]) - - tQre := tagQuery(kind, testImageWithReference(), true) - assert.Equal(t, 2, len(tQe)) - assert.Equal(t, testImageWithReference(), tQre[containerImageTag]) - assert.Equal(t, "cpu/usage", tQre[descriptorTag]) - - kind = api.ResourceMemory - tQ = tagQuery(kind, testImageWithReference(), true) - assert.Equal(t, "memory/usage", tQ[descriptorTag]) - - kind = api.ResourceStorage - tQ = tagQuery(kind, testImageWithReference(), true) - assert.Equal(t, "", tQ[descriptorTag]) -} - -func newSource(t *testing.T) (map[string]string, dataSource) { - tenant := "16a8884e4c155457ee38a8901df6b536" - reqs := make(map[string]string) - - s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, tenant, r.Header.Get("Hawkular-Tenant")) - assert.Equal(t, "Basic", r.Header.Get("Authorization")[:5]) - - if strings.Contains(r.RequestURI, "counters/data") { - assert.True(t, strings.Contains(r.RequestURI, url.QueryEscape(testImageWithVersion()))) - assert.True(t, strings.Contains(r.RequestURI, "cpu%2Fusage")) - assert.True(t, strings.Contains(r.RequestURI, "percentiles=90")) - - reqs["counters/data"] = r.RequestURI - fmt.Fprintf(w, ` [{"start":1444620095882,"end":1444648895882,"min":1.45,"avg":1.45,"median":1.45,"max":1.45,"percentile95th":1.45,"samples":123456,"percentiles":[{"value":7896.54,"quantile":0.9},{"value":1.45,"quantile":0.99}],"empty":false}]`) - } else { - reqs["unknown"] = r.RequestURI - } - })) - - paramUri := fmt.Sprintf("%s?user=test&pass=yep&tenant=foo&insecure=true", s.URL) - - hSource, err := newHawkularSource(paramUri) - assert.NoError(t, err) - - return reqs, hSource -} - -func TestInsecureMustBeBool(t *testing.T) { - paramUri := fmt.Sprintf("localhost?user=test&pass=yep&insecure=foo") - _, err := newHawkularSource(paramUri) - if err == nil { - t.Errorf("Expected error from newHawkularSource") - } -} - -func TestCAFileMustExist(t *testing.T) { - paramUri := fmt.Sprintf("localhost?user=test&pass=yep&caCert=foo") - _, err := newHawkularSource(paramUri) - if err == nil { - t.Errorf("Expected error from newHawkularSource") - } -} - -func TestServiceAccountIsMutuallyExclusiveWithAuth(t *testing.T) { - paramUri := fmt.Sprintf("localhost?user=test&pass=yep&useServiceAccount=true") - _, err := newHawkularSource(paramUri) - if err == nil { - t.Errorf("Expected error from newHawkularSource") - } -} - -func TestGetUsagePercentile(t *testing.T) { - reqs, hSource := newSource(t) - - usage, samples, err := hSource.GetUsagePercentile(api.ResourceCPU, 90, testImageWithVersion(), "16a8884e4c155457ee38a8901df6b536", true, time.Now(), time.Now()) - assert.NoError(t, err) - - assert.Equal(t, 1, len(reqs)) - assert.Equal(t, "", reqs["unknown"]) - - assert.Equal(t, int64(123456), int64(samples)) - assert.Equal(t, int64(7896), usage) // float64 -> int64 -} diff --git a/plugin/pkg/admission/initialresources/influxdb.go b/plugin/pkg/admission/initialresources/influxdb.go deleted file mode 100644 index 2986367a73..0000000000 --- a/plugin/pkg/admission/initialresources/influxdb.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2015 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 initialresources - -import ( - "fmt" - "strings" - "time" - - influxdb "github.com/influxdata/influxdb/client" - api "k8s.io/kubernetes/pkg/apis/core" -) - -const ( - cpuSeriesName = "autoscaling.cpu.usage.2m" - memSeriesName = "autoscaling.memory.usage.2m" - cpuContinuousQuery = "select derivative(value) as value from \"cpu/usage_ns_cumulative\" where pod_id <> '' group by pod_id, pod_namespace, container_name, container_base_image, time(2m) into " + cpuSeriesName - memContinuousQuery = "select mean(value) as value from \"memory/usage_bytes_gauge\" where pod_id <> '' group by pod_id, pod_namespace, container_name, container_base_image, time(2m) into " + memSeriesName - timeFormat = "2006-01-02 15:04:05" -) - -// TODO(piosz): rewrite this once we will migrate into InfluxDB v0.9. -type influxdbSource struct{} - -func newInfluxdbSource(host, user, password, db string) (dataSource, error) { - return &influxdbSource{}, nil -} - -func (s *influxdbSource) query(query string) ([]*influxdb.Response, error) { - // TODO(piosz): add support again - return nil, fmt.Errorf("temporary not supported; see #18826 for more details") -} - -func (s *influxdbSource) GetUsagePercentile(kind api.ResourceName, perc int64, image, namespace string, exactMatch bool, start, end time.Time) (int64, int64, error) { - var series string - if kind == api.ResourceCPU { - series = cpuSeriesName - } else if kind == api.ResourceMemory { - series = memSeriesName - } - - var imgPattern string - if exactMatch { - imgPattern = "='" + image + "'" - } else { - // Escape character "/" in image pattern. - imgPattern = "=~/^" + strings.Replace(image, "/", "\\/", -1) + "/" - } - var namespaceCond string - if namespace != "" { - namespaceCond = " and pod_namespace='" + namespace + "'" - } - - query := fmt.Sprintf("select percentile(value, %v), count(pod_id) from %v where container_base_image%v%v and time > '%v' and time < '%v'", perc, series, imgPattern, namespaceCond, start.UTC().Format(timeFormat), end.UTC().Format(timeFormat)) - if _, err := s.query(query); err != nil { - return 0, 0, fmt.Errorf("error while trying to query InfluxDB: %v", err) - } - return 0, 0, nil -} diff --git a/plugin/pkg/admission/initialresources/influxdb_test.go b/plugin/pkg/admission/initialresources/influxdb_test.go deleted file mode 100644 index 34106ee727..0000000000 --- a/plugin/pkg/admission/initialresources/influxdb_test.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2017 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 initialresources - -import ( - "testing" - "time" - - api "k8s.io/kubernetes/pkg/apis/core" -) - -func TestInfluxDBGetUsagePercentileCPU(t *testing.T) { - source, _ := newInfluxdbSource("", "", "", "") - _, _, err := source.GetUsagePercentile(api.ResourceCPU, 90, "", "", true, time.Now(), time.Now()) - if err == nil { - t.Errorf("Expected error because InfluxDB is temporarily disabled") - } -} - -func TestInfluxDBGetUsagePercentileMemory(t *testing.T) { - source, _ := newInfluxdbSource("", "", "", "") - _, _, err := source.GetUsagePercentile(api.ResourceMemory, 90, "", "foo", false, time.Now(), time.Now()) - if err == nil { - t.Errorf("Expected error because InfluxDB is temporarily disabled") - } -} diff --git a/test/test_owners.csv b/test/test_owners.csv index 173b536724..0430a2be55 100644 --- a/test/test_owners.csv +++ b/test/test_owners.csv @@ -847,7 +847,6 @@ k8s.io/kubernetes/plugin/pkg/admission/deny,eparis,1, k8s.io/kubernetes/plugin/pkg/admission/exec,deads2k,1, k8s.io/kubernetes/plugin/pkg/admission/gc,kevin-wangzefeng,1, k8s.io/kubernetes/plugin/pkg/admission/imagepolicy,apelisse,1, -k8s.io/kubernetes/plugin/pkg/admission/initialresources,piosz,0, k8s.io/kubernetes/plugin/pkg/admission/limitranger,ncdc,1, k8s.io/kubernetes/plugin/pkg/admission/namespace/autoprovision,derekwaynecarr,0, k8s.io/kubernetes/plugin/pkg/admission/namespace/exists,derekwaynecarr,0,