Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -1,40 +1,5 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"interfaces.go",
"resources.go",
],
importpath = "k8s.io/kubernetes/pkg/quota",
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["resources_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
@ -46,9 +11,7 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/quota/evaluator/core:all-srcs",
"//pkg/quota/generic:all-srcs",
"//pkg/quota/install:all-srcs",
"//pkg/quota/v1:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -1,74 +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 = [
"doc.go",
"persistent_volume_claims.go",
"pods.go",
"registry.go",
"services.go",
],
importpath = "k8s.io/kubernetes/pkg/quota/evaluator/core",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/core/helper/qos:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubeapiserver/admission/util:go_default_library",
"//pkg/quota:go_default_library",
"//pkg/quota/generic:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/initialization:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/features:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"persistent_volume_claims_test.go",
"pods_test.go",
"services_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/quota:go_default_library",
"//pkg/quota/generic:go_default_library",
"//pkg/util/node: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/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,40 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"configuration.go",
"evaluator.go",
"registry.go",
],
importpath = "k8s.io/kubernetes/pkg/quota/generic",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/quota:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,321 +0,0 @@
/*
Copyright 2016 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 quota
import (
"testing"
"k8s.io/apimachinery/pkg/api/resource"
api "k8s.io/kubernetes/pkg/apis/core"
)
func TestEquals(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
b api.ResourceList
expected bool
}{
"isEqual": {
a: api.ResourceList{},
b: api.ResourceList{},
expected: true,
},
"isEqualWithKeys": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
b: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
expected: true,
},
"isNotEqualSameKeys": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("200m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
b: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
expected: false,
},
"isNotEqualDiffKeys": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
b: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("1Gi"),
api.ResourcePods: resource.MustParse("1"),
},
expected: false,
},
}
for testName, testCase := range testCases {
if result := Equals(testCase.a, testCase.b); result != testCase.expected {
t.Errorf("%s expected: %v, actual: %v, a=%v, b=%v", testName, testCase.expected, result, testCase.a, testCase.b)
}
}
}
func TestMax(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
b api.ResourceList
expected api.ResourceList
}{
"noKeys": {
a: api.ResourceList{},
b: api.ResourceList{},
expected: api.ResourceList{},
},
"toEmpty": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
b: api.ResourceList{},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
},
"matching": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
b: api.ResourceList{api.ResourceCPU: resource.MustParse("150m")},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("150m")},
},
"matching(reverse)": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("150m")},
b: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("150m")},
},
"matching-equal": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
b: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
},
}
for testName, testCase := range testCases {
sum := Max(testCase.a, testCase.b)
if result := Equals(testCase.expected, sum); !result {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum)
}
}
}
func TestAdd(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
b api.ResourceList
expected api.ResourceList
}{
"noKeys": {
a: api.ResourceList{},
b: api.ResourceList{},
expected: api.ResourceList{},
},
"toEmpty": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
b: api.ResourceList{},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
},
"matching": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
b: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
},
}
for testName, testCase := range testCases {
sum := Add(testCase.a, testCase.b)
if result := Equals(testCase.expected, sum); !result {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum)
}
}
}
func TestSubtract(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
b api.ResourceList
expected api.ResourceList
}{
"noKeys": {
a: api.ResourceList{},
b: api.ResourceList{},
expected: api.ResourceList{},
},
"value-empty": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
b: api.ResourceList{},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
},
"empty-value": {
a: api.ResourceList{},
b: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("-100m")},
},
"value-value": {
a: api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
b: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
expected: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
},
}
for testName, testCase := range testCases {
sub := Subtract(testCase.a, testCase.b)
if result := Equals(testCase.expected, sub); !result {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sub)
}
}
}
func TestResourceNames(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
expected []api.ResourceName
}{
"empty": {
a: api.ResourceList{},
expected: []api.ResourceName{},
},
"values": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
expected: []api.ResourceName{api.ResourceMemory, api.ResourceCPU},
},
}
for testName, testCase := range testCases {
actualSet := ToSet(ResourceNames(testCase.a))
expectedSet := ToSet(testCase.expected)
if !actualSet.Equal(expectedSet) {
t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet)
}
}
}
func TestContains(t *testing.T) {
testCases := map[string]struct {
a []api.ResourceName
b api.ResourceName
expected bool
}{
"does-not-contain": {
a: []api.ResourceName{api.ResourceMemory},
b: api.ResourceCPU,
expected: false,
},
"does-contain": {
a: []api.ResourceName{api.ResourceMemory, api.ResourceCPU},
b: api.ResourceCPU,
expected: true,
},
}
for testName, testCase := range testCases {
if actual := Contains(testCase.a, testCase.b); actual != testCase.expected {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual)
}
}
}
func TestContainsPrefix(t *testing.T) {
testCases := map[string]struct {
a []string
b api.ResourceName
expected bool
}{
"does-not-contain": {
a: []string{api.ResourceHugePagesPrefix},
b: api.ResourceCPU,
expected: false,
},
"does-contain": {
a: []string{api.ResourceHugePagesPrefix},
b: api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"),
expected: true,
},
}
for testName, testCase := range testCases {
if actual := ContainsPrefix(testCase.a, testCase.b); actual != testCase.expected {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual)
}
}
}
func TestIsZero(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
expected bool
}{
"empty": {
a: api.ResourceList{},
expected: true,
},
"zero": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("0"),
api.ResourceMemory: resource.MustParse("0"),
},
expected: true,
},
"non-zero": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("200m"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
expected: false,
},
}
for testName, testCase := range testCases {
if result := IsZero(testCase.a); result != testCase.expected {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, result)
}
}
}
func TestIsNegative(t *testing.T) {
testCases := map[string]struct {
a api.ResourceList
expected []api.ResourceName
}{
"empty": {
a: api.ResourceList{},
expected: []api.ResourceName{},
},
"some-negative": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("-10"),
api.ResourceMemory: resource.MustParse("0"),
},
expected: []api.ResourceName{api.ResourceCPU},
},
"all-negative": {
a: api.ResourceList{
api.ResourceCPU: resource.MustParse("-200m"),
api.ResourceMemory: resource.MustParse("-1Gi"),
},
expected: []api.ResourceName{api.ResourceCPU, api.ResourceMemory},
},
}
for testName, testCase := range testCases {
actual := IsNegative(testCase.a)
actualSet := ToSet(actual)
expectedSet := ToSet(testCase.expected)
if !actualSet.Equal(expectedSet) {
t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet)
}
}
}

53
vendor/k8s.io/kubernetes/pkg/quota/v1/BUILD generated vendored Normal file
View File

@ -0,0 +1,53 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"interfaces.go",
"resources.go",
],
importpath = "k8s.io/kubernetes/pkg/quota/v1",
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["resources_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/quota/v1/evaluator/core:all-srcs",
"//pkg/quota/v1/generic:all-srcs",
"//pkg/quota/v1/install:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -7,3 +7,5 @@ reviewers:
- derekwaynecarr
- smarterclayton
- vishh
labels:
- sig/api-machinery

View File

@ -0,0 +1,75 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"persistent_volume_claims.go",
"pods.go",
"registry.go",
"services.go",
],
importpath = "k8s.io/kubernetes/pkg/quota/v1/evaluator/core",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/apis/core/v1/helper/qos:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubeapiserver/admission/util:go_default_library",
"//pkg/quota/v1:go_default_library",
"//pkg/quota/v1/generic:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/initialization:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"persistent_volume_claims_test.go",
"pods_test.go",
"services_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/quota/v1:go_default_library",
"//pkg/quota/v1/generic:go_default_library",
"//pkg/util/node:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -15,4 +15,4 @@ limitations under the License.
*/
// core contains modules that interface with the core api group
package core // import "k8s.io/kubernetes/pkg/quota/evaluator/core"
package core // import "k8s.io/kubernetes/pkg/quota/v1/evaluator/core"

View File

@ -20,7 +20,7 @@ import (
"fmt"
"strings"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -30,22 +30,22 @@ import (
"k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
k8sfeatures "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubeapiserver/admission/util"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
)
// the name used for object count quota
var pvcObjectCountName = generic.ObjectCountQuotaResourceNameFor(v1.SchemeGroupVersion.WithResource("persistentvolumeclaims").GroupResource())
var pvcObjectCountName = generic.ObjectCountQuotaResourceNameFor(corev1.SchemeGroupVersion.WithResource("persistentvolumeclaims").GroupResource())
// pvcResources are the set of static resources managed by quota associated with pvcs.
// for each resource in this list, it may be refined dynamically based on storage class.
var pvcResources = []api.ResourceName{
api.ResourcePersistentVolumeClaims,
api.ResourceRequestsStorage,
var pvcResources = []corev1.ResourceName{
corev1.ResourcePersistentVolumeClaims,
corev1.ResourceRequestsStorage,
}
// storageClassSuffix is the suffix to the qualified portion of storage class resource name.
@ -56,19 +56,21 @@ var pvcResources = []api.ResourceName{
// * bronze.storageclass.storage.k8s.io/requests.storage: 500Gi
const storageClassSuffix string = ".storageclass.storage.k8s.io/"
/* TODO: prune?
// ResourceByStorageClass returns a quota resource name by storage class.
func ResourceByStorageClass(storageClass string, resourceName api.ResourceName) api.ResourceName {
return api.ResourceName(string(storageClass + storageClassSuffix + string(resourceName)))
func ResourceByStorageClass(storageClass string, resourceName corev1.ResourceName) corev1.ResourceName {
return corev1.ResourceName(string(storageClass + storageClassSuffix + string(resourceName)))
}
*/
// V1ResourceByStorageClass returns a quota resource name by storage class.
func V1ResourceByStorageClass(storageClass string, resourceName v1.ResourceName) v1.ResourceName {
return v1.ResourceName(string(storageClass + storageClassSuffix + string(resourceName)))
func V1ResourceByStorageClass(storageClass string, resourceName corev1.ResourceName) corev1.ResourceName {
return corev1.ResourceName(string(storageClass + storageClassSuffix + string(resourceName)))
}
// NewPersistentVolumeClaimEvaluator returns an evaluator that can evaluate persistent volume claims
func NewPersistentVolumeClaimEvaluator(f quota.ListerForResourceFunc) quota.Evaluator {
listFuncByNamespace := generic.ListResourceUsingListerFunc(f, v1.SchemeGroupVersion.WithResource("persistentvolumeclaims"))
listFuncByNamespace := generic.ListResourceUsingListerFunc(f, corev1.SchemeGroupVersion.WithResource("persistentvolumeclaims"))
pvcEvaluator := &pvcEvaluator{listFuncByNamespace: listFuncByNamespace}
return pvcEvaluator
}
@ -80,14 +82,14 @@ type pvcEvaluator struct {
}
// Constraints verifies that all required resources are present on the item.
func (p *pvcEvaluator) Constraints(required []api.ResourceName, item runtime.Object) error {
func (p *pvcEvaluator) Constraints(required []corev1.ResourceName, item runtime.Object) error {
// no-op for persistent volume claims
return nil
}
// GroupResource that this evaluator tracks
func (p *pvcEvaluator) GroupResource() schema.GroupResource {
return v1.SchemeGroupVersion.WithResource("persistentvolumeclaims").GroupResource()
return corev1.SchemeGroupVersion.WithResource("persistentvolumeclaims").GroupResource()
}
// Handles returns true if the evaluator should handle the specified operation.
@ -119,27 +121,27 @@ func (p *pvcEvaluator) Handles(a admission.Attributes) bool {
}
// Matches returns true if the evaluator matches the specified quota with the provided input item
func (p *pvcEvaluator) Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error) {
func (p *pvcEvaluator) Matches(resourceQuota *corev1.ResourceQuota, item runtime.Object) (bool, error) {
return generic.Matches(resourceQuota, item, p.MatchingResources, generic.MatchesNoScopeFunc)
}
// MatchingScopes takes the input specified list of scopes and input object. Returns the set of scopes resource matches.
func (p *pvcEvaluator) MatchingScopes(item runtime.Object, scopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
return []api.ScopedResourceSelectorRequirement{}, nil
func (p *pvcEvaluator) MatchingScopes(item runtime.Object, scopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
return []corev1.ScopedResourceSelectorRequirement{}, nil
}
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes.
// It returns the scopes which are in limited scopes but dont have a corresponding covering quota scope
func (p *pvcEvaluator) UncoveredQuotaScopes(limitedScopes []api.ScopedResourceSelectorRequirement, matchedQuotaScopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
return []api.ScopedResourceSelectorRequirement{}, nil
func (p *pvcEvaluator) UncoveredQuotaScopes(limitedScopes []corev1.ScopedResourceSelectorRequirement, matchedQuotaScopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
return []corev1.ScopedResourceSelectorRequirement{}, nil
}
// MatchingResources takes the input specified list of resources and returns the set of resources it matches.
func (p *pvcEvaluator) MatchingResources(items []api.ResourceName) []api.ResourceName {
result := []api.ResourceName{}
func (p *pvcEvaluator) MatchingResources(items []corev1.ResourceName) []corev1.ResourceName {
result := []corev1.ResourceName{}
for _, item := range items {
// match object count quota fields
if quota.Contains([]api.ResourceName{pvcObjectCountName}, item) {
if quota.Contains([]corev1.ResourceName{pvcObjectCountName}, item) {
result = append(result, item)
continue
}
@ -161,15 +163,15 @@ func (p *pvcEvaluator) MatchingResources(items []api.ResourceName) []api.Resourc
}
// Usage knows how to measure usage associated with item.
func (p *pvcEvaluator) Usage(item runtime.Object) (api.ResourceList, error) {
result := api.ResourceList{}
pvc, err := toInternalPersistentVolumeClaimOrError(item)
func (p *pvcEvaluator) Usage(item runtime.Object) (corev1.ResourceList, error) {
result := corev1.ResourceList{}
pvc, err := toExternalPersistentVolumeClaimOrError(item)
if err != nil {
return result, err
}
// charge for claim
result[api.ResourcePersistentVolumeClaims] = *(resource.NewQuantity(1, resource.DecimalSI))
result[corev1.ResourcePersistentVolumeClaims] = *(resource.NewQuantity(1, resource.DecimalSI))
result[pvcObjectCountName] = *(resource.NewQuantity(1, resource.DecimalSI))
if utilfeature.DefaultFeatureGate.Enabled(features.Initializers) {
if !initialization.IsInitialized(pvc.Initializers) {
@ -179,16 +181,16 @@ func (p *pvcEvaluator) Usage(item runtime.Object) (api.ResourceList, error) {
}
storageClassRef := helper.GetPersistentVolumeClaimClass(pvc)
if len(storageClassRef) > 0 {
storageClassClaim := api.ResourceName(storageClassRef + storageClassSuffix + string(api.ResourcePersistentVolumeClaims))
storageClassClaim := corev1.ResourceName(storageClassRef + storageClassSuffix + string(corev1.ResourcePersistentVolumeClaims))
result[storageClassClaim] = *(resource.NewQuantity(1, resource.DecimalSI))
}
// charge for storage
if request, found := pvc.Spec.Resources.Requests[api.ResourceStorage]; found {
result[api.ResourceRequestsStorage] = request
if request, found := pvc.Spec.Resources.Requests[corev1.ResourceStorage]; found {
result[corev1.ResourceRequestsStorage] = request
// charge usage to the storage class (if present)
if len(storageClassRef) > 0 {
storageClassStorage := api.ResourceName(storageClassRef + storageClassSuffix + string(api.ResourceRequestsStorage))
storageClassStorage := corev1.ResourceName(storageClassRef + storageClassSuffix + string(corev1.ResourceRequestsStorage))
result[storageClassStorage] = request
}
}
@ -203,15 +205,15 @@ func (p *pvcEvaluator) UsageStats(options quota.UsageStatsOptions) (quota.UsageS
// ensure we implement required interface
var _ quota.Evaluator = &pvcEvaluator{}
func toInternalPersistentVolumeClaimOrError(obj runtime.Object) (*api.PersistentVolumeClaim, error) {
pvc := &api.PersistentVolumeClaim{}
func toExternalPersistentVolumeClaimOrError(obj runtime.Object) (*corev1.PersistentVolumeClaim, error) {
pvc := &corev1.PersistentVolumeClaim{}
switch t := obj.(type) {
case *v1.PersistentVolumeClaim:
if err := k8s_api_v1.Convert_v1_PersistentVolumeClaim_To_core_PersistentVolumeClaim(t, pvc, nil); err != nil {
case *corev1.PersistentVolumeClaim:
pvc = t
case *api.PersistentVolumeClaim:
if err := k8s_api_v1.Convert_core_PersistentVolumeClaim_To_v1_PersistentVolumeClaim(t, pvc, nil); err != nil {
return nil, err
}
case *api.PersistentVolumeClaim:
pvc = t
default:
return nil, fmt.Errorf("expect *api.PersistentVolumeClaim or *v1.PersistentVolumeClaim, got %v", t)
}

View File

@ -19,12 +19,13 @@ package core
import (
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
)
func testVolumeClaim(name string, namespace string, spec api.PersistentVolumeClaimSpec) *api.PersistentVolumeClaim {
@ -79,23 +80,23 @@ func TestPersistentVolumeClaimEvaluatorUsage(t *testing.T) {
evaluator := NewPersistentVolumeClaimEvaluator(nil)
testCases := map[string]struct {
pvc *api.PersistentVolumeClaim
usage api.ResourceList
usage corev1.ResourceList
}{
"pvc-usage": {
pvc: validClaim,
usage: api.ResourceList{
api.ResourceRequestsStorage: resource.MustParse("10Gi"),
api.ResourcePersistentVolumeClaims: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceRequestsStorage: resource.MustParse("10Gi"),
corev1.ResourcePersistentVolumeClaims: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "persistentvolumeclaims"}): resource.MustParse("1"),
},
},
"pvc-usage-by-class": {
pvc: validClaimByStorageClass,
usage: api.ResourceList{
api.ResourceRequestsStorage: resource.MustParse("10Gi"),
api.ResourcePersistentVolumeClaims: resource.MustParse("1"),
ResourceByStorageClass(classGold, api.ResourceRequestsStorage): resource.MustParse("10Gi"),
ResourceByStorageClass(classGold, api.ResourcePersistentVolumeClaims): resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceRequestsStorage: resource.MustParse("10Gi"),
corev1.ResourcePersistentVolumeClaims: resource.MustParse("1"),
V1ResourceByStorageClass(classGold, corev1.ResourceRequestsStorage): resource.MustParse("10Gi"),
V1ResourceByStorageClass(classGold, corev1.ResourcePersistentVolumeClaims): resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "persistentvolumeclaims"}): resource.MustParse("1"),
},
},

View File

@ -21,7 +21,7 @@ import (
"strings"
"time"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@ -32,57 +32,57 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/admission"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/apis/core/helper/qos"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/apis/core/v1/helper/qos"
"k8s.io/kubernetes/pkg/kubeapiserver/admission/util"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
)
// the name used for object count quota
var podObjectCountName = generic.ObjectCountQuotaResourceNameFor(v1.SchemeGroupVersion.WithResource("pods").GroupResource())
var podObjectCountName = generic.ObjectCountQuotaResourceNameFor(corev1.SchemeGroupVersion.WithResource("pods").GroupResource())
// podResources are the set of resources managed by quota associated with pods.
var podResources = []api.ResourceName{
var podResources = []corev1.ResourceName{
podObjectCountName,
api.ResourceCPU,
api.ResourceMemory,
api.ResourceEphemeralStorage,
api.ResourceRequestsCPU,
api.ResourceRequestsMemory,
api.ResourceRequestsEphemeralStorage,
api.ResourceLimitsCPU,
api.ResourceLimitsMemory,
api.ResourceLimitsEphemeralStorage,
api.ResourcePods,
corev1.ResourceCPU,
corev1.ResourceMemory,
corev1.ResourceEphemeralStorage,
corev1.ResourceRequestsCPU,
corev1.ResourceRequestsMemory,
corev1.ResourceRequestsEphemeralStorage,
corev1.ResourceLimitsCPU,
corev1.ResourceLimitsMemory,
corev1.ResourceLimitsEphemeralStorage,
corev1.ResourcePods,
}
// podResourcePrefixes are the set of prefixes for resources (Hugepages, and other
// potential extended reources with specific prefix) managed by quota associated with pods.
var podResourcePrefixes = []string{
api.ResourceHugePagesPrefix,
api.ResourceRequestsHugePagesPrefix,
corev1.ResourceHugePagesPrefix,
corev1.ResourceRequestsHugePagesPrefix,
}
// requestedResourcePrefixes are the set of prefixes for resources
// that might be declared in pod's Resources.Requests/Limits
var requestedResourcePrefixes = []string{
api.ResourceHugePagesPrefix,
corev1.ResourceHugePagesPrefix,
}
// maskResourceWithPrefix mask resource with certain prefix
// e.g. hugepages-XXX -> requests.hugepages-XXX
func maskResourceWithPrefix(resource api.ResourceName, prefix string) api.ResourceName {
return api.ResourceName(fmt.Sprintf("%s%s", prefix, string(resource)))
func maskResourceWithPrefix(resource corev1.ResourceName, prefix string) corev1.ResourceName {
return corev1.ResourceName(fmt.Sprintf("%s%s", prefix, string(resource)))
}
// isExtendedResourceNameForQuota returns true if the extended resource name
// has the quota related resource prefix.
func isExtendedResourceNameForQuota(name api.ResourceName) bool {
func isExtendedResourceNameForQuota(name corev1.ResourceName) bool {
// As overcommit is not supported by extended resources for now,
// only quota objects in format of "requests.resourceName" is allowed.
return !helper.IsNativeResource(name) && strings.HasPrefix(string(name), api.DefaultResourceRequestsPrefix)
return !helper.IsNativeResource(name) && strings.HasPrefix(string(name), corev1.DefaultResourceRequestsPrefix)
}
// NOTE: it was a mistake, but if a quota tracks cpu or memory related resources,
@ -90,17 +90,17 @@ func isExtendedResourceNameForQuota(name api.ResourceName) bool {
// this mistake for other future resources (gpus, ephemeral-storage,etc).
// do not add more resources to this list!
var validationSet = sets.NewString(
string(api.ResourceCPU),
string(api.ResourceMemory),
string(api.ResourceRequestsCPU),
string(api.ResourceRequestsMemory),
string(api.ResourceLimitsCPU),
string(api.ResourceLimitsMemory),
string(corev1.ResourceCPU),
string(corev1.ResourceMemory),
string(corev1.ResourceRequestsCPU),
string(corev1.ResourceRequestsMemory),
string(corev1.ResourceLimitsCPU),
string(corev1.ResourceLimitsMemory),
)
// NewPodEvaluator returns an evaluator that can evaluate pods
func NewPodEvaluator(f quota.ListerForResourceFunc, clock clock.Clock) quota.Evaluator {
listFuncByNamespace := generic.ListResourceUsingListerFunc(f, v1.SchemeGroupVersion.WithResource("pods"))
listFuncByNamespace := generic.ListResourceUsingListerFunc(f, corev1.SchemeGroupVersion.WithResource("pods"))
podEvaluator := &podEvaluator{listFuncByNamespace: listFuncByNamespace, clock: clock}
return podEvaluator
}
@ -115,10 +115,10 @@ type podEvaluator struct {
// Constraints verifies that all required resources are present on the pod
// In addition, it validates that the resources are valid (i.e. requests < limits)
func (p *podEvaluator) Constraints(required []api.ResourceName, item runtime.Object) error {
pod, ok := item.(*api.Pod)
if !ok {
return fmt.Errorf("unexpected input object %v", item)
func (p *podEvaluator) Constraints(required []corev1.ResourceName, item runtime.Object) error {
pod, err := toExternalPodOrError(item)
if err != nil {
return err
}
// BACKWARD COMPATIBILITY REQUIREMENT: if we quota cpu or memory, then each container
@ -141,7 +141,7 @@ func (p *podEvaluator) Constraints(required []api.ResourceName, item runtime.Obj
// GroupResource that this evaluator tracks
func (p *podEvaluator) GroupResource() schema.GroupResource {
return v1.SchemeGroupVersion.WithResource("pods").GroupResource()
return corev1.SchemeGroupVersion.WithResource("pods").GroupResource()
}
// Handles returns true if the evaluator should handle the specified attributes.
@ -161,12 +161,12 @@ func (p *podEvaluator) Handles(a admission.Attributes) bool {
}
// Matches returns true if the evaluator matches the specified quota with the provided input item
func (p *podEvaluator) Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error) {
func (p *podEvaluator) Matches(resourceQuota *corev1.ResourceQuota, item runtime.Object) (bool, error) {
return generic.Matches(resourceQuota, item, p.MatchingResources, podMatchesScopeFunc)
}
// MatchingResources takes the input specified list of resources and returns the set of resources it matches.
func (p *podEvaluator) MatchingResources(input []api.ResourceName) []api.ResourceName {
func (p *podEvaluator) MatchingResources(input []corev1.ResourceName) []corev1.ResourceName {
result := quota.Intersection(input, podResources)
for _, resource := range input {
// for resources with certain prefix, e.g. hugepages
@ -183,12 +183,12 @@ func (p *podEvaluator) MatchingResources(input []api.ResourceName) []api.Resourc
}
// MatchingScopes takes the input specified list of scopes and pod object. Returns the set of scope selectors pod matches.
func (p *podEvaluator) MatchingScopes(item runtime.Object, scopeSelectors []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
matchedScopes := []api.ScopedResourceSelectorRequirement{}
func (p *podEvaluator) MatchingScopes(item runtime.Object, scopeSelectors []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
matchedScopes := []corev1.ScopedResourceSelectorRequirement{}
for _, selector := range scopeSelectors {
match, err := podMatchesScopeFunc(selector, item)
if err != nil {
return []api.ScopedResourceSelectorRequirement{}, fmt.Errorf("error on matching scope %v: %v", selector, err)
return []corev1.ScopedResourceSelectorRequirement{}, fmt.Errorf("error on matching scope %v: %v", selector, err)
}
if match {
matchedScopes = append(matchedScopes, selector)
@ -199,8 +199,8 @@ func (p *podEvaluator) MatchingScopes(item runtime.Object, scopeSelectors []api.
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes.
// It returns the scopes which are in limited scopes but dont have a corresponding covering quota scope
func (p *podEvaluator) UncoveredQuotaScopes(limitedScopes []api.ScopedResourceSelectorRequirement, matchedQuotaScopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
uncoveredScopes := []api.ScopedResourceSelectorRequirement{}
func (p *podEvaluator) UncoveredQuotaScopes(limitedScopes []corev1.ScopedResourceSelectorRequirement, matchedQuotaScopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
uncoveredScopes := []corev1.ScopedResourceSelectorRequirement{}
for _, selector := range limitedScopes {
isCovered := false
for _, matchedScopeSelector := range matchedQuotaScopes {
@ -218,7 +218,7 @@ func (p *podEvaluator) UncoveredQuotaScopes(limitedScopes []api.ScopedResourceSe
}
// Usage knows how to measure usage associated with pods
func (p *podEvaluator) Usage(item runtime.Object) (api.ResourceList, error) {
func (p *podEvaluator) Usage(item runtime.Object) (corev1.ResourceList, error) {
// delegate to normal usage
return PodUsageFunc(item, p.clock)
}
@ -233,7 +233,7 @@ var _ quota.Evaluator = &podEvaluator{}
// enforcePodContainerConstraints checks for required resources that are not set on this container and
// adds them to missingSet.
func enforcePodContainerConstraints(container *api.Container, requiredSet, missingSet sets.String) {
func enforcePodContainerConstraints(container *corev1.Container, requiredSet, missingSet sets.String) {
requests := container.Resources.Requests
limits := container.Resources.Limits
containerUsage := podComputeUsageHelper(requests, limits)
@ -245,55 +245,55 @@ func enforcePodContainerConstraints(container *api.Container, requiredSet, missi
}
// podComputeUsageHelper can summarize the pod compute quota usage based on requests and limits
func podComputeUsageHelper(requests api.ResourceList, limits api.ResourceList) api.ResourceList {
result := api.ResourceList{}
result[api.ResourcePods] = resource.MustParse("1")
if request, found := requests[api.ResourceCPU]; found {
result[api.ResourceCPU] = request
result[api.ResourceRequestsCPU] = request
func podComputeUsageHelper(requests corev1.ResourceList, limits corev1.ResourceList) corev1.ResourceList {
result := corev1.ResourceList{}
result[corev1.ResourcePods] = resource.MustParse("1")
if request, found := requests[corev1.ResourceCPU]; found {
result[corev1.ResourceCPU] = request
result[corev1.ResourceRequestsCPU] = request
}
if limit, found := limits[api.ResourceCPU]; found {
result[api.ResourceLimitsCPU] = limit
if limit, found := limits[corev1.ResourceCPU]; found {
result[corev1.ResourceLimitsCPU] = limit
}
if request, found := requests[api.ResourceMemory]; found {
result[api.ResourceMemory] = request
result[api.ResourceRequestsMemory] = request
if request, found := requests[corev1.ResourceMemory]; found {
result[corev1.ResourceMemory] = request
result[corev1.ResourceRequestsMemory] = request
}
if limit, found := limits[api.ResourceMemory]; found {
result[api.ResourceLimitsMemory] = limit
if limit, found := limits[corev1.ResourceMemory]; found {
result[corev1.ResourceLimitsMemory] = limit
}
if request, found := requests[api.ResourceEphemeralStorage]; found {
result[api.ResourceEphemeralStorage] = request
result[api.ResourceRequestsEphemeralStorage] = request
if request, found := requests[corev1.ResourceEphemeralStorage]; found {
result[corev1.ResourceEphemeralStorage] = request
result[corev1.ResourceRequestsEphemeralStorage] = request
}
if limit, found := limits[api.ResourceEphemeralStorage]; found {
result[api.ResourceLimitsEphemeralStorage] = limit
if limit, found := limits[corev1.ResourceEphemeralStorage]; found {
result[corev1.ResourceLimitsEphemeralStorage] = limit
}
for resource, request := range requests {
// for resources with certain prefix, e.g. hugepages
if quota.ContainsPrefix(requestedResourcePrefixes, resource) {
result[resource] = request
result[maskResourceWithPrefix(resource, api.DefaultResourceRequestsPrefix)] = request
result[maskResourceWithPrefix(resource, corev1.DefaultResourceRequestsPrefix)] = request
}
// for extended resources
if helper.IsExtendedResourceName(resource) {
// only quota objects in format of "requests.resourceName" is allowed for extended resource.
result[maskResourceWithPrefix(resource, api.DefaultResourceRequestsPrefix)] = request
result[maskResourceWithPrefix(resource, corev1.DefaultResourceRequestsPrefix)] = request
}
}
return result
}
func toInternalPodOrError(obj runtime.Object) (*api.Pod, error) {
pod := &api.Pod{}
func toExternalPodOrError(obj runtime.Object) (*corev1.Pod, error) {
pod := &corev1.Pod{}
switch t := obj.(type) {
case *v1.Pod:
if err := k8s_api_v1.Convert_v1_Pod_To_core_Pod(t, pod, nil); err != nil {
case *corev1.Pod:
pod = t
case *api.Pod:
if err := k8s_api_v1.Convert_core_Pod_To_v1_Pod(t, pod, nil); err != nil {
return nil, err
}
case *api.Pod:
pod = t
default:
return nil, fmt.Errorf("expect *api.Pod or *v1.Pod, got %v", t)
}
@ -301,21 +301,21 @@ func toInternalPodOrError(obj runtime.Object) (*api.Pod, error) {
}
// podMatchesScopeFunc is a function that knows how to evaluate if a pod matches a scope
func podMatchesScopeFunc(selector api.ScopedResourceSelectorRequirement, object runtime.Object) (bool, error) {
pod, err := toInternalPodOrError(object)
func podMatchesScopeFunc(selector corev1.ScopedResourceSelectorRequirement, object runtime.Object) (bool, error) {
pod, err := toExternalPodOrError(object)
if err != nil {
return false, err
}
switch selector.ScopeName {
case api.ResourceQuotaScopeTerminating:
case corev1.ResourceQuotaScopeTerminating:
return isTerminating(pod), nil
case api.ResourceQuotaScopeNotTerminating:
case corev1.ResourceQuotaScopeNotTerminating:
return !isTerminating(pod), nil
case api.ResourceQuotaScopeBestEffort:
case corev1.ResourceQuotaScopeBestEffort:
return isBestEffort(pod), nil
case api.ResourceQuotaScopeNotBestEffort:
case corev1.ResourceQuotaScopeNotBestEffort:
return !isBestEffort(pod), nil
case api.ResourceQuotaScopePriorityClass:
case corev1.ResourceQuotaScopePriorityClass:
return podMatchesSelector(pod, selector)
}
return false, nil
@ -325,28 +325,28 @@ func podMatchesScopeFunc(selector api.ScopedResourceSelectorRequirement, object
// A pod is charged for quota if the following are not true.
// - pod has a terminal phase (failed or succeeded)
// - pod has been marked for deletion and grace period has expired
func PodUsageFunc(obj runtime.Object, clock clock.Clock) (api.ResourceList, error) {
pod, err := toInternalPodOrError(obj)
func PodUsageFunc(obj runtime.Object, clock clock.Clock) (corev1.ResourceList, error) {
pod, err := toExternalPodOrError(obj)
if err != nil {
return api.ResourceList{}, err
return corev1.ResourceList{}, err
}
// always quota the object count (even if the pod is end of life)
// object count quotas track all objects that are in storage.
// where "pods" tracks all pods that have not reached a terminal state,
// count/pods tracks all pods independent of state.
result := api.ResourceList{
result := corev1.ResourceList{
podObjectCountName: *(resource.NewQuantity(1, resource.DecimalSI)),
}
// by convention, we do not quota compute resources that have reached end-of life
// note: the "pods" resource is considered a compute resource since it is tied to life-cycle.
if !QuotaPod(pod, clock) {
if !QuotaV1Pod(pod, clock) {
return result, nil
}
requests := api.ResourceList{}
limits := api.ResourceList{}
requests := corev1.ResourceList{}
limits := corev1.ResourceList{}
// TODO: ideally, we have pod level requests and limits in the future.
for i := range pod.Spec.Containers {
requests = quota.Add(requests, pod.Spec.Containers[i].Resources.Requests)
@ -364,59 +364,37 @@ func PodUsageFunc(obj runtime.Object, clock clock.Clock) (api.ResourceList, erro
return result, nil
}
func isBestEffort(pod *api.Pod) bool {
return qos.GetPodQOS(pod) == api.PodQOSBestEffort
func isBestEffort(pod *corev1.Pod) bool {
return qos.GetPodQOS(pod) == corev1.PodQOSBestEffort
}
func isTerminating(pod *api.Pod) bool {
func isTerminating(pod *corev1.Pod) bool {
if pod.Spec.ActiveDeadlineSeconds != nil && *pod.Spec.ActiveDeadlineSeconds >= int64(0) {
return true
}
return false
}
func podMatchesSelector(pod *api.Pod, selector api.ScopedResourceSelectorRequirement) (bool, error) {
func podMatchesSelector(pod *corev1.Pod, selector corev1.ScopedResourceSelectorRequirement) (bool, error) {
labelSelector, err := helper.ScopedResourceSelectorRequirementsAsSelector(selector)
if err != nil {
return false, fmt.Errorf("failed to parse and convert selector: %v", err)
}
m := map[string]string{string(api.ResourceQuotaScopePriorityClass): pod.Spec.PriorityClassName}
var m map[string]string
if len(pod.Spec.PriorityClassName) != 0 {
m = map[string]string{string(corev1.ResourceQuotaScopePriorityClass): pod.Spec.PriorityClassName}
}
if labelSelector.Matches(labels.Set(m)) {
return true, nil
}
return false, nil
}
// QuotaPod returns true if the pod is eligible to track against a quota
// A pod is eligible for quota, unless any of the following are true:
// - pod has a terminal phase (failed or succeeded)
// - pod has been marked for deletion and grace period has expired.
func QuotaPod(pod *api.Pod, clock clock.Clock) bool {
// if pod is terminal, ignore it for quota
if api.PodFailed == pod.Status.Phase || api.PodSucceeded == pod.Status.Phase {
return false
}
// deleted pods that should be gone should not be charged to user quota.
// this can happen if a node is lost, and the kubelet is never able to confirm deletion.
// even though the cluster may have drifting clocks, quota makes a reasonable effort
// to balance cluster needs against user needs. user's do not control clocks,
// but at worst a small drive in clocks will only slightly impact quota.
if pod.DeletionTimestamp != nil && pod.DeletionGracePeriodSeconds != nil {
now := clock.Now()
deletionTime := pod.DeletionTimestamp.Time
gracePeriod := time.Duration(*pod.DeletionGracePeriodSeconds) * time.Second
if now.After(deletionTime.Add(gracePeriod)) {
return false
}
}
return true
}
// QuotaV1Pod returns true if the pod is eligible to track against a quota
// if it's not in a terminal state according to its phase.
func QuotaV1Pod(pod *v1.Pod, clock clock.Clock) bool {
func QuotaV1Pod(pod *corev1.Pod, clock clock.Clock) bool {
// if pod is terminal, ignore it for quota
if v1.PodFailed == pod.Status.Phase || v1.PodSucceeded == pod.Status.Phase {
if corev1.PodFailed == pod.Status.Phase || corev1.PodSucceeded == pod.Status.Phase {
return false
}
// if pods are stuck terminating (for example, a node is lost), we do not want

View File

@ -20,20 +20,21 @@ import (
"testing"
"time"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/clock"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
"k8s.io/kubernetes/pkg/util/node"
)
func TestPodConstraintsFunc(t *testing.T) {
testCases := map[string]struct {
pod *api.Pod
required []api.ResourceName
required []corev1.ResourceName
err string
}{
"init container resource missing": {
@ -47,7 +48,7 @@ func TestPodConstraintsFunc(t *testing.T) {
}},
},
},
required: []api.ResourceName{api.ResourceMemory},
required: []corev1.ResourceName{corev1.ResourceMemory},
err: `must specify memory`,
},
"container resource missing": {
@ -61,7 +62,7 @@ func TestPodConstraintsFunc(t *testing.T) {
}},
},
},
required: []api.ResourceName{api.ResourceMemory},
required: []corev1.ResourceName{corev1.ResourceMemory},
err: `must specify memory`,
},
}
@ -90,7 +91,7 @@ func TestPodEvaluatorUsage(t *testing.T) {
testCases := map[string]struct {
pod *api.Pod
usage api.ResourceList
usage corev1.ResourceList
}{
"init container CPU": {
pod: &api.Pod{
@ -103,11 +104,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceRequestsCPU: resource.MustParse("1m"),
api.ResourceLimitsCPU: resource.MustParse("2m"),
api.ResourcePods: resource.MustParse("1"),
api.ResourceCPU: resource.MustParse("1m"),
usage: corev1.ResourceList{
corev1.ResourceRequestsCPU: resource.MustParse("1m"),
corev1.ResourceLimitsCPU: resource.MustParse("2m"),
corev1.ResourcePods: resource.MustParse("1"),
corev1.ResourceCPU: resource.MustParse("1m"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -122,11 +123,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceRequestsMemory: resource.MustParse("1m"),
api.ResourceLimitsMemory: resource.MustParse("2m"),
api.ResourcePods: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1m"),
usage: corev1.ResourceList{
corev1.ResourceRequestsMemory: resource.MustParse("1m"),
corev1.ResourceLimitsMemory: resource.MustParse("2m"),
corev1.ResourcePods: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("1m"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -141,11 +142,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceEphemeralStorage: resource.MustParse("32Mi"),
api.ResourceRequestsEphemeralStorage: resource.MustParse("32Mi"),
api.ResourceLimitsEphemeralStorage: resource.MustParse("64Mi"),
api.ResourcePods: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceEphemeralStorage: resource.MustParse("32Mi"),
corev1.ResourceRequestsEphemeralStorage: resource.MustParse("32Mi"),
corev1.ResourceLimitsEphemeralStorage: resource.MustParse("64Mi"),
corev1.ResourcePods: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -159,10 +160,10 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
api.ResourceName(api.ResourceRequestsHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
api.ResourcePods: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
corev1.ResourceName(corev1.ResourceRequestsHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
corev1.ResourcePods: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -177,9 +178,9 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceName("requests.example.com/dongle"): resource.MustParse("3"),
api.ResourcePods: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceName("requests.example.com/dongle"): resource.MustParse("3"),
corev1.ResourcePods: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -194,11 +195,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceRequestsCPU: resource.MustParse("1m"),
api.ResourceLimitsCPU: resource.MustParse("2m"),
api.ResourcePods: resource.MustParse("1"),
api.ResourceCPU: resource.MustParse("1m"),
usage: corev1.ResourceList{
corev1.ResourceRequestsCPU: resource.MustParse("1m"),
corev1.ResourceLimitsCPU: resource.MustParse("2m"),
corev1.ResourcePods: resource.MustParse("1"),
corev1.ResourceCPU: resource.MustParse("1m"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -213,11 +214,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceRequestsMemory: resource.MustParse("1m"),
api.ResourceLimitsMemory: resource.MustParse("2m"),
api.ResourcePods: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1m"),
usage: corev1.ResourceList{
corev1.ResourceRequestsMemory: resource.MustParse("1m"),
corev1.ResourceLimitsMemory: resource.MustParse("2m"),
corev1.ResourcePods: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("1m"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -232,11 +233,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceEphemeralStorage: resource.MustParse("32Mi"),
api.ResourceRequestsEphemeralStorage: resource.MustParse("32Mi"),
api.ResourceLimitsEphemeralStorage: resource.MustParse("64Mi"),
api.ResourcePods: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceEphemeralStorage: resource.MustParse("32Mi"),
corev1.ResourceRequestsEphemeralStorage: resource.MustParse("32Mi"),
corev1.ResourceLimitsEphemeralStorage: resource.MustParse("64Mi"),
corev1.ResourcePods: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -250,10 +251,10 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
api.ResourceName(api.ResourceRequestsHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
api.ResourcePods: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
corev1.ResourceName(api.ResourceRequestsHugePagesPrefix + "2Mi"): resource.MustParse("100Mi"),
corev1.ResourcePods: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -268,9 +269,9 @@ func TestPodEvaluatorUsage(t *testing.T) {
}},
},
},
usage: api.ResourceList{
api.ResourceName("requests.example.com/dongle"): resource.MustParse("3"),
api.ResourcePods: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceName("requests.example.com/dongle"): resource.MustParse("3"),
corev1.ResourcePods: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -339,15 +340,15 @@ func TestPodEvaluatorUsage(t *testing.T) {
},
},
},
usage: api.ResourceList{
api.ResourceRequestsCPU: resource.MustParse("4"),
api.ResourceRequestsMemory: resource.MustParse("100M"),
api.ResourceLimitsCPU: resource.MustParse("8"),
api.ResourceLimitsMemory: resource.MustParse("200M"),
api.ResourcePods: resource.MustParse("1"),
api.ResourceCPU: resource.MustParse("4"),
api.ResourceMemory: resource.MustParse("100M"),
api.ResourceName("requests.example.com/dongle"): resource.MustParse("4"),
usage: corev1.ResourceList{
corev1.ResourceRequestsCPU: resource.MustParse("4"),
corev1.ResourceRequestsMemory: resource.MustParse("100M"),
corev1.ResourceLimitsCPU: resource.MustParse("8"),
corev1.ResourceLimitsMemory: resource.MustParse("200M"),
corev1.ResourcePods: resource.MustParse("1"),
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("100M"),
corev1.ResourceName("requests.example.com/dongle"): resource.MustParse("4"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -378,7 +379,7 @@ func TestPodEvaluatorUsage(t *testing.T) {
},
},
},
usage: api.ResourceList{
usage: corev1.ResourceList{
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},
@ -406,11 +407,11 @@ func TestPodEvaluatorUsage(t *testing.T) {
},
},
},
usage: api.ResourceList{
api.ResourceRequestsCPU: resource.MustParse("1"),
api.ResourceLimitsCPU: resource.MustParse("2"),
api.ResourcePods: resource.MustParse("1"),
api.ResourceCPU: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceRequestsCPU: resource.MustParse("1"),
corev1.ResourceLimitsCPU: resource.MustParse("2"),
corev1.ResourcePods: resource.MustParse("1"),
corev1.ResourceCPU: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "pods"}): resource.MustParse("1"),
},
},

View File

@ -17,20 +17,19 @@ limitations under the License.
package core
import (
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/clock"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
)
// legacyObjectCountAliases are what we used to do simple object counting quota with mapped to alias
var legacyObjectCountAliases = map[schema.GroupVersionResource]api.ResourceName{
v1.SchemeGroupVersion.WithResource("configmaps"): api.ResourceConfigMaps,
v1.SchemeGroupVersion.WithResource("resourcequotas"): api.ResourceQuotas,
v1.SchemeGroupVersion.WithResource("replicationcontrollers"): api.ResourceReplicationControllers,
v1.SchemeGroupVersion.WithResource("secrets"): api.ResourceSecrets,
var legacyObjectCountAliases = map[schema.GroupVersionResource]corev1.ResourceName{
corev1.SchemeGroupVersion.WithResource("configmaps"): corev1.ResourceConfigMaps,
corev1.SchemeGroupVersion.WithResource("resourcequotas"): corev1.ResourceQuotas,
corev1.SchemeGroupVersion.WithResource("replicationcontrollers"): corev1.ResourceReplicationControllers,
corev1.SchemeGroupVersion.WithResource("secrets"): corev1.ResourceSecrets,
}
// NewEvaluators returns the list of static evaluators that manage more than counts
@ -44,7 +43,7 @@ func NewEvaluators(f quota.ListerForResourceFunc) []quota.Evaluator {
// these evaluators require an alias for backwards compatibility
for gvr, alias := range legacyObjectCountAliases {
result = append(result,
generic.NewObjectCountEvaluator(false, gvr.GroupResource(), generic.ListResourceUsingListerFunc(f, gvr), alias))
generic.NewObjectCountEvaluator(gvr.GroupResource(), generic.ListResourceUsingListerFunc(f, gvr), alias))
}
return result
}

View File

@ -19,31 +19,31 @@ package core
import (
"fmt"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
api "k8s.io/kubernetes/pkg/apis/core"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
"k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
)
// the name used for object count quota
var serviceObjectCountName = generic.ObjectCountQuotaResourceNameFor(v1.SchemeGroupVersion.WithResource("services").GroupResource())
var serviceObjectCountName = generic.ObjectCountQuotaResourceNameFor(corev1.SchemeGroupVersion.WithResource("services").GroupResource())
// serviceResources are the set of resources managed by quota associated with services.
var serviceResources = []api.ResourceName{
var serviceResources = []corev1.ResourceName{
serviceObjectCountName,
api.ResourceServices,
api.ResourceServicesNodePorts,
api.ResourceServicesLoadBalancers,
corev1.ResourceServices,
corev1.ResourceServicesNodePorts,
corev1.ResourceServicesLoadBalancers,
}
// NewServiceEvaluator returns an evaluator that can evaluate services.
func NewServiceEvaluator(f quota.ListerForResourceFunc) quota.Evaluator {
listFuncByNamespace := generic.ListResourceUsingListerFunc(f, v1.SchemeGroupVersion.WithResource("services"))
listFuncByNamespace := generic.ListResourceUsingListerFunc(f, corev1.SchemeGroupVersion.WithResource("services"))
serviceEvaluator := &serviceEvaluator{listFuncByNamespace: listFuncByNamespace}
return serviceEvaluator
}
@ -55,14 +55,14 @@ type serviceEvaluator struct {
}
// Constraints verifies that all required resources are present on the item
func (p *serviceEvaluator) Constraints(required []api.ResourceName, item runtime.Object) error {
func (p *serviceEvaluator) Constraints(required []corev1.ResourceName, item runtime.Object) error {
// this is a no-op for services
return nil
}
// GroupResource that this evaluator tracks
func (p *serviceEvaluator) GroupResource() schema.GroupResource {
return v1.SchemeGroupVersion.WithResource("services").GroupResource()
return corev1.SchemeGroupVersion.WithResource("services").GroupResource()
}
// Handles returns true of the evaluator should handle the specified operation.
@ -73,36 +73,36 @@ func (p *serviceEvaluator) Handles(a admission.Attributes) bool {
}
// Matches returns true if the evaluator matches the specified quota with the provided input item
func (p *serviceEvaluator) Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error) {
func (p *serviceEvaluator) Matches(resourceQuota *corev1.ResourceQuota, item runtime.Object) (bool, error) {
return generic.Matches(resourceQuota, item, p.MatchingResources, generic.MatchesNoScopeFunc)
}
// MatchingResources takes the input specified list of resources and returns the set of resources it matches.
func (p *serviceEvaluator) MatchingResources(input []api.ResourceName) []api.ResourceName {
func (p *serviceEvaluator) MatchingResources(input []corev1.ResourceName) []corev1.ResourceName {
return quota.Intersection(input, serviceResources)
}
// MatchingScopes takes the input specified list of scopes and input object. Returns the set of scopes resource matches.
func (p *serviceEvaluator) MatchingScopes(item runtime.Object, scopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
return []api.ScopedResourceSelectorRequirement{}, nil
func (p *serviceEvaluator) MatchingScopes(item runtime.Object, scopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
return []corev1.ScopedResourceSelectorRequirement{}, nil
}
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes.
// It returns the scopes which are in limited scopes but dont have a corresponding covering quota scope
func (p *serviceEvaluator) UncoveredQuotaScopes(limitedScopes []api.ScopedResourceSelectorRequirement, matchedQuotaScopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
return []api.ScopedResourceSelectorRequirement{}, nil
func (p *serviceEvaluator) UncoveredQuotaScopes(limitedScopes []corev1.ScopedResourceSelectorRequirement, matchedQuotaScopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
return []corev1.ScopedResourceSelectorRequirement{}, nil
}
// convert the input object to an internal service object or error.
func toInternalServiceOrError(obj runtime.Object) (*api.Service, error) {
svc := &api.Service{}
func toExternalServiceOrError(obj runtime.Object) (*corev1.Service, error) {
svc := &corev1.Service{}
switch t := obj.(type) {
case *v1.Service:
if err := k8s_api_v1.Convert_v1_Service_To_core_Service(t, svc, nil); err != nil {
case *corev1.Service:
svc = t
case *api.Service:
if err := k8s_api_v1.Convert_core_Service_To_v1_Service(t, svc, nil); err != nil {
return nil, err
}
case *api.Service:
svc = t
default:
return nil, fmt.Errorf("expect *api.Service or *v1.Service, got %v", t)
}
@ -110,28 +110,28 @@ func toInternalServiceOrError(obj runtime.Object) (*api.Service, error) {
}
// Usage knows how to measure usage associated with services
func (p *serviceEvaluator) Usage(item runtime.Object) (api.ResourceList, error) {
result := api.ResourceList{}
svc, err := toInternalServiceOrError(item)
func (p *serviceEvaluator) Usage(item runtime.Object) (corev1.ResourceList, error) {
result := corev1.ResourceList{}
svc, err := toExternalServiceOrError(item)
if err != nil {
return result, err
}
ports := len(svc.Spec.Ports)
// default service usage
result[serviceObjectCountName] = *(resource.NewQuantity(1, resource.DecimalSI))
result[api.ResourceServices] = *(resource.NewQuantity(1, resource.DecimalSI))
result[api.ResourceServicesLoadBalancers] = resource.Quantity{Format: resource.DecimalSI}
result[api.ResourceServicesNodePorts] = resource.Quantity{Format: resource.DecimalSI}
result[corev1.ResourceServices] = *(resource.NewQuantity(1, resource.DecimalSI))
result[corev1.ResourceServicesLoadBalancers] = resource.Quantity{Format: resource.DecimalSI}
result[corev1.ResourceServicesNodePorts] = resource.Quantity{Format: resource.DecimalSI}
switch svc.Spec.Type {
case api.ServiceTypeNodePort:
case corev1.ServiceTypeNodePort:
// node port services need to count node ports
value := resource.NewQuantity(int64(ports), resource.DecimalSI)
result[api.ResourceServicesNodePorts] = *value
case api.ServiceTypeLoadBalancer:
result[corev1.ResourceServicesNodePorts] = *value
case corev1.ServiceTypeLoadBalancer:
// load balancer services need to count node ports and load balancers
value := resource.NewQuantity(int64(ports), resource.DecimalSI)
result[api.ResourceServicesNodePorts] = *value
result[api.ResourceServicesLoadBalancers] = *(resource.NewQuantity(1, resource.DecimalSI))
result[corev1.ResourceServicesNodePorts] = *value
result[corev1.ResourceServicesLoadBalancers] = *(resource.NewQuantity(1, resource.DecimalSI))
}
return result, nil
}
@ -144,12 +144,12 @@ func (p *serviceEvaluator) UsageStats(options quota.UsageStatsOptions) (quota.Us
var _ quota.Evaluator = &serviceEvaluator{}
//GetQuotaServiceType returns ServiceType if the service type is eligible to track against a quota, nor return ""
func GetQuotaServiceType(service *v1.Service) v1.ServiceType {
func GetQuotaServiceType(service *corev1.Service) corev1.ServiceType {
switch service.Spec.Type {
case v1.ServiceTypeNodePort:
return v1.ServiceTypeNodePort
case v1.ServiceTypeLoadBalancer:
return v1.ServiceTypeLoadBalancer
case corev1.ServiceTypeNodePort:
return corev1.ServiceTypeNodePort
case corev1.ServiceTypeLoadBalancer:
return corev1.ServiceTypeLoadBalancer
}
return v1.ServiceType("")
return corev1.ServiceType("")
}

View File

@ -19,28 +19,29 @@ package core
import (
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime/schema"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
"k8s.io/kubernetes/pkg/quota/v1/generic"
)
func TestServiceEvaluatorMatchesResources(t *testing.T) {
evaluator := NewServiceEvaluator(nil)
// we give a lot of resources
input := []api.ResourceName{
api.ResourceConfigMaps,
api.ResourceCPU,
api.ResourceServices,
api.ResourceServicesNodePorts,
api.ResourceServicesLoadBalancers,
input := []corev1.ResourceName{
corev1.ResourceConfigMaps,
corev1.ResourceCPU,
corev1.ResourceServices,
corev1.ResourceServicesNodePorts,
corev1.ResourceServicesLoadBalancers,
}
// but we only match these...
expected := quota.ToSet([]api.ResourceName{
api.ResourceServices,
api.ResourceServicesNodePorts,
api.ResourceServicesLoadBalancers,
expected := quota.ToSet([]corev1.ResourceName{
corev1.ResourceServices,
corev1.ResourceServicesNodePorts,
corev1.ResourceServicesLoadBalancers,
})
actual := quota.ToSet(evaluator.MatchingResources(input))
if !expected.Equal(actual) {
@ -52,7 +53,7 @@ func TestServiceEvaluatorUsage(t *testing.T) {
evaluator := NewServiceEvaluator(nil)
testCases := map[string]struct {
service *api.Service
usage api.ResourceList
usage corev1.ResourceList
}{
"loadbalancer": {
service: &api.Service{
@ -60,10 +61,10 @@ func TestServiceEvaluatorUsage(t *testing.T) {
Type: api.ServiceTypeLoadBalancer,
},
},
usage: api.ResourceList{
api.ResourceServicesNodePorts: resource.MustParse("0"),
api.ResourceServicesLoadBalancers: resource.MustParse("1"),
api.ResourceServices: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceServicesNodePorts: resource.MustParse("0"),
corev1.ResourceServicesLoadBalancers: resource.MustParse("1"),
corev1.ResourceServices: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
},
@ -78,10 +79,10 @@ func TestServiceEvaluatorUsage(t *testing.T) {
},
},
},
usage: api.ResourceList{
api.ResourceServicesNodePorts: resource.MustParse("1"),
api.ResourceServicesLoadBalancers: resource.MustParse("1"),
api.ResourceServices: resource.MustParse("1"),
usage: corev1.ResourceList{
corev1.ResourceServicesNodePorts: resource.MustParse("1"),
corev1.ResourceServicesLoadBalancers: resource.MustParse("1"),
corev1.ResourceServices: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
},
@ -91,10 +92,10 @@ func TestServiceEvaluatorUsage(t *testing.T) {
Type: api.ServiceTypeClusterIP,
},
},
usage: api.ResourceList{
api.ResourceServices: resource.MustParse("1"),
api.ResourceServicesNodePorts: resource.MustParse("0"),
api.ResourceServicesLoadBalancers: resource.MustParse("0"),
usage: corev1.ResourceList{
corev1.ResourceServices: resource.MustParse("1"),
corev1.ResourceServicesNodePorts: resource.MustParse("0"),
corev1.ResourceServicesLoadBalancers: resource.MustParse("0"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
},
@ -109,10 +110,10 @@ func TestServiceEvaluatorUsage(t *testing.T) {
},
},
},
usage: api.ResourceList{
api.ResourceServices: resource.MustParse("1"),
api.ResourceServicesNodePorts: resource.MustParse("1"),
api.ResourceServicesLoadBalancers: resource.MustParse("0"),
usage: corev1.ResourceList{
corev1.ResourceServices: resource.MustParse("1"),
corev1.ResourceServicesNodePorts: resource.MustParse("1"),
corev1.ResourceServicesLoadBalancers: resource.MustParse("0"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
},
@ -130,10 +131,10 @@ func TestServiceEvaluatorUsage(t *testing.T) {
},
},
},
usage: api.ResourceList{
api.ResourceServices: resource.MustParse("1"),
api.ResourceServicesNodePorts: resource.MustParse("2"),
api.ResourceServicesLoadBalancers: resource.MustParse("0"),
usage: corev1.ResourceList{
corev1.ResourceServices: resource.MustParse("1"),
corev1.ResourceServicesNodePorts: resource.MustParse("2"),
corev1.ResourceServicesLoadBalancers: resource.MustParse("0"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
},
@ -152,7 +153,7 @@ func TestServiceEvaluatorUsage(t *testing.T) {
func TestServiceConstraintsFunc(t *testing.T) {
testCases := map[string]struct {
service *api.Service
required []api.ResourceName
required []corev1.ResourceName
err string
}{
"loadbalancer": {
@ -161,7 +162,7 @@ func TestServiceConstraintsFunc(t *testing.T) {
Type: api.ServiceTypeLoadBalancer,
},
},
required: []api.ResourceName{api.ResourceServicesLoadBalancers},
required: []corev1.ResourceName{corev1.ResourceServicesLoadBalancers},
},
"clusterip": {
service: &api.Service{
@ -169,7 +170,7 @@ func TestServiceConstraintsFunc(t *testing.T) {
Type: api.ServiceTypeClusterIP,
},
},
required: []api.ResourceName{api.ResourceServicesLoadBalancers, api.ResourceServices},
required: []corev1.ResourceName{corev1.ResourceServicesLoadBalancers, corev1.ResourceServices},
},
"nodeports": {
service: &api.Service{
@ -182,7 +183,7 @@ func TestServiceConstraintsFunc(t *testing.T) {
},
},
},
required: []api.ResourceName{api.ResourceServicesNodePorts},
required: []corev1.ResourceName{corev1.ResourceServicesNodePorts},
},
"multi-nodeports": {
service: &api.Service{
@ -198,7 +199,7 @@ func TestServiceConstraintsFunc(t *testing.T) {
},
},
},
required: []api.ResourceName{api.ResourceServicesNodePorts},
required: []corev1.ResourceName{corev1.ResourceServicesNodePorts},
},
}

40
vendor/k8s.io/kubernetes/pkg/quota/v1/generic/BUILD generated vendored Normal file
View File

@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"configuration.go",
"evaluator.go",
"registry.go",
],
importpath = "k8s.io/kubernetes/pkg/quota/v1/generic",
deps = [
"//pkg/quota/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -18,7 +18,7 @@ package generic
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/quota"
quota "k8s.io/kubernetes/pkg/quota/v1"
)
// implements a basic configuration

View File

@ -19,6 +19,7 @@ package generic
import (
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@ -26,8 +27,7 @@ import (
"k8s.io/apiserver/pkg/admission"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/quota"
quota "k8s.io/kubernetes/pkg/quota/v1"
)
// InformerForResourceFunc knows how to provision an informer
@ -56,33 +56,33 @@ func ListResourceUsingListerFunc(l quota.ListerForResourceFunc, resource schema.
}
// ObjectCountQuotaResourceNameFor returns the object count quota name for specified groupResource
func ObjectCountQuotaResourceNameFor(groupResource schema.GroupResource) api.ResourceName {
func ObjectCountQuotaResourceNameFor(groupResource schema.GroupResource) corev1.ResourceName {
if len(groupResource.Group) == 0 {
return api.ResourceName("count/" + groupResource.Resource)
return corev1.ResourceName("count/" + groupResource.Resource)
}
return api.ResourceName("count/" + groupResource.Resource + "." + groupResource.Group)
return corev1.ResourceName("count/" + groupResource.Resource + "." + groupResource.Group)
}
// ListFuncByNamespace knows how to list resources in a namespace
type ListFuncByNamespace func(namespace string) ([]runtime.Object, error)
// MatchesScopeFunc knows how to evaluate if an object matches a scope
type MatchesScopeFunc func(scope api.ScopedResourceSelectorRequirement, object runtime.Object) (bool, error)
type MatchesScopeFunc func(scope corev1.ScopedResourceSelectorRequirement, object runtime.Object) (bool, error)
// UsageFunc knows how to measure usage associated with an object
type UsageFunc func(object runtime.Object) (api.ResourceList, error)
type UsageFunc func(object runtime.Object) (corev1.ResourceList, error)
// MatchingResourceNamesFunc is a function that returns the list of resources matched
type MatchingResourceNamesFunc func(input []api.ResourceName) []api.ResourceName
type MatchingResourceNamesFunc func(input []corev1.ResourceName) []corev1.ResourceName
// MatchesNoScopeFunc returns false on all match checks
func MatchesNoScopeFunc(scope api.ScopedResourceSelectorRequirement, object runtime.Object) (bool, error) {
func MatchesNoScopeFunc(scope corev1.ScopedResourceSelectorRequirement, object runtime.Object) (bool, error) {
return false, nil
}
// Matches returns true if the quota matches the specified item.
func Matches(
resourceQuota *api.ResourceQuota, item runtime.Object,
resourceQuota *corev1.ResourceQuota, item runtime.Object,
matchFunc MatchingResourceNamesFunc, scopeFunc MatchesScopeFunc) (bool, error) {
if resourceQuota == nil {
return false, fmt.Errorf("expected non-nil quota")
@ -101,12 +101,12 @@ func Matches(
return matchResource && matchScope, nil
}
func getScopeSelectorsFromQuota(quota *api.ResourceQuota) []api.ScopedResourceSelectorRequirement {
selectors := []api.ScopedResourceSelectorRequirement{}
func getScopeSelectorsFromQuota(quota *corev1.ResourceQuota) []corev1.ScopedResourceSelectorRequirement {
selectors := []corev1.ScopedResourceSelectorRequirement{}
for _, scope := range quota.Spec.Scopes {
selectors = append(selectors, api.ScopedResourceSelectorRequirement{
selectors = append(selectors, corev1.ScopedResourceSelectorRequirement{
ScopeName: scope,
Operator: api.ScopeSelectorOpExists})
Operator: corev1.ScopeSelectorOpExists})
}
if quota.Spec.ScopeSelector != nil {
for _, scopeSelector := range quota.Spec.ScopeSelector.MatchExpressions {
@ -122,7 +122,7 @@ func CalculateUsageStats(options quota.UsageStatsOptions,
scopeFunc MatchesScopeFunc,
usageFunc UsageFunc) (quota.UsageStats, error) {
// default each tracked resource to zero
result := quota.UsageStats{Used: api.ResourceList{}}
result := quota.UsageStats{Used: corev1.ResourceList{}}
for _, resourceName := range options.Resources {
result.Used[resourceName] = resource.Quantity{Format: resource.DecimalSI}
}
@ -134,7 +134,7 @@ func CalculateUsageStats(options quota.UsageStatsOptions,
// need to verify that the item matches the set of scopes
matchesScopes := true
for _, scope := range options.Scopes {
innerMatch, err := scopeFunc(api.ScopedResourceSelectorRequirement{ScopeName: scope}, item)
innerMatch, err := scopeFunc(corev1.ScopedResourceSelectorRequirement{ScopeName: scope}, item)
if err != nil {
return result, nil
}
@ -167,9 +167,6 @@ func CalculateUsageStats(options quota.UsageStatsOptions,
// that associates usage of the specified resource based on the number of items
// returned by the specified listing function.
type objectCountEvaluator struct {
// allowCreateOnUpdate if true will ensure the evaluator tracks create
// and update operations.
allowCreateOnUpdate bool
// GroupResource that this evaluator tracks.
// It is used to construct a generic object count quota name
groupResource schema.GroupResource
@ -177,11 +174,11 @@ type objectCountEvaluator struct {
// TODO move to dynamic client in future
listFuncByNamespace ListFuncByNamespace
// Names associated with this resource in the quota for generic counting.
resourceNames []api.ResourceName
resourceNames []corev1.ResourceName
}
// Constraints returns an error if the configured resource name is not in the required set.
func (o *objectCountEvaluator) Constraints(required []api.ResourceName, item runtime.Object) error {
func (o *objectCountEvaluator) Constraints(required []corev1.ResourceName, item runtime.Object) error {
// no-op for object counting
return nil
}
@ -189,34 +186,34 @@ func (o *objectCountEvaluator) Constraints(required []api.ResourceName, item run
// Handles returns true if the object count evaluator needs to track this attributes.
func (o *objectCountEvaluator) Handles(a admission.Attributes) bool {
operation := a.GetOperation()
return operation == admission.Create || (o.allowCreateOnUpdate && operation == admission.Update)
return operation == admission.Create
}
// Matches returns true if the evaluator matches the specified quota with the provided input item
func (o *objectCountEvaluator) Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error) {
func (o *objectCountEvaluator) Matches(resourceQuota *corev1.ResourceQuota, item runtime.Object) (bool, error) {
return Matches(resourceQuota, item, o.MatchingResources, MatchesNoScopeFunc)
}
// MatchingResources takes the input specified list of resources and returns the set of resources it matches.
func (o *objectCountEvaluator) MatchingResources(input []api.ResourceName) []api.ResourceName {
func (o *objectCountEvaluator) MatchingResources(input []corev1.ResourceName) []corev1.ResourceName {
return quota.Intersection(input, o.resourceNames)
}
// MatchingScopes takes the input specified list of scopes and input object. Returns the set of scopes resource matches.
func (o *objectCountEvaluator) MatchingScopes(item runtime.Object, scopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
return []api.ScopedResourceSelectorRequirement{}, nil
func (o *objectCountEvaluator) MatchingScopes(item runtime.Object, scopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
return []corev1.ScopedResourceSelectorRequirement{}, nil
}
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes.
// It returns the scopes which are in limited scopes but dont have a corresponding covering quota scope
func (o *objectCountEvaluator) UncoveredQuotaScopes(limitedScopes []api.ScopedResourceSelectorRequirement, matchedQuotaScopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error) {
return []api.ScopedResourceSelectorRequirement{}, nil
func (o *objectCountEvaluator) UncoveredQuotaScopes(limitedScopes []corev1.ScopedResourceSelectorRequirement, matchedQuotaScopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error) {
return []corev1.ScopedResourceSelectorRequirement{}, nil
}
// Usage returns the resource usage for the specified object
func (o *objectCountEvaluator) Usage(object runtime.Object) (api.ResourceList, error) {
func (o *objectCountEvaluator) Usage(object runtime.Object) (corev1.ResourceList, error) {
quantity := resource.NewQuantity(1, resource.DecimalSI)
resourceList := api.ResourceList{}
resourceList := corev1.ResourceList{}
for _, resourceName := range o.resourceNames {
resourceList[resourceName] = *quantity
}
@ -241,17 +238,15 @@ var _ quota.Evaluator = &objectCountEvaluator{}
// purposes for the legacy object counting names in quota. Unless its supporting
// backward compatibility, alias should not be used.
func NewObjectCountEvaluator(
allowCreateOnUpdate bool,
groupResource schema.GroupResource, listFuncByNamespace ListFuncByNamespace,
alias api.ResourceName) quota.Evaluator {
alias corev1.ResourceName) quota.Evaluator {
resourceNames := []api.ResourceName{ObjectCountQuotaResourceNameFor(groupResource)}
resourceNames := []corev1.ResourceName{ObjectCountQuotaResourceNameFor(groupResource)}
if len(alias) > 0 {
resourceNames = append(resourceNames, alias)
}
return &objectCountEvaluator{
allowCreateOnUpdate: allowCreateOnUpdate,
groupResource: groupResource,
listFuncByNamespace: listFuncByNamespace,
resourceNames: resourceNames,

View File

@ -20,7 +20,7 @@ import (
"sync"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/quota"
quota "k8s.io/kubernetes/pkg/quota/v1"
)
// implements a basic registry

View File

@ -8,12 +8,12 @@ load(
go_library(
name = "go_default_library",
srcs = ["registry.go"],
importpath = "k8s.io/kubernetes/pkg/quota/install",
importpath = "k8s.io/kubernetes/pkg/quota/v1/install",
deps = [
"//pkg/quota:go_default_library",
"//pkg/quota/evaluator/core:go_default_library",
"//pkg/quota/generic:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//pkg/quota/v1:go_default_library",
"//pkg/quota/v1/evaluator/core:go_default_library",
"//pkg/quota/v1/generic:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)

View File

@ -18,9 +18,9 @@ package install
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/evaluator/core"
"k8s.io/kubernetes/pkg/quota/generic"
quota "k8s.io/kubernetes/pkg/quota/v1"
core "k8s.io/kubernetes/pkg/quota/v1/evaluator/core"
generic "k8s.io/kubernetes/pkg/quota/v1/generic"
)
// NewQuotaConfigurationForAdmission returns a quota configuration for admission control.
@ -37,18 +37,7 @@ func NewQuotaConfigurationForControllers(f quota.ListerForResourceFunc) quota.Co
// ignoredResources are ignored by quota by default
var ignoredResources = map[schema.GroupResource]struct{}{
{Group: "extensions", Resource: "replicationcontrollers"}: {},
{Group: "extensions", Resource: "networkpolicies"}: {},
{Group: "", Resource: "bindings"}: {},
{Group: "", Resource: "componentstatuses"}: {},
{Group: "", Resource: "events"}: {},
{Group: "authentication.k8s.io", Resource: "tokenreviews"}: {},
{Group: "authorization.k8s.io", Resource: "subjectaccessreviews"}: {},
{Group: "authorization.k8s.io", Resource: "selfsubjectaccessreviews"}: {},
{Group: "authorization.k8s.io", Resource: "localsubjectaccessreviews"}: {},
{Group: "authorization.k8s.io", Resource: "selfsubjectrulesreviews"}: {},
{Group: "apiregistration.k8s.io", Resource: "apiservices"}: {},
{Group: "apiextensions.k8s.io", Resource: "customresourcedefinitions"}: {},
{Group: "", Resource: "events"}: {},
}
// DefaultIgnoredResources returns the default set of resources that quota system

View File

@ -17,11 +17,11 @@ limitations under the License.
package quota
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
"k8s.io/client-go/tools/cache"
api "k8s.io/kubernetes/pkg/apis/core"
)
// UsageStatsOptions is an options structs that describes how stats should be calculated
@ -29,37 +29,37 @@ type UsageStatsOptions struct {
// Namespace where stats should be calculate
Namespace string
// Scopes that must match counted objects
Scopes []api.ResourceQuotaScope
Scopes []corev1.ResourceQuotaScope
// Resources are the set of resources to include in the measurement
Resources []api.ResourceName
ScopeSelector *api.ScopeSelector
Resources []corev1.ResourceName
ScopeSelector *corev1.ScopeSelector
}
// UsageStats is result of measuring observed resource use in the system
type UsageStats struct {
// Used maps resource to quantity used
Used api.ResourceList
Used corev1.ResourceList
}
// Evaluator knows how to evaluate quota usage for a particular group resource
type Evaluator interface {
// Constraints ensures that each required resource is present on item
Constraints(required []api.ResourceName, item runtime.Object) error
Constraints(required []corev1.ResourceName, item runtime.Object) error
// GroupResource returns the groupResource that this object knows how to evaluate
GroupResource() schema.GroupResource
// Handles determines if quota could be impacted by the specified attribute.
// If true, admission control must perform quota processing for the operation, otherwise it is safe to ignore quota.
Handles(operation admission.Attributes) bool
// Matches returns true if the specified quota matches the input item
Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error)
Matches(resourceQuota *corev1.ResourceQuota, item runtime.Object) (bool, error)
// MatchingScopes takes the input specified list of scopes and input object and returns the set of scopes that matches input object.
MatchingScopes(item runtime.Object, scopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error)
MatchingScopes(item runtime.Object, scopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error)
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes. It returns the scopes which are in limited scopes but dont have a corresponding covering quota scope
UncoveredQuotaScopes(limitedScopes []api.ScopedResourceSelectorRequirement, matchedQuotaScopes []api.ScopedResourceSelectorRequirement) ([]api.ScopedResourceSelectorRequirement, error)
UncoveredQuotaScopes(limitedScopes []corev1.ScopedResourceSelectorRequirement, matchedQuotaScopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error)
// MatchingResources takes the input specified list of resources and returns the set of resources evaluator matches.
MatchingResources(input []api.ResourceName) []api.ResourceName
MatchingResources(input []corev1.ResourceName) []corev1.ResourceName
// Usage returns the resource usage for the specified object
Usage(item runtime.Object) (api.ResourceList, error)
Usage(item runtime.Object) (corev1.ResourceList, error)
// UsageStats calculates latest observed usage stats for all objects
UsageStats(options UsageStatsOptions) (UsageStats, error)
}

View File

@ -19,14 +19,17 @@ package quota
import (
"strings"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
api "k8s.io/kubernetes/pkg/apis/core"
)
// Equals returns true if the two lists are equivalent
func Equals(a api.ResourceList, b api.ResourceList) bool {
func Equals(a corev1.ResourceList, b corev1.ResourceList) bool {
if len(a) != len(b) {
return false
}
for key, value1 := range a {
value2, found := b[key]
if !found {
@ -36,20 +39,16 @@ func Equals(a api.ResourceList, b api.ResourceList) bool {
return false
}
}
for key, value1 := range b {
value2, found := a[key]
if !found {
return false
}
if value1.Cmp(value2) != 0 {
return false
}
}
return true
}
// V1Equals returns true if the two lists are equivalent
func V1Equals(a v1.ResourceList, b v1.ResourceList) bool {
func V1Equals(a corev1.ResourceList, b corev1.ResourceList) bool {
if len(a) != len(b) {
return false
}
for key, value1 := range a {
value2, found := b[key]
if !found {
@ -59,23 +58,15 @@ func V1Equals(a v1.ResourceList, b v1.ResourceList) bool {
return false
}
}
for key, value1 := range b {
value2, found := a[key]
if !found {
return false
}
if value1.Cmp(value2) != 0 {
return false
}
}
return true
}
// LessThanOrEqual returns true if a < b for each key in b
// If false, it returns the keys in a that exceeded b
func LessThanOrEqual(a api.ResourceList, b api.ResourceList) (bool, []api.ResourceName) {
func LessThanOrEqual(a corev1.ResourceList, b corev1.ResourceList) (bool, []corev1.ResourceName) {
result := true
resourceNames := []api.ResourceName{}
resourceNames := []corev1.ResourceName{}
for key, value := range b {
if other, found := a[key]; found {
if other.Cmp(value) > 0 {
@ -88,8 +79,8 @@ func LessThanOrEqual(a api.ResourceList, b api.ResourceList) (bool, []api.Resour
}
// Max returns the result of Max(a, b) for each named resource
func Max(a api.ResourceList, b api.ResourceList) api.ResourceList {
result := api.ResourceList{}
func Max(a corev1.ResourceList, b corev1.ResourceList) corev1.ResourceList {
result := corev1.ResourceList{}
for key, value := range a {
if other, found := b[key]; found {
if value.Cmp(other) <= 0 {
@ -108,8 +99,8 @@ func Max(a api.ResourceList, b api.ResourceList) api.ResourceList {
}
// Add returns the result of a + b for each named resource
func Add(a api.ResourceList, b api.ResourceList) api.ResourceList {
result := api.ResourceList{}
func Add(a corev1.ResourceList, b corev1.ResourceList) corev1.ResourceList {
result := corev1.ResourceList{}
for key, value := range a {
quantity := *value.Copy()
if other, found := b[key]; found {
@ -128,10 +119,10 @@ func Add(a api.ResourceList, b api.ResourceList) api.ResourceList {
// SubtractWithNonNegativeResult - subtracts and returns result of a - b but
// makes sure we don't return negative values to prevent negative resource usage.
func SubtractWithNonNegativeResult(a api.ResourceList, b api.ResourceList) api.ResourceList {
func SubtractWithNonNegativeResult(a corev1.ResourceList, b corev1.ResourceList) corev1.ResourceList {
zero := resource.MustParse("0")
result := api.ResourceList{}
result := corev1.ResourceList{}
for key, value := range a {
quantity := *value.Copy()
if other, found := b[key]; found {
@ -153,8 +144,8 @@ func SubtractWithNonNegativeResult(a api.ResourceList, b api.ResourceList) api.R
}
// Subtract returns the result of a - b for each named resource
func Subtract(a api.ResourceList, b api.ResourceList) api.ResourceList {
result := api.ResourceList{}
func Subtract(a corev1.ResourceList, b corev1.ResourceList) corev1.ResourceList {
result := corev1.ResourceList{}
for key, value := range a {
quantity := *value.Copy()
if other, found := b[key]; found {
@ -173,9 +164,9 @@ func Subtract(a api.ResourceList, b api.ResourceList) api.ResourceList {
}
// Mask returns a new resource list that only has the values with the specified names
func Mask(resources api.ResourceList, names []api.ResourceName) api.ResourceList {
func Mask(resources corev1.ResourceList, names []corev1.ResourceName) corev1.ResourceList {
nameSet := ToSet(names)
result := api.ResourceList{}
result := corev1.ResourceList{}
for key, value := range resources {
if nameSet.Has(string(key)) {
result[key] = *value.Copy()
@ -185,8 +176,8 @@ func Mask(resources api.ResourceList, names []api.ResourceName) api.ResourceList
}
// ResourceNames returns a list of all resource names in the ResourceList
func ResourceNames(resources api.ResourceList) []api.ResourceName {
result := []api.ResourceName{}
func ResourceNames(resources corev1.ResourceList) []corev1.ResourceName {
result := []corev1.ResourceName{}
for resourceName := range resources {
result = append(result, resourceName)
}
@ -194,12 +185,12 @@ func ResourceNames(resources api.ResourceList) []api.ResourceName {
}
// Contains returns true if the specified item is in the list of items
func Contains(items []api.ResourceName, item api.ResourceName) bool {
func Contains(items []corev1.ResourceName, item corev1.ResourceName) bool {
return ToSet(items).Has(string(item))
}
// ContainsPrefix returns true if the specified item has a prefix that contained in given prefix Set
func ContainsPrefix(prefixSet []string, item api.ResourceName) bool {
func ContainsPrefix(prefixSet []string, item corev1.ResourceName) bool {
for _, prefix := range prefixSet {
if strings.HasPrefix(string(item), prefix) {
return true
@ -209,19 +200,19 @@ func ContainsPrefix(prefixSet []string, item api.ResourceName) bool {
}
// Intersection returns the intersection of both list of resources
func Intersection(a []api.ResourceName, b []api.ResourceName) []api.ResourceName {
func Intersection(a []corev1.ResourceName, b []corev1.ResourceName) []corev1.ResourceName {
setA := ToSet(a)
setB := ToSet(b)
setC := setA.Intersection(setB)
result := []api.ResourceName{}
result := []corev1.ResourceName{}
for _, resourceName := range setC.List() {
result = append(result, api.ResourceName(resourceName))
result = append(result, corev1.ResourceName(resourceName))
}
return result
}
// IsZero returns true if each key maps to the quantity value 0
func IsZero(a api.ResourceList) bool {
func IsZero(a corev1.ResourceList) bool {
zero := resource.MustParse("0")
for _, v := range a {
if v.Cmp(zero) != 0 {
@ -232,8 +223,8 @@ func IsZero(a api.ResourceList) bool {
}
// IsNegative returns the set of resource names that have a negative value.
func IsNegative(a api.ResourceList) []api.ResourceName {
results := []api.ResourceName{}
func IsNegative(a corev1.ResourceList) []corev1.ResourceName {
results := []corev1.ResourceName{}
zero := resource.MustParse("0")
for k, v := range a {
if v.Cmp(zero) < 0 {
@ -244,7 +235,7 @@ func IsNegative(a api.ResourceList) []api.ResourceName {
}
// ToSet takes a list of resource names and converts to a string set
func ToSet(resourceNames []api.ResourceName) sets.String {
func ToSet(resourceNames []corev1.ResourceName) sets.String {
result := sets.NewString()
for _, resourceName := range resourceNames {
result.Insert(string(resourceName))
@ -253,12 +244,12 @@ func ToSet(resourceNames []api.ResourceName) sets.String {
}
// CalculateUsage calculates and returns the requested ResourceList usage
func CalculateUsage(namespaceName string, scopes []api.ResourceQuotaScope, hardLimits api.ResourceList, registry Registry, scopeSelector *api.ScopeSelector) (api.ResourceList, error) {
func CalculateUsage(namespaceName string, scopes []corev1.ResourceQuotaScope, hardLimits corev1.ResourceList, registry Registry, scopeSelector *corev1.ScopeSelector) (corev1.ResourceList, error) {
// find the intersection between the hard resources on the quota
// and the resources this controller can track to know what we can
// look to measure updated usage stats for
hardResources := ResourceNames(hardLimits)
potentialResources := []api.ResourceName{}
potentialResources := []corev1.ResourceName{}
evaluators := registry.List()
for _, evaluator := range evaluators {
potentialResources = append(potentialResources, evaluator.MatchingResources(hardResources)...)
@ -267,7 +258,7 @@ func CalculateUsage(namespaceName string, scopes []api.ResourceQuotaScope, hardL
matchedResources := Intersection(hardResources, potentialResources)
// sum the observed usage from each evaluator
newUsage := api.ResourceList{}
newUsage := corev1.ResourceList{}
for _, evaluator := range evaluators {
// only trigger the evaluator if it matches a resource in the quota, otherwise, skip calculating anything
intersection := evaluator.MatchingResources(matchedResources)

321
vendor/k8s.io/kubernetes/pkg/quota/v1/resources_test.go generated vendored Normal file
View File

@ -0,0 +1,321 @@
/*
Copyright 2016 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 quota
import (
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestEquals(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
b corev1.ResourceList
expected bool
}{
"isEqual": {
a: corev1.ResourceList{},
b: corev1.ResourceList{},
expected: true,
},
"isEqualWithKeys": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
b: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
expected: true,
},
"isNotEqualSameKeys": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("200m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
b: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
expected: false,
},
"isNotEqualDiffKeys": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
b: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
corev1.ResourcePods: resource.MustParse("1"),
},
expected: false,
},
}
for testName, testCase := range testCases {
if result := Equals(testCase.a, testCase.b); result != testCase.expected {
t.Errorf("%s expected: %v, actual: %v, a=%v, b=%v", testName, testCase.expected, result, testCase.a, testCase.b)
}
}
}
func TestMax(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
b corev1.ResourceList
expected corev1.ResourceList
}{
"noKeys": {
a: corev1.ResourceList{},
b: corev1.ResourceList{},
expected: corev1.ResourceList{},
},
"toEmpty": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: corev1.ResourceList{},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
"matching": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
},
"matching(reverse)": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
},
"matching-equal": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
}
for testName, testCase := range testCases {
sum := Max(testCase.a, testCase.b)
if result := Equals(testCase.expected, sum); !result {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum)
}
}
}
func TestAdd(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
b corev1.ResourceList
expected corev1.ResourceList
}{
"noKeys": {
a: corev1.ResourceList{},
b: corev1.ResourceList{},
expected: corev1.ResourceList{},
},
"toEmpty": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: corev1.ResourceList{},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
"matching": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
},
}
for testName, testCase := range testCases {
sum := Add(testCase.a, testCase.b)
if result := Equals(testCase.expected, sum); !result {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum)
}
}
}
func TestSubtract(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
b corev1.ResourceList
expected corev1.ResourceList
}{
"noKeys": {
a: corev1.ResourceList{},
b: corev1.ResourceList{},
expected: corev1.ResourceList{},
},
"value-empty": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: corev1.ResourceList{},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
"empty-value": {
a: corev1.ResourceList{},
b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("-100m")},
},
"value-value": {
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
}
for testName, testCase := range testCases {
sub := Subtract(testCase.a, testCase.b)
if result := Equals(testCase.expected, sub); !result {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sub)
}
}
}
func TestResourceNames(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
expected []corev1.ResourceName
}{
"empty": {
a: corev1.ResourceList{},
expected: []corev1.ResourceName{},
},
"values": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
expected: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU},
},
}
for testName, testCase := range testCases {
actualSet := ToSet(ResourceNames(testCase.a))
expectedSet := ToSet(testCase.expected)
if !actualSet.Equal(expectedSet) {
t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet)
}
}
}
func TestContains(t *testing.T) {
testCases := map[string]struct {
a []corev1.ResourceName
b corev1.ResourceName
expected bool
}{
"does-not-contain": {
a: []corev1.ResourceName{corev1.ResourceMemory},
b: corev1.ResourceCPU,
expected: false,
},
"does-contain": {
a: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU},
b: corev1.ResourceCPU,
expected: true,
},
}
for testName, testCase := range testCases {
if actual := Contains(testCase.a, testCase.b); actual != testCase.expected {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual)
}
}
}
func TestContainsPrefix(t *testing.T) {
testCases := map[string]struct {
a []string
b corev1.ResourceName
expected bool
}{
"does-not-contain": {
a: []string{corev1.ResourceHugePagesPrefix},
b: corev1.ResourceCPU,
expected: false,
},
"does-contain": {
a: []string{corev1.ResourceHugePagesPrefix},
b: corev1.ResourceName(corev1.ResourceHugePagesPrefix + "2Mi"),
expected: true,
},
}
for testName, testCase := range testCases {
if actual := ContainsPrefix(testCase.a, testCase.b); actual != testCase.expected {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual)
}
}
}
func TestIsZero(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
expected bool
}{
"empty": {
a: corev1.ResourceList{},
expected: true,
},
"zero": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("0"),
corev1.ResourceMemory: resource.MustParse("0"),
},
expected: true,
},
"non-zero": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("200m"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
expected: false,
},
}
for testName, testCase := range testCases {
if result := IsZero(testCase.a); result != testCase.expected {
t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, result)
}
}
}
func TestIsNegative(t *testing.T) {
testCases := map[string]struct {
a corev1.ResourceList
expected []corev1.ResourceName
}{
"empty": {
a: corev1.ResourceList{},
expected: []corev1.ResourceName{},
},
"some-negative": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("-10"),
corev1.ResourceMemory: resource.MustParse("0"),
},
expected: []corev1.ResourceName{corev1.ResourceCPU},
},
"all-negative": {
a: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("-200m"),
corev1.ResourceMemory: resource.MustParse("-1Gi"),
},
expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
},
}
for testName, testCase := range testCases {
actual := IsNegative(testCase.a)
actualSet := ToSet(actual)
expectedSet := ToSet(testCase.expected)
if !actualSet.Equal(expectedSet) {
t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet)
}
}
}