mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
vendor files
This commit is contained in:
61
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/BUILD
generated
vendored
Normal file
61
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/BUILD
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"backoff_utils_test.go",
|
||||
"testutil_test.go",
|
||||
"utils_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/scheduler/util",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/apis/scheduling:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"backoff_utils.go",
|
||||
"testutil.go",
|
||||
"utils.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/scheduler/util",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/install:go_default_library",
|
||||
"//pkg/apis/scheduling:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1: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/types:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
137
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/backoff_utils.go
generated
vendored
Normal file
137
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/backoff_utils.go
generated
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
ktypes "k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
type clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
type realClock struct{}
|
||||
|
||||
func (realClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// backoffEntry is single threaded. in particular, it only allows a single action to be waiting on backoff at a time.
|
||||
// It is expected that all users will only use the public TryWait(...) method
|
||||
// It is also not safe to copy this object.
|
||||
type backoffEntry struct {
|
||||
backoff time.Duration
|
||||
lastUpdate time.Time
|
||||
reqInFlight int32
|
||||
}
|
||||
|
||||
// tryLock attempts to acquire a lock via atomic compare and swap.
|
||||
// returns true if the lock was acquired, false otherwise
|
||||
func (b *backoffEntry) tryLock() bool {
|
||||
return atomic.CompareAndSwapInt32(&b.reqInFlight, 0, 1)
|
||||
}
|
||||
|
||||
// unlock returns the lock. panics if the lock isn't held
|
||||
func (b *backoffEntry) unlock() {
|
||||
if !atomic.CompareAndSwapInt32(&b.reqInFlight, 1, 0) {
|
||||
panic(fmt.Sprintf("unexpected state on unlocking: %+v", b))
|
||||
}
|
||||
}
|
||||
|
||||
// TryWait tries to acquire the backoff lock, maxDuration is the maximum allowed period to wait for.
|
||||
func (b *backoffEntry) TryWait(maxDuration time.Duration) bool {
|
||||
if !b.tryLock() {
|
||||
return false
|
||||
}
|
||||
defer b.unlock()
|
||||
b.wait(maxDuration)
|
||||
return true
|
||||
}
|
||||
|
||||
func (entry *backoffEntry) getBackoff(maxDuration time.Duration) time.Duration {
|
||||
duration := entry.backoff
|
||||
newDuration := time.Duration(duration) * 2
|
||||
if newDuration > maxDuration {
|
||||
newDuration = maxDuration
|
||||
}
|
||||
entry.backoff = newDuration
|
||||
glog.V(4).Infof("Backing off %s", duration.String())
|
||||
return duration
|
||||
}
|
||||
|
||||
func (entry *backoffEntry) wait(maxDuration time.Duration) {
|
||||
time.Sleep(entry.getBackoff(maxDuration))
|
||||
}
|
||||
|
||||
type PodBackoff struct {
|
||||
perPodBackoff map[ktypes.NamespacedName]*backoffEntry
|
||||
lock sync.Mutex
|
||||
clock clock
|
||||
defaultDuration time.Duration
|
||||
maxDuration time.Duration
|
||||
}
|
||||
|
||||
func (p *PodBackoff) MaxDuration() time.Duration {
|
||||
return p.maxDuration
|
||||
}
|
||||
|
||||
func CreateDefaultPodBackoff() *PodBackoff {
|
||||
return CreatePodBackoff(1*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
func CreatePodBackoff(defaultDuration, maxDuration time.Duration) *PodBackoff {
|
||||
return CreatePodBackoffWithClock(defaultDuration, maxDuration, realClock{})
|
||||
}
|
||||
|
||||
func CreatePodBackoffWithClock(defaultDuration, maxDuration time.Duration, clock clock) *PodBackoff {
|
||||
return &PodBackoff{
|
||||
perPodBackoff: map[ktypes.NamespacedName]*backoffEntry{},
|
||||
clock: clock,
|
||||
defaultDuration: defaultDuration,
|
||||
maxDuration: maxDuration,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PodBackoff) GetEntry(podID ktypes.NamespacedName) *backoffEntry {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
entry, ok := p.perPodBackoff[podID]
|
||||
if !ok {
|
||||
entry = &backoffEntry{backoff: p.defaultDuration}
|
||||
p.perPodBackoff[podID] = entry
|
||||
}
|
||||
entry.lastUpdate = p.clock.Now()
|
||||
return entry
|
||||
}
|
||||
|
||||
func (p *PodBackoff) Gc() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
now := p.clock.Now()
|
||||
for podID, entry := range p.perPodBackoff {
|
||||
if now.Sub(entry.lastUpdate) > p.maxDuration {
|
||||
delete(p.perPodBackoff, podID)
|
||||
}
|
||||
}
|
||||
}
|
86
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/backoff_utils_test.go
generated
vendored
Normal file
86
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/backoff_utils_test.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ktypes "k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
type fakeClock struct {
|
||||
t time.Time
|
||||
}
|
||||
|
||||
func (f *fakeClock) Now() time.Time {
|
||||
return f.t
|
||||
}
|
||||
|
||||
func TestBackoff(t *testing.T) {
|
||||
clock := fakeClock{}
|
||||
backoff := CreatePodBackoffWithClock(1*time.Second, 60*time.Second, &clock)
|
||||
tests := []struct {
|
||||
podID ktypes.NamespacedName
|
||||
expectedDuration time.Duration
|
||||
advanceClock time.Duration
|
||||
}{
|
||||
{
|
||||
podID: ktypes.NamespacedName{Namespace: "default", Name: "foo"},
|
||||
expectedDuration: 1 * time.Second,
|
||||
},
|
||||
{
|
||||
podID: ktypes.NamespacedName{Namespace: "default", Name: "foo"},
|
||||
expectedDuration: 2 * time.Second,
|
||||
},
|
||||
{
|
||||
podID: ktypes.NamespacedName{Namespace: "default", Name: "foo"},
|
||||
expectedDuration: 4 * time.Second,
|
||||
},
|
||||
{
|
||||
podID: ktypes.NamespacedName{Namespace: "default", Name: "bar"},
|
||||
expectedDuration: 1 * time.Second,
|
||||
advanceClock: 120 * time.Second,
|
||||
},
|
||||
// 'foo' should have been gc'd here.
|
||||
{
|
||||
podID: ktypes.NamespacedName{Namespace: "default", Name: "foo"},
|
||||
expectedDuration: 1 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
duration := backoff.GetEntry(test.podID).getBackoff(backoff.maxDuration)
|
||||
if duration != test.expectedDuration {
|
||||
t.Errorf("expected: %s, got %s for %s", test.expectedDuration.String(), duration.String(), test.podID)
|
||||
}
|
||||
clock.t = clock.t.Add(test.advanceClock)
|
||||
backoff.Gc()
|
||||
}
|
||||
fooID := ktypes.NamespacedName{Namespace: "default", Name: "foo"}
|
||||
backoff.perPodBackoff[fooID].backoff = 60 * time.Second
|
||||
duration := backoff.GetEntry(fooID).getBackoff(backoff.maxDuration)
|
||||
if duration != 60*time.Second {
|
||||
t.Errorf("expected: 60, got %s", duration.String())
|
||||
}
|
||||
// Verify that we split on namespaces correctly, same name, different namespace
|
||||
fooID.Namespace = "other"
|
||||
duration = backoff.GetEntry(fooID).getBackoff(backoff.maxDuration)
|
||||
if duration != 1*time.Second {
|
||||
t.Errorf("expected: 1, got %s", duration.String())
|
||||
}
|
||||
}
|
169
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/testutil.go
generated
vendored
Normal file
169
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/testutil.go
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
)
|
||||
|
||||
type TestGroup struct {
|
||||
externalGroupVersion schema.GroupVersion
|
||||
internalGroupVersion schema.GroupVersion
|
||||
internalTypes map[string]reflect.Type
|
||||
externalTypes map[string]reflect.Type
|
||||
}
|
||||
|
||||
var (
|
||||
Groups = make(map[string]TestGroup)
|
||||
Test TestGroup
|
||||
|
||||
serializer runtime.SerializerInfo
|
||||
)
|
||||
|
||||
func init() {
|
||||
if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
|
||||
var ok bool
|
||||
mediaType, _, err := mime.ParseMediaType(apiMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
serializer, ok = runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", apiMediaType))
|
||||
}
|
||||
}
|
||||
|
||||
kubeTestAPI := os.Getenv("KUBE_TEST_API")
|
||||
if len(kubeTestAPI) != 0 {
|
||||
// priority is "first in list preferred", so this has to run in reverse order
|
||||
testGroupVersions := strings.Split(kubeTestAPI, ",")
|
||||
for i := len(testGroupVersions) - 1; i >= 0; i-- {
|
||||
gvString := testGroupVersions[i]
|
||||
groupVersion, err := schema.ParseGroupVersion(gvString)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error parsing groupversion %v: %v", gvString, err))
|
||||
}
|
||||
|
||||
internalGroupVersion := schema.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal}
|
||||
Groups[groupVersion.Group] = TestGroup{
|
||||
externalGroupVersion: groupVersion,
|
||||
internalGroupVersion: internalGroupVersion,
|
||||
internalTypes: legacyscheme.Scheme.KnownTypes(internalGroupVersion),
|
||||
externalTypes: legacyscheme.Scheme.KnownTypes(groupVersion),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := Groups[api.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: api.GroupName, Version: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.Version}
|
||||
Groups[api.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
internalGroupVersion: api.SchemeGroupVersion,
|
||||
internalTypes: legacyscheme.Scheme.KnownTypes(api.SchemeGroupVersion),
|
||||
externalTypes: legacyscheme.Scheme.KnownTypes(externalGroupVersion),
|
||||
}
|
||||
}
|
||||
|
||||
Test = Groups[api.GroupName]
|
||||
}
|
||||
|
||||
// Codec returns the codec for the API version to test against, as set by the
|
||||
// KUBE_TEST_API_TYPE env var.
|
||||
func (g TestGroup) Codec() runtime.Codec {
|
||||
if serializer.Serializer == nil {
|
||||
return legacyscheme.Codecs.LegacyCodec(g.externalGroupVersion)
|
||||
}
|
||||
return legacyscheme.Codecs.CodecForVersions(serializer.Serializer, legacyscheme.Codecs.UniversalDeserializer(), schema.GroupVersions{g.externalGroupVersion}, nil)
|
||||
}
|
||||
|
||||
// SelfLink returns a self link that will appear to be for the version Version().
|
||||
// 'resource' should be the resource path, e.g. "pods" for the Pod type. 'name' should be
|
||||
// empty for lists.
|
||||
func (g TestGroup) SelfLink(resource, name string) string {
|
||||
if g.externalGroupVersion.Group == api.GroupName {
|
||||
if name == "" {
|
||||
return fmt.Sprintf("/api/%s/%s", g.externalGroupVersion.Version, resource)
|
||||
}
|
||||
return fmt.Sprintf("/api/%s/%s/%s", g.externalGroupVersion.Version, resource, name)
|
||||
}
|
||||
|
||||
// TODO: will need a /apis prefix once we have proper multi-group
|
||||
// support
|
||||
if name == "" {
|
||||
return fmt.Sprintf("/apis/%s/%s/%s", g.externalGroupVersion.Group, g.externalGroupVersion.Version, resource)
|
||||
}
|
||||
return fmt.Sprintf("/apis/%s/%s/%s/%s", g.externalGroupVersion.Group, g.externalGroupVersion.Version, resource, name)
|
||||
}
|
||||
|
||||
// ResourcePathWithPrefix returns the appropriate path for the given prefix (watch, proxy, redirect, etc), resource, namespace and name.
|
||||
// For ex, this is of the form:
|
||||
// /api/v1/watch/namespaces/foo/pods/pod0 for v1.
|
||||
func (g TestGroup) ResourcePathWithPrefix(prefix, resource, namespace, name string) string {
|
||||
var path string
|
||||
if g.externalGroupVersion.Group == api.GroupName {
|
||||
path = "/api/" + g.externalGroupVersion.Version
|
||||
} else {
|
||||
// TODO: switch back once we have proper multiple group support
|
||||
// path = "/apis/" + g.Group + "/" + Version(group...)
|
||||
path = "/apis/" + g.externalGroupVersion.Group + "/" + g.externalGroupVersion.Version
|
||||
}
|
||||
|
||||
if prefix != "" {
|
||||
path = path + "/" + prefix
|
||||
}
|
||||
if namespace != "" {
|
||||
path = path + "/namespaces/" + namespace
|
||||
}
|
||||
// Resource names are lower case.
|
||||
resource = strings.ToLower(resource)
|
||||
if resource != "" {
|
||||
path = path + "/" + resource
|
||||
}
|
||||
if name != "" {
|
||||
path = path + "/" + name
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// ResourcePath returns the appropriate path for the given resource, namespace and name.
|
||||
// For example, this is of the form:
|
||||
// /api/v1/namespaces/foo/pods/pod0 for v1.
|
||||
func (g TestGroup) ResourcePath(resource, namespace, name string) string {
|
||||
return g.ResourcePathWithPrefix("", resource, namespace, name)
|
||||
}
|
||||
|
||||
// SubResourcePath returns the appropriate path for the given resource, namespace,
|
||||
// name and subresource.
|
||||
func (g TestGroup) SubResourcePath(resource, namespace, name, sub string) string {
|
||||
path := g.ResourcePathWithPrefix("", resource, namespace, name)
|
||||
if sub != "" {
|
||||
path = path + "/" + sub
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
214
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/testutil_test.go
generated
vendored
Normal file
214
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/testutil_test.go
generated
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestResourcePathWithPrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
prefix string
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"prefix", "resource", "mynamespace", "myresource", "/api/" + Test.externalGroupVersion.Version + "/prefix/namespaces/mynamespace/resource/myresource"},
|
||||
{"prefix", "resource", "", "myresource", "/api/" + Test.externalGroupVersion.Version + "/prefix/resource/myresource"},
|
||||
{"prefix", "resource", "mynamespace", "", "/api/" + Test.externalGroupVersion.Version + "/prefix/namespaces/mynamespace/resource"},
|
||||
{"prefix", "resource", "", "", "/api/" + Test.externalGroupVersion.Version + "/prefix/resource"},
|
||||
{"", "resource", "mynamespace", "myresource", "/api/" + Test.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Test.ResourcePathWithPrefix(item.prefix, item.resource, item.namespace, item.name); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for prefix: %s, resource: %s, namespace: %s and name: %s", item.expected, actual, item.prefix, item.resource, item.namespace, item.name)
|
||||
}
|
||||
}
|
||||
|
||||
TestGroup := Test
|
||||
TestGroup.externalGroupVersion.Group = "TestGroup"
|
||||
|
||||
testGroupCases := []struct {
|
||||
prefix string
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"prefix", "resource", "mynamespace", "myresource", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/prefix/namespaces/mynamespace/resource/myresource"},
|
||||
{"prefix", "resource", "", "myresource", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/prefix/resource/myresource"},
|
||||
{"prefix", "resource", "mynamespace", "", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/prefix/namespaces/mynamespace/resource"},
|
||||
{"prefix", "resource", "", "", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/prefix/resource"},
|
||||
{"", "resource", "mynamespace", "myresource", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
}
|
||||
for _, item := range testGroupCases {
|
||||
if actual := TestGroup.ResourcePathWithPrefix(item.prefix, item.resource, item.namespace, item.name); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for prefix: %s, resource: %s, namespace: %s and name: %s", item.expected, actual, item.prefix, item.resource, item.namespace, item.name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestResourcePath(t *testing.T) {
|
||||
testCases := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "mynamespace", "myresource", "/api/" + Test.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
{"resource", "", "myresource", "/api/" + Test.externalGroupVersion.Version + "/resource/myresource"},
|
||||
{"resource", "mynamespace", "", "/api/" + Test.externalGroupVersion.Version + "/namespaces/mynamespace/resource"},
|
||||
{"resource", "", "", "/api/" + Test.externalGroupVersion.Version + "/resource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Test.ResourcePath(item.resource, item.namespace, item.name); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name)
|
||||
}
|
||||
}
|
||||
|
||||
TestGroup := Test
|
||||
TestGroup.externalGroupVersion.Group = "TestGroup"
|
||||
|
||||
testGroupCases := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "mynamespace", "myresource", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
{"resource", "", "myresource", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/resource/myresource"},
|
||||
{"resource", "mynamespace", "", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/namespaces/mynamespace/resource"},
|
||||
{"resource", "", "", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/resource"},
|
||||
}
|
||||
for _, item := range testGroupCases {
|
||||
if actual := TestGroup.ResourcePath(item.resource, item.namespace, item.name); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSubResourcePath(t *testing.T) {
|
||||
testCases := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
sub string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "mynamespace", "myresource", "subresource", "/api/" + Test.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource/subresource"},
|
||||
{"resource", "mynamespace", "myresource", "", "/api/" + Test.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Test.SubResourcePath(item.resource, item.namespace, item.name, item.sub); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s, name: %s and sub: %s", item.expected, actual, item.resource, item.namespace, item.name, item.sub)
|
||||
}
|
||||
}
|
||||
|
||||
TestGroup := Test
|
||||
TestGroup.externalGroupVersion.Group = "TestGroup"
|
||||
|
||||
testGroupCases := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
sub string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "mynamespace", "myresource", "subresource", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource/subresource"},
|
||||
{"resource", "mynamespace", "myresource", "", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
}
|
||||
for _, item := range testGroupCases {
|
||||
if actual := TestGroup.SubResourcePath(item.resource, item.namespace, item.name, item.sub); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s, name: %s and sub: %s", item.expected, actual, item.resource, item.namespace, item.name, item.sub)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSelfLink(t *testing.T) {
|
||||
testCases := []struct {
|
||||
resource string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "name", "/api/" + Test.externalGroupVersion.Version + "/resource/name"},
|
||||
{"resource", "", "/api/" + Test.externalGroupVersion.Version + "/resource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Test.SelfLink(item.resource, item.name); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for resource: %s and name: %s", item.expected, actual, item.resource, item.name)
|
||||
}
|
||||
}
|
||||
|
||||
TestGroup := Test
|
||||
TestGroup.externalGroupVersion.Group = "TestGroup"
|
||||
|
||||
testGroupCases := []struct {
|
||||
resource string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "name", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/resource/name"},
|
||||
{"resource", "", "/apis/" + TestGroup.externalGroupVersion.Group + "/" + TestGroup.externalGroupVersion.Version + "/resource"},
|
||||
}
|
||||
for _, item := range testGroupCases {
|
||||
if actual := TestGroup.SelfLink(item.resource, item.name); actual != item.expected {
|
||||
t.Errorf("Expected: %s, got: %s for resource: %s and name: %s", item.expected, actual, item.resource, item.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var status = &metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: 200,
|
||||
Reason: metav1.StatusReasonUnknown,
|
||||
Message: "",
|
||||
}
|
||||
|
||||
func TestV1EncodeDecodeStatus(t *testing.T) {
|
||||
v1Codec := Test.Codec()
|
||||
|
||||
encoded, err := runtime.Encode(v1Codec, status)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
typeMeta := metav1.TypeMeta{}
|
||||
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if typeMeta.Kind != "Status" {
|
||||
t.Errorf("Kind is not set to \"Status\". Got %v", string(encoded))
|
||||
}
|
||||
if typeMeta.APIVersion != "v1" {
|
||||
t.Errorf("APIVersion is not set to \"v1\". Got %v", string(encoded))
|
||||
}
|
||||
decoded, err := runtime.Decode(v1Codec, encoded)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(status, decoded) {
|
||||
t.Errorf("expected: %#v, got: %#v", status, decoded)
|
||||
}
|
||||
}
|
120
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/utils.go
generated
vendored
Normal file
120
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/utils.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
const DefaultBindAllHostIP = "0.0.0.0"
|
||||
|
||||
// GetUsedPorts returns the used host ports of Pods: if 'port' was used, a 'port:true' pair
|
||||
// will be in the result; but it does not resolve port conflict.
|
||||
func GetUsedPorts(pods ...*v1.Pod) map[string]bool {
|
||||
ports := make(map[string]bool)
|
||||
for _, pod := range pods {
|
||||
for j := range pod.Spec.Containers {
|
||||
container := &pod.Spec.Containers[j]
|
||||
for k := range container.Ports {
|
||||
podPort := &container.Ports[k]
|
||||
// "0" is explicitly ignored in PodFitsHostPorts,
|
||||
// which is the only function that uses this value.
|
||||
if podPort.HostPort != 0 {
|
||||
// user does not explicitly set protocol, default is tcp
|
||||
portProtocol := podPort.Protocol
|
||||
if podPort.Protocol == "" {
|
||||
portProtocol = v1.ProtocolTCP
|
||||
}
|
||||
|
||||
// user does not explicitly set hostIP, default is 0.0.0.0
|
||||
portHostIP := podPort.HostIP
|
||||
if podPort.HostIP == "" {
|
||||
portHostIP = "0.0.0.0"
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("%s/%s/%d", portProtocol, portHostIP, podPort.HostPort)
|
||||
ports[str] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ports
|
||||
}
|
||||
|
||||
// PodPriorityEnabled indicates whether pod priority feature is enabled.
|
||||
func PodPriorityEnabled() bool {
|
||||
return feature.DefaultFeatureGate.Enabled(features.PodPriority)
|
||||
}
|
||||
|
||||
// GetPodFullName returns a name that uniquely identifies a pod.
|
||||
func GetPodFullName(pod *v1.Pod) string {
|
||||
// Use underscore as the delimiter because it is not allowed in pod name
|
||||
// (DNS subdomain format).
|
||||
return pod.Name + "_" + pod.Namespace
|
||||
}
|
||||
|
||||
// GetPodPriority return priority of the given pod.
|
||||
func GetPodPriority(pod *v1.Pod) int32 {
|
||||
if pod.Spec.Priority != nil {
|
||||
return *pod.Spec.Priority
|
||||
}
|
||||
// When priority of a running pod is nil, it means it was created at a time
|
||||
// that there was no global default priority class and the priority class
|
||||
// name of the pod was empty. So, we resolve to the static default priority.
|
||||
return scheduling.DefaultPriorityWhenNoDefaultClassExists
|
||||
}
|
||||
|
||||
// SortableList is a list that implements sort.Interface.
|
||||
type SortableList struct {
|
||||
Items []interface{}
|
||||
CompFunc LessFunc
|
||||
}
|
||||
|
||||
// LessFunc is a function that receives two items and returns true if the first
|
||||
// item should be placed before the second one when the list is sorted.
|
||||
type LessFunc func(item1, item2 interface{}) bool
|
||||
|
||||
var _ = sort.Interface(&SortableList{})
|
||||
|
||||
func (l *SortableList) Len() int { return len(l.Items) }
|
||||
|
||||
func (l *SortableList) Less(i, j int) bool {
|
||||
return l.CompFunc(l.Items[i], l.Items[j])
|
||||
}
|
||||
|
||||
func (l *SortableList) Swap(i, j int) {
|
||||
l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
|
||||
}
|
||||
|
||||
// Sort sorts the items in the list using the given CompFunc. Item1 is placed
|
||||
// before Item2 when CompFunc(Item1, Item2) returns true.
|
||||
func (l *SortableList) Sort() {
|
||||
sort.Sort(l)
|
||||
}
|
||||
|
||||
// HigherPriorityPod return true when priority of the first pod is higher than
|
||||
// the second one. It takes arguments of the type "interface{}" to be used with
|
||||
// SortableList, but expects those arguments to be *v1.Pod.
|
||||
func HigherPriorityPod(pod1, pod2 interface{}) bool {
|
||||
return GetPodPriority(pod1.(*v1.Pod)) > GetPodPriority(pod2.(*v1.Pod))
|
||||
}
|
95
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/utils_test.go
generated
vendored
Normal file
95
vendor/k8s.io/kubernetes/plugin/pkg/scheduler/util/utils_test.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
)
|
||||
|
||||
// TestGetPodPriority tests GetPodPriority function.
|
||||
func TestGetPodPriority(t *testing.T) {
|
||||
p := int32(20)
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *v1.Pod
|
||||
expectedPriority int32
|
||||
}{
|
||||
{
|
||||
name: "no priority pod resolves to static default priority",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{Containers: []v1.Container{
|
||||
{Name: "container", Image: "image"}},
|
||||
},
|
||||
},
|
||||
expectedPriority: scheduling.DefaultPriorityWhenNoDefaultClassExists,
|
||||
},
|
||||
{
|
||||
name: "pod with priority resolves correctly",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{Containers: []v1.Container{
|
||||
{Name: "container", Image: "image"}},
|
||||
Priority: &p,
|
||||
},
|
||||
},
|
||||
expectedPriority: p,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if GetPodPriority(test.pod) != test.expectedPriority {
|
||||
t.Errorf("expected pod priority: %v, got %v", test.expectedPriority, GetPodPriority(test.pod))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TestSortableList tests SortableList by storing pods in the list and sorting
|
||||
// them by their priority.
|
||||
func TestSortableList(t *testing.T) {
|
||||
higherPriority := func(pod1, pod2 interface{}) bool {
|
||||
return GetPodPriority(pod1.(*v1.Pod)) > GetPodPriority(pod2.(*v1.Pod))
|
||||
}
|
||||
podList := SortableList{CompFunc: higherPriority}
|
||||
// Add a few Pods with different priorities from lowest to highest priority.
|
||||
for i := 0; i < 10; i++ {
|
||||
var p int32 = int32(i)
|
||||
pod := &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "container",
|
||||
Image: "image",
|
||||
},
|
||||
},
|
||||
Priority: &p,
|
||||
},
|
||||
}
|
||||
podList.Items = append(podList.Items, pod)
|
||||
}
|
||||
podList.Sort()
|
||||
if len(podList.Items) != 10 {
|
||||
t.Errorf("expected length of list was 10, got: %v", len(podList.Items))
|
||||
}
|
||||
var prevPriority = int32(10)
|
||||
for _, p := range podList.Items {
|
||||
if *p.(*v1.Pod).Spec.Priority >= prevPriority {
|
||||
t.Errorf("Pods are not soreted. Current pod pririty is %v, while previous one was %v.", *p.(*v1.Pod).Spec.Priority, prevPriority)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user