mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
13
vendor/k8s.io/kubernetes/pkg/.import-restrictions
generated
vendored
13
vendor/k8s.io/kubernetes/pkg/.import-restrictions
generated
vendored
@ -1,13 +0,0 @@
|
||||
{
|
||||
"Rules": [
|
||||
{
|
||||
"SelectorRegexp": "k8s[.]io/kubernetes",
|
||||
"AllowedPrefixes": [
|
||||
""
|
||||
],
|
||||
"ForbiddenPrefixes": [
|
||||
"k8s.io/kubernetes/cmd"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
90
vendor/k8s.io/kubernetes/pkg/BUILD
generated
vendored
90
vendor/k8s.io/kubernetes/pkg/BUILD
generated
vendored
@ -1,90 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/api/endpoints:all-srcs",
|
||||
"//pkg/api/legacyscheme:all-srcs",
|
||||
"//pkg/api/persistentvolume:all-srcs",
|
||||
"//pkg/api/persistentvolumeclaim:all-srcs",
|
||||
"//pkg/api/pod:all-srcs",
|
||||
"//pkg/api/podsecuritypolicy:all-srcs",
|
||||
"//pkg/api/ref:all-srcs",
|
||||
"//pkg/api/resource:all-srcs",
|
||||
"//pkg/api/service:all-srcs",
|
||||
"//pkg/api/testapi:all-srcs",
|
||||
"//pkg/api/testing:all-srcs",
|
||||
"//pkg/api/v1/endpoints:all-srcs",
|
||||
"//pkg/api/v1/node:all-srcs",
|
||||
"//pkg/api/v1/persistentvolume:all-srcs",
|
||||
"//pkg/api/v1/pod:all-srcs",
|
||||
"//pkg/api/v1/resource:all-srcs",
|
||||
"//pkg/api/v1/service:all-srcs",
|
||||
"//pkg/apis/abac:all-srcs",
|
||||
"//pkg/apis/admission:all-srcs",
|
||||
"//pkg/apis/admissionregistration:all-srcs",
|
||||
"//pkg/apis/apps:all-srcs",
|
||||
"//pkg/apis/auditregistration:all-srcs",
|
||||
"//pkg/apis/authentication:all-srcs",
|
||||
"//pkg/apis/authorization:all-srcs",
|
||||
"//pkg/apis/autoscaling:all-srcs",
|
||||
"//pkg/apis/batch:all-srcs",
|
||||
"//pkg/apis/certificates:all-srcs",
|
||||
"//pkg/apis/coordination:all-srcs",
|
||||
"//pkg/apis/core:all-srcs",
|
||||
"//pkg/apis/events:all-srcs",
|
||||
"//pkg/apis/extensions:all-srcs",
|
||||
"//pkg/apis/imagepolicy:all-srcs",
|
||||
"//pkg/apis/networking:all-srcs",
|
||||
"//pkg/apis/policy:all-srcs",
|
||||
"//pkg/apis/rbac:all-srcs",
|
||||
"//pkg/apis/scheduling:all-srcs",
|
||||
"//pkg/apis/settings:all-srcs",
|
||||
"//pkg/apis/storage:all-srcs",
|
||||
"//pkg/auth/authorizer/abac:all-srcs",
|
||||
"//pkg/auth/nodeidentifier:all-srcs",
|
||||
"//pkg/capabilities:all-srcs",
|
||||
"//pkg/client/clientset_generated/internalclientset:all-srcs",
|
||||
"//pkg/client/conditions:all-srcs",
|
||||
"//pkg/client/leaderelectionconfig:all-srcs",
|
||||
"//pkg/client/metrics/prometheus:all-srcs",
|
||||
"//pkg/client/testdata:all-srcs",
|
||||
"//pkg/client/tests:all-srcs",
|
||||
"//pkg/cloudprovider:all-srcs",
|
||||
"//pkg/controller:all-srcs",
|
||||
"//pkg/credentialprovider:all-srcs",
|
||||
"//pkg/features:all-srcs",
|
||||
"//pkg/fieldpath:all-srcs",
|
||||
"//pkg/generated:all-srcs",
|
||||
"//pkg/kubeapiserver:all-srcs",
|
||||
"//pkg/kubectl:all-srcs",
|
||||
"//pkg/kubelet:all-srcs",
|
||||
"//pkg/kubemark:all-srcs",
|
||||
"//pkg/master:all-srcs",
|
||||
"//pkg/printers:all-srcs",
|
||||
"//pkg/probe:all-srcs",
|
||||
"//pkg/proxy:all-srcs",
|
||||
"//pkg/quota:all-srcs",
|
||||
"//pkg/registry:all-srcs",
|
||||
"//pkg/routes:all-srcs",
|
||||
"//pkg/scheduler:all-srcs",
|
||||
"//pkg/security:all-srcs",
|
||||
"//pkg/securitycontext:all-srcs",
|
||||
"//pkg/serviceaccount:all-srcs",
|
||||
"//pkg/ssh:all-srcs",
|
||||
"//pkg/util:all-srcs",
|
||||
"//pkg/version:all-srcs",
|
||||
"//pkg/volume:all-srcs",
|
||||
"//pkg/watch/json:all-srcs",
|
||||
"//pkg/windows/service:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
12
vendor/k8s.io/kubernetes/pkg/OWNERS
generated
vendored
12
vendor/k8s.io/kubernetes/pkg/OWNERS
generated
vendored
@ -1,12 +0,0 @@
|
||||
reviewers:
|
||||
- brendandburns
|
||||
- dchen1107
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- thockin
|
||||
approvers:
|
||||
- brendandburns
|
||||
- dchen1107
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- thockin
|
17
vendor/k8s.io/kubernetes/pkg/api/OWNERS
generated
vendored
17
vendor/k8s.io/kubernetes/pkg/api/OWNERS
generated
vendored
@ -1,17 +0,0 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
# Disable inheritance as this is an api owners file
|
||||
options:
|
||||
no_parent_owners: true
|
||||
filters:
|
||||
".*":
|
||||
approvers:
|
||||
- api-approvers
|
||||
reviewers:
|
||||
- api-reviewers
|
||||
|
||||
# examples:
|
||||
# pkg/api/types.go
|
||||
# pkg/api/*/register.go
|
||||
"([^/]+/)?(register|types)\\.go$":
|
||||
labels:
|
||||
- kind/api-change
|
42
vendor/k8s.io/kubernetes/pkg/api/endpoints/BUILD
generated
vendored
42
vendor/k8s.io/kubernetes/pkg/api/endpoints/BUILD
generated
vendored
@ -1,42 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/endpoints",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/util/hash:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
8
vendor/k8s.io/kubernetes/pkg/api/endpoints/OWNERS
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/api/endpoints/OWNERS
generated
vendored
@ -1,8 +0,0 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- smarterclayton
|
||||
- mikedanese
|
||||
- sttts
|
||||
- eparis
|
||||
- resouer
|
||||
- david-mcmahon
|
235
vendor/k8s.io/kubernetes/pkg/api/endpoints/util.go
generated
vendored
235
vendor/k8s.io/kubernetes/pkg/api/endpoints/util.go
generated
vendored
@ -1,235 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"sort"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||
)
|
||||
|
||||
// RepackSubsets takes a slice of EndpointSubset objects, expands it to the full
|
||||
// representation, and then repacks that into the canonical layout. This
|
||||
// ensures that code which operates on these objects can rely on the common
|
||||
// form for things like comparison. The result is a newly allocated slice.
|
||||
func RepackSubsets(subsets []api.EndpointSubset) []api.EndpointSubset {
|
||||
// First map each unique port definition to the sets of hosts that
|
||||
// offer it.
|
||||
allAddrs := map[addressKey]*api.EndpointAddress{}
|
||||
portToAddrReadyMap := map[api.EndpointPort]addressSet{}
|
||||
for i := range subsets {
|
||||
if len(subsets[i].Ports) == 0 {
|
||||
// Don't discard endpoints with no ports defined, use a sentinel.
|
||||
mapAddressesByPort(&subsets[i], api.EndpointPort{Port: -1}, allAddrs, portToAddrReadyMap)
|
||||
} else {
|
||||
for _, port := range subsets[i].Ports {
|
||||
mapAddressesByPort(&subsets[i], port, allAddrs, portToAddrReadyMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, map the sets of hosts to the sets of ports they offer.
|
||||
// Go does not allow maps or slices as keys to maps, so we have
|
||||
// to synthesize an artificial key and do a sort of 2-part
|
||||
// associative entity.
|
||||
type keyString string
|
||||
keyToAddrReadyMap := map[keyString]addressSet{}
|
||||
addrReadyMapKeyToPorts := map[keyString][]api.EndpointPort{}
|
||||
for port, addrs := range portToAddrReadyMap {
|
||||
key := keyString(hashAddresses(addrs))
|
||||
keyToAddrReadyMap[key] = addrs
|
||||
if port.Port > 0 { // avoid sentinels
|
||||
addrReadyMapKeyToPorts[key] = append(addrReadyMapKeyToPorts[key], port)
|
||||
} else {
|
||||
if _, found := addrReadyMapKeyToPorts[key]; !found {
|
||||
// Force it to be present in the map
|
||||
addrReadyMapKeyToPorts[key] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, build the N-to-M association the API wants.
|
||||
final := []api.EndpointSubset{}
|
||||
for key, ports := range addrReadyMapKeyToPorts {
|
||||
var readyAddrs, notReadyAddrs []api.EndpointAddress
|
||||
for addr, ready := range keyToAddrReadyMap[key] {
|
||||
if ready {
|
||||
readyAddrs = append(readyAddrs, *addr)
|
||||
} else {
|
||||
notReadyAddrs = append(notReadyAddrs, *addr)
|
||||
}
|
||||
}
|
||||
final = append(final, api.EndpointSubset{Addresses: readyAddrs, NotReadyAddresses: notReadyAddrs, Ports: ports})
|
||||
}
|
||||
|
||||
// Finally, sort it.
|
||||
return SortSubsets(final)
|
||||
}
|
||||
|
||||
// The sets of hosts must be de-duped, using IP+UID as the key.
|
||||
type addressKey struct {
|
||||
ip string
|
||||
uid types.UID
|
||||
}
|
||||
|
||||
// mapAddressesByPort adds all ready and not-ready addresses into a map by a single port.
|
||||
func mapAddressesByPort(subset *api.EndpointSubset, port api.EndpointPort, allAddrs map[addressKey]*api.EndpointAddress, portToAddrReadyMap map[api.EndpointPort]addressSet) {
|
||||
for k := range subset.Addresses {
|
||||
mapAddressByPort(&subset.Addresses[k], port, true, allAddrs, portToAddrReadyMap)
|
||||
}
|
||||
for k := range subset.NotReadyAddresses {
|
||||
mapAddressByPort(&subset.NotReadyAddresses[k], port, false, allAddrs, portToAddrReadyMap)
|
||||
}
|
||||
}
|
||||
|
||||
// mapAddressByPort adds one address into a map by port, registering the address with a unique pointer, and preserving
|
||||
// any existing ready state.
|
||||
func mapAddressByPort(addr *api.EndpointAddress, port api.EndpointPort, ready bool, allAddrs map[addressKey]*api.EndpointAddress, portToAddrReadyMap map[api.EndpointPort]addressSet) *api.EndpointAddress {
|
||||
// use addressKey to distinguish between two endpoints that are identical addresses
|
||||
// but may have come from different hosts, for attribution.
|
||||
key := addressKey{ip: addr.IP}
|
||||
if addr.TargetRef != nil {
|
||||
key.uid = addr.TargetRef.UID
|
||||
}
|
||||
|
||||
// Accumulate the address. The full EndpointAddress structure is preserved for use when
|
||||
// we rebuild the subsets so that the final TargetRef has all of the necessary data.
|
||||
existingAddress := allAddrs[key]
|
||||
if existingAddress == nil {
|
||||
// Make a copy so we don't write to the
|
||||
// input args of this function.
|
||||
existingAddress = &api.EndpointAddress{}
|
||||
*existingAddress = *addr
|
||||
allAddrs[key] = existingAddress
|
||||
}
|
||||
|
||||
// Remember that this port maps to this address.
|
||||
if _, found := portToAddrReadyMap[port]; !found {
|
||||
portToAddrReadyMap[port] = addressSet{}
|
||||
}
|
||||
// if we have not yet recorded this port for this address, or if the previous
|
||||
// state was ready, write the current ready state. not ready always trumps
|
||||
// ready.
|
||||
if wasReady, found := portToAddrReadyMap[port][existingAddress]; !found || wasReady {
|
||||
portToAddrReadyMap[port][existingAddress] = ready
|
||||
}
|
||||
return existingAddress
|
||||
}
|
||||
|
||||
type addressSet map[*api.EndpointAddress]bool
|
||||
|
||||
type addrReady struct {
|
||||
addr *api.EndpointAddress
|
||||
ready bool
|
||||
}
|
||||
|
||||
func hashAddresses(addrs addressSet) string {
|
||||
// Flatten the list of addresses into a string so it can be used as a
|
||||
// map key. Unfortunately, DeepHashObject is implemented in terms of
|
||||
// spew, and spew does not handle non-primitive map keys well. So
|
||||
// first we collapse it into a slice, sort the slice, then hash that.
|
||||
slice := make([]addrReady, 0, len(addrs))
|
||||
for k, ready := range addrs {
|
||||
slice = append(slice, addrReady{k, ready})
|
||||
}
|
||||
sort.Sort(addrsReady(slice))
|
||||
hasher := md5.New()
|
||||
hashutil.DeepHashObject(hasher, slice)
|
||||
return hex.EncodeToString(hasher.Sum(nil)[0:])
|
||||
}
|
||||
|
||||
func lessAddrReady(a, b addrReady) bool {
|
||||
// ready is not significant to hashing since we can't have duplicate addresses
|
||||
return LessEndpointAddress(a.addr, b.addr)
|
||||
}
|
||||
|
||||
type addrsReady []addrReady
|
||||
|
||||
func (sl addrsReady) Len() int { return len(sl) }
|
||||
func (sl addrsReady) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl addrsReady) Less(i, j int) bool {
|
||||
return lessAddrReady(sl[i], sl[j])
|
||||
}
|
||||
|
||||
// LessEndpointAddress compares IP addresses lexicographically and returns true if first argument is lesser than second
|
||||
func LessEndpointAddress(a, b *api.EndpointAddress) bool {
|
||||
ipComparison := bytes.Compare([]byte(a.IP), []byte(b.IP))
|
||||
if ipComparison != 0 {
|
||||
return ipComparison < 0
|
||||
}
|
||||
if b.TargetRef == nil {
|
||||
return false
|
||||
}
|
||||
if a.TargetRef == nil {
|
||||
return true
|
||||
}
|
||||
return a.TargetRef.UID < b.TargetRef.UID
|
||||
}
|
||||
|
||||
// SortSubsets sorts an array of EndpointSubset objects in place. For ease of
|
||||
// use it returns the input slice.
|
||||
func SortSubsets(subsets []api.EndpointSubset) []api.EndpointSubset {
|
||||
for i := range subsets {
|
||||
ss := &subsets[i]
|
||||
sort.Sort(addrsByIPAndUID(ss.Addresses))
|
||||
sort.Sort(addrsByIPAndUID(ss.NotReadyAddresses))
|
||||
sort.Sort(portsByHash(ss.Ports))
|
||||
}
|
||||
sort.Sort(subsetsByHash(subsets))
|
||||
return subsets
|
||||
}
|
||||
|
||||
func hashObject(hasher hash.Hash, obj interface{}) []byte {
|
||||
hashutil.DeepHashObject(hasher, obj)
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
type subsetsByHash []api.EndpointSubset
|
||||
|
||||
func (sl subsetsByHash) Len() int { return len(sl) }
|
||||
func (sl subsetsByHash) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl subsetsByHash) Less(i, j int) bool {
|
||||
hasher := md5.New()
|
||||
h1 := hashObject(hasher, sl[i])
|
||||
h2 := hashObject(hasher, sl[j])
|
||||
return bytes.Compare(h1, h2) < 0
|
||||
}
|
||||
|
||||
type addrsByIPAndUID []api.EndpointAddress
|
||||
|
||||
func (sl addrsByIPAndUID) Len() int { return len(sl) }
|
||||
func (sl addrsByIPAndUID) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl addrsByIPAndUID) Less(i, j int) bool {
|
||||
return LessEndpointAddress(&sl[i], &sl[j])
|
||||
}
|
||||
|
||||
type portsByHash []api.EndpointPort
|
||||
|
||||
func (sl portsByHash) Len() int { return len(sl) }
|
||||
func (sl portsByHash) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl portsByHash) Less(i, j int) bool {
|
||||
hasher := md5.New()
|
||||
h1 := hashObject(hasher, sl[i])
|
||||
h2 := hashObject(hasher, sl[j])
|
||||
return bytes.Compare(h1, h2) < 0
|
||||
}
|
464
vendor/k8s.io/kubernetes/pkg/api/endpoints/util_test.go
generated
vendored
464
vendor/k8s.io/kubernetes/pkg/api/endpoints/util_test.go
generated
vendored
@ -1,464 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func podRef(uid string) *api.ObjectReference {
|
||||
ref := api.ObjectReference{UID: types.UID(uid)}
|
||||
return &ref
|
||||
}
|
||||
|
||||
func TestPackSubsets(t *testing.T) {
|
||||
// The downside of table-driven tests is that some things have to live outside the table.
|
||||
fooObjRef := api.ObjectReference{Name: "foo"}
|
||||
barObjRef := api.ObjectReference{Name: "bar"}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
given []api.EndpointSubset
|
||||
expect []api.EndpointSubset
|
||||
}{
|
||||
{
|
||||
name: "empty everything",
|
||||
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{}, Ports: []api.EndpointPort{}}},
|
||||
expect: []api.EndpointSubset{},
|
||||
}, {
|
||||
name: "empty addresses",
|
||||
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{}, Ports: []api.EndpointPort{{Port: 111}}}},
|
||||
expect: []api.EndpointSubset{},
|
||||
}, {
|
||||
name: "empty ports",
|
||||
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []api.EndpointPort{}}},
|
||||
expect: []api.EndpointSubset{{Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: nil}},
|
||||
}, {
|
||||
name: "empty ports",
|
||||
given: []api.EndpointSubset{{NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []api.EndpointPort{}}},
|
||||
expect: []api.EndpointSubset{{NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: nil}},
|
||||
}, {
|
||||
name: "one set, one ip, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, one port (IPv6)",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "beef::1:2:3:4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "beef::1:2:3:4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one notReady ip, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, one UID, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one notReady ip, one UID, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, empty UID, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one notReady ip, empty UID, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, two ips, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, two mixed ips, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, two duplicate ips, one port, notReady is covered by ready",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, two ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup ips, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup ips, one port (IPv6)",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "beef::1"}, {IP: "beef::1"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "beef::1"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup ips with target-refs, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: &fooObjRef},
|
||||
{IP: "1.2.3.4", TargetRef: &barObjRef},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &fooObjRef}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup mixed ips with target-refs, one port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: &fooObjRef},
|
||||
},
|
||||
NotReadyAddresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: &barObjRef},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
// finding the same address twice is considered an error on input, only the first address+port
|
||||
// reference is preserved
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &fooObjRef}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, dup ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}, {Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup ip, dup port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup mixed ip, dup port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup ip, two ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup ip, dup uids, two ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup mixed ip, dup uids, two ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two ips, dup port",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two set, dup ip, two uids, dup ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-2")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-2")},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two set, dup ip, with and without uid, dup ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-2")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-2")},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two ips, two dup ip with uid, dup port, wrong order",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "5.6.7.8", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
|
||||
{IP: "5.6.7.8"},
|
||||
{IP: "5.6.7.8", TargetRef: podRef("uid-1")},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two mixed ips, two dup ip with uid, dup port, wrong order, ends up with split addresses",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "5.6.7.8", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "5.6.7.8"},
|
||||
},
|
||||
NotReadyAddresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
|
||||
{IP: "5.6.7.8", TargetRef: podRef("uid-1")},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two ips, two ports",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "four sets, three ips, three ports, jumbled",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.6"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []api.EndpointPort{{Port: 333}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.6"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}, {Port: 333}},
|
||||
}},
|
||||
}, {
|
||||
name: "four sets, three mixed ips, three ports, jumbled",
|
||||
given: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}},
|
||||
}, {
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.6"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []api.EndpointPort{{Port: 333}},
|
||||
}},
|
||||
expect: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.6"}},
|
||||
Ports: []api.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []api.EndpointPort{{Port: 222}, {Port: 333}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
result := RepackSubsets(tc.given)
|
||||
if !reflect.DeepEqual(result, SortSubsets(tc.expect)) {
|
||||
t.Errorf("case %q: expected %s, got %s", tc.name, spew.Sprintf("%#v", SortSubsets(tc.expect)), spew.Sprintf("%#v", result))
|
||||
}
|
||||
}
|
||||
}
|
26
vendor/k8s.io/kubernetes/pkg/api/legacyscheme/BUILD
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/api/legacyscheme/BUILD
generated
vendored
@ -1,26 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["scheme.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/legacyscheme",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
35
vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go
generated
vendored
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 legacyscheme
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered.
|
||||
// NOTE: If you are copying this file to start a new api group, STOP! Copy the
|
||||
// extensions group instead. This Scheme is special and should appear ONLY in
|
||||
// the api group, unless you really know what you're doing.
|
||||
// TODO(lavalamp): make the above error impossible.
|
||||
var Scheme = runtime.NewScheme()
|
||||
|
||||
// Codecs provides access to encoding and decoding for the scheme
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
|
||||
// ParameterCodec handles versioning of objects that are converted to query parameters.
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
40
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/BUILD
generated
vendored
40
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/BUILD
generated
vendored
@ -1,40 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/persistentvolume",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/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"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
|
||||
],
|
||||
)
|
4
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/OWNERS
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/OWNERS
generated
vendored
@ -1,4 +0,0 @@
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- jsafrane
|
||||
- david-mcmahon
|
43
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/util.go
generated
vendored
43
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/util.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolume
|
||||
|
||||
import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// DropDisabledFields removes disabled fields from the pv spec.
|
||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pv spec.
|
||||
func DropDisabledFields(pvSpec *api.PersistentVolumeSpec, oldPVSpec *api.PersistentVolumeSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
// TODO(liggitt): change this to only drop pvSpec.VolumeMode if (oldPVSpec == nil || oldPVSpec.VolumeMode == nil)
|
||||
// Requires more coordinated changes to validation
|
||||
pvSpec.VolumeMode = nil
|
||||
if oldPVSpec != nil {
|
||||
oldPVSpec.VolumeMode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
|
||||
// if this is a new PV, or the old PV didn't already have the CSI field, clear it
|
||||
if oldPVSpec == nil || oldPVSpec.PersistentVolumeSource.CSI == nil {
|
||||
pvSpec.PersistentVolumeSource.CSI = nil
|
||||
}
|
||||
}
|
||||
}
|
155
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/util_test.go
generated
vendored
155
vendor/k8s.io/kubernetes/pkg/api/persistentvolume/util_test.go
generated
vendored
@ -1,155 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolume
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestDropDisabledFields(t *testing.T) {
|
||||
specWithCSI := func() *api.PersistentVolumeSpec {
|
||||
return &api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{CSI: &api.CSIPersistentVolumeSource{}}}
|
||||
}
|
||||
specWithoutCSI := func() *api.PersistentVolumeSpec {
|
||||
return &api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{CSI: nil}}
|
||||
}
|
||||
specWithMode := func(mode *api.PersistentVolumeMode) *api.PersistentVolumeSpec {
|
||||
return &api.PersistentVolumeSpec{VolumeMode: mode}
|
||||
}
|
||||
|
||||
modeBlock := api.PersistentVolumeBlock
|
||||
|
||||
tests := map[string]struct {
|
||||
oldSpec *api.PersistentVolumeSpec
|
||||
newSpec *api.PersistentVolumeSpec
|
||||
expectOldSpec *api.PersistentVolumeSpec
|
||||
expectNewSpec *api.PersistentVolumeSpec
|
||||
csiEnabled bool
|
||||
blockEnabled bool
|
||||
}{
|
||||
"disabled csi clears new": {
|
||||
csiEnabled: false,
|
||||
newSpec: specWithCSI(),
|
||||
expectNewSpec: specWithoutCSI(),
|
||||
oldSpec: nil,
|
||||
expectOldSpec: nil,
|
||||
},
|
||||
"disabled csi clears update when old pv did not use csi": {
|
||||
csiEnabled: false,
|
||||
newSpec: specWithCSI(),
|
||||
expectNewSpec: specWithoutCSI(),
|
||||
oldSpec: specWithoutCSI(),
|
||||
expectOldSpec: specWithoutCSI(),
|
||||
},
|
||||
"disabled csi preserves update when old pv did use csi": {
|
||||
csiEnabled: false,
|
||||
newSpec: specWithCSI(),
|
||||
expectNewSpec: specWithCSI(),
|
||||
oldSpec: specWithCSI(),
|
||||
expectOldSpec: specWithCSI(),
|
||||
},
|
||||
|
||||
"enabled csi preserves new": {
|
||||
csiEnabled: true,
|
||||
newSpec: specWithCSI(),
|
||||
expectNewSpec: specWithCSI(),
|
||||
oldSpec: nil,
|
||||
expectOldSpec: nil,
|
||||
},
|
||||
"enabled csi preserves update when old pv did not use csi": {
|
||||
csiEnabled: true,
|
||||
newSpec: specWithCSI(),
|
||||
expectNewSpec: specWithCSI(),
|
||||
oldSpec: specWithoutCSI(),
|
||||
expectOldSpec: specWithoutCSI(),
|
||||
},
|
||||
"enabled csi preserves update when old pv did use csi": {
|
||||
csiEnabled: true,
|
||||
newSpec: specWithCSI(),
|
||||
expectNewSpec: specWithCSI(),
|
||||
oldSpec: specWithCSI(),
|
||||
expectOldSpec: specWithCSI(),
|
||||
},
|
||||
|
||||
"disabled block clears new": {
|
||||
blockEnabled: false,
|
||||
newSpec: specWithMode(&modeBlock),
|
||||
expectNewSpec: specWithMode(nil),
|
||||
oldSpec: nil,
|
||||
expectOldSpec: nil,
|
||||
},
|
||||
"disabled block clears update when old pv did not use block": {
|
||||
blockEnabled: false,
|
||||
newSpec: specWithMode(&modeBlock),
|
||||
expectNewSpec: specWithMode(nil),
|
||||
oldSpec: specWithMode(nil),
|
||||
expectOldSpec: specWithMode(nil),
|
||||
},
|
||||
// TODO: consider changing this case to preserve
|
||||
"disabled block clears old and new on update when old pv did use block": {
|
||||
blockEnabled: false,
|
||||
newSpec: specWithMode(&modeBlock),
|
||||
expectNewSpec: specWithMode(nil),
|
||||
oldSpec: specWithMode(&modeBlock),
|
||||
expectOldSpec: specWithMode(nil),
|
||||
},
|
||||
|
||||
"enabled block preserves new": {
|
||||
blockEnabled: true,
|
||||
newSpec: specWithMode(&modeBlock),
|
||||
expectNewSpec: specWithMode(&modeBlock),
|
||||
oldSpec: nil,
|
||||
expectOldSpec: nil,
|
||||
},
|
||||
"enabled block preserves update when old pv did not use block": {
|
||||
blockEnabled: true,
|
||||
newSpec: specWithMode(&modeBlock),
|
||||
expectNewSpec: specWithMode(&modeBlock),
|
||||
oldSpec: specWithMode(nil),
|
||||
expectOldSpec: specWithMode(nil),
|
||||
},
|
||||
"enabled block preserves update when old pv did use block": {
|
||||
blockEnabled: true,
|
||||
newSpec: specWithMode(&modeBlock),
|
||||
expectNewSpec: specWithMode(&modeBlock),
|
||||
oldSpec: specWithMode(&modeBlock),
|
||||
expectOldSpec: specWithMode(&modeBlock),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIPersistentVolume, tc.csiEnabled)()
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, tc.blockEnabled)()
|
||||
|
||||
DropDisabledFields(tc.newSpec, tc.oldSpec)
|
||||
if !reflect.DeepEqual(tc.newSpec, tc.expectNewSpec) {
|
||||
t.Error(diff.ObjectReflectDiff(tc.newSpec, tc.expectNewSpec))
|
||||
}
|
||||
if !reflect.DeepEqual(tc.oldSpec, tc.expectOldSpec) {
|
||||
t.Error(diff.ObjectReflectDiff(tc.oldSpec, tc.expectOldSpec))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
46
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/BUILD
generated
vendored
46
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/BUILD
generated
vendored
@ -1,46 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/persistentvolumeclaim",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/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"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"main_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
|
||||
],
|
||||
)
|
4
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/OWNERS
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/OWNERS
generated
vendored
@ -1,4 +0,0 @@
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- jsafrane
|
||||
- david-mcmahon
|
29
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/main_test.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/main_test.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolumeclaim
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
_ "k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
utilfeaturetesting.VerifyFeatureGatesUnchanged(utilfeature.DefaultFeatureGate, m.Run)
|
||||
}
|
31
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/util.go
generated
vendored
31
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/util.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolumeclaim
|
||||
|
||||
import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// DropDisabledAlphaFields removes disabled fields from the pvc spec.
|
||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pvc spec.
|
||||
func DropDisabledAlphaFields(pvcSpec *core.PersistentVolumeClaimSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
pvcSpec.VolumeMode = nil
|
||||
}
|
||||
}
|
60
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/util_test.go
generated
vendored
60
vendor/k8s.io/kubernetes/pkg/api/persistentvolumeclaim/util_test.go
generated
vendored
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolumeclaim
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestDropAlphaPVCVolumeMode(t *testing.T) {
|
||||
vmode := core.PersistentVolumeFilesystem
|
||||
|
||||
// PersistentVolume with VolumeMode set
|
||||
pvc := core.PersistentVolumeClaim{
|
||||
Spec: core.PersistentVolumeClaimSpec{
|
||||
AccessModes: []core.PersistentVolumeAccessMode{core.ReadWriteOnce},
|
||||
VolumeMode: &vmode,
|
||||
},
|
||||
}
|
||||
|
||||
// Enable alpha feature BlockVolume
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
// now test dropping the fields - should not be dropped
|
||||
DropDisabledAlphaFields(&pvc.Spec)
|
||||
|
||||
// check to make sure VolumeDevices is still present
|
||||
// if featureset is set to true
|
||||
if pvc.Spec.VolumeMode == nil {
|
||||
t.Error("VolumeMode in pvc.Spec should not have been dropped based on feature-gate")
|
||||
}
|
||||
|
||||
// Disable alpha feature BlockVolume
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, false)()
|
||||
// now test dropping the fields
|
||||
DropDisabledAlphaFields(&pvc.Spec)
|
||||
|
||||
// check to make sure VolumeDevices is nil
|
||||
// if featureset is set to false
|
||||
if pvc.Spec.VolumeMode != nil {
|
||||
t.Error("DropDisabledAlphaFields VolumeMode for pvc.Spec failed")
|
||||
}
|
||||
}
|
49
vendor/k8s.io/kubernetes/pkg/api/pod/BUILD
generated
vendored
49
vendor/k8s.io/kubernetes/pkg/api/pod/BUILD
generated
vendored
@ -1,49 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/pod",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/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"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"main_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
|
||||
],
|
||||
)
|
4
vendor/k8s.io/kubernetes/pkg/api/pod/OWNERS
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/api/pod/OWNERS
generated
vendored
@ -1,4 +0,0 @@
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- thockin
|
||||
- david-mcmahon
|
29
vendor/k8s.io/kubernetes/pkg/api/pod/main_test.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/api/pod/main_test.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pod
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
_ "k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
utilfeaturetesting.VerifyFeatureGatesUnchanged(utilfeature.DefaultFeatureGate, m.Run)
|
||||
}
|
311
vendor/k8s.io/kubernetes/pkg/api/pod/util.go
generated
vendored
311
vendor/k8s.io/kubernetes/pkg/api/pod/util.go
generated
vendored
@ -1,311 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pod
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// Visitor is called with each object name, and returns true if visiting should continue
|
||||
type Visitor func(name string) (shouldContinue bool)
|
||||
|
||||
// VisitPodSecretNames invokes the visitor function with the name of every secret
|
||||
// referenced by the pod spec. If visitor returns false, visiting is short-circuited.
|
||||
// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
|
||||
// Returns true if visiting completed, false if visiting was short-circuited.
|
||||
func VisitPodSecretNames(pod *api.Pod, visitor Visitor) bool {
|
||||
for _, reference := range pod.Spec.ImagePullSecrets {
|
||||
if !visitor(reference.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.InitContainers {
|
||||
if !visitContainerSecretNames(&pod.Spec.InitContainers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.Containers {
|
||||
if !visitContainerSecretNames(&pod.Spec.Containers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
var source *api.VolumeSource
|
||||
for i := range pod.Spec.Volumes {
|
||||
source = &pod.Spec.Volumes[i].VolumeSource
|
||||
switch {
|
||||
case source.AzureFile != nil:
|
||||
if len(source.AzureFile.SecretName) > 0 && !visitor(source.AzureFile.SecretName) {
|
||||
return false
|
||||
}
|
||||
case source.CephFS != nil:
|
||||
if source.CephFS.SecretRef != nil && !visitor(source.CephFS.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.Cinder != nil:
|
||||
if source.Cinder.SecretRef != nil && !visitor(source.Cinder.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.FlexVolume != nil:
|
||||
if source.FlexVolume.SecretRef != nil && !visitor(source.FlexVolume.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.Projected != nil:
|
||||
for j := range source.Projected.Sources {
|
||||
if source.Projected.Sources[j].Secret != nil {
|
||||
if !visitor(source.Projected.Sources[j].Secret.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case source.RBD != nil:
|
||||
if source.RBD.SecretRef != nil && !visitor(source.RBD.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.Secret != nil:
|
||||
if !visitor(source.Secret.SecretName) {
|
||||
return false
|
||||
}
|
||||
case source.ScaleIO != nil:
|
||||
if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.ISCSI != nil:
|
||||
if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.StorageOS != nil:
|
||||
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func visitContainerSecretNames(container *api.Container, visitor Visitor) bool {
|
||||
for _, env := range container.EnvFrom {
|
||||
if env.SecretRef != nil {
|
||||
if !visitor(env.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, envVar := range container.Env {
|
||||
if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil {
|
||||
if !visitor(envVar.ValueFrom.SecretKeyRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// VisitPodConfigmapNames invokes the visitor function with the name of every configmap
|
||||
// referenced by the pod spec. If visitor returns false, visiting is short-circuited.
|
||||
// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
|
||||
// Returns true if visiting completed, false if visiting was short-circuited.
|
||||
func VisitPodConfigmapNames(pod *api.Pod, visitor Visitor) bool {
|
||||
for i := range pod.Spec.InitContainers {
|
||||
if !visitContainerConfigmapNames(&pod.Spec.InitContainers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.Containers {
|
||||
if !visitContainerConfigmapNames(&pod.Spec.Containers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
var source *api.VolumeSource
|
||||
for i := range pod.Spec.Volumes {
|
||||
source = &pod.Spec.Volumes[i].VolumeSource
|
||||
switch {
|
||||
case source.Projected != nil:
|
||||
for j := range source.Projected.Sources {
|
||||
if source.Projected.Sources[j].ConfigMap != nil {
|
||||
if !visitor(source.Projected.Sources[j].ConfigMap.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case source.ConfigMap != nil:
|
||||
if !visitor(source.ConfigMap.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func visitContainerConfigmapNames(container *api.Container, visitor Visitor) bool {
|
||||
for _, env := range container.EnvFrom {
|
||||
if env.ConfigMapRef != nil {
|
||||
if !visitor(env.ConfigMapRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, envVar := range container.Env {
|
||||
if envVar.ValueFrom != nil && envVar.ValueFrom.ConfigMapKeyRef != nil {
|
||||
if !visitor(envVar.ValueFrom.ConfigMapKeyRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsPodReady returns true if a pod is ready; false otherwise.
|
||||
func IsPodReady(pod *api.Pod) bool {
|
||||
return IsPodReadyConditionTrue(pod.Status)
|
||||
}
|
||||
|
||||
// IsPodReadyConditionTrue returns true if a pod is ready; false otherwise.
|
||||
func IsPodReadyConditionTrue(status api.PodStatus) bool {
|
||||
condition := GetPodReadyCondition(status)
|
||||
return condition != nil && condition.Status == api.ConditionTrue
|
||||
}
|
||||
|
||||
// GetPodReadyCondition extracts the pod ready condition from the given status and returns that.
|
||||
// Returns nil if the condition is not present.
|
||||
func GetPodReadyCondition(status api.PodStatus) *api.PodCondition {
|
||||
_, condition := GetPodCondition(&status, api.PodReady)
|
||||
return condition
|
||||
}
|
||||
|
||||
// GetPodCondition extracts the provided condition from the given status and returns that.
|
||||
// Returns nil and -1 if the condition is not present, and the index of the located condition.
|
||||
func GetPodCondition(status *api.PodStatus, conditionType api.PodConditionType) (int, *api.PodCondition) {
|
||||
if status == nil {
|
||||
return -1, nil
|
||||
}
|
||||
for i := range status.Conditions {
|
||||
if status.Conditions[i].Type == conditionType {
|
||||
return i, &status.Conditions[i]
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// UpdatePodCondition updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
|
||||
// status has changed.
|
||||
// Returns true if pod condition has changed or has been added.
|
||||
func UpdatePodCondition(status *api.PodStatus, condition *api.PodCondition) bool {
|
||||
condition.LastTransitionTime = metav1.Now()
|
||||
// Try to find this pod condition.
|
||||
conditionIndex, oldCondition := GetPodCondition(status, condition.Type)
|
||||
|
||||
if oldCondition == nil {
|
||||
// We are adding new pod condition.
|
||||
status.Conditions = append(status.Conditions, *condition)
|
||||
return true
|
||||
}
|
||||
// We are updating an existing condition, so we need to check if it has changed.
|
||||
if condition.Status == oldCondition.Status {
|
||||
condition.LastTransitionTime = oldCondition.LastTransitionTime
|
||||
}
|
||||
|
||||
isEqual := condition.Status == oldCondition.Status &&
|
||||
condition.Reason == oldCondition.Reason &&
|
||||
condition.Message == oldCondition.Message &&
|
||||
condition.LastProbeTime.Equal(&oldCondition.LastProbeTime) &&
|
||||
condition.LastTransitionTime.Equal(&oldCondition.LastTransitionTime)
|
||||
|
||||
status.Conditions[conditionIndex] = *condition
|
||||
// Return true if one of the fields have changed.
|
||||
return !isEqual
|
||||
}
|
||||
|
||||
// DropDisabledAlphaFields removes disabled fields from the pod spec.
|
||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pod spec.
|
||||
func DropDisabledAlphaFields(podSpec *api.PodSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodPriority) {
|
||||
podSpec.Priority = nil
|
||||
podSpec.PriorityClassName = ""
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
|
||||
for i := range podSpec.Volumes {
|
||||
if podSpec.Volumes[i].EmptyDir != nil {
|
||||
podSpec.Volumes[i].EmptyDir.SizeLimit = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropDisabledVolumeDevicesAlphaFields(podSpec)
|
||||
|
||||
DropDisabledRunAsGroupField(podSpec)
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) && podSpec.RuntimeClassName != nil {
|
||||
podSpec.RuntimeClassName = nil
|
||||
}
|
||||
|
||||
DropDisabledProcMountField(podSpec)
|
||||
}
|
||||
|
||||
// DropDisabledRunAsGroupField removes disabled fields from PodSpec related
|
||||
// to RunAsGroup
|
||||
func DropDisabledRunAsGroupField(podSpec *api.PodSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.RunAsGroup) {
|
||||
if podSpec.SecurityContext != nil {
|
||||
podSpec.SecurityContext.RunAsGroup = nil
|
||||
}
|
||||
for i := range podSpec.Containers {
|
||||
if podSpec.Containers[i].SecurityContext != nil {
|
||||
podSpec.Containers[i].SecurityContext.RunAsGroup = nil
|
||||
}
|
||||
}
|
||||
for i := range podSpec.InitContainers {
|
||||
if podSpec.InitContainers[i].SecurityContext != nil {
|
||||
podSpec.InitContainers[i].SecurityContext.RunAsGroup = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DropDisabledProcMountField removes disabled fields from PodSpec related
|
||||
// to ProcMount
|
||||
func DropDisabledProcMountField(podSpec *api.PodSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) {
|
||||
defProcMount := api.DefaultProcMount
|
||||
for i := range podSpec.Containers {
|
||||
if podSpec.Containers[i].SecurityContext != nil {
|
||||
podSpec.Containers[i].SecurityContext.ProcMount = &defProcMount
|
||||
}
|
||||
}
|
||||
for i := range podSpec.InitContainers {
|
||||
if podSpec.InitContainers[i].SecurityContext != nil {
|
||||
podSpec.InitContainers[i].SecurityContext.ProcMount = &defProcMount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DropDisabledVolumeDevicesAlphaFields removes disabled fields from []VolumeDevice.
|
||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a VolumeDevice
|
||||
func DropDisabledVolumeDevicesAlphaFields(podSpec *api.PodSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
for i := range podSpec.Containers {
|
||||
podSpec.Containers[i].VolumeDevices = nil
|
||||
}
|
||||
for i := range podSpec.InitContainers {
|
||||
podSpec.InitContainers[i].VolumeDevices = nil
|
||||
}
|
||||
}
|
||||
}
|
335
vendor/k8s.io/kubernetes/pkg/api/pod/util_test.go
generated
vendored
335
vendor/k8s.io/kubernetes/pkg/api/pod/util_test.go
generated
vendored
@ -1,335 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pod
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestPodSecrets(t *testing.T) {
|
||||
// Stub containing all possible secret references in a pod.
|
||||
// The names of the referenced secrets match struct paths detected by reflection.
|
||||
pod := &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
EnvFrom: []api.EnvFromSource{{
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].EnvFrom[*].SecretRef"}}}},
|
||||
Env: []api.EnvVar{{
|
||||
ValueFrom: &api.EnvVarSource{
|
||||
SecretKeyRef: &api.SecretKeySelector{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].Env[*].ValueFrom.SecretKeyRef"}}}}}}},
|
||||
ImagePullSecrets: []api.LocalObjectReference{{
|
||||
Name: "Spec.ImagePullSecrets"}},
|
||||
InitContainers: []api.Container{{
|
||||
EnvFrom: []api.EnvFromSource{{
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].EnvFrom[*].SecretRef"}}}},
|
||||
Env: []api.EnvVar{{
|
||||
ValueFrom: &api.EnvVarSource{
|
||||
SecretKeyRef: &api.SecretKeySelector{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].Env[*].ValueFrom.SecretKeyRef"}}}}}}},
|
||||
Volumes: []api.Volume{{
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureFile: &api.AzureFileVolumeSource{
|
||||
SecretName: "Spec.Volumes[*].VolumeSource.AzureFile.SecretName"}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
CephFS: &api.CephFSVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.CephFS.SecretRef"}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
Cinder: &api.CinderVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.Cinder.SecretRef"}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
FlexVolume: &api.FlexVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.FlexVolume.SecretRef"}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
Projected: &api.ProjectedVolumeSource{
|
||||
Sources: []api.VolumeProjection{{
|
||||
Secret: &api.SecretProjection{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.Projected.Sources[*].Secret"}}}}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
RBD: &api.RBDVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.RBD.SecretRef"}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
Secret: &api.SecretVolumeSource{
|
||||
SecretName: "Spec.Volumes[*].VolumeSource.Secret.SecretName"}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
Secret: &api.SecretVolumeSource{
|
||||
SecretName: "Spec.Volumes[*].VolumeSource.Secret"}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
ScaleIO: &api.ScaleIOVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef"}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
ISCSI: &api.ISCSIVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.ISCSI.SecretRef"}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
StorageOS: &api.StorageOSVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef"}}}}},
|
||||
},
|
||||
}
|
||||
extractedNames := sets.NewString()
|
||||
VisitPodSecretNames(pod, func(name string) bool {
|
||||
extractedNames.Insert(name)
|
||||
return true
|
||||
})
|
||||
|
||||
// excludedSecretPaths holds struct paths to fields with "secret" in the name that are not actually references to secret API objects
|
||||
excludedSecretPaths := sets.NewString(
|
||||
"Spec.Volumes[*].VolumeSource.CephFS.SecretFile",
|
||||
)
|
||||
// expectedSecretPaths holds struct paths to fields with "secret" in the name that are references to secret API objects.
|
||||
// every path here should be represented as an example in the Pod stub above, with the secret name set to the path.
|
||||
expectedSecretPaths := sets.NewString(
|
||||
"Spec.Containers[*].EnvFrom[*].SecretRef",
|
||||
"Spec.Containers[*].Env[*].ValueFrom.SecretKeyRef",
|
||||
"Spec.ImagePullSecrets",
|
||||
"Spec.InitContainers[*].EnvFrom[*].SecretRef",
|
||||
"Spec.InitContainers[*].Env[*].ValueFrom.SecretKeyRef",
|
||||
"Spec.Volumes[*].VolumeSource.AzureFile.SecretName",
|
||||
"Spec.Volumes[*].VolumeSource.CephFS.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.Cinder.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.FlexVolume.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.Projected.Sources[*].Secret",
|
||||
"Spec.Volumes[*].VolumeSource.RBD.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.Secret",
|
||||
"Spec.Volumes[*].VolumeSource.Secret.SecretName",
|
||||
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.StorageOS.SecretRef",
|
||||
)
|
||||
secretPaths := collectResourcePaths(t, "secret", nil, "", reflect.TypeOf(&api.Pod{}))
|
||||
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
||||
if missingPaths := expectedSecretPaths.Difference(secretPaths); len(missingPaths) > 0 {
|
||||
t.Logf("Missing expected secret paths:\n%s", strings.Join(missingPaths.List(), "\n"))
|
||||
t.Error("Missing expected secret paths. Verify VisitPodSecretNames() is correctly finding the missing paths, then correct expectedSecretPaths")
|
||||
}
|
||||
if extraPaths := secretPaths.Difference(expectedSecretPaths); len(extraPaths) > 0 {
|
||||
t.Logf("Extra secret paths:\n%s", strings.Join(extraPaths.List(), "\n"))
|
||||
t.Error("Extra fields with 'secret' in the name found. Verify VisitPodSecretNames() is including these fields if appropriate, then correct expectedSecretPaths")
|
||||
}
|
||||
|
||||
if missingNames := expectedSecretPaths.Difference(extractedNames); len(missingNames) > 0 {
|
||||
t.Logf("Missing expected secret names:\n%s", strings.Join(missingNames.List(), "\n"))
|
||||
t.Error("Missing expected secret names. Verify the pod stub above includes these references, then verify VisitPodSecretNames() is correctly finding the missing names")
|
||||
}
|
||||
if extraNames := extractedNames.Difference(expectedSecretPaths); len(extraNames) > 0 {
|
||||
t.Logf("Extra secret names:\n%s", strings.Join(extraNames.List(), "\n"))
|
||||
t.Error("Extra secret names extracted. Verify VisitPodSecretNames() is correctly extracting secret names")
|
||||
}
|
||||
}
|
||||
|
||||
// collectResourcePaths traverses the object, computing all the struct paths that lead to fields with resourcename in the name.
|
||||
func collectResourcePaths(t *testing.T, resourcename string, path *field.Path, name string, tp reflect.Type) sets.String {
|
||||
resourcename = strings.ToLower(resourcename)
|
||||
resourcePaths := sets.NewString()
|
||||
|
||||
if tp.Kind() == reflect.Ptr {
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...)
|
||||
return resourcePaths
|
||||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(name), resourcename) {
|
||||
resourcePaths.Insert(path.String())
|
||||
}
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Ptr:
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...)
|
||||
case reflect.Struct:
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
field := tp.Field(i)
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Child(field.Name), field.Name, field.Type).List()...)
|
||||
}
|
||||
case reflect.Interface:
|
||||
t.Errorf("cannot find %s fields in interface{} field %s", resourcename, path.String())
|
||||
case reflect.Map:
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...)
|
||||
case reflect.Slice:
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...)
|
||||
default:
|
||||
// all primitive types
|
||||
}
|
||||
|
||||
return resourcePaths
|
||||
}
|
||||
|
||||
func TestPodConfigmaps(t *testing.T) {
|
||||
// Stub containing all possible ConfigMap references in a pod.
|
||||
// The names of the referenced ConfigMaps match struct paths detected by reflection.
|
||||
pod := &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
EnvFrom: []api.EnvFromSource{{
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].EnvFrom[*].ConfigMapRef"}}}},
|
||||
Env: []api.EnvVar{{
|
||||
ValueFrom: &api.EnvVarSource{
|
||||
ConfigMapKeyRef: &api.ConfigMapKeySelector{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef"}}}}}}},
|
||||
InitContainers: []api.Container{{
|
||||
EnvFrom: []api.EnvFromSource{{
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].EnvFrom[*].ConfigMapRef"}}}},
|
||||
Env: []api.EnvVar{{
|
||||
ValueFrom: &api.EnvVarSource{
|
||||
ConfigMapKeyRef: &api.ConfigMapKeySelector{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef"}}}}}}},
|
||||
Volumes: []api.Volume{{
|
||||
VolumeSource: api.VolumeSource{
|
||||
Projected: &api.ProjectedVolumeSource{
|
||||
Sources: []api.VolumeProjection{{
|
||||
ConfigMap: &api.ConfigMapProjection{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap"}}}}}}}, {
|
||||
VolumeSource: api.VolumeSource{
|
||||
ConfigMap: &api.ConfigMapVolumeSource{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.ConfigMap"}}}}},
|
||||
},
|
||||
}
|
||||
extractedNames := sets.NewString()
|
||||
VisitPodConfigmapNames(pod, func(name string) bool {
|
||||
extractedNames.Insert(name)
|
||||
return true
|
||||
})
|
||||
|
||||
// expectedPaths holds struct paths to fields with "ConfigMap" in the name that are references to ConfigMap API objects.
|
||||
// every path here should be represented as an example in the Pod stub above, with the ConfigMap name set to the path.
|
||||
expectedPaths := sets.NewString(
|
||||
"Spec.Containers[*].EnvFrom[*].ConfigMapRef",
|
||||
"Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef",
|
||||
"Spec.InitContainers[*].EnvFrom[*].ConfigMapRef",
|
||||
"Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef",
|
||||
"Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap",
|
||||
"Spec.Volumes[*].VolumeSource.ConfigMap",
|
||||
)
|
||||
collectPaths := collectResourcePaths(t, "ConfigMap", nil, "", reflect.TypeOf(&api.Pod{}))
|
||||
if missingPaths := expectedPaths.Difference(collectPaths); len(missingPaths) > 0 {
|
||||
t.Logf("Missing expected paths:\n%s", strings.Join(missingPaths.List(), "\n"))
|
||||
t.Error("Missing expected paths. Verify VisitPodConfigmapNames() is correctly finding the missing paths, then correct expectedPaths")
|
||||
}
|
||||
if extraPaths := collectPaths.Difference(expectedPaths); len(extraPaths) > 0 {
|
||||
t.Logf("Extra paths:\n%s", strings.Join(extraPaths.List(), "\n"))
|
||||
t.Error("Extra fields with resource in the name found. Verify VisitPodConfigmapNames() is including these fields if appropriate, then correct expectedPaths")
|
||||
}
|
||||
|
||||
if missingNames := expectedPaths.Difference(extractedNames); len(missingNames) > 0 {
|
||||
t.Logf("Missing expected names:\n%s", strings.Join(missingNames.List(), "\n"))
|
||||
t.Error("Missing expected names. Verify the pod stub above includes these references, then verify VisitPodConfigmapNames() is correctly finding the missing names")
|
||||
}
|
||||
if extraNames := extractedNames.Difference(expectedPaths); len(extraNames) > 0 {
|
||||
t.Logf("Extra names:\n%s", strings.Join(extraNames.List(), "\n"))
|
||||
t.Error("Extra names extracted. Verify VisitPodConfigmapNames() is correctly extracting resource names")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropAlphaVolumeDevices(t *testing.T) {
|
||||
testPod := api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "container1",
|
||||
Image: "testimage",
|
||||
VolumeDevices: []api.VolumeDevice{
|
||||
{
|
||||
Name: "myvolume",
|
||||
DevicePath: "/usr/test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{
|
||||
Name: "container1",
|
||||
Image: "testimage",
|
||||
VolumeDevices: []api.VolumeDevice{
|
||||
{
|
||||
Name: "myvolume",
|
||||
DevicePath: "/usr/test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "myvolume",
|
||||
VolumeSource: api.VolumeSource{
|
||||
HostPath: &api.HostPathVolumeSource{
|
||||
Path: "/dev/xvdc",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Enable alpha feature BlockVolume
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
|
||||
// now test dropping the fields - should not be dropped
|
||||
DropDisabledAlphaFields(&testPod.Spec)
|
||||
|
||||
// check to make sure VolumeDevices is still present
|
||||
// if featureset is set to true
|
||||
if testPod.Spec.Containers[0].VolumeDevices == nil {
|
||||
t.Error("VolumeDevices in Container should not have been dropped based on feature-gate")
|
||||
}
|
||||
if testPod.Spec.InitContainers[0].VolumeDevices == nil {
|
||||
t.Error("VolumeDevices in InitContainers should not have been dropped based on feature-gate")
|
||||
}
|
||||
|
||||
// Disable alpha feature BlockVolume
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, false)()
|
||||
|
||||
// now test dropping the fields
|
||||
DropDisabledAlphaFields(&testPod.Spec)
|
||||
|
||||
// check to make sure VolumeDevices is nil
|
||||
// if featureset is set to false
|
||||
if testPod.Spec.Containers[0].VolumeDevices != nil {
|
||||
t.Error("DropDisabledAlphaFields for Containers failed")
|
||||
}
|
||||
if testPod.Spec.InitContainers[0].VolumeDevices != nil {
|
||||
t.Error("DropDisabledAlphaFields for InitContainers failed")
|
||||
}
|
||||
}
|
47
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/BUILD
generated
vendored
47
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/BUILD
generated
vendored
@ -1,47 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/podsecuritypolicy",
|
||||
deps = [
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/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"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"main_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
|
||||
],
|
||||
)
|
3
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/OWNERS
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/OWNERS
generated
vendored
@ -1,3 +0,0 @@
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- jessfraz
|
29
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/main_test.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/main_test.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package podsecuritypolicy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
_ "k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
utilfeaturetesting.VerifyFeatureGatesUnchanged(utilfeature.DefaultFeatureGate, m.Run)
|
||||
}
|
34
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/util.go
generated
vendored
34
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/util.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package podsecuritypolicy
|
||||
|
||||
import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// DropDisabledAlphaFields removes disabled fields from the pod security policy spec.
|
||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a od security policy spec.
|
||||
func DropDisabledAlphaFields(pspSpec *policy.PodSecurityPolicySpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) {
|
||||
pspSpec.AllowedProcMountTypes = nil
|
||||
}
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.RunAsGroup) {
|
||||
pspSpec.RunAsGroup = nil
|
||||
}
|
||||
}
|
69
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/util_test.go
generated
vendored
69
vendor/k8s.io/kubernetes/pkg/api/podsecuritypolicy/util_test.go
generated
vendored
@ -1,69 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package podsecuritypolicy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestDropAlphaProcMountType(t *testing.T) {
|
||||
// PodSecurityPolicy with AllowedProcMountTypes set
|
||||
psp := policy.PodSecurityPolicy{
|
||||
Spec: policy.PodSecurityPolicySpec{
|
||||
AllowedProcMountTypes: []api.ProcMountType{api.UnmaskedProcMount},
|
||||
},
|
||||
}
|
||||
|
||||
// Enable alpha feature ProcMountType
|
||||
err1 := utilfeature.DefaultFeatureGate.Set("ProcMountType=true")
|
||||
if err1 != nil {
|
||||
t.Fatalf("Failed to enable feature gate for ProcMountType: %v", err1)
|
||||
}
|
||||
|
||||
// now test dropping the fields - should not be dropped
|
||||
DropDisabledAlphaFields(&psp.Spec)
|
||||
|
||||
// check to make sure AllowedProcMountTypes is still present
|
||||
// if featureset is set to true
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) {
|
||||
if psp.Spec.AllowedProcMountTypes == nil {
|
||||
t.Error("AllowedProcMountTypes in pvc.Spec should not have been dropped based on feature-gate")
|
||||
}
|
||||
}
|
||||
|
||||
// Disable alpha feature ProcMountType
|
||||
err := utilfeature.DefaultFeatureGate.Set("ProcMountType=false")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to disable feature gate for ProcMountType: %v", err)
|
||||
}
|
||||
|
||||
// now test dropping the fields
|
||||
DropDisabledAlphaFields(&psp.Spec)
|
||||
|
||||
// check to make sure AllowedProcMountTypes is nil
|
||||
// if featureset is set to false
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) {
|
||||
if psp.Spec.AllowedProcMountTypes != nil {
|
||||
t.Error("DropDisabledAlphaFields AllowedProcMountTypes for psp.Spec failed")
|
||||
}
|
||||
}
|
||||
}
|
46
vendor/k8s.io/kubernetes/pkg/api/ref/BUILD
generated
vendored
46
vendor/k8s.io/kubernetes/pkg/api/ref/BUILD
generated
vendored
@ -1,46 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["ref_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["ref.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/ref",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
122
vendor/k8s.io/kubernetes/pkg/api/ref/ref.go
generated
vendored
122
vendor/k8s.io/kubernetes/pkg/api/ref/ref.go
generated
vendored
@ -1,122 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 ref
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// Errors that could be returned by GetReference.
|
||||
var (
|
||||
ErrNilObject = errors.New("can't reference a nil object")
|
||||
ErrNoSelfLink = errors.New("selfLink was empty, can't make reference")
|
||||
)
|
||||
|
||||
// GetReference returns an ObjectReference which refers to the given
|
||||
// object, or an error if the object doesn't follow the conventions
|
||||
// that would allow this.
|
||||
// TODO: should take a meta.Interface see http://issue.k8s.io/7127
|
||||
func GetReference(scheme *runtime.Scheme, obj runtime.Object) (*api.ObjectReference, error) {
|
||||
if obj == nil {
|
||||
return nil, ErrNilObject
|
||||
}
|
||||
if ref, ok := obj.(*api.ObjectReference); ok {
|
||||
// Don't make a reference to a reference.
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
|
||||
// if the object referenced is actually persisted, we can just get kind from meta
|
||||
// if we are building an object reference to something not yet persisted, we should fallback to scheme
|
||||
kind := gvk.Kind
|
||||
if len(kind) == 0 {
|
||||
// TODO: this is wrong
|
||||
gvks, _, err := scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kind = gvks[0].Kind
|
||||
}
|
||||
|
||||
// An object that implements only List has enough metadata to build a reference
|
||||
var listMeta metav1.Common
|
||||
objectMeta, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
listMeta, err = meta.CommonAccessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
listMeta = objectMeta
|
||||
}
|
||||
|
||||
// if the object referenced is actually persisted, we can also get version from meta
|
||||
version := gvk.GroupVersion().String()
|
||||
if len(version) == 0 {
|
||||
selfLink := listMeta.GetSelfLink()
|
||||
if len(selfLink) == 0 {
|
||||
return nil, ErrNoSelfLink
|
||||
}
|
||||
selfLinkURL, err := url.Parse(selfLink)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// example paths: /<prefix>/<version>/*
|
||||
parts := strings.Split(selfLinkURL.Path, "/")
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", selfLink, version)
|
||||
}
|
||||
version = parts[2]
|
||||
}
|
||||
|
||||
// only has list metadata
|
||||
if objectMeta == nil {
|
||||
return &api.ObjectReference{
|
||||
Kind: kind,
|
||||
APIVersion: version,
|
||||
ResourceVersion: listMeta.GetResourceVersion(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &api.ObjectReference{
|
||||
Kind: kind,
|
||||
APIVersion: version,
|
||||
Name: objectMeta.GetName(),
|
||||
Namespace: objectMeta.GetNamespace(),
|
||||
UID: objectMeta.GetUID(),
|
||||
ResourceVersion: objectMeta.GetResourceVersion(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetPartialReference is exactly like GetReference, but allows you to set the FieldPath.
|
||||
func GetPartialReference(scheme *runtime.Scheme, obj runtime.Object, fieldPath string) (*api.ObjectReference, error) {
|
||||
ref, err := GetReference(scheme, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref.FieldPath = fieldPath
|
||||
return ref, nil
|
||||
}
|
150
vendor/k8s.io/kubernetes/pkg/api/ref/ref_test.go
generated
vendored
150
vendor/k8s.io/kubernetes/pkg/api/ref/ref_test.go
generated
vendored
@ -1,150 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 ref
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
type FakeAPIObject struct{}
|
||||
|
||||
func (obj *FakeAPIObject) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
func (obj *FakeAPIObject) DeepCopyObject() runtime.Object {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
clone := *obj
|
||||
return &clone
|
||||
}
|
||||
|
||||
type ExtensionAPIObject struct {
|
||||
metav1.TypeMeta
|
||||
metav1.ObjectMeta
|
||||
}
|
||||
|
||||
func (obj *ExtensionAPIObject) DeepCopyObject() runtime.Object {
|
||||
panic("ExtensionAPIObject does not support DeepCopy")
|
||||
}
|
||||
|
||||
func TestGetReference(t *testing.T) {
|
||||
|
||||
// when vendoring kube, if you don't force the set of registered versions (like make test does)
|
||||
// then you run into trouble because the types aren't registered in the scheme by anything. This does the
|
||||
// register manually to allow unit test execution
|
||||
if _, _, err := legacyscheme.Scheme.ObjectKinds(&api.Pod{}); err != nil {
|
||||
require.NoError(t, api.AddToScheme(legacyscheme.Scheme))
|
||||
}
|
||||
|
||||
table := map[string]struct {
|
||||
obj runtime.Object
|
||||
ref *api.ObjectReference
|
||||
fieldPath string
|
||||
shouldErr bool
|
||||
}{
|
||||
"pod": {
|
||||
obj: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
UID: "bar",
|
||||
ResourceVersion: "42",
|
||||
SelfLink: "/api/version1/pods/foo",
|
||||
},
|
||||
},
|
||||
fieldPath: ".desiredState.containers[0]",
|
||||
ref: &api.ObjectReference{
|
||||
Kind: "Pod",
|
||||
APIVersion: "version1",
|
||||
Name: "foo",
|
||||
UID: "bar",
|
||||
ResourceVersion: "42",
|
||||
FieldPath: ".desiredState.containers[0]",
|
||||
},
|
||||
},
|
||||
"serviceList": {
|
||||
obj: &api.ServiceList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "42",
|
||||
SelfLink: "/api/version2/services",
|
||||
},
|
||||
},
|
||||
ref: &api.ObjectReference{
|
||||
Kind: "ServiceList",
|
||||
APIVersion: "version2",
|
||||
ResourceVersion: "42",
|
||||
},
|
||||
},
|
||||
"extensionAPIObject": {
|
||||
obj: &ExtensionAPIObject{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ExtensionAPIObject",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
UID: "bar",
|
||||
ResourceVersion: "42",
|
||||
SelfLink: "/custom_prefix/version1/extensions/foo",
|
||||
},
|
||||
},
|
||||
ref: &api.ObjectReference{
|
||||
Kind: "ExtensionAPIObject",
|
||||
APIVersion: "version1",
|
||||
Name: "foo",
|
||||
UID: "bar",
|
||||
ResourceVersion: "42",
|
||||
},
|
||||
},
|
||||
"badSelfLink": {
|
||||
obj: &api.ServiceList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "42",
|
||||
SelfLink: "version2/services",
|
||||
},
|
||||
},
|
||||
shouldErr: true,
|
||||
},
|
||||
"error": {
|
||||
obj: &FakeAPIObject{},
|
||||
ref: nil,
|
||||
shouldErr: true,
|
||||
},
|
||||
"errorNil": {
|
||||
obj: nil,
|
||||
ref: nil,
|
||||
shouldErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, item := range table {
|
||||
ref, err := GetPartialReference(legacyscheme.Scheme, item.obj, item.fieldPath)
|
||||
if e, a := item.shouldErr, (err != nil); e != a {
|
||||
t.Errorf("%v: expected %v, got %v, err %v", name, e, a, err)
|
||||
continue
|
||||
}
|
||||
if e, a := item.ref, ref; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%v: expected %#v, got %#v", name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
42
vendor/k8s.io/kubernetes/pkg/api/resource/BUILD
generated
vendored
42
vendor/k8s.io/kubernetes/pkg/api/resource/BUILD
generated
vendored
@ -1,42 +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 = ["helpers.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/resource",
|
||||
deps = [
|
||||
"//pkg/apis/core: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"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["helpers_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core: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/util/uuid:go_default_library",
|
||||
],
|
||||
)
|
118
vendor/k8s.io/kubernetes/pkg/api/resource/helpers.go
generated
vendored
118
vendor/k8s.io/kubernetes/pkg/api/resource/helpers.go
generated
vendored
@ -1,118 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// addResourceList adds the resources in newList to list
|
||||
func addResourceList(list, new api.ResourceList) {
|
||||
for name, quantity := range new {
|
||||
if value, ok := list[name]; !ok {
|
||||
list[name] = *quantity.Copy()
|
||||
} else {
|
||||
value.Add(quantity)
|
||||
list[name] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maxResourceList sets list to the greater of list/newList for every resource
|
||||
// either list
|
||||
func maxResourceList(list, new api.ResourceList) {
|
||||
for name, quantity := range new {
|
||||
if value, ok := list[name]; !ok {
|
||||
list[name] = *quantity.Copy()
|
||||
continue
|
||||
} else {
|
||||
if quantity.Cmp(value) > 0 {
|
||||
list[name] = *quantity.Copy()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
|
||||
// containers of the pod.
|
||||
func PodRequestsAndLimits(pod *api.Pod) (reqs api.ResourceList, limits api.ResourceList) {
|
||||
reqs, limits = api.ResourceList{}, api.ResourceList{}
|
||||
for _, container := range pod.Spec.Containers {
|
||||
addResourceList(reqs, container.Resources.Requests)
|
||||
addResourceList(limits, container.Resources.Limits)
|
||||
}
|
||||
// init containers define the minimum of any resource
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
maxResourceList(reqs, container.Resources.Requests)
|
||||
maxResourceList(limits, container.Resources.Limits)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ExtractContainerResourceValue extracts the value of a resource
|
||||
// in an already known container
|
||||
func ExtractContainerResourceValue(fs *api.ResourceFieldSelector, container *api.Container) (string, error) {
|
||||
divisor := resource.Quantity{}
|
||||
if divisor.Cmp(fs.Divisor) == 0 {
|
||||
divisor = resource.MustParse("1")
|
||||
} else {
|
||||
divisor = fs.Divisor
|
||||
}
|
||||
|
||||
switch fs.Resource {
|
||||
case "limits.cpu":
|
||||
return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor)
|
||||
case "limits.memory":
|
||||
return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor)
|
||||
case "limits.ephemeral-storage":
|
||||
return convertResourceEphemeralStorageToString(container.Resources.Limits.StorageEphemeral(), divisor)
|
||||
case "requests.cpu":
|
||||
return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor)
|
||||
case "requests.memory":
|
||||
return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor)
|
||||
case "requests.ephemeral-storage":
|
||||
return convertResourceEphemeralStorageToString(container.Resources.Requests.StorageEphemeral(), divisor)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unsupported container resource : %v", fs.Resource)
|
||||
}
|
||||
|
||||
// convertResourceCPUToString converts cpu value to the format of divisor and returns
|
||||
// ceiling of the value.
|
||||
func convertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) {
|
||||
c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue())))
|
||||
return strconv.FormatInt(c, 10), nil
|
||||
}
|
||||
|
||||
// convertResourceMemoryToString converts memory value to the format of divisor and returns
|
||||
// ceiling of the value.
|
||||
func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) {
|
||||
m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value())))
|
||||
return strconv.FormatInt(m, 10), nil
|
||||
}
|
||||
|
||||
// convertResourceEphemeralStorageToString converts ephemeral storage value to the format of divisor and returns
|
||||
// ceiling of the value.
|
||||
func convertResourceEphemeralStorageToString(ephemeralStorage *resource.Quantity, divisor resource.Quantity) (string, error) {
|
||||
m := int64(math.Ceil(float64(ephemeralStorage.Value()) / float64(divisor.Value())))
|
||||
return strconv.FormatInt(m, 10), nil
|
||||
}
|
246
vendor/k8s.io/kubernetes/pkg/api/resource/helpers_test.go
generated
vendored
246
vendor/k8s.io/kubernetes/pkg/api/resource/helpers_test.go
generated
vendored
@ -1,246 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func TestResourceHelpers(t *testing.T) {
|
||||
cpuLimit := resource.MustParse("10")
|
||||
memoryLimit := resource.MustParse("10G")
|
||||
resourceSpec := api.ResourceRequirements{
|
||||
Limits: api.ResourceList{
|
||||
api.ResourceCPU: cpuLimit,
|
||||
api.ResourceMemory: memoryLimit,
|
||||
},
|
||||
}
|
||||
if res := resourceSpec.Limits.Cpu(); res.Cmp(cpuLimit) != 0 {
|
||||
t.Errorf("expected cpulimit %v, got %v", cpuLimit, res)
|
||||
}
|
||||
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
|
||||
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
|
||||
}
|
||||
resourceSpec = api.ResourceRequirements{
|
||||
Limits: api.ResourceList{
|
||||
api.ResourceMemory: memoryLimit,
|
||||
},
|
||||
}
|
||||
if res := resourceSpec.Limits.Cpu(); res.Value() != 0 {
|
||||
t.Errorf("expected cpulimit %v, got %v", 0, res)
|
||||
}
|
||||
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
|
||||
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultResourceHelpers(t *testing.T) {
|
||||
resourceList := api.ResourceList{}
|
||||
if resourceList.Cpu().Format != resource.DecimalSI {
|
||||
t.Errorf("expected %v, actual %v", resource.DecimalSI, resourceList.Cpu().Format)
|
||||
}
|
||||
if resourceList.Memory().Format != resource.BinarySI {
|
||||
t.Errorf("expected %v, actual %v", resource.BinarySI, resourceList.Memory().Format)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPodRequestsAndLimits(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *api.Pod
|
||||
expectreqs map[api.ResourceName]resource.Quantity
|
||||
expectlimits map[api.ResourceName]resource.Quantity
|
||||
}{
|
||||
{
|
||||
name: "InitContainers resource < Containers resource",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: uuid.NewUUID(),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{
|
||||
makeContainer("100m", "200m", "100Mi", "200Mi"),
|
||||
},
|
||||
Containers: []api.Container{
|
||||
makeContainer("100m", "400m", "100Mi", "400Mi"),
|
||||
makeContainer("100m", "200m", "100Mi", "200Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectreqs: map[api.ResourceName]resource.Quantity{
|
||||
api.ResourceCPU: resource.MustParse("200m"),
|
||||
api.ResourceMemory: resource.MustParse("200Mi"),
|
||||
},
|
||||
expectlimits: map[api.ResourceName]resource.Quantity{
|
||||
api.ResourceCPU: resource.MustParse("600m"),
|
||||
api.ResourceMemory: resource.MustParse("600Mi"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "InitContainers resource > Containers resource",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: uuid.NewUUID(),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{
|
||||
makeContainer("500m", "500m", "500Mi", "500Mi"),
|
||||
makeContainer("100m", "200m", "100Mi", "200Mi"),
|
||||
},
|
||||
Containers: []api.Container{
|
||||
makeContainer("100m", "200m", "100Mi", "200Mi"),
|
||||
makeContainer("100m", "200m", "100Mi", "200Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectreqs: map[api.ResourceName]resource.Quantity{
|
||||
api.ResourceCPU: resource.MustParse("500m"),
|
||||
api.ResourceMemory: resource.MustParse("500Mi"),
|
||||
},
|
||||
expectlimits: map[api.ResourceName]resource.Quantity{
|
||||
api.ResourceCPU: resource.MustParse("500m"),
|
||||
api.ResourceMemory: resource.MustParse("500Mi"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
requests, limits := PodRequestsAndLimits(test.pod)
|
||||
for name, quantity := range test.expectreqs {
|
||||
if value, ok := requests[name]; !ok {
|
||||
t.Errorf("case[%d]: Error to get value of key=%s from requests result", i, name)
|
||||
} else if quantity.Cmp(value) != 0 {
|
||||
t.Errorf("case[%d]: Expected value of key=%s from requests result:%v, Got:%v", i, name, quantity, value)
|
||||
}
|
||||
}
|
||||
for name, quantity := range test.expectlimits {
|
||||
if value, ok := limits[name]; !ok {
|
||||
t.Errorf("case[%d]: Error to get value of key=%s from limits result", i, name)
|
||||
} else if quantity.Cmp(value) != 0 {
|
||||
t.Errorf("case[%d]: Expected value of key=%s from limits result:%v, Got:%v", i, name, quantity, value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractContainerResourceValue(t *testing.T) {
|
||||
testcontainer := &api.Container{
|
||||
Name: string(uuid.NewUUID()),
|
||||
Resources: api.ResourceRequirements{
|
||||
Limits: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("200m"),
|
||||
api.ResourceMemory: resource.MustParse("200Mi"),
|
||||
api.ResourceStorage: resource.MustParse("2G"),
|
||||
api.ResourceEphemeralStorage: resource.MustParse("2G"),
|
||||
},
|
||||
Requests: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("100m"),
|
||||
api.ResourceMemory: resource.MustParse("100Mi"),
|
||||
api.ResourceStorage: resource.MustParse("1G"),
|
||||
api.ResourceEphemeralStorage: resource.MustParse("300Mi"),
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
filed *api.ResourceFieldSelector
|
||||
expectresult string
|
||||
expecterr string
|
||||
}{
|
||||
{
|
||||
name: "get limits cpu",
|
||||
filed: &api.ResourceFieldSelector{Resource: "limits.cpu", Divisor: resource.MustParse("1m")},
|
||||
expectresult: "200",
|
||||
expecterr: "",
|
||||
},
|
||||
{
|
||||
name: "get limits memory",
|
||||
filed: &api.ResourceFieldSelector{Resource: "limits.memory"},
|
||||
expectresult: "209715200",
|
||||
expecterr: "",
|
||||
},
|
||||
{
|
||||
name: "get limits ephemeral-storage",
|
||||
filed: &api.ResourceFieldSelector{Resource: "limits.ephemeral-storage", Divisor: resource.MustParse("1G")},
|
||||
expectresult: "2",
|
||||
expecterr: "",
|
||||
},
|
||||
{
|
||||
name: "get requests cpu",
|
||||
filed: &api.ResourceFieldSelector{Resource: "requests.cpu", Divisor: resource.MustParse("1m")},
|
||||
expectresult: "100",
|
||||
expecterr: "",
|
||||
},
|
||||
{
|
||||
name: "get requests memory",
|
||||
filed: &api.ResourceFieldSelector{Resource: "requests.memory", Divisor: resource.MustParse("1G")},
|
||||
expectresult: "1",
|
||||
expecterr: "",
|
||||
},
|
||||
{
|
||||
name: "get requests ephemeral-storage",
|
||||
filed: &api.ResourceFieldSelector{Resource: "requests.ephemeral-storage"},
|
||||
expectresult: "314572800",
|
||||
expecterr: "",
|
||||
},
|
||||
{
|
||||
name: "get limits storage",
|
||||
filed: &api.ResourceFieldSelector{Resource: "limits.storage", Divisor: resource.MustParse("1G")},
|
||||
expectresult: "",
|
||||
expecterr: "unsupported container resource",
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
result, err := ExtractContainerResourceValue(test.filed, testcontainer)
|
||||
if test.expecterr != "" {
|
||||
if !strings.Contains(err.Error(), test.expecterr) {
|
||||
t.Errorf("case[%d]:%s Expected err:%s, Got err:%s", i, test.name, test.expecterr, err.Error())
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("case[%d]:%s Expected no err, Got err:%s", i, test.name, err.Error())
|
||||
}
|
||||
if result != test.expectresult {
|
||||
t.Errorf("case[%d]:%s Expected result:%s, Got result:%s", i, test.name, test.expectresult, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeContainer(cpuReq, cpuLim, memReq, memLim string) api.Container {
|
||||
return api.Container{
|
||||
Name: string(uuid.NewUUID()),
|
||||
Resources: api.ResourceRequirements{
|
||||
Limits: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse(cpuLim),
|
||||
api.ResourceMemory: resource.MustParse(memLim),
|
||||
},
|
||||
Requests: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse(cpuReq),
|
||||
api.ResourceMemory: resource.MustParse(memReq),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
40
vendor/k8s.io/kubernetes/pkg/api/service/BUILD
generated
vendored
40
vendor/k8s.io/kubernetes/pkg/api/service/BUILD
generated
vendored
@ -1,40 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/service",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/util/net/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/util/net/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
4
vendor/k8s.io/kubernetes/pkg/api/service/OWNERS
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/api/service/OWNERS
generated
vendored
@ -1,4 +0,0 @@
|
||||
reviewers:
|
||||
- justinsb
|
||||
- freehan
|
||||
- david-mcmahon
|
85
vendor/k8s.io/kubernetes/pkg/api/service/util.go
generated
vendored
85
vendor/k8s.io/kubernetes/pkg/api/service/util.go
generated
vendored
@ -1,85 +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 service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLoadBalancerSourceRanges = "0.0.0.0/0"
|
||||
)
|
||||
|
||||
// IsAllowAll checks whether the netsets.IPNet allows traffic from 0.0.0.0/0
|
||||
func IsAllowAll(ipnets netsets.IPNet) bool {
|
||||
for _, s := range ipnets.StringSlice() {
|
||||
if s == "0.0.0.0/0" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service.
|
||||
// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service,
|
||||
// extracting the source ranges to allow, and if not present returns a default (allow-all) value.
|
||||
func GetLoadBalancerSourceRanges(service *api.Service) (netsets.IPNet, error) {
|
||||
var ipnets netsets.IPNet
|
||||
var err error
|
||||
// if SourceRange field is specified, ignore sourceRange annotation
|
||||
if len(service.Spec.LoadBalancerSourceRanges) > 0 {
|
||||
specs := service.Spec.LoadBalancerSourceRanges
|
||||
ipnets, err = netsets.ParseIPNets(specs...)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err)
|
||||
}
|
||||
} else {
|
||||
val := service.Annotations[api.AnnotationLoadBalancerSourceRangesKey]
|
||||
val = strings.TrimSpace(val)
|
||||
if val == "" {
|
||||
val = defaultLoadBalancerSourceRanges
|
||||
}
|
||||
specs := strings.Split(val, ",")
|
||||
ipnets, err = netsets.ParseIPNets(specs...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", api.AnnotationLoadBalancerSourceRangesKey, val)
|
||||
}
|
||||
}
|
||||
return ipnets, nil
|
||||
}
|
||||
|
||||
// RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic.
|
||||
func RequestsOnlyLocalTraffic(service *api.Service) bool {
|
||||
if service.Spec.Type != api.ServiceTypeLoadBalancer &&
|
||||
service.Spec.Type != api.ServiceTypeNodePort {
|
||||
return false
|
||||
}
|
||||
|
||||
return service.Spec.ExternalTrafficPolicy == api.ServiceExternalTrafficPolicyTypeLocal
|
||||
}
|
||||
|
||||
// NeedsHealthCheck checks if service needs health check.
|
||||
func NeedsHealthCheck(service *api.Service) bool {
|
||||
if service.Spec.Type != api.ServiceTypeLoadBalancer {
|
||||
return false
|
||||
}
|
||||
return RequestsOnlyLocalTraffic(service)
|
||||
}
|
216
vendor/k8s.io/kubernetes/pkg/api/service/util_test.go
generated
vendored
216
vendor/k8s.io/kubernetes/pkg/api/service/util_test.go
generated
vendored
@ -1,216 +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 service
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||
)
|
||||
|
||||
func TestGetLoadBalancerSourceRanges(t *testing.T) {
|
||||
checkError := func(v string) {
|
||||
annotations := make(map[string]string)
|
||||
annotations[api.AnnotationLoadBalancerSourceRangesKey] = v
|
||||
svc := api.Service{}
|
||||
svc.Annotations = annotations
|
||||
_, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error parsing: %q", v)
|
||||
}
|
||||
svc = api.Service{}
|
||||
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
|
||||
_, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error parsing: %q", v)
|
||||
}
|
||||
}
|
||||
checkError("10.0.0.1/33")
|
||||
checkError("foo.bar")
|
||||
checkError("10.0.0.1/32,*")
|
||||
checkError("10.0.0.1/32,")
|
||||
checkError("10.0.0.1/32, ")
|
||||
checkError("10.0.0.1")
|
||||
|
||||
checkOK := func(v string) netsets.IPNet {
|
||||
annotations := make(map[string]string)
|
||||
annotations[api.AnnotationLoadBalancerSourceRangesKey] = v
|
||||
svc := api.Service{}
|
||||
svc.Annotations = annotations
|
||||
cidrs, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing: %q", v)
|
||||
}
|
||||
svc = api.Service{}
|
||||
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
|
||||
cidrs, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing: %q", v)
|
||||
}
|
||||
return cidrs
|
||||
}
|
||||
cidrs := checkOK("192.168.0.1/32")
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK("192.168.0.1/32,192.168.0.1/32")
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR (after de-dup): %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK("192.168.0.1/32,192.168.0.2/32")
|
||||
if len(cidrs) != 2 {
|
||||
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK(" 192.168.0.1/32 , 192.168.0.2/32 ")
|
||||
if len(cidrs) != 2 {
|
||||
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
|
||||
}
|
||||
// check LoadBalancerSourceRanges not specified
|
||||
svc := api.Service{}
|
||||
cidrs, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
if !IsAllowAll(cidrs) {
|
||||
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
|
||||
}
|
||||
// check SourceRanges annotation is empty
|
||||
annotations := make(map[string]string)
|
||||
annotations[api.AnnotationLoadBalancerSourceRangesKey] = ""
|
||||
svc = api.Service{}
|
||||
svc.Annotations = annotations
|
||||
cidrs, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
if !IsAllowAll(cidrs) {
|
||||
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowAll(t *testing.T) {
|
||||
checkAllowAll := func(allowAll bool, cidrs ...string) {
|
||||
ipnets, err := netsets.ParseIPNets(cidrs...)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing cidrs: %v", cidrs)
|
||||
}
|
||||
if allowAll != IsAllowAll(ipnets) {
|
||||
t.Errorf("IsAllowAll did not return expected value for %v", cidrs)
|
||||
}
|
||||
}
|
||||
checkAllowAll(false, "10.0.0.1/32")
|
||||
checkAllowAll(false, "10.0.0.1/32", "10.0.0.2/32")
|
||||
checkAllowAll(false, "10.0.0.1/32", "10.0.0.1/32")
|
||||
|
||||
checkAllowAll(true, "0.0.0.0/0")
|
||||
checkAllowAll(true, "192.168.0.0/0")
|
||||
checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0")
|
||||
}
|
||||
|
||||
func TestRequestsOnlyLocalTraffic(t *testing.T) {
|
||||
checkRequestsOnlyLocalTraffic := func(requestsOnlyLocalTraffic bool, service *api.Service) {
|
||||
res := RequestsOnlyLocalTraffic(service)
|
||||
if res != requestsOnlyLocalTraffic {
|
||||
t.Errorf("Expected requests OnlyLocal traffic = %v, got %v",
|
||||
requestsOnlyLocalTraffic, res)
|
||||
}
|
||||
}
|
||||
|
||||
checkRequestsOnlyLocalTraffic(false, &api.Service{})
|
||||
checkRequestsOnlyLocalTraffic(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeNodePort,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(true, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(true, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestNeedsHealthCheck(t *testing.T) {
|
||||
checkNeedsHealthCheck := func(needsHealthCheck bool, service *api.Service) {
|
||||
res := NeedsHealthCheck(service)
|
||||
if res != needsHealthCheck {
|
||||
t.Errorf("Expected needs health check = %v, got %v",
|
||||
needsHealthCheck, res)
|
||||
}
|
||||
}
|
||||
|
||||
checkNeedsHealthCheck(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(false, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(true, &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
}
|
81
vendor/k8s.io/kubernetes/pkg/api/testapi/BUILD
generated
vendored
81
vendor/k8s.io/kubernetes/pkg/api/testapi/BUILD
generated
vendored
@ -1,81 +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 = ["testapi.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/testapi",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/admission:go_default_library",
|
||||
"//pkg/apis/admission/install:go_default_library",
|
||||
"//pkg/apis/admissionregistration:go_default_library",
|
||||
"//pkg/apis/admissionregistration/install:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/apps/install:go_default_library",
|
||||
"//pkg/apis/auditregistration:go_default_library",
|
||||
"//pkg/apis/auditregistration/install:go_default_library",
|
||||
"//pkg/apis/authentication/install:go_default_library",
|
||||
"//pkg/apis/authorization:go_default_library",
|
||||
"//pkg/apis/authorization/install:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/autoscaling/install:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/batch/install:go_default_library",
|
||||
"//pkg/apis/certificates:go_default_library",
|
||||
"//pkg/apis/certificates/install:go_default_library",
|
||||
"//pkg/apis/coordination:go_default_library",
|
||||
"//pkg/apis/coordination/install:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/install:go_default_library",
|
||||
"//pkg/apis/events:go_default_library",
|
||||
"//pkg/apis/events/install:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/install:go_default_library",
|
||||
"//pkg/apis/imagepolicy:go_default_library",
|
||||
"//pkg/apis/imagepolicy/install:go_default_library",
|
||||
"//pkg/apis/networking:go_default_library",
|
||||
"//pkg/apis/networking/install:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/policy/install:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/apis/rbac/install:go_default_library",
|
||||
"//pkg/apis/scheduling:go_default_library",
|
||||
"//pkg/apis/scheduling/install:go_default_library",
|
||||
"//pkg/apis/settings:go_default_library",
|
||||
"//pkg/apis/settings/install:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/apis/storage/install: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/runtime/serializer/recognizer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["testapi_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
19
vendor/k8s.io/kubernetes/pkg/api/testapi/OWNERS
generated
vendored
19
vendor/k8s.io/kubernetes/pkg/api/testapi/OWNERS
generated
vendored
@ -1,19 +0,0 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- erictune
|
||||
- tallclair
|
||||
- eparis
|
||||
- soltysh
|
||||
- madhusudancs
|
||||
- markturansky
|
||||
- mml
|
||||
- david-mcmahon
|
||||
- jianhuiz
|
393
vendor/k8s.io/kubernetes/pkg/api/testapi/testapi.go
generated
vendored
393
vendor/k8s.io/kubernetes/pkg/api/testapi/testapi.go
generated
vendored
@ -1,393 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 testapi provides a helper for retrieving the KUBE_TEST_API environment variable.
|
||||
//
|
||||
// TODO(lavalamp): this package is a huge disaster at the moment. I intend to
|
||||
// refactor. All code currently using this package should change:
|
||||
// 1. Declare your own api.Registry.APIGroupRegistrationManager in your own test code.
|
||||
// 2. Import the relevant install packages.
|
||||
// 3. Register the types you need, from the announced.APIGroupAnnouncementManager.
|
||||
package testapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/admission"
|
||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/auditregistration"
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
"k8s.io/kubernetes/pkg/apis/coordination"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/events"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/imagepolicy"
|
||||
"k8s.io/kubernetes/pkg/apis/networking"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
"k8s.io/kubernetes/pkg/apis/settings"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
|
||||
// Initialize install packages
|
||||
_ "k8s.io/kubernetes/pkg/apis/admission/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/admissionregistration/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/auditregistration/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/coordination/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/events/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/imagepolicy/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/networking/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/policy/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/settings/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
||||
)
|
||||
|
||||
// Variables to store GroupName
|
||||
var (
|
||||
Groups = make(map[string]TestGroup)
|
||||
Default TestGroup
|
||||
Autoscaling TestGroup
|
||||
Batch TestGroup
|
||||
Extensions TestGroup
|
||||
Apps TestGroup
|
||||
Policy TestGroup
|
||||
Rbac TestGroup
|
||||
Storage TestGroup
|
||||
Admission TestGroup
|
||||
|
||||
serializer runtime.SerializerInfo
|
||||
storageSerializer runtime.SerializerInfo
|
||||
)
|
||||
|
||||
// TestGroup contains GroupVersion to uniquely identify the API
|
||||
type TestGroup struct {
|
||||
externalGroupVersion schema.GroupVersion
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
if storageMediaType := StorageMediaType(); len(storageMediaType) > 0 {
|
||||
var ok bool
|
||||
mediaType, _, err := mime.ParseMediaType(storageMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
storageSerializer, ok = runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", storageMediaType))
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
Groups[groupVersion.Group] = TestGroup{
|
||||
externalGroupVersion: groupVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := Groups[api.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: api.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(api.GroupName)[0].Version}
|
||||
Groups[api.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[extensions.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: extensions.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(extensions.GroupName)[0].Version}
|
||||
Groups[extensions.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[autoscaling.GroupName]; !ok {
|
||||
internalTypes := make(map[string]reflect.Type)
|
||||
for k, t := range legacyscheme.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
|
||||
if k == "Scale" {
|
||||
continue
|
||||
}
|
||||
internalTypes[k] = t
|
||||
}
|
||||
externalGroupVersion := schema.GroupVersion{Group: autoscaling.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(autoscaling.GroupName)[0].Version}
|
||||
Groups[autoscaling.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[autoscaling.GroupName+"IntraGroup"]; !ok {
|
||||
internalTypes := make(map[string]reflect.Type)
|
||||
for k, t := range legacyscheme.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
|
||||
if k == "Scale" {
|
||||
internalTypes[k] = t
|
||||
break
|
||||
}
|
||||
}
|
||||
externalGroupVersion := schema.GroupVersion{Group: autoscaling.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(autoscaling.GroupName)[0].Version}
|
||||
Groups[autoscaling.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[batch.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: batch.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(batch.GroupName)[0].Version}
|
||||
Groups[batch.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[apps.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: apps.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(apps.GroupName)[0].Version}
|
||||
Groups[apps.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[policy.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: policy.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(policy.GroupName)[0].Version}
|
||||
Groups[policy.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[rbac.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: rbac.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(rbac.GroupName)[0].Version}
|
||||
Groups[rbac.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[scheduling.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: scheduling.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(scheduling.GroupName)[0].Version}
|
||||
Groups[scheduling.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[settings.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: settings.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(settings.GroupName)[0].Version}
|
||||
Groups[settings.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[storage.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: storage.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(storage.GroupName)[0].Version}
|
||||
Groups[storage.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[certificates.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: certificates.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(certificates.GroupName)[0].Version}
|
||||
Groups[certificates.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[imagepolicy.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: imagepolicy.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(imagepolicy.GroupName)[0].Version}
|
||||
Groups[imagepolicy.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[authorization.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: authorization.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(authorization.GroupName)[0].Version}
|
||||
Groups[authorization.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[admissionregistration.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: admissionregistration.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(admissionregistration.GroupName)[0].Version}
|
||||
Groups[admissionregistration.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[admission.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: admission.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(admission.GroupName)[0].Version}
|
||||
Groups[admission.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[networking.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: networking.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(networking.GroupName)[0].Version}
|
||||
Groups[networking.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[events.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: events.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(events.GroupName)[0].Version}
|
||||
Groups[events.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[coordination.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: coordination.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(coordination.GroupName)[0].Version}
|
||||
Groups[coordination.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[auditregistration.GroupName]; !ok {
|
||||
externalGroupVersion := schema.GroupVersion{Group: auditregistration.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(auditregistration.GroupName)[0].Version}
|
||||
Groups[auditregistration.GroupName] = TestGroup{
|
||||
externalGroupVersion: externalGroupVersion,
|
||||
}
|
||||
}
|
||||
|
||||
Default = Groups[api.GroupName]
|
||||
Autoscaling = Groups[autoscaling.GroupName]
|
||||
Batch = Groups[batch.GroupName]
|
||||
Apps = Groups[apps.GroupName]
|
||||
Policy = Groups[policy.GroupName]
|
||||
Extensions = Groups[extensions.GroupName]
|
||||
Rbac = Groups[rbac.GroupName]
|
||||
Storage = Groups[storage.GroupName]
|
||||
Admission = Groups[admission.GroupName]
|
||||
}
|
||||
|
||||
// GroupVersion makes copy of schema.GroupVersion
|
||||
func (g TestGroup) GroupVersion() *schema.GroupVersion {
|
||||
copyOfGroupVersion := g.externalGroupVersion
|
||||
return ©OfGroupVersion
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// StorageMediaType finds media type set by KUBE_TEST_API_STORAGE_TYPE env var used to store objects in storage
|
||||
func StorageMediaType() string {
|
||||
return os.Getenv("KUBE_TEST_API_STORAGE_TYPE")
|
||||
}
|
||||
|
||||
// StorageCodec returns the codec for the API version to store in etcd, as set by the
|
||||
// KUBE_TEST_API_STORAGE_TYPE env var.
|
||||
func (g TestGroup) StorageCodec() runtime.Codec {
|
||||
s := storageSerializer.Serializer
|
||||
|
||||
if s == nil {
|
||||
return legacyscheme.Codecs.LegacyCodec(g.externalGroupVersion)
|
||||
}
|
||||
|
||||
// etcd2 only supports string data - we must wrap any result before returning
|
||||
// TODO: remove for etcd3 / make parameterizable
|
||||
if !storageSerializer.EncodesAsText {
|
||||
s = runtime.NewBase64Serializer(s, s)
|
||||
}
|
||||
ds := recognizer.NewDecoder(s, legacyscheme.Codecs.UniversalDeserializer())
|
||||
|
||||
return legacyscheme.Codecs.CodecForVersions(s, ds, 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
|
||||
}
|
204
vendor/k8s.io/kubernetes/pkg/api/testapi/testapi_test.go
generated
vendored
204
vendor/k8s.io/kubernetes/pkg/api/testapi/testapi_test.go
generated
vendored
@ -1,204 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testapi
|
||||
|
||||
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/" + Default.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource/myresource"},
|
||||
{"prefix", "resource", "", "myresource", "/api/" + Default.GroupVersion().Version + "/prefix/resource/myresource"},
|
||||
{"prefix", "resource", "mynamespace", "", "/api/" + Default.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource"},
|
||||
{"prefix", "resource", "", "", "/api/" + Default.GroupVersion().Version + "/prefix/resource"},
|
||||
{"", "resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Default.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)
|
||||
}
|
||||
}
|
||||
|
||||
testGroupCases := []struct {
|
||||
prefix string
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"prefix", "resource", "mynamespace", "myresource", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource/myresource"},
|
||||
{"prefix", "resource", "", "myresource", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/resource/myresource"},
|
||||
{"prefix", "resource", "mynamespace", "", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource"},
|
||||
{"prefix", "resource", "", "", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/resource"},
|
||||
{"", "resource", "mynamespace", "myresource", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
}
|
||||
for _, item := range testGroupCases {
|
||||
if actual := Admission.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/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
|
||||
{"resource", "", "myresource", "/api/" + Default.GroupVersion().Version + "/resource/myresource"},
|
||||
{"resource", "mynamespace", "", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource"},
|
||||
{"resource", "", "", "/api/" + Default.GroupVersion().Version + "/resource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Default.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", "mysub", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource/mysub"},
|
||||
{"resource", "", "myresource", "mysub", "/api/" + Default.GroupVersion().Version + "/resource/myresource/mysub"},
|
||||
{"resource", "mynamespace", "", "mysub", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/mysub"},
|
||||
{"resource", "", "", "mysub", "/api/" + Default.GroupVersion().Version + "/resource/mysub"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Default.SubResourcePath(item.resource, item.namespace, item.name, item.sub); 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var status = &metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: 200,
|
||||
Reason: metav1.StatusReasonUnknown,
|
||||
Message: "",
|
||||
}
|
||||
|
||||
func TestSelfLink(t *testing.T) {
|
||||
testCases := []struct {
|
||||
resource string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "name", "/api/" + Default.GroupVersion().Version + "/resource/name"},
|
||||
{"resource", "", "/api/" + Default.GroupVersion().Version + "/resource"},
|
||||
}
|
||||
for _, item := range testCases {
|
||||
if actual := Default.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)
|
||||
}
|
||||
}
|
||||
|
||||
testGroupCases := []struct {
|
||||
resource string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"resource", "name", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/resource/name"},
|
||||
{"resource", "", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/resource"},
|
||||
}
|
||||
for _, item := range testGroupCases {
|
||||
if actual := Admission.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestV1EncodeDecodeStatus(t *testing.T) {
|
||||
v1Codec := Default.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)
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeDecodeStatus(t *testing.T, codec runtime.Codec) {
|
||||
encoded, err := runtime.Encode(codec, 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 %s", encoded)
|
||||
}
|
||||
if typeMeta.APIVersion != "v1" {
|
||||
t.Errorf("APIVersion is not set to \"\". Got %s", encoded)
|
||||
}
|
||||
decoded, err := runtime.Decode(codec, encoded)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(status, decoded) {
|
||||
t.Errorf("expected: %v, got: %v", status, decoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoscalingEncodeDecodeStatus(t *testing.T) {
|
||||
testEncodeDecodeStatus(t, Autoscaling.Codec())
|
||||
}
|
||||
|
||||
func TestBatchEncodeDecodeStatus(t *testing.T) {
|
||||
testEncodeDecodeStatus(t, Batch.Codec())
|
||||
}
|
||||
|
||||
func TestExperimentalEncodeDecodeStatus(t *testing.T) {
|
||||
testEncodeDecodeStatus(t, Extensions.Codec())
|
||||
}
|
12
vendor/k8s.io/kubernetes/pkg/api/testing/.import-restrictions
generated
vendored
12
vendor/k8s.io/kubernetes/pkg/api/testing/.import-restrictions
generated
vendored
@ -1,12 +0,0 @@
|
||||
{
|
||||
"Rules": [
|
||||
{
|
||||
"SelectorRegexp": "k8s[.]io/kubernetes/cmd",
|
||||
"AllowedPrefixes": [
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
],
|
||||
"ForbiddenPrefixes": [
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
114
vendor/k8s.io/kubernetes/pkg/api/testing/BUILD
generated
vendored
114
vendor/k8s.io/kubernetes/pkg/api/testing/BUILD
generated
vendored
@ -1,114 +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 = [
|
||||
"conversion.go",
|
||||
"doc.go",
|
||||
"fuzzer.go",
|
||||
"pod_specs.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/testing",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/admissionregistration/fuzzer:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/apps/fuzzer:go_default_library",
|
||||
"//pkg/apis/auditregistration/fuzzer:go_default_library",
|
||||
"//pkg/apis/autoscaling/fuzzer:go_default_library",
|
||||
"//pkg/apis/batch/fuzzer:go_default_library",
|
||||
"//pkg/apis/certificates/fuzzer:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/fuzzer:go_default_library",
|
||||
"//pkg/apis/extensions/fuzzer:go_default_library",
|
||||
"//pkg/apis/networking/fuzzer:go_default_library",
|
||||
"//pkg/apis/policy/fuzzer:go_default_library",
|
||||
"//pkg/apis/rbac/fuzzer:go_default_library",
|
||||
"//pkg/apis/storage/fuzzer:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/fuzzer:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/fields: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/runtime/serializer:go_default_library",
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/api/testing/compat:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"backward_compatibility_test.go",
|
||||
"conversion_test.go",
|
||||
"copy_test.go",
|
||||
"deep_copy_test.go",
|
||||
"defaulting_test.go",
|
||||
"meta_test.go",
|
||||
"serialization_proto_test.go",
|
||||
"serialization_test.go",
|
||||
"unstructured_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/testing/compat:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/apps/v1:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/install:go_default_library",
|
||||
"//pkg/apis/core/v1:go_default_library",
|
||||
"//pkg/apis/core/validation:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/fuzzer:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/roundtrip:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/conversion: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/runtime/serializer/json:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/github.com/json-iterator/go:go_default_library",
|
||||
],
|
||||
)
|
39
vendor/k8s.io/kubernetes/pkg/api/testing/OWNERS
generated
vendored
39
vendor/k8s.io/kubernetes/pkg/api/testing/OWNERS
generated
vendored
@ -1,39 +0,0 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- yujuhong
|
||||
- brendandburns
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- vishh
|
||||
- mikedanese
|
||||
- nikhiljindal
|
||||
- erictune
|
||||
- pmorie
|
||||
- dchen1107
|
||||
- saad-ali
|
||||
- zmerlynn
|
||||
- justinsb
|
||||
- pwittrock
|
||||
- roberthbailey
|
||||
- tallclair
|
||||
- yifan-gu
|
||||
- eparis
|
||||
- soltysh
|
||||
- jsafrane
|
||||
- madhusudancs
|
||||
- hongchaodeng
|
||||
- rootfs
|
||||
- jszczepkowski
|
||||
- markturansky
|
||||
- fgrzadkowski
|
||||
- aveshagarwal
|
||||
- david-mcmahon
|
||||
- pweil-
|
||||
- rata
|
||||
- feihujiang
|
||||
- sdminonne
|
||||
- ghodss
|
169
vendor/k8s.io/kubernetes/pkg/api/testing/backward_compatibility_test.go
generated
vendored
169
vendor/k8s.io/kubernetes/pkg/api/testing/backward_compatibility_test.go
generated
vendored
@ -1,169 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/api/testing/compat"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
)
|
||||
|
||||
func TestCompatibility_v1_PodSecurityContext(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input string
|
||||
expectedKeys map[string]string
|
||||
absentKeys []string
|
||||
}{
|
||||
{
|
||||
name: "hostNetwork = true",
|
||||
input: `
|
||||
{
|
||||
"kind":"Pod",
|
||||
"apiVersion":"v1",
|
||||
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
|
||||
"spec": {
|
||||
"hostNetwork": true,
|
||||
"containers":[{
|
||||
"name":"a",
|
||||
"image":"my-container-image"
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectedKeys: map[string]string{
|
||||
"spec.hostNetwork": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hostNetwork = false",
|
||||
input: `
|
||||
{
|
||||
"kind":"Pod",
|
||||
"apiVersion":"v1",
|
||||
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
|
||||
"spec": {
|
||||
"hostNetwork": false,
|
||||
"containers":[{
|
||||
"name":"a",
|
||||
"image":"my-container-image"
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
absentKeys: []string{
|
||||
"spec.hostNetwork",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hostIPC = true",
|
||||
input: `
|
||||
{
|
||||
"kind":"Pod",
|
||||
"apiVersion":"v1",
|
||||
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
|
||||
"spec": {
|
||||
"hostIPC": true,
|
||||
"containers":[{
|
||||
"name":"a",
|
||||
"image":"my-container-image"
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectedKeys: map[string]string{
|
||||
"spec.hostIPC": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hostIPC = false",
|
||||
input: `
|
||||
{
|
||||
"kind":"Pod",
|
||||
"apiVersion":"v1",
|
||||
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
|
||||
"spec": {
|
||||
"hostIPC": false,
|
||||
"containers":[{
|
||||
"name":"a",
|
||||
"image":"my-container-image"
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
absentKeys: []string{
|
||||
"spec.hostIPC",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hostPID = true",
|
||||
input: `
|
||||
{
|
||||
"kind":"Pod",
|
||||
"apiVersion":"v1",
|
||||
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
|
||||
"spec": {
|
||||
"hostPID": true,
|
||||
"containers":[{
|
||||
"name":"a",
|
||||
"image":"my-container-image"
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectedKeys: map[string]string{
|
||||
"spec.hostPID": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hostPID = false",
|
||||
input: `
|
||||
{
|
||||
"kind":"Pod",
|
||||
"apiVersion":"v1",
|
||||
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
|
||||
"spec": {
|
||||
"hostPID": false,
|
||||
"containers":[{
|
||||
"name":"a",
|
||||
"image":"my-container-image"
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
absentKeys: []string{
|
||||
"spec.hostPID",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
validator := func(obj runtime.Object) field.ErrorList {
|
||||
return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), field.NewPath("spec"))
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Logf("Testing 1.0.0 backward compatibility for %v", tc.name)
|
||||
compat.TestCompatibility(t, v1.SchemeGroupVersion, []byte(tc.input), validator, tc.expectedKeys, tc.absentKeys)
|
||||
}
|
||||
}
|
31
vendor/k8s.io/kubernetes/pkg/api/testing/compat/BUILD
generated
vendored
31
vendor/k8s.io/kubernetes/pkg/api/testing/compat/BUILD
generated
vendored
@ -1,31 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["compatibility_tester.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/testing/compat",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme: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/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
141
vendor/k8s.io/kubernetes/pkg/api/testing/compat/compatibility_tester.go
generated
vendored
141
vendor/k8s.io/kubernetes/pkg/api/testing/compat/compatibility_tester.go
generated
vendored
@ -1,141 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compat
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
)
|
||||
|
||||
// TestCompatibility reencodes the input using the codec for the given
|
||||
// version and checks for the presence of the expected keys and absent
|
||||
// keys in the resulting JSON.
|
||||
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
|
||||
func TestCompatibility(
|
||||
t *testing.T,
|
||||
version schema.GroupVersion,
|
||||
input []byte,
|
||||
validator func(obj runtime.Object) field.ErrorList,
|
||||
expectedKeys map[string]string,
|
||||
absentKeys []string,
|
||||
) {
|
||||
|
||||
// Decode
|
||||
codec := legacyscheme.Codecs.LegacyCodec(version)
|
||||
obj, err := runtime.Decode(codec, input)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Validate
|
||||
errs := validator(obj)
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("Unexpected validation errors: %v", errs)
|
||||
}
|
||||
|
||||
// Encode
|
||||
output, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Validate old and new fields are encoded
|
||||
generic := map[string]interface{}{}
|
||||
if err := json.Unmarshal(output, &generic); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
for k, expectedValue := range expectedKeys {
|
||||
keys := strings.Split(k, ".")
|
||||
if actualValue, ok, err := getJSONValue(generic, keys...); err != nil || !ok {
|
||||
t.Errorf("Unexpected error for %s: %v", k, err)
|
||||
} else if !reflect.DeepEqual(expectedValue, fmt.Sprintf("%v", actualValue)) {
|
||||
t.Errorf("Unexpected value for %v: expected %v, got %v", k, expectedValue, actualValue)
|
||||
}
|
||||
}
|
||||
|
||||
for _, absentKey := range absentKeys {
|
||||
keys := strings.Split(absentKey, ".")
|
||||
actualValue, ok, err := getJSONValue(generic, keys...)
|
||||
if err == nil || ok {
|
||||
t.Errorf("Unexpected value found for key %s: %v", absentKey, actualValue)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
data, err := json.MarshalIndent(obj, "", " ")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
} else {
|
||||
t.Log(string(data))
|
||||
}
|
||||
t.Logf("2: Encoded value: %v", string(output))
|
||||
}
|
||||
}
|
||||
|
||||
func getJSONValue(data map[string]interface{}, keys ...string) (interface{}, bool, error) {
|
||||
// No keys, current value is it
|
||||
if len(keys) == 0 {
|
||||
return data, true, nil
|
||||
}
|
||||
|
||||
// Get the key (and optional index)
|
||||
key := keys[0]
|
||||
index := -1
|
||||
if matches := regexp.MustCompile(`^(.*)\[(\d+)\]$`).FindStringSubmatch(key); len(matches) > 0 {
|
||||
key = matches[1]
|
||||
index, _ = strconv.Atoi(matches[2])
|
||||
}
|
||||
|
||||
// Look up the value
|
||||
value, ok := data[key]
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("No key %s found", key)
|
||||
}
|
||||
|
||||
// Get the indexed value if an index is specified
|
||||
if index >= 0 {
|
||||
valueSlice, ok := value.([]interface{})
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("Key %s did not hold a slice", key)
|
||||
}
|
||||
if index >= len(valueSlice) {
|
||||
return nil, false, fmt.Errorf("Index %d out of bounds for slice at key: %v", index, key)
|
||||
}
|
||||
value = valueSlice[index]
|
||||
}
|
||||
|
||||
if len(keys) == 1 {
|
||||
return value, true, nil
|
||||
}
|
||||
|
||||
childData, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("Key %s did not hold a map", keys[0])
|
||||
}
|
||||
return getJSONValue(childData, keys[1:]...)
|
||||
}
|
80
vendor/k8s.io/kubernetes/pkg/api/testing/conversion.go
generated
vendored
80
vendor/k8s.io/kubernetes/pkg/api/testing/conversion.go
generated
vendored
@ -1,80 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
)
|
||||
|
||||
// TestSelectableFieldLabelConversionsOfKind verifies that given resource have field
|
||||
// label conversion defined for each its selectable field.
|
||||
// fields contains selectable fields of the resource.
|
||||
// labelMap maps deprecated labels to their canonical names.
|
||||
func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string, kind string, fields fields.Set, labelMap map[string]string) {
|
||||
badFieldLabels := []string{
|
||||
"name",
|
||||
".name",
|
||||
"bad",
|
||||
"metadata",
|
||||
"foo.bar",
|
||||
}
|
||||
|
||||
value := "value"
|
||||
|
||||
gv, err := schema.ParseGroupVersion(apiVersion)
|
||||
if err != nil {
|
||||
t.Errorf("kind=%s: got unexpected error: %v", kind, err)
|
||||
return
|
||||
}
|
||||
gvk := gv.WithKind(kind)
|
||||
|
||||
if len(fields) == 0 {
|
||||
t.Logf("no selectable fields for kind %q, skipping", kind)
|
||||
}
|
||||
for label := range fields {
|
||||
if label == "name" {
|
||||
t.Logf("FIXME: \"name\" is deprecated by \"metadata.name\", it should be removed from selectable fields of kind=%s", kind)
|
||||
continue
|
||||
}
|
||||
newLabel, newValue, err := legacyscheme.Scheme.ConvertFieldLabel(gvk, label, value)
|
||||
if err != nil {
|
||||
t.Errorf("kind=%s label=%s: got unexpected error: %v", kind, label, err)
|
||||
} else {
|
||||
expectedLabel := label
|
||||
if l, exists := labelMap[label]; exists {
|
||||
expectedLabel = l
|
||||
}
|
||||
if newLabel != expectedLabel {
|
||||
t.Errorf("kind=%s label=%s: got unexpected label name (%q != %q)", kind, label, newLabel, expectedLabel)
|
||||
}
|
||||
if newValue != value {
|
||||
t.Errorf("kind=%s label=%s: got unexpected new value (%q != %q)", kind, label, newValue, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, label := range badFieldLabels {
|
||||
_, _, err := legacyscheme.Scheme.ConvertFieldLabel(gvk, label, "value")
|
||||
if err == nil {
|
||||
t.Errorf("kind=%s label=%s: got unexpected non-error", kind, label)
|
||||
}
|
||||
}
|
||||
}
|
118
vendor/k8s.io/kubernetes/pkg/api/testing/conversion_test.go
generated
vendored
118
vendor/k8s.io/kubernetes/pkg/api/testing/conversion_test.go
generated
vendored
@ -1,118 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func BenchmarkPodConversion(b *testing.B) {
|
||||
apiObjectFuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
|
||||
items := make([]api.Pod, 4)
|
||||
for i := range items {
|
||||
apiObjectFuzzer.Fuzz(&items[i])
|
||||
items[i].Spec.InitContainers = nil
|
||||
items[i].Status.InitContainerStatuses = nil
|
||||
}
|
||||
|
||||
// add a fixed item
|
||||
items = append(items, benchmarkPod)
|
||||
width := len(items)
|
||||
|
||||
scheme := legacyscheme.Scheme
|
||||
for i := 0; i < b.N; i++ {
|
||||
pod := &items[i%width]
|
||||
versionedObj, err := scheme.UnsafeConvertToVersion(pod, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
if _, err = scheme.UnsafeConvertToVersion(versionedObj, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal}); err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNodeConversion(b *testing.B) {
|
||||
data, err := ioutil.ReadFile("node_example.json")
|
||||
if err != nil {
|
||||
b.Fatalf("Unexpected error while reading file: %v", err)
|
||||
}
|
||||
var node api.Node
|
||||
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &node); err != nil {
|
||||
b.Fatalf("Unexpected error decoding node: %v", err)
|
||||
}
|
||||
|
||||
scheme := legacyscheme.Scheme
|
||||
var result *api.Node
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
versionedObj, err := scheme.UnsafeConvertToVersion(&node, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
obj, err := scheme.UnsafeConvertToVersion(versionedObj, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal})
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
result = obj.(*api.Node)
|
||||
}
|
||||
b.StopTimer()
|
||||
if !apiequality.Semantic.DeepDerivative(node, *result) {
|
||||
b.Fatalf("Incorrect conversion: %s", diff.ObjectDiff(node, *result))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReplicationControllerConversion(b *testing.B) {
|
||||
data, err := ioutil.ReadFile("replication_controller_example.json")
|
||||
if err != nil {
|
||||
b.Fatalf("Unexpected error while reading file: %v", err)
|
||||
}
|
||||
var replicationController api.ReplicationController
|
||||
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &replicationController); err != nil {
|
||||
b.Fatalf("Unexpected error decoding node: %v", err)
|
||||
}
|
||||
|
||||
scheme := legacyscheme.Scheme
|
||||
var result *api.ReplicationController
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
versionedObj, err := scheme.UnsafeConvertToVersion(&replicationController, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
obj, err := scheme.UnsafeConvertToVersion(versionedObj, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal})
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
result = obj.(*api.ReplicationController)
|
||||
}
|
||||
b.StopTimer()
|
||||
if !apiequality.Semantic.DeepDerivative(replicationController, *result) {
|
||||
b.Fatalf("Incorrect conversion: expected %v, got %v", replicationController, *result)
|
||||
}
|
||||
}
|
86
vendor/k8s.io/kubernetes/pkg/api/testing/copy_test.go
generated
vendored
86
vendor/k8s.io/kubernetes/pkg/api/testing/copy_test.go
generated
vendored
@ -1,86 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
)
|
||||
|
||||
func TestDeepCopyApiObjects(t *testing.T) {
|
||||
for i := 0; i < *roundtrip.FuzzIters; i++ {
|
||||
for _, version := range []schema.GroupVersion{{Group: "", Version: runtime.APIVersionInternal}, {Group: "", Version: "v1"}} {
|
||||
f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(rand.Int63()), legacyscheme.Codecs)
|
||||
for kind := range legacyscheme.Scheme.KnownTypes(version) {
|
||||
doDeepCopyTest(t, version.WithKind(kind), f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doDeepCopyTest(t *testing.T, kind schema.GroupVersionKind, f *fuzz.Fuzzer) {
|
||||
item, err := legacyscheme.Scheme.New(kind)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a %v: %s", kind, err)
|
||||
}
|
||||
f.Fuzz(item)
|
||||
itemCopy := item.DeepCopyObject()
|
||||
if !reflect.DeepEqual(item, itemCopy) {
|
||||
t.Errorf("\nexpected: %#v\n\ngot: %#v\n\ndiff: %v", item, itemCopy, diff.ObjectReflectDiff(item, itemCopy))
|
||||
}
|
||||
|
||||
prefuzzData := &bytes.Buffer{}
|
||||
if err := legacyscheme.Codecs.LegacyCodec(kind.GroupVersion()).Encode(item, prefuzzData); err != nil {
|
||||
t.Errorf("Could not encode a %v: %s", kind, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Refuzz the copy, which should have no effect on the original
|
||||
f.Fuzz(itemCopy)
|
||||
|
||||
postfuzzData := &bytes.Buffer{}
|
||||
if err := legacyscheme.Codecs.LegacyCodec(kind.GroupVersion()).Encode(item, postfuzzData); err != nil {
|
||||
t.Errorf("Could not encode a %v: %s", kind, err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(prefuzzData.Bytes(), postfuzzData.Bytes()) != 0 {
|
||||
t.Log(diff.StringDiff(prefuzzData.String(), postfuzzData.String()))
|
||||
t.Errorf("Fuzzing copy modified original of %#v", kind)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopySingleType(t *testing.T) {
|
||||
for i := 0; i < *roundtrip.FuzzIters; i++ {
|
||||
for _, version := range []schema.GroupVersion{{Group: "", Version: runtime.APIVersionInternal}, {Group: "", Version: "v1"}} {
|
||||
f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(rand.Int63()), legacyscheme.Codecs)
|
||||
doDeepCopyTest(t, version.WithKind("Pod"), f)
|
||||
}
|
||||
}
|
||||
}
|
177
vendor/k8s.io/kubernetes/pkg/api/testing/deep_copy_test.go
generated
vendored
177
vendor/k8s.io/kubernetes/pkg/api/testing/deep_copy_test.go
generated
vendored
@ -1,177 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func parseTimeOrDie(ts string) metav1.Time {
|
||||
t, err := time.Parse(time.RFC3339, ts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return metav1.Time{Time: t}
|
||||
}
|
||||
|
||||
var benchmarkPod = api.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "etcd-server-e2e-test-wojtekt-master",
|
||||
Namespace: "default",
|
||||
SelfLink: "/api/v1/namespaces/default/pods/etcd-server-e2e-test-wojtekt-master",
|
||||
UID: types.UID("a671734a-e8e5-11e4-8fde-42010af09327"),
|
||||
ResourceVersion: "22",
|
||||
CreationTimestamp: parseTimeOrDie("2015-04-22T11:49:36Z"),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "varetcd",
|
||||
VolumeSource: api.VolumeSource{
|
||||
HostPath: &api.HostPathVolumeSource{
|
||||
Path: "/mnt/master-pd/var/etcd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "etcd-container",
|
||||
Image: "k8s.gcr.io/etcd:2.0.9",
|
||||
Command: []string{
|
||||
"/usr/local/bin/etcd",
|
||||
"--addr",
|
||||
"127.0.0.1:2379",
|
||||
"--bind-addr",
|
||||
"127.0.0.1:2379",
|
||||
"--data-dir",
|
||||
"/var/etcd/data",
|
||||
},
|
||||
Ports: []api.ContainerPort{
|
||||
{
|
||||
Name: "serverport",
|
||||
HostPort: 2380,
|
||||
ContainerPort: 2380,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
{
|
||||
Name: "clientport",
|
||||
HostPort: 2379,
|
||||
ContainerPort: 2379,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "varetcd",
|
||||
MountPath: "/var/etcd",
|
||||
},
|
||||
},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
NodeName: "e2e-test-wojtekt-master",
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: api.PodRunning,
|
||||
Conditions: []api.PodCondition{
|
||||
{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{
|
||||
Name: "etcd-container",
|
||||
State: api.ContainerState{
|
||||
Running: &api.ContainerStateRunning{
|
||||
StartedAt: parseTimeOrDie("2015-04-22T11:49:32Z"),
|
||||
},
|
||||
},
|
||||
Ready: true,
|
||||
RestartCount: 0,
|
||||
Image: "k8s.gcr.io/etcd:2.0.9",
|
||||
ImageID: "docker://b6b9a86dc06aa1361357ca1b105feba961f6a4145adca6c54e142c0be0fe87b0",
|
||||
ContainerID: "docker://3cbbf818f1addfc252957b4504f56ef2907a313fe6afc47fc75373674255d46d",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func BenchmarkPodCopy(b *testing.B) {
|
||||
var result *api.Pod
|
||||
for i := 0; i < b.N; i++ {
|
||||
result = benchmarkPod.DeepCopy()
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(benchmarkPod, *result) {
|
||||
b.Fatalf("Incorrect copy: expected %v, got %v", benchmarkPod, *result)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNodeCopy(b *testing.B) {
|
||||
data, err := ioutil.ReadFile("node_example.json")
|
||||
if err != nil {
|
||||
b.Fatalf("Unexpected error while reading file: %v", err)
|
||||
}
|
||||
var node api.Node
|
||||
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &node); err != nil {
|
||||
b.Fatalf("Unexpected error decoding node: %v", err)
|
||||
}
|
||||
|
||||
var result *api.Node
|
||||
for i := 0; i < b.N; i++ {
|
||||
result = node.DeepCopy()
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(node, *result) {
|
||||
b.Fatalf("Incorrect copy: expected %v, got %v", node, *result)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReplicationControllerCopy(b *testing.B) {
|
||||
data, err := ioutil.ReadFile("replication_controller_example.json")
|
||||
if err != nil {
|
||||
b.Fatalf("Unexpected error while reading file: %v", err)
|
||||
}
|
||||
var replicationController api.ReplicationController
|
||||
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &replicationController); err != nil {
|
||||
b.Fatalf("Unexpected error decoding node: %v", err)
|
||||
}
|
||||
|
||||
var result *api.ReplicationController
|
||||
for i := 0; i < b.N; i++ {
|
||||
result = replicationController.DeepCopy()
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(replicationController, *result) {
|
||||
b.Fatalf("Incorrect copy: expected %v, got %v", replicationController, *result)
|
||||
}
|
||||
}
|
235
vendor/k8s.io/kubernetes/pkg/api/testing/defaulting_test.go
generated
vendored
235
vendor/k8s.io/kubernetes/pkg/api/testing/defaulting_test.go
generated
vendored
@ -1,235 +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 testing
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
roundtrip "k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
)
|
||||
|
||||
type orderedGroupVersionKinds []schema.GroupVersionKind
|
||||
|
||||
func (o orderedGroupVersionKinds) Len() int { return len(o) }
|
||||
func (o orderedGroupVersionKinds) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
|
||||
func (o orderedGroupVersionKinds) Less(i, j int) bool {
|
||||
return o[i].String() < o[j].String()
|
||||
}
|
||||
|
||||
// TODO: add a reflexive test that verifies that all SetDefaults functions are registered
|
||||
func TestDefaulting(t *testing.T) {
|
||||
// these are the known types with defaulters - you must add to this list if you add a top level defaulter
|
||||
typesWithDefaulting := map[schema.GroupVersionKind]struct{}{
|
||||
{Group: "", Version: "v1", Kind: "ConfigMap"}: {},
|
||||
{Group: "", Version: "v1", Kind: "ConfigMapList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "Endpoints"}: {},
|
||||
{Group: "", Version: "v1", Kind: "EndpointsList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "Namespace"}: {},
|
||||
{Group: "", Version: "v1", Kind: "NamespaceList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "Node"}: {},
|
||||
{Group: "", Version: "v1", Kind: "NodeList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PersistentVolume"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PersistentVolumeList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PersistentVolumeClaimList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "Pod"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PodList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PodTemplate"}: {},
|
||||
{Group: "", Version: "v1", Kind: "PodTemplateList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "ReplicationController"}: {},
|
||||
{Group: "", Version: "v1", Kind: "ReplicationControllerList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "Secret"}: {},
|
||||
{Group: "", Version: "v1", Kind: "SecretList"}: {},
|
||||
{Group: "", Version: "v1", Kind: "Service"}: {},
|
||||
{Group: "", Version: "v1", Kind: "ServiceList"}: {},
|
||||
{Group: "apps", Version: "v1beta1", Kind: "StatefulSet"}: {},
|
||||
{Group: "apps", Version: "v1beta1", Kind: "StatefulSetList"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "StatefulSet"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "StatefulSetList"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "StatefulSet"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "StatefulSetList"}: {},
|
||||
{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}: {},
|
||||
{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscalerList"}: {},
|
||||
{Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscaler"}: {},
|
||||
{Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscalerList"}: {},
|
||||
{Group: "batch", Version: "v1", Kind: "Job"}: {},
|
||||
{Group: "batch", Version: "v1", Kind: "JobList"}: {},
|
||||
{Group: "batch", Version: "v1beta1", Kind: "CronJob"}: {},
|
||||
{Group: "batch", Version: "v1beta1", Kind: "CronJobList"}: {},
|
||||
{Group: "batch", Version: "v1beta1", Kind: "JobTemplate"}: {},
|
||||
{Group: "batch", Version: "v2alpha1", Kind: "CronJob"}: {},
|
||||
{Group: "batch", Version: "v2alpha1", Kind: "CronJobList"}: {},
|
||||
{Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {},
|
||||
{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequest"}: {},
|
||||
{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequestList"}: {},
|
||||
{Group: "kubeadm.k8s.io", Version: "v1alpha1", Kind: "MasterConfiguration"}: {},
|
||||
// This object contains only int fields which currently breaks the defaulting test because
|
||||
// it's pretty stupid. Once we add non integer fields, we should uncomment this.
|
||||
// {Group: "kubeadm.k8s.io", Version: "v1alpha1", Kind: "NodeConfiguration"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "DaemonSet"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "DaemonSetList"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "DaemonSet"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "DaemonSetList"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "DaemonSet"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "DaemonSetList"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "Deployment"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "DeploymentList"}: {},
|
||||
{Group: "apps", Version: "v1beta1", Kind: "Deployment"}: {},
|
||||
{Group: "apps", Version: "v1beta1", Kind: "DeploymentList"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "Deployment"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "DeploymentList"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "Deployment"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "DeploymentList"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "PodSecurityPolicy"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "PodSecurityPolicyList"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "ReplicaSet"}: {},
|
||||
{Group: "apps", Version: "v1beta2", Kind: "ReplicaSetList"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "ReplicaSet"}: {},
|
||||
{Group: "apps", Version: "v1", Kind: "ReplicaSetList"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "ReplicaSet"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "ReplicaSetList"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"}: {},
|
||||
{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicyList"}: {},
|
||||
{Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicy"}: {},
|
||||
{Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicyList"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBinding"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBindingList"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBinding"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBindingList"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBinding"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBindingList"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBinding"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBindingList"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBindingList"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}: {},
|
||||
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBindingList"}: {},
|
||||
{Group: "settings.k8s.io", Version: "v1alpha1", Kind: "PodPreset"}: {},
|
||||
{Group: "settings.k8s.io", Version: "v1alpha1", Kind: "PodPresetList"}: {},
|
||||
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfiguration"}: {},
|
||||
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfigurationList"}: {},
|
||||
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfiguration"}: {},
|
||||
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfigurationList"}: {},
|
||||
{Group: "auditregistration.k8s.io", Version: "v1alpha1", Kind: "AuditSink"}: {},
|
||||
{Group: "auditregistration.k8s.io", Version: "v1alpha1", Kind: "AuditSinkList"}: {},
|
||||
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"}: {},
|
||||
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClassList"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClassList"}: {},
|
||||
{Group: "authentication.k8s.io", Version: "v1", Kind: "TokenRequest"}: {},
|
||||
}
|
||||
|
||||
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
|
||||
f.Funcs(
|
||||
func(s *runtime.RawExtension, c fuzz.Continue) {},
|
||||
func(s *metav1.LabelSelector, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
s.MatchExpressions = nil // need to fuzz this specially
|
||||
},
|
||||
func(s *metav1.ListOptions, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
s.LabelSelector = "" // need to fuzz requirement strings specially
|
||||
s.FieldSelector = "" // need to fuzz requirement strings specially
|
||||
},
|
||||
func(s *extensionsv1beta1.ScaleStatus, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
s.TargetSelector = "" // need to fuzz requirement strings specially
|
||||
},
|
||||
)
|
||||
|
||||
scheme := legacyscheme.Scheme
|
||||
var testTypes orderedGroupVersionKinds
|
||||
for gvk := range scheme.AllKnownTypes() {
|
||||
if gvk.Version == runtime.APIVersionInternal {
|
||||
continue
|
||||
}
|
||||
testTypes = append(testTypes, gvk)
|
||||
}
|
||||
sort.Sort(testTypes)
|
||||
|
||||
for _, gvk := range testTypes {
|
||||
_, expectedChanged := typesWithDefaulting[gvk]
|
||||
iter := 0
|
||||
changedOnce := false
|
||||
for {
|
||||
if iter > *roundtrip.FuzzIters {
|
||||
if !expectedChanged || changedOnce {
|
||||
break
|
||||
}
|
||||
if iter > 300 {
|
||||
t.Errorf("expected %s to trigger defaulting due to fuzzing", gvk)
|
||||
break
|
||||
}
|
||||
// if we expected defaulting, continue looping until the fuzzer gives us one
|
||||
// at worst, we will timeout
|
||||
}
|
||||
iter++
|
||||
|
||||
src, err := scheme.New(gvk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Fuzz(src)
|
||||
|
||||
src.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
|
||||
|
||||
original := src.DeepCopyObject()
|
||||
|
||||
// get internal
|
||||
withDefaults := src.DeepCopyObject()
|
||||
scheme.Default(withDefaults.(runtime.Object))
|
||||
|
||||
if !reflect.DeepEqual(original, withDefaults) {
|
||||
changedOnce = true
|
||||
if !expectedChanged {
|
||||
t.Errorf("{Group: \"%s\", Version: \"%s\", Kind: \"%s\"} did not expect defaults to be set - update expected or check defaulter registering: %s", gvk.Group, gvk.Version, gvk.Kind, diff.ObjectReflectDiff(original, withDefaults))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPodDefaulting(b *testing.B) {
|
||||
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
|
||||
items := make([]apiv1.Pod, 100)
|
||||
for i := range items {
|
||||
f.Fuzz(&items[i])
|
||||
}
|
||||
|
||||
scheme := legacyscheme.Scheme
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
pod := &items[i%len(items)]
|
||||
|
||||
scheme.Default(pod)
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
20
vendor/k8s.io/kubernetes/pkg/api/testing/doc.go
generated
vendored
20
vendor/k8s.io/kubernetes/pkg/api/testing/doc.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package testing contains
|
||||
// - all generic API tests which depend on Kubernetes API types
|
||||
// - all cross-Kubernetes-API tests.
|
||||
package testing
|
108
vendor/k8s.io/kubernetes/pkg/api/testing/fuzzer.go
generated
vendored
108
vendor/k8s.io/kubernetes/pkg/api/testing/fuzzer.go
generated
vendored
@ -1,108 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/apitesting"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
genericfuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
admissionregistrationfuzzer "k8s.io/kubernetes/pkg/apis/admissionregistration/fuzzer"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
appsfuzzer "k8s.io/kubernetes/pkg/apis/apps/fuzzer"
|
||||
auditregistrationfuzzer "k8s.io/kubernetes/pkg/apis/auditregistration/fuzzer"
|
||||
autoscalingfuzzer "k8s.io/kubernetes/pkg/apis/autoscaling/fuzzer"
|
||||
batchfuzzer "k8s.io/kubernetes/pkg/apis/batch/fuzzer"
|
||||
certificatesfuzzer "k8s.io/kubernetes/pkg/apis/certificates/fuzzer"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
corefuzzer "k8s.io/kubernetes/pkg/apis/core/fuzzer"
|
||||
extensionsfuzzer "k8s.io/kubernetes/pkg/apis/extensions/fuzzer"
|
||||
networkingfuzzer "k8s.io/kubernetes/pkg/apis/networking/fuzzer"
|
||||
policyfuzzer "k8s.io/kubernetes/pkg/apis/policy/fuzzer"
|
||||
rbacfuzzer "k8s.io/kubernetes/pkg/apis/rbac/fuzzer"
|
||||
storagefuzzer "k8s.io/kubernetes/pkg/apis/storage/fuzzer"
|
||||
)
|
||||
|
||||
// overrideGenericFuncs override some generic fuzzer funcs from k8s.io/apiserver in order to have more realistic
|
||||
// values in a Kubernetes context.
|
||||
func overrideGenericFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&api.Pod{}, &apps.Deployment{}, &api.Service{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
|
||||
var codec runtime.Codec
|
||||
switch obj.(type) {
|
||||
case *apps.Deployment:
|
||||
codec = apitesting.TestCodec(codecs, appsv1.SchemeGroupVersion)
|
||||
default:
|
||||
codec = apitesting.TestCodec(codecs, v1.SchemeGroupVersion)
|
||||
}
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to encode object: %v", err))
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuzzerFuncs is a list of fuzzer functions
|
||||
var FuzzerFuncs = fuzzer.MergeFuzzerFuncs(
|
||||
genericfuzzer.Funcs,
|
||||
overrideGenericFuncs,
|
||||
corefuzzer.Funcs,
|
||||
extensionsfuzzer.Funcs,
|
||||
appsfuzzer.Funcs,
|
||||
batchfuzzer.Funcs,
|
||||
autoscalingfuzzer.Funcs,
|
||||
rbacfuzzer.Funcs,
|
||||
policyfuzzer.Funcs,
|
||||
certificatesfuzzer.Funcs,
|
||||
admissionregistrationfuzzer.Funcs,
|
||||
auditregistrationfuzzer.Funcs,
|
||||
storagefuzzer.Funcs,
|
||||
networkingfuzzer.Funcs,
|
||||
)
|
103
vendor/k8s.io/kubernetes/pkg/api/testing/meta_test.go
generated
vendored
103
vendor/k8s.io/kubernetes/pkg/api/testing/meta_test.go
generated
vendored
@ -1,103 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 testing
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
)
|
||||
|
||||
var _ metav1.Object = &metav1.ObjectMeta{}
|
||||
|
||||
func TestAccessorImplementations(t *testing.T) {
|
||||
for _, gv := range legacyscheme.Scheme.PrioritizedVersionsAllGroups() {
|
||||
internalGV := schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}
|
||||
for _, gv := range []schema.GroupVersion{gv, internalGV} {
|
||||
for kind, knownType := range legacyscheme.Scheme.KnownTypes(gv) {
|
||||
value := reflect.New(knownType)
|
||||
obj := value.Interface()
|
||||
if _, ok := obj.(runtime.Object); !ok {
|
||||
t.Errorf("%v (%v) does not implement runtime.Object", gv.WithKind(kind), knownType)
|
||||
}
|
||||
lm, isLM := obj.(meta.ListMetaAccessor)
|
||||
om, isOM := obj.(metav1.ObjectMetaAccessor)
|
||||
switch {
|
||||
case isLM && isOM:
|
||||
t.Errorf("%v (%v) implements ListMetaAccessor and ObjectMetaAccessor", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
case isLM:
|
||||
m := lm.GetListMeta()
|
||||
if m == nil {
|
||||
t.Errorf("%v (%v) returns nil ListMeta", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
m.SetResourceVersion("102030")
|
||||
if m.GetResourceVersion() != "102030" {
|
||||
t.Errorf("%v (%v) did not preserve resource version", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
m.SetSelfLink("102030")
|
||||
if m.GetSelfLink() != "102030" {
|
||||
t.Errorf("%v (%v) did not preserve self link", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
case isOM:
|
||||
m := om.GetObjectMeta()
|
||||
if m == nil {
|
||||
t.Errorf("%v (%v) returns nil ObjectMeta", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
m.SetResourceVersion("102030")
|
||||
if m.GetResourceVersion() != "102030" {
|
||||
t.Errorf("%v (%v) did not preserve resource version", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
m.SetSelfLink("102030")
|
||||
if m.GetSelfLink() != "102030" {
|
||||
t.Errorf("%v (%v) did not preserve self link", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
labels := map[string]string{"a": "b"}
|
||||
m.SetLabels(labels)
|
||||
if !reflect.DeepEqual(m.GetLabels(), labels) {
|
||||
t.Errorf("%v (%v) did not preserve labels", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
default:
|
||||
if _, ok := obj.(metav1.ListMetaAccessor); ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := value.Elem().Type().FieldByName("ObjectMeta"); ok {
|
||||
t.Errorf("%v (%v) has ObjectMeta but does not implement ObjectMetaAccessor", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
if _, ok := value.Elem().Type().FieldByName("ListMeta"); ok {
|
||||
t.Errorf("%v (%v) has ListMeta but does not implement ListMetaAccessor", gv.WithKind(kind), knownType)
|
||||
continue
|
||||
}
|
||||
t.Logf("%v (%v) does not implement ListMetaAccessor or ObjectMetaAccessor", gv.WithKind(kind), knownType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
vendor/k8s.io/kubernetes/pkg/api/testing/node_example.json
generated
vendored
49
vendor/k8s.io/kubernetes/pkg/api/testing/node_example.json
generated
vendored
@ -1,49 +0,0 @@
|
||||
{
|
||||
"kind": "Node",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "e2e-test-wojtekt-node-etd6",
|
||||
"selfLink": "/api/v1/nodes/e2e-test-wojtekt-node-etd6",
|
||||
"uid": "a7e89222-e8e5-11e4-8fde-42010af09327",
|
||||
"resourceVersion": "379",
|
||||
"creationTimestamp": "2015-04-22T11:49:39Z"
|
||||
},
|
||||
"spec": {
|
||||
"externalID": "15488322946290398375"
|
||||
},
|
||||
"status": {
|
||||
"capacity": {
|
||||
"cpu": "1",
|
||||
"memory": "1745152Ki"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"type": "Ready",
|
||||
"status": "True",
|
||||
"lastHeartbeatTime": "2015-04-22T11:58:17Z",
|
||||
"lastTransitionTime": "2015-04-22T11:49:52Z",
|
||||
"reason": "kubelet is posting ready status"
|
||||
}
|
||||
],
|
||||
"addresses": [
|
||||
{
|
||||
"type": "ExternalIP",
|
||||
"address": "104.197.49.213"
|
||||
},
|
||||
{
|
||||
"type": "LegacyHostIP",
|
||||
"address": "104.197.20.11"
|
||||
}
|
||||
],
|
||||
"nodeInfo": {
|
||||
"machineID": "",
|
||||
"systemUUID": "D59FA3FA-7B5B-7287-5E1A-1D79F13CB577",
|
||||
"bootID": "44a832f3-8cfb-4de5-b7d2-d66030b6cd95",
|
||||
"kernelVersion": "3.16.0-0.bpo.4-amd64",
|
||||
"osImage": "Debian GNU/Linux 7 (wheezy)",
|
||||
"containerRuntimeVersion": "docker://1.5.0",
|
||||
"kubeletVersion": "v0.15.0-484-g0c8ee980d705a3-dirty",
|
||||
"kubeProxyVersion": "v0.15.0-484-g0c8ee980d705a3-dirty"
|
||||
}
|
||||
}
|
||||
}
|
45
vendor/k8s.io/kubernetes/pkg/api/testing/pod_specs.go
generated
vendored
45
vendor/k8s.io/kubernetes/pkg/api/testing/pod_specs.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// DeepEqualSafePodSpec returns a PodSpec which is ready to be used with apiequality.Semantic.DeepEqual
|
||||
func DeepEqualSafePodSpec() api.PodSpec {
|
||||
grace := int64(30)
|
||||
return api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
}
|
||||
}
|
||||
|
||||
// V1DeepEqualSafePodSpec returns a PodSpec which is ready to be used with apiequality.Semantic.DeepEqual
|
||||
func V1DeepEqualSafePodSpec() v1.PodSpec {
|
||||
grace := int64(30)
|
||||
return v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyAlways,
|
||||
DNSPolicy: v1.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
}
|
||||
}
|
83
vendor/k8s.io/kubernetes/pkg/api/testing/replication_controller_example.json
generated
vendored
83
vendor/k8s.io/kubernetes/pkg/api/testing/replication_controller_example.json
generated
vendored
@ -1,83 +0,0 @@
|
||||
{
|
||||
"kind": "ReplicationController",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "elasticsearch-logging-controller",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/replicationcontrollers/elasticsearch-logging-controller",
|
||||
"uid": "aa76f162-e8e5-11e4-8fde-42010af09327",
|
||||
"resourceVersion": "98",
|
||||
"creationTimestamp": "2015-04-22T11:49:43Z",
|
||||
"labels": {
|
||||
"kubernetes.io/cluster-service": "true",
|
||||
"name": "elasticsearch-logging"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"name": "elasticsearch-logging"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"kubernetes.io/cluster-service": "true",
|
||||
"name": "elasticsearch-logging"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
{
|
||||
"name": "es-persistent-storage",
|
||||
"hostPath": null,
|
||||
"emptyDir": {
|
||||
"medium": ""
|
||||
},
|
||||
"gcePersistentDisk": null,
|
||||
"awsElasticBlockStore": null,
|
||||
"gitRepo": null,
|
||||
"secret": null,
|
||||
"nfs": null,
|
||||
"iscsi": null,
|
||||
"glusterfs": null,
|
||||
"quobyte": null
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "elasticsearch-logging",
|
||||
"image": "k8s.gcr.io/elasticsearch:1.0",
|
||||
"ports": [
|
||||
{
|
||||
"name": "db",
|
||||
"containerPort": 9200,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"name": "transport",
|
||||
"containerPort": 9300,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "es-persistent-storage",
|
||||
"mountPath": "/data"
|
||||
}
|
||||
],
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"capabilities": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"dnsPolicy": "ClusterFirst"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"replicas": 1
|
||||
}
|
||||
}
|
217
vendor/k8s.io/kubernetes/pkg/api/testing/serialization_proto_test.go
generated
vendored
217
vendor/k8s.io/kubernetes/pkg/api/testing/serialization_proto_test.go
generated
vendored
@ -1,217 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
func TestUniversalDeserializer(t *testing.T) {
|
||||
expected := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "test"}}
|
||||
d := legacyscheme.Codecs.UniversalDeserializer()
|
||||
for _, mediaType := range []string{"application/json", "application/yaml", "application/vnd.kubernetes.protobuf"} {
|
||||
info, ok := runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
t.Fatal(mediaType)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
if err := info.Serializer.Encode(expected, buf); err != nil {
|
||||
t.Fatalf("%s: %v", mediaType, err)
|
||||
}
|
||||
obj, _, err := d.Decode(buf.Bytes(), &schema.GroupVersionKind{Kind: "Pod", Version: "v1"}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", mediaType, err)
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(expected, obj) {
|
||||
t.Fatalf("%s: %#v", mediaType, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllFieldsHaveTags(t *testing.T) {
|
||||
for gvk, obj := range legacyscheme.Scheme.AllKnownTypes() {
|
||||
if gvk.Version == runtime.APIVersionInternal {
|
||||
// internal versions are not serialized to protobuf
|
||||
continue
|
||||
}
|
||||
if gvk.Group == "componentconfig" {
|
||||
// component config is not serialized to protobuf
|
||||
continue
|
||||
}
|
||||
if err := fieldsHaveProtobufTags(obj); err != nil {
|
||||
t.Errorf("type %s as gvk %v is missing tags: %v", obj, gvk, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fieldsHaveProtobufTags(obj reflect.Type) error {
|
||||
switch obj.Kind() {
|
||||
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Array:
|
||||
return fieldsHaveProtobufTags(obj.Elem())
|
||||
case reflect.Struct:
|
||||
for i := 0; i < obj.NumField(); i++ {
|
||||
f := obj.Field(i)
|
||||
if f.Name == "TypeMeta" && f.Type.Name() == "TypeMeta" {
|
||||
// TypeMeta is not included in external protobuf because we use an envelope type with TypeMeta
|
||||
continue
|
||||
}
|
||||
if len(f.Tag.Get("json")) > 0 && len(f.Tag.Get("protobuf")) == 0 {
|
||||
return fmt.Errorf("field %s in %s has a 'json' tag but no protobuf tag", f.Name, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestProtobufRoundTrip(t *testing.T) {
|
||||
obj := &v1.Pod{}
|
||||
fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs).Fuzz(obj)
|
||||
// InitContainers are turned into annotations by conversion.
|
||||
obj.Spec.InitContainers = nil
|
||||
obj.Status.InitContainerStatuses = nil
|
||||
data, err := obj.Marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out := &v1.Pod{}
|
||||
if err := out.Unmarshal(data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !apiequality.Semantic.Equalities.DeepEqual(out, obj) {
|
||||
t.Logf("marshal\n%s", hex.Dump(data))
|
||||
t.Fatalf("Unmarshal is unequal\n%s", diff.ObjectGoPrintDiff(out, obj))
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
|
||||
// reflection (to clear APIVersion and Kind)
|
||||
func BenchmarkEncodeCodecProtobuf(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := runtime.Encode(s, &items[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkEncodeCodecFromInternalProtobuf measures the cost of performing a codec encode,
|
||||
// including conversions and any type setting. This is a "full" encode.
|
||||
func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encodable := make([]api.Pod, width)
|
||||
for i := range items {
|
||||
if err := legacyscheme.Scheme.Convert(&items[i], &encodable[i], nil); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type")
|
||||
codec := legacyscheme.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := runtime.Encode(codec, &encodable[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := items[i%width].Marshal(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeCodecToInternalProtobuf measures the cost of performing a codec decode,
|
||||
// including conversions and any type setting. This is a "full" decode.
|
||||
func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
s := protobuf.NewSerializer(legacyscheme.Scheme, legacyscheme.Scheme, "application/arbitrary.content.type")
|
||||
encoder := legacyscheme.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion)
|
||||
var encoded [][]byte
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(encoder, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded = append(encoded, data)
|
||||
}
|
||||
|
||||
decoder := legacyscheme.Codecs.DecoderToVersion(s, api.SchemeGroupVersion)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := runtime.Decode(decoder, encoded[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
|
||||
func BenchmarkDecodeIntoProtobuf(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := (&items[i]).Marshal()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
validate := &v1.Pod{}
|
||||
if err := proto.Unmarshal(data, validate); err != nil {
|
||||
b.Fatalf("Failed to unmarshal %d: %v\n%#v", i, err, items[i])
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := proto.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
613
vendor/k8s.io/kubernetes/pkg/api/testing/serialization_test.go
generated
vendored
613
vendor/k8s.io/kubernetes/pkg/api/testing/serialization_test.go
generated
vendored
@ -1,613 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
gojson "encoding/json"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
k8s_apps_v1 "k8s.io/kubernetes/pkg/apis/apps/v1"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
|
||||
)
|
||||
|
||||
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
|
||||
// fuzzer registered with the apitesting package.
|
||||
func fuzzInternalObject(t *testing.T, forVersion schema.GroupVersion, item runtime.Object, seed int64) runtime.Object {
|
||||
fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs).Fuzz(item)
|
||||
|
||||
j, err := meta.TypeAccessor(item)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v for %#v", err, item)
|
||||
}
|
||||
j.SetKind("")
|
||||
j.SetAPIVersion("")
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func ConvertV1ReplicaSetToAPIReplicationController(in *appsv1.ReplicaSet, out *api.ReplicationController, s conversion.Scope) error {
|
||||
intermediate1 := &apps.ReplicaSet{}
|
||||
if err := k8s_apps_v1.Convert_v1_ReplicaSet_To_apps_ReplicaSet(in, intermediate1, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
intermediate2 := &v1.ReplicationController{}
|
||||
if err := k8s_api_v1.Convert_apps_ReplicaSet_To_v1_ReplicationController(intermediate1, intermediate2, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return k8s_api_v1.Convert_v1_ReplicationController_To_core_ReplicationController(intermediate2, out, s)
|
||||
}
|
||||
|
||||
func TestSetControllerConversion(t *testing.T) {
|
||||
if err := legacyscheme.Scheme.AddConversionFuncs(ConvertV1ReplicaSetToAPIReplicationController); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rs := &apps.ReplicaSet{}
|
||||
rc := &api.ReplicationController{}
|
||||
|
||||
extGroup := testapi.Apps
|
||||
defaultGroup := testapi.Default
|
||||
|
||||
fuzzInternalObject(t, schema.GroupVersion{Group: "apps", Version: runtime.APIVersionInternal}, rs, rand.Int63())
|
||||
|
||||
// explicitly set the selector to something that is convertible to old-style selectors
|
||||
// (since normally we'll fuzz the selectors with things that aren't convertible)
|
||||
rs.Spec.Selector = &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "quux",
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("rs._internal.apps -> rs.v1.apps")
|
||||
data, err := runtime.Encode(extGroup.Codec(), rs)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected encoding error: %v", err)
|
||||
}
|
||||
|
||||
decoder := legacyscheme.Codecs.DecoderToVersion(
|
||||
legacyscheme.Codecs.UniversalDeserializer(),
|
||||
runtime.NewMultiGroupVersioner(
|
||||
*defaultGroup.GroupVersion(),
|
||||
schema.GroupKind{Group: defaultGroup.GroupVersion().Group},
|
||||
schema.GroupKind{Group: extGroup.GroupVersion().Group},
|
||||
),
|
||||
)
|
||||
|
||||
t.Logf("rs.v1.apps -> rc._internal")
|
||||
if err := runtime.DecodeInto(decoder, data, rc); err != nil {
|
||||
t.Fatalf("unexpected decoding error: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("rc._internal -> rc.v1")
|
||||
data, err = runtime.Encode(defaultGroup.Codec(), rc)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected encoding error: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("rc.v1 -> rs._internal.apps")
|
||||
if err := runtime.DecodeInto(decoder, data, rs); err != nil {
|
||||
t.Fatalf("unexpected decoding error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSpecificKind round-trips a single specific kind and is intended to help
|
||||
// debug issues that arise while adding a new API type.
|
||||
func TestSpecificKind(t *testing.T) {
|
||||
// Uncomment the following line to enable logging of which conversions
|
||||
// legacyscheme.Scheme.Log(t)
|
||||
internalGVK := schema.GroupVersionKind{Group: "apps", Version: runtime.APIVersionInternal, Kind: "DaemonSet"}
|
||||
|
||||
seed := rand.Int63()
|
||||
fuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs)
|
||||
|
||||
roundtrip.RoundTripSpecificKind(t, internalGVK, legacyscheme.Scheme, legacyscheme.Codecs, fuzzer, nil)
|
||||
}
|
||||
|
||||
var nonRoundTrippableTypes = sets.NewString(
|
||||
"ExportOptions",
|
||||
"GetOptions",
|
||||
// WatchEvent does not include kind and version and can only be deserialized
|
||||
// implicitly (if the caller expects the specific object). The watch call defines
|
||||
// the schema by content type, rather than via kind/version included in each
|
||||
// object.
|
||||
"WatchEvent",
|
||||
// ListOptions is now part of the meta group
|
||||
"ListOptions",
|
||||
// DeleteOptions, CreateOptions and UpdateOptions are only read in metav1
|
||||
"DeleteOptions",
|
||||
"CreateOptions",
|
||||
"UpdateOptions",
|
||||
)
|
||||
|
||||
var commonKinds = []string{"Status", "ListOptions", "DeleteOptions", "ExportOptions", "GetOptions", "CreateOptions", "UpdateOptions"}
|
||||
|
||||
// TestCommonKindsRegistered verifies that all group/versions registered with
|
||||
// the testapi package have the common kinds.
|
||||
func TestCommonKindsRegistered(t *testing.T) {
|
||||
for _, kind := range commonKinds {
|
||||
for _, group := range testapi.Groups {
|
||||
gv := group.GroupVersion()
|
||||
gvk := gv.WithKind(kind)
|
||||
obj, err := legacyscheme.Scheme.New(gvk)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defaults := gv.WithKind("")
|
||||
var got *schema.GroupVersionKind
|
||||
if obj, got, err = legacyscheme.Codecs.LegacyCodec().Decode([]byte(`{"kind":"`+kind+`"}`), &defaults, obj); err != nil || gvk != *got {
|
||||
t.Errorf("expected %v: %v %v", gvk, got, err)
|
||||
}
|
||||
data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(*gv), obj)
|
||||
if err != nil {
|
||||
t.Errorf("expected %v: %v\n%s", gvk, err, string(data))
|
||||
continue
|
||||
}
|
||||
if !bytes.Contains(data, []byte(`"kind":"`+kind+`","apiVersion":"`+gv.String()+`"`)) {
|
||||
if kind != "Status" {
|
||||
t.Errorf("expected %v: %v\n%s", gvk, err, string(data))
|
||||
continue
|
||||
}
|
||||
// TODO: this is wrong, but legacy clients expect it
|
||||
if !bytes.Contains(data, []byte(`"kind":"`+kind+`","apiVersion":"v1"`)) {
|
||||
t.Errorf("expected %v: %v\n%s", gvk, err, string(data))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestRoundTripTypes applies the round-trip test to all round-trippable Kinds
|
||||
// in all of the API groups registered for test in the testapi package.
|
||||
func TestRoundTripTypes(t *testing.T) {
|
||||
seed := rand.Int63()
|
||||
fuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs)
|
||||
nonRoundTrippableTypes := map[schema.GroupVersionKind]bool{}
|
||||
|
||||
roundtrip.RoundTripTypes(t, legacyscheme.Scheme, legacyscheme.Codecs, fuzzer, nonRoundTrippableTypes)
|
||||
}
|
||||
|
||||
// TestEncodePtr tests that a pointer to a golang type can be encoded and
|
||||
// decoded without information loss or mutation.
|
||||
func TestEncodePtr(t *testing.T) {
|
||||
grace := int64(30)
|
||||
enableServiceLinks := v1.DefaultEnableServiceLinks
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"name": "foo"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
EnableServiceLinks: &enableServiceLinks,
|
||||
},
|
||||
}
|
||||
obj := runtime.Object(pod)
|
||||
data, err := runtime.Encode(testapi.Default.Codec(), obj)
|
||||
obj2, err2 := runtime.Decode(testapi.Default.Codec(), data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
}
|
||||
if _, ok := obj2.(*api.Pod); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(obj2, pod) {
|
||||
t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeTimeStampWithoutQuotes(t *testing.T) {
|
||||
testYAML := []byte(`
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: 2018-08-30T14:10:58Z
|
||||
name: test
|
||||
spec:
|
||||
containers: null
|
||||
status: {}`)
|
||||
if obj, err := runtime.Decode(testapi.Default.Codec(), testYAML); err != nil {
|
||||
t.Fatalf("unable to decode yaml: %v", err)
|
||||
} else {
|
||||
if obj2, ok := obj.(*api.Pod); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
} else {
|
||||
if obj2.ObjectMeta.CreationTimestamp.UnixNano() != parseTimeOrDie("2018-08-30T14:10:58Z").UnixNano() {
|
||||
t.Fatalf("Time stamps do not match")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestBadJSONRejection establishes that a JSON object without a kind or with
|
||||
// an unknown kind will not be decoded without error.
|
||||
func TestBadJSONRejection(t *testing.T) {
|
||||
badJSONMissingKind := []byte(`{ }`)
|
||||
if _, err := runtime.Decode(testapi.Default.Codec(), badJSONMissingKind); err == nil {
|
||||
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
|
||||
}
|
||||
badJSONUnknownType := []byte(`{"kind": "bar"}`)
|
||||
if _, err1 := runtime.Decode(testapi.Default.Codec(), badJSONUnknownType); err1 == nil {
|
||||
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
|
||||
}
|
||||
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
if err2 := DecodeInto(badJSONKindMismatch, &Node{}); err2 == nil {
|
||||
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
|
||||
}*/
|
||||
}
|
||||
|
||||
// TestUnversionedTypes establishes that the default codec can encode and
|
||||
// decode unversioned objects.
|
||||
func TestUnversionedTypes(t *testing.T) {
|
||||
testcases := []runtime.Object{
|
||||
&metav1.Status{Status: "Failure", Message: "something went wrong"},
|
||||
&metav1.APIVersions{Versions: []string{"A", "B", "C"}},
|
||||
&metav1.APIGroupList{Groups: []metav1.APIGroup{{Name: "mygroup"}}},
|
||||
&metav1.APIGroup{Name: "mygroup"},
|
||||
&metav1.APIResourceList{GroupVersion: "mygroup/myversion"},
|
||||
}
|
||||
|
||||
for _, obj := range testcases {
|
||||
// Make sure the unversioned codec can encode
|
||||
unversionedJSON, err := runtime.Encode(testapi.Default.Codec(), obj)
|
||||
if err != nil {
|
||||
t.Errorf("%v: unexpected error: %v", obj, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Make sure the versioned codec under test can decode
|
||||
versionDecodedObject, err := runtime.Decode(testapi.Default.Codec(), unversionedJSON)
|
||||
if err != nil {
|
||||
t.Errorf("%v: unexpected error: %v", obj, err)
|
||||
continue
|
||||
}
|
||||
// Make sure it decodes correctly
|
||||
if !reflect.DeepEqual(obj, versionDecodedObject) {
|
||||
t.Errorf("%v: expected %#v, got %#v", obj, obj, versionDecodedObject)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestObjectWatchFraming establishes that a watch event can be encoded and
|
||||
// decoded correctly through each of the supported RFC2046 media types.
|
||||
func TestObjectWatchFraming(t *testing.T) {
|
||||
f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
|
||||
secret := &api.Secret{}
|
||||
f.Fuzz(secret)
|
||||
if secret.Data == nil {
|
||||
secret.Data = map[string][]byte{}
|
||||
}
|
||||
secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00}
|
||||
secret.Data["utf8"] = []byte("a string with \u0345 characters")
|
||||
secret.Data["long"] = bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x00}, 1000)
|
||||
converted, _ := legacyscheme.Scheme.ConvertToVersion(secret, v1.SchemeGroupVersion)
|
||||
v1secret := converted.(*v1.Secret)
|
||||
for _, info := range legacyscheme.Codecs.SupportedMediaTypes() {
|
||||
if info.StreamSerializer == nil {
|
||||
continue
|
||||
}
|
||||
s := info.StreamSerializer
|
||||
framer := s.Framer
|
||||
embedded := info.Serializer
|
||||
if embedded == nil {
|
||||
t.Errorf("no embedded serializer for %s", info.MediaType)
|
||||
continue
|
||||
}
|
||||
innerDecode := legacyscheme.Codecs.DecoderToVersion(embedded, api.SchemeGroupVersion)
|
||||
|
||||
// write a single object through the framer and back out
|
||||
obj := &bytes.Buffer{}
|
||||
if err := s.Encode(v1secret, obj); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out := &bytes.Buffer{}
|
||||
w := framer.NewFrameWriter(out)
|
||||
if n, err := w.Write(obj.Bytes()); err != nil || n != len(obj.Bytes()) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sr := streaming.NewDecoder(framer.NewFrameReader(ioutil.NopCloser(out)), s)
|
||||
resultSecret := &v1.Secret{}
|
||||
res, _, err := sr.Decode(nil, resultSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("%v:\n%s", err, hex.Dump(obj.Bytes()))
|
||||
}
|
||||
resultSecret.Kind = "Secret"
|
||||
resultSecret.APIVersion = "v1"
|
||||
if !apiequality.Semantic.DeepEqual(v1secret, res) {
|
||||
t.Fatalf("objects did not match: %s", diff.ObjectGoPrintDiff(v1secret, res))
|
||||
}
|
||||
|
||||
// write a watch event through the frame writer and read it back in
|
||||
// via the frame reader for this media type
|
||||
obj = &bytes.Buffer{}
|
||||
if err := embedded.Encode(v1secret, obj); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
event := &metav1.WatchEvent{Type: string(watch.Added)}
|
||||
event.Object.Raw = obj.Bytes()
|
||||
obj = &bytes.Buffer{}
|
||||
if err := s.Encode(event, obj); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = &bytes.Buffer{}
|
||||
w = framer.NewFrameWriter(out)
|
||||
if n, err := w.Write(obj.Bytes()); err != nil || n != len(obj.Bytes()) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sr = streaming.NewDecoder(framer.NewFrameReader(ioutil.NopCloser(out)), s)
|
||||
outEvent := &metav1.WatchEvent{}
|
||||
res, _, err = sr.Decode(nil, outEvent)
|
||||
if err != nil || outEvent.Type != string(watch.Added) {
|
||||
t.Fatalf("%v: %#v", err, outEvent)
|
||||
}
|
||||
if outEvent.Object.Object == nil && outEvent.Object.Raw != nil {
|
||||
outEvent.Object.Object, err = runtime.Decode(innerDecode, outEvent.Object.Raw)
|
||||
if err != nil {
|
||||
t.Fatalf("%v:\n%s", err, hex.Dump(outEvent.Object.Raw))
|
||||
}
|
||||
}
|
||||
|
||||
if !apiequality.Semantic.DeepEqual(secret, outEvent.Object.Object) {
|
||||
t.Fatalf("%s: did not match after frame decoding: %s", info.MediaType, diff.ObjectGoPrintDiff(secret, outEvent.Object.Object))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const benchmarkSeed = 100
|
||||
|
||||
func benchmarkItems(b *testing.B) []v1.Pod {
|
||||
apiObjectFuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
|
||||
items := make([]v1.Pod, 10)
|
||||
for i := range items {
|
||||
var pod api.Pod
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
pod.Spec.InitContainers, pod.Status.InitContainerStatuses = nil, nil
|
||||
out, err := legacyscheme.Scheme.ConvertToVersion(&pod, v1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
items[i] = *out.(*v1.Pod)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
|
||||
// reflection (to clear APIVersion and Kind)
|
||||
func BenchmarkEncodeCodec(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := runtime.Encode(testapi.Default.Codec(), &items[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkEncodeCodecFromInternal measures the cost of performing a codec encode,
|
||||
// including conversions.
|
||||
func BenchmarkEncodeCodecFromInternal(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encodable := make([]api.Pod, width)
|
||||
for i := range items {
|
||||
if err := legacyscheme.Scheme.Convert(&items[i], &encodable[i], nil); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := runtime.Encode(testapi.Default.Codec(), &encodable[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance
|
||||
func BenchmarkEncodeJSONMarshal(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := gojson.Marshal(&items[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(codec, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := runtime.Decode(codec, encoded[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(codec, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := runtime.DecodeInto(codec, encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(codec, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := api.Pod{}
|
||||
if err := runtime.DecodeInto(codec, encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
|
||||
func BenchmarkDecodeIntoJSON(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(codec, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := gojson.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeIntoJSONCodecGenConfigFast provides a baseline
|
||||
// for JSON decode performance with jsoniter.ConfigFast
|
||||
func BenchmarkDecodeIntoJSONCodecGenConfigFast(b *testing.B) {
|
||||
kcodec := testapi.Default.Codec()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(kcodec, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := jsoniter.ConfigFastest.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary provides a
|
||||
// baseline for JSON decode performance with
|
||||
// jsoniter.ConfigCompatibleWithStandardLibrary, but with case sensitivity set
|
||||
// to true
|
||||
func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testing.B) {
|
||||
kcodec := testapi.Default.Codec()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := runtime.Encode(kcodec, &items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
iter := json.CaseSensitiveJsonIterator()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := iter.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
214
vendor/k8s.io/kubernetes/pkg/api/testing/unstructured_test.go
generated
vendored
214
vendor/k8s.io/kubernetes/pkg/api/testing/unstructured_test.go
generated
vendored
@ -1,214 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metaunstruct "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func doRoundTrip(t *testing.T, internalVersion schema.GroupVersion, externalVersion schema.GroupVersion, kind string) {
|
||||
// We do fuzzing on the internal version of the object, and only then
|
||||
// convert to the external version. This is because custom fuzzing
|
||||
// function are only supported for internal objects.
|
||||
internalObj, err := legacyscheme.Scheme.New(internalVersion.WithKind(kind))
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create internal object %v: %v", kind, err)
|
||||
}
|
||||
seed := rand.Int63()
|
||||
fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs).
|
||||
// We are explicitly overwriting custom fuzzing functions, to ensure
|
||||
// that InitContainers and their statuses are not generated. This is
|
||||
// because in thise test we are simply doing json operations, in which
|
||||
// those disappear.
|
||||
Funcs(
|
||||
func(s *api.PodSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
s.InitContainers = nil
|
||||
},
|
||||
func(s *api.PodStatus, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
s.InitContainerStatuses = nil
|
||||
},
|
||||
).Fuzz(internalObj)
|
||||
|
||||
item, err := legacyscheme.Scheme.New(externalVersion.WithKind(kind))
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create external object %v: %v", kind, err)
|
||||
}
|
||||
if err := legacyscheme.Scheme.Convert(internalObj, item, nil); err != nil {
|
||||
t.Fatalf("Conversion for %v failed: %v", kind, err)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(item)
|
||||
if err != nil {
|
||||
t.Errorf("Error when marshaling object: %v", err)
|
||||
return
|
||||
}
|
||||
unstr := make(map[string]interface{})
|
||||
err = json.Unmarshal(data, &unstr)
|
||||
if err != nil {
|
||||
t.Errorf("Error when unmarshaling to unstructured: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
data, err = json.Marshal(unstr)
|
||||
if err != nil {
|
||||
t.Errorf("Error when marshaling unstructured: %v", err)
|
||||
return
|
||||
}
|
||||
unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
|
||||
err = json.Unmarshal(data, &unmarshalledObj)
|
||||
if err != nil {
|
||||
t.Errorf("Error when unmarshaling to object: %v", err)
|
||||
return
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(item, unmarshalledObj) {
|
||||
t.Errorf("Object changed during JSON operations, diff: %v", diff.ObjectReflectDiff(item, unmarshalledObj))
|
||||
return
|
||||
}
|
||||
|
||||
newUnstr, err := runtime.NewTestUnstructuredConverter(apiequality.Semantic).ToUnstructured(item)
|
||||
if err != nil {
|
||||
t.Errorf("ToUnstructured failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object)
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(newUnstr, newObj)
|
||||
if err != nil {
|
||||
t.Errorf("FromUnstructured failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !apiequality.Semantic.DeepEqual(item, newObj) {
|
||||
t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(item, newObj))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
for groupKey, group := range testapi.Groups {
|
||||
for kind := range legacyscheme.Scheme.KnownTypes(*group.GroupVersion()) {
|
||||
if nonRoundTrippableTypes.Has(kind) {
|
||||
continue
|
||||
}
|
||||
t.Logf("Testing: %v in %v", kind, groupKey)
|
||||
for i := 0; i < 50; i++ {
|
||||
doRoundTrip(t, schema.GroupVersion{Group: groupKey, Version: runtime.APIVersionInternal}, *group.GroupVersion(), kind)
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTripWithEmptyCreationTimestamp(t *testing.T) {
|
||||
for groupKey, group := range testapi.Groups {
|
||||
for kind := range legacyscheme.Scheme.KnownTypes(*group.GroupVersion()) {
|
||||
if nonRoundTrippableTypes.Has(kind) {
|
||||
continue
|
||||
}
|
||||
item, err := legacyscheme.Scheme.New(group.GroupVersion().WithKind(kind))
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create external object %v: %v", kind, err)
|
||||
}
|
||||
t.Logf("Testing: %v in %v", kind, groupKey)
|
||||
|
||||
unstrBody, err := runtime.DefaultUnstructuredConverter.ToUnstructured(item)
|
||||
if err != nil {
|
||||
t.Fatalf("ToUnstructured failed: %v", err)
|
||||
}
|
||||
|
||||
unstructObj := &metaunstruct.Unstructured{}
|
||||
unstructObj.Object = unstrBody
|
||||
|
||||
if meta, err := meta.Accessor(unstructObj); err == nil {
|
||||
meta.SetCreationTimestamp(metav1.Time{})
|
||||
} else {
|
||||
t.Fatalf("Unable to set creation timestamp: %v", err)
|
||||
}
|
||||
|
||||
// attempt to re-convert unstructured object - conversion should not fail
|
||||
// based on empty metadata fields, such as creationTimestamp
|
||||
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object)
|
||||
err = runtime.NewTestUnstructuredConverter(apiequality.Semantic).FromUnstructured(unstructObj.Object, newObj)
|
||||
if err != nil {
|
||||
t.Fatalf("FromUnstructured failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToFromUnstructured(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
size := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
unstr, err := runtime.NewTestUnstructuredConverter(apiequality.Semantic).ToUnstructured(&items[i%size])
|
||||
if err != nil {
|
||||
b.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
obj := v1.Pod{}
|
||||
if err := runtime.NewTestUnstructuredConverter(apiequality.Semantic).FromUnstructured(unstr, &obj); err != nil {
|
||||
b.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkToFromUnstructuredViaJSON(b *testing.B) {
|
||||
items := benchmarkItems(b)
|
||||
size := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
data, err := json.Marshal(&items[i%size])
|
||||
if err != nil {
|
||||
b.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
unstr := map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &unstr); err != nil {
|
||||
b.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
data, err = json.Marshal(unstr)
|
||||
if err != nil {
|
||||
b.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
obj := v1.Pod{}
|
||||
if err := json.Unmarshal(data, &obj); err != nil {
|
||||
b.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
38
vendor/k8s.io/kubernetes/pkg/api/v1/OWNERS
generated
vendored
38
vendor/k8s.io/kubernetes/pkg/api/v1/OWNERS
generated
vendored
@ -1,38 +0,0 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- yujuhong
|
||||
- brendandburns
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- vishh
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- erictune
|
||||
- davidopp
|
||||
- pmorie
|
||||
- sttts
|
||||
- dchen1107
|
||||
- saad-ali
|
||||
- zmerlynn
|
||||
- luxas
|
||||
- janetkuo
|
||||
- justinsb
|
||||
- roberthbailey
|
||||
- ncdc
|
||||
- tallclair
|
||||
- eparis
|
||||
- piosz
|
||||
- jsafrane
|
||||
- dims
|
||||
- errordeveloper
|
||||
- madhusudancs
|
||||
- krousey
|
||||
- jayunit100
|
||||
- rootfs
|
||||
- markturansky
|
42
vendor/k8s.io/kubernetes/pkg/api/v1/endpoints/BUILD
generated
vendored
42
vendor/k8s.io/kubernetes/pkg/api/v1/endpoints/BUILD
generated
vendored
@ -1,42 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/endpoints",
|
||||
deps = [
|
||||
"//pkg/util/hash:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
236
vendor/k8s.io/kubernetes/pkg/api/v1/endpoints/util.go
generated
vendored
236
vendor/k8s.io/kubernetes/pkg/api/v1/endpoints/util.go
generated
vendored
@ -1,236 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"sort"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||
)
|
||||
|
||||
// RepackSubsets takes a slice of EndpointSubset objects, expands it to the full
|
||||
// representation, and then repacks that into the canonical layout. This
|
||||
// ensures that code which operates on these objects can rely on the common
|
||||
// form for things like comparison. The result is a newly allocated slice.
|
||||
func RepackSubsets(subsets []v1.EndpointSubset) []v1.EndpointSubset {
|
||||
// First map each unique port definition to the sets of hosts that
|
||||
// offer it.
|
||||
allAddrs := map[addressKey]*v1.EndpointAddress{}
|
||||
portToAddrReadyMap := map[v1.EndpointPort]addressSet{}
|
||||
for i := range subsets {
|
||||
if len(subsets[i].Ports) == 0 {
|
||||
// Don't discard endpoints with no ports defined, use a sentinel.
|
||||
mapAddressesByPort(&subsets[i], v1.EndpointPort{Port: -1}, allAddrs, portToAddrReadyMap)
|
||||
} else {
|
||||
for _, port := range subsets[i].Ports {
|
||||
mapAddressesByPort(&subsets[i], port, allAddrs, portToAddrReadyMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, map the sets of hosts to the sets of ports they offer.
|
||||
// Go does not allow maps or slices as keys to maps, so we have
|
||||
// to synthesize an artificial key and do a sort of 2-part
|
||||
// associative entity.
|
||||
type keyString string
|
||||
keyToAddrReadyMap := map[keyString]addressSet{}
|
||||
addrReadyMapKeyToPorts := map[keyString][]v1.EndpointPort{}
|
||||
for port, addrs := range portToAddrReadyMap {
|
||||
key := keyString(hashAddresses(addrs))
|
||||
keyToAddrReadyMap[key] = addrs
|
||||
if port.Port > 0 { // avoid sentinels
|
||||
addrReadyMapKeyToPorts[key] = append(addrReadyMapKeyToPorts[key], port)
|
||||
} else {
|
||||
if _, found := addrReadyMapKeyToPorts[key]; !found {
|
||||
// Force it to be present in the map
|
||||
addrReadyMapKeyToPorts[key] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, build the N-to-M association the API wants.
|
||||
final := []v1.EndpointSubset{}
|
||||
for key, ports := range addrReadyMapKeyToPorts {
|
||||
var readyAddrs, notReadyAddrs []v1.EndpointAddress
|
||||
for addr, ready := range keyToAddrReadyMap[key] {
|
||||
if ready {
|
||||
readyAddrs = append(readyAddrs, *addr)
|
||||
} else {
|
||||
notReadyAddrs = append(notReadyAddrs, *addr)
|
||||
}
|
||||
}
|
||||
final = append(final, v1.EndpointSubset{Addresses: readyAddrs, NotReadyAddresses: notReadyAddrs, Ports: ports})
|
||||
}
|
||||
|
||||
// Finally, sort it.
|
||||
return SortSubsets(final)
|
||||
}
|
||||
|
||||
// The sets of hosts must be de-duped, using IP+UID as the key.
|
||||
type addressKey struct {
|
||||
ip string
|
||||
uid types.UID
|
||||
}
|
||||
|
||||
// mapAddressesByPort adds all ready and not-ready addresses into a map by a single port.
|
||||
func mapAddressesByPort(subset *v1.EndpointSubset, port v1.EndpointPort, allAddrs map[addressKey]*v1.EndpointAddress, portToAddrReadyMap map[v1.EndpointPort]addressSet) {
|
||||
for k := range subset.Addresses {
|
||||
mapAddressByPort(&subset.Addresses[k], port, true, allAddrs, portToAddrReadyMap)
|
||||
}
|
||||
for k := range subset.NotReadyAddresses {
|
||||
mapAddressByPort(&subset.NotReadyAddresses[k], port, false, allAddrs, portToAddrReadyMap)
|
||||
}
|
||||
}
|
||||
|
||||
// mapAddressByPort adds one address into a map by port, registering the address with a unique pointer, and preserving
|
||||
// any existing ready state.
|
||||
func mapAddressByPort(addr *v1.EndpointAddress, port v1.EndpointPort, ready bool, allAddrs map[addressKey]*v1.EndpointAddress, portToAddrReadyMap map[v1.EndpointPort]addressSet) *v1.EndpointAddress {
|
||||
// use addressKey to distinguish between two endpoints that are identical addresses
|
||||
// but may have come from different hosts, for attribution. For instance, Mesos
|
||||
// assigns pods the node IP, but the pods are distinct.
|
||||
key := addressKey{ip: addr.IP}
|
||||
if addr.TargetRef != nil {
|
||||
key.uid = addr.TargetRef.UID
|
||||
}
|
||||
|
||||
// Accumulate the address. The full EndpointAddress structure is preserved for use when
|
||||
// we rebuild the subsets so that the final TargetRef has all of the necessary data.
|
||||
existingAddress := allAddrs[key]
|
||||
if existingAddress == nil {
|
||||
// Make a copy so we don't write to the
|
||||
// input args of this function.
|
||||
existingAddress = &v1.EndpointAddress{}
|
||||
*existingAddress = *addr
|
||||
allAddrs[key] = existingAddress
|
||||
}
|
||||
|
||||
// Remember that this port maps to this address.
|
||||
if _, found := portToAddrReadyMap[port]; !found {
|
||||
portToAddrReadyMap[port] = addressSet{}
|
||||
}
|
||||
// if we have not yet recorded this port for this address, or if the previous
|
||||
// state was ready, write the current ready state. not ready always trumps
|
||||
// ready.
|
||||
if wasReady, found := portToAddrReadyMap[port][existingAddress]; !found || wasReady {
|
||||
portToAddrReadyMap[port][existingAddress] = ready
|
||||
}
|
||||
return existingAddress
|
||||
}
|
||||
|
||||
type addressSet map[*v1.EndpointAddress]bool
|
||||
|
||||
type addrReady struct {
|
||||
addr *v1.EndpointAddress
|
||||
ready bool
|
||||
}
|
||||
|
||||
func hashAddresses(addrs addressSet) string {
|
||||
// Flatten the list of addresses into a string so it can be used as a
|
||||
// map key. Unfortunately, DeepHashObject is implemented in terms of
|
||||
// spew, and spew does not handle non-primitive map keys well. So
|
||||
// first we collapse it into a slice, sort the slice, then hash that.
|
||||
slice := make([]addrReady, 0, len(addrs))
|
||||
for k, ready := range addrs {
|
||||
slice = append(slice, addrReady{k, ready})
|
||||
}
|
||||
sort.Sort(addrsReady(slice))
|
||||
hasher := md5.New()
|
||||
hashutil.DeepHashObject(hasher, slice)
|
||||
return hex.EncodeToString(hasher.Sum(nil)[0:])
|
||||
}
|
||||
|
||||
func lessAddrReady(a, b addrReady) bool {
|
||||
// ready is not significant to hashing since we can't have duplicate addresses
|
||||
return LessEndpointAddress(a.addr, b.addr)
|
||||
}
|
||||
|
||||
type addrsReady []addrReady
|
||||
|
||||
func (sl addrsReady) Len() int { return len(sl) }
|
||||
func (sl addrsReady) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl addrsReady) Less(i, j int) bool {
|
||||
return lessAddrReady(sl[i], sl[j])
|
||||
}
|
||||
|
||||
// LessEndpointAddress compares IP addresses lexicographically and returns true if first argument is lesser than second
|
||||
func LessEndpointAddress(a, b *v1.EndpointAddress) bool {
|
||||
ipComparison := bytes.Compare([]byte(a.IP), []byte(b.IP))
|
||||
if ipComparison != 0 {
|
||||
return ipComparison < 0
|
||||
}
|
||||
if b.TargetRef == nil {
|
||||
return false
|
||||
}
|
||||
if a.TargetRef == nil {
|
||||
return true
|
||||
}
|
||||
return a.TargetRef.UID < b.TargetRef.UID
|
||||
}
|
||||
|
||||
// SortSubsets sorts an array of EndpointSubset objects in place. For ease of
|
||||
// use it returns the input slice.
|
||||
func SortSubsets(subsets []v1.EndpointSubset) []v1.EndpointSubset {
|
||||
for i := range subsets {
|
||||
ss := &subsets[i]
|
||||
sort.Sort(addrsByIPAndUID(ss.Addresses))
|
||||
sort.Sort(addrsByIPAndUID(ss.NotReadyAddresses))
|
||||
sort.Sort(portsByHash(ss.Ports))
|
||||
}
|
||||
sort.Sort(subsetsByHash(subsets))
|
||||
return subsets
|
||||
}
|
||||
|
||||
func hashObject(hasher hash.Hash, obj interface{}) []byte {
|
||||
hashutil.DeepHashObject(hasher, obj)
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
type subsetsByHash []v1.EndpointSubset
|
||||
|
||||
func (sl subsetsByHash) Len() int { return len(sl) }
|
||||
func (sl subsetsByHash) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl subsetsByHash) Less(i, j int) bool {
|
||||
hasher := md5.New()
|
||||
h1 := hashObject(hasher, sl[i])
|
||||
h2 := hashObject(hasher, sl[j])
|
||||
return bytes.Compare(h1, h2) < 0
|
||||
}
|
||||
|
||||
type addrsByIPAndUID []v1.EndpointAddress
|
||||
|
||||
func (sl addrsByIPAndUID) Len() int { return len(sl) }
|
||||
func (sl addrsByIPAndUID) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl addrsByIPAndUID) Less(i, j int) bool {
|
||||
return LessEndpointAddress(&sl[i], &sl[j])
|
||||
}
|
||||
|
||||
type portsByHash []v1.EndpointPort
|
||||
|
||||
func (sl portsByHash) Len() int { return len(sl) }
|
||||
func (sl portsByHash) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
|
||||
func (sl portsByHash) Less(i, j int) bool {
|
||||
hasher := md5.New()
|
||||
h1 := hashObject(hasher, sl[i])
|
||||
h2 := hashObject(hasher, sl[j])
|
||||
return bytes.Compare(h1, h2) < 0
|
||||
}
|
464
vendor/k8s.io/kubernetes/pkg/api/v1/endpoints/util_test.go
generated
vendored
464
vendor/k8s.io/kubernetes/pkg/api/v1/endpoints/util_test.go
generated
vendored
@ -1,464 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func podRef(uid string) *v1.ObjectReference {
|
||||
ref := v1.ObjectReference{UID: types.UID(uid)}
|
||||
return &ref
|
||||
}
|
||||
|
||||
func TestPackSubsets(t *testing.T) {
|
||||
// The downside of table-driven tests is that some things have to live outside the table.
|
||||
fooObjRef := v1.ObjectReference{Name: "foo"}
|
||||
barObjRef := v1.ObjectReference{Name: "bar"}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
given []v1.EndpointSubset
|
||||
expect []v1.EndpointSubset
|
||||
}{
|
||||
{
|
||||
name: "empty everything",
|
||||
given: []v1.EndpointSubset{{Addresses: []v1.EndpointAddress{}, Ports: []v1.EndpointPort{}}},
|
||||
expect: []v1.EndpointSubset{},
|
||||
}, {
|
||||
name: "empty addresses",
|
||||
given: []v1.EndpointSubset{{Addresses: []v1.EndpointAddress{}, Ports: []v1.EndpointPort{{Port: 111}}}},
|
||||
expect: []v1.EndpointSubset{},
|
||||
}, {
|
||||
name: "empty ports",
|
||||
given: []v1.EndpointSubset{{Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []v1.EndpointPort{}}},
|
||||
expect: []v1.EndpointSubset{{Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: nil}},
|
||||
}, {
|
||||
name: "empty ports",
|
||||
given: []v1.EndpointSubset{{NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []v1.EndpointPort{}}},
|
||||
expect: []v1.EndpointSubset{{NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: nil}},
|
||||
}, {
|
||||
name: "one set, one ip, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, one port (IPv6)",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "beef::1:2:3:4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "beef::1:2:3:4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one notReady ip, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, one UID, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one notReady ip, one UID, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, empty UID, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one notReady ip, empty UID, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, two ips, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, two mixed ips, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, two duplicate ips, one port, notReady is covered by ready",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, two ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup ips, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup ips, one port (IPv6)",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "beef::1"}, {IP: "beef::1"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "beef::1"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup ips with target-refs, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: &fooObjRef},
|
||||
{IP: "1.2.3.4", TargetRef: &barObjRef},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: &fooObjRef}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, dup mixed ips with target-refs, one port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: &fooObjRef},
|
||||
},
|
||||
NotReadyAddresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: &barObjRef},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
// finding the same address twice is considered an error on input, only the first address+port
|
||||
// reference is preserved
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: &fooObjRef}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "one set, one ip, dup ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}, {Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup ip, dup port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup mixed ip, dup port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup ip, two ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup ip, dup uids, two ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}, {Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, dup mixed ip, dup uids, two ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two ips, dup port",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two set, dup ip, two uids, dup ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-2")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-2")},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two set, dup ip, with and without uid, dup ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-2")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-2")},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two ips, two dup ip with uid, dup port, wrong order",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "5.6.7.8", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
|
||||
{IP: "5.6.7.8"},
|
||||
{IP: "5.6.7.8", TargetRef: podRef("uid-1")},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two mixed ips, two dup ip with uid, dup port, wrong order, ends up with split addresses",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "5.6.7.8", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{IP: "5.6.7.8"},
|
||||
},
|
||||
NotReadyAddresses: []v1.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
|
||||
{IP: "5.6.7.8", TargetRef: podRef("uid-1")},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}},
|
||||
}, {
|
||||
name: "two sets, two ips, two ports",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "5.6.7.8"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}},
|
||||
}, {
|
||||
name: "four sets, three ips, three ports, jumbled",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.6"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []v1.EndpointPort{{Port: 333}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.6"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}, {Port: 333}},
|
||||
}},
|
||||
}, {
|
||||
name: "four sets, three mixed ips, three ports, jumbled",
|
||||
given: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}},
|
||||
}, {
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.6"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []v1.EndpointPort{{Port: 333}},
|
||||
}},
|
||||
expect: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.6"}},
|
||||
Ports: []v1.EndpointPort{{Port: 111}},
|
||||
}, {
|
||||
NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.5"}},
|
||||
Ports: []v1.EndpointPort{{Port: 222}, {Port: 333}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
result := RepackSubsets(tc.given)
|
||||
if !reflect.DeepEqual(result, SortSubsets(tc.expect)) {
|
||||
t.Errorf("case %q: expected %s, got %s", tc.name, spew.Sprintf("%#v", SortSubsets(tc.expect)), spew.Sprintf("%#v", result))
|
||||
}
|
||||
}
|
||||
}
|
26
vendor/k8s.io/kubernetes/pkg/api/v1/node/BUILD
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/api/v1/node/BUILD
generated
vendored
@ -1,26 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/node",
|
||||
deps = ["//staging/src/k8s.io/api/core/v1:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
47
vendor/k8s.io/kubernetes/pkg/api/v1/node/util.go
generated
vendored
47
vendor/k8s.io/kubernetes/pkg/api/v1/node/util.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO: merge with pkg/util/node
|
||||
|
||||
package node
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// GetNodeCondition extracts the provided condition from the given status and returns that.
|
||||
// Returns nil and -1 if the condition is not present, and the index of the located condition.
|
||||
func GetNodeCondition(status *v1.NodeStatus, conditionType v1.NodeConditionType) (int, *v1.NodeCondition) {
|
||||
if status == nil {
|
||||
return -1, nil
|
||||
}
|
||||
for i := range status.Conditions {
|
||||
if status.Conditions[i].Type == conditionType {
|
||||
return i, &status.Conditions[i]
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// IsNodeReady returns true if a node is ready; false otherwise.
|
||||
func IsNodeReady(node *v1.Node) bool {
|
||||
for _, c := range node.Status.Conditions {
|
||||
if c.Type == v1.NodeReady {
|
||||
return c.Status == v1.ConditionTrue
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
35
vendor/k8s.io/kubernetes/pkg/api/v1/persistentvolume/BUILD
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/api/v1/persistentvolume/BUILD
generated
vendored
@ -1,35 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/persistentvolume",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//staging/src/k8s.io/api/core/v1:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
134
vendor/k8s.io/kubernetes/pkg/api/v1/persistentvolume/util.go
generated
vendored
134
vendor/k8s.io/kubernetes/pkg/api/v1/persistentvolume/util.go
generated
vendored
@ -1,134 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolume
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func getClaimRefNamespace(pv *corev1.PersistentVolume) string {
|
||||
if pv.Spec.ClaimRef != nil {
|
||||
return pv.Spec.ClaimRef.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Visitor is called with each object's namespace and name, and returns true if visiting should continue
|
||||
type Visitor func(namespace, name string, kubeletVisible bool) (shouldContinue bool)
|
||||
|
||||
// VisitPVSecretNames invokes the visitor function with the name of every secret
|
||||
// referenced by the PV spec. If visitor returns false, visiting is short-circuited.
|
||||
// Returns true if visiting completed, false if visiting was short-circuited.
|
||||
func VisitPVSecretNames(pv *corev1.PersistentVolume, visitor Visitor) bool {
|
||||
source := &pv.Spec.PersistentVolumeSource
|
||||
switch {
|
||||
case source.AzureFile != nil:
|
||||
if source.AzureFile.SecretNamespace != nil && len(*source.AzureFile.SecretNamespace) > 0 {
|
||||
if len(source.AzureFile.SecretName) > 0 && !visitor(*source.AzureFile.SecretNamespace, source.AzureFile.SecretName, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if len(source.AzureFile.SecretName) > 0 && !visitor(getClaimRefNamespace(pv), source.AzureFile.SecretName, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case source.CephFS != nil:
|
||||
if source.CephFS.SecretRef != nil {
|
||||
// previously persisted PV objects use claimRef namespace
|
||||
ns := getClaimRefNamespace(pv)
|
||||
if len(source.CephFS.SecretRef.Namespace) > 0 {
|
||||
// use the secret namespace if namespace is set
|
||||
ns = source.CephFS.SecretRef.Namespace
|
||||
}
|
||||
if !visitor(ns, source.CephFS.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case source.Cinder != nil:
|
||||
if source.Cinder.SecretRef != nil && !visitor(source.Cinder.SecretRef.Namespace, source.Cinder.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
case source.FlexVolume != nil:
|
||||
if source.FlexVolume.SecretRef != nil {
|
||||
// previously persisted PV objects use claimRef namespace
|
||||
ns := getClaimRefNamespace(pv)
|
||||
if len(source.FlexVolume.SecretRef.Namespace) > 0 {
|
||||
// use the secret namespace if namespace is set
|
||||
ns = source.FlexVolume.SecretRef.Namespace
|
||||
}
|
||||
if !visitor(ns, source.FlexVolume.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case source.RBD != nil:
|
||||
if source.RBD.SecretRef != nil {
|
||||
// previously persisted PV objects use claimRef namespace
|
||||
ns := getClaimRefNamespace(pv)
|
||||
if len(source.RBD.SecretRef.Namespace) > 0 {
|
||||
// use the secret namespace if namespace is set
|
||||
ns = source.RBD.SecretRef.Namespace
|
||||
}
|
||||
if !visitor(ns, source.RBD.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case source.ScaleIO != nil:
|
||||
if source.ScaleIO.SecretRef != nil {
|
||||
ns := getClaimRefNamespace(pv)
|
||||
if source.ScaleIO.SecretRef != nil && len(source.ScaleIO.SecretRef.Namespace) > 0 {
|
||||
ns = source.ScaleIO.SecretRef.Namespace
|
||||
}
|
||||
if !visitor(ns, source.ScaleIO.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case source.ISCSI != nil:
|
||||
if source.ISCSI.SecretRef != nil {
|
||||
// previously persisted PV objects use claimRef namespace
|
||||
ns := getClaimRefNamespace(pv)
|
||||
if len(source.ISCSI.SecretRef.Namespace) > 0 {
|
||||
// use the secret namespace if namespace is set
|
||||
ns = source.ISCSI.SecretRef.Namespace
|
||||
}
|
||||
if !visitor(ns, source.ISCSI.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case source.StorageOS != nil:
|
||||
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Namespace, source.StorageOS.SecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
case source.CSI != nil:
|
||||
if source.CSI.ControllerPublishSecretRef != nil {
|
||||
if !visitor(source.CSI.ControllerPublishSecretRef.Namespace, source.CSI.ControllerPublishSecretRef.Name, false /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if source.CSI.NodePublishSecretRef != nil {
|
||||
if !visitor(source.CSI.NodePublishSecretRef.Namespace, source.CSI.NodePublishSecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if source.CSI.NodeStageSecretRef != nil {
|
||||
if !visitor(source.CSI.NodeStageSecretRef.Namespace, source.CSI.NodeStageSecretRef.Name, true /* kubeletVisible */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
272
vendor/k8s.io/kubernetes/pkg/api/v1/persistentvolume/util_test.go
generated
vendored
272
vendor/k8s.io/kubernetes/pkg/api/v1/persistentvolume/util_test.go
generated
vendored
@ -1,272 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistentvolume
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func TestPVSecrets(t *testing.T) {
|
||||
// Stub containing all possible secret references in a PV.
|
||||
// The names of the referenced secrets match struct paths detected by reflection.
|
||||
secretNamespace := "Spec.PersistentVolumeSource.AzureFile.SecretNamespace"
|
||||
pvs := []*corev1.PersistentVolume{
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
AzureFile: &corev1.AzureFilePersistentVolumeSource{
|
||||
SecretName: "Spec.PersistentVolumeSource.AzureFile.SecretName"}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
AzureFile: &corev1.AzureFilePersistentVolumeSource{
|
||||
SecretName: "Spec.PersistentVolumeSource.AzureFile.SecretName",
|
||||
SecretNamespace: &secretNamespace}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
CephFS: &corev1.CephFSPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.CephFS.SecretRef",
|
||||
Namespace: "cephfs"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
CephFS: &corev1.CephFSPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.CephFS.SecretRef"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
Cinder: &corev1.CinderPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.Cinder.SecretRef",
|
||||
Namespace: "cinder"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
FlexVolume: &corev1.FlexPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.FlexVolume.SecretRef",
|
||||
Namespace: "flexns"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
FlexVolume: &corev1.FlexPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.FlexVolume.SecretRef"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
RBD: &corev1.RBDPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.RBD.SecretRef"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
RBD: &corev1.RBDPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
Namespace: "rbdns"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
ScaleIO: &corev1.ScaleIOPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
ScaleIO: &corev1.ScaleIOPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||
Namespace: "scaleions"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
ISCSI: &corev1.ISCSIPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||
Namespace: "iscsi"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
ISCSI: &corev1.ISCSIPersistentVolumeSource{
|
||||
SecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
StorageOS: &corev1.StorageOSPersistentVolumeSource{
|
||||
SecretRef: &corev1.ObjectReference{
|
||||
Name: "Spec.PersistentVolumeSource.StorageOS.SecretRef",
|
||||
Namespace: "storageosns"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
CSI: &corev1.CSIPersistentVolumeSource{
|
||||
ControllerPublishSecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.CSI.ControllerPublishSecretRef",
|
||||
Namespace: "csi"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
CSI: &corev1.CSIPersistentVolumeSource{
|
||||
NodePublishSecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.CSI.NodePublishSecretRef",
|
||||
Namespace: "csi"}}}}},
|
||||
{Spec: corev1.PersistentVolumeSpec{
|
||||
ClaimRef: &corev1.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||
CSI: &corev1.CSIPersistentVolumeSource{
|
||||
NodeStageSecretRef: &corev1.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.CSI.NodeStageSecretRef",
|
||||
Namespace: "csi"}}}}},
|
||||
}
|
||||
extractedNames := sets.NewString()
|
||||
extractedNamesWithNamespace := sets.NewString()
|
||||
for _, pv := range pvs {
|
||||
VisitPVSecretNames(pv, func(namespace, name string, kubeletVisible bool) bool {
|
||||
extractedNames.Insert(name)
|
||||
extractedNamesWithNamespace.Insert(namespace + "/" + name)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// excludedSecretPaths holds struct paths to fields with "secret" in the name that are not actually references to secret API objects
|
||||
excludedSecretPaths := sets.NewString(
|
||||
"Spec.PersistentVolumeSource.CephFS.SecretFile",
|
||||
"Spec.PersistentVolumeSource.AzureFile.SecretNamespace",
|
||||
)
|
||||
// expectedSecretPaths holds struct paths to fields with "secret" in the name that are references to secret API objects.
|
||||
// every path here should be represented as an example in the PV stub above, with the secret name set to the path.
|
||||
expectedSecretPaths := sets.NewString(
|
||||
"Spec.PersistentVolumeSource.AzureFile.SecretName",
|
||||
"Spec.PersistentVolumeSource.CephFS.SecretRef",
|
||||
"Spec.PersistentVolumeSource.Cinder.SecretRef",
|
||||
"Spec.PersistentVolumeSource.FlexVolume.SecretRef",
|
||||
"Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
"Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||
"Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||
"Spec.PersistentVolumeSource.StorageOS.SecretRef",
|
||||
"Spec.PersistentVolumeSource.CSI.ControllerPublishSecretRef",
|
||||
"Spec.PersistentVolumeSource.CSI.NodePublishSecretRef",
|
||||
"Spec.PersistentVolumeSource.CSI.NodeStageSecretRef",
|
||||
)
|
||||
secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&api.PersistentVolume{}))
|
||||
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
||||
if missingPaths := expectedSecretPaths.Difference(secretPaths); len(missingPaths) > 0 {
|
||||
t.Logf("Missing expected secret paths:\n%s", strings.Join(missingPaths.List(), "\n"))
|
||||
t.Error("Missing expected secret paths. Verify VisitPVSecretNames() is correctly finding the missing paths, then correct expectedSecretPaths")
|
||||
}
|
||||
if extraPaths := secretPaths.Difference(expectedSecretPaths); len(extraPaths) > 0 {
|
||||
t.Logf("Extra secret paths:\n%s", strings.Join(extraPaths.List(), "\n"))
|
||||
t.Error("Extra fields with 'secret' in the name found. Verify VisitPVSecretNames() is including these fields if appropriate, then correct expectedSecretPaths")
|
||||
}
|
||||
|
||||
if missingNames := expectedSecretPaths.Difference(extractedNames); len(missingNames) > 0 {
|
||||
t.Logf("Missing expected secret names:\n%s", strings.Join(missingNames.List(), "\n"))
|
||||
t.Error("Missing expected secret names. Verify the PV stub above includes these references, then verify VisitPVSecretNames() is correctly finding the missing names")
|
||||
}
|
||||
if extraNames := extractedNames.Difference(expectedSecretPaths); len(extraNames) > 0 {
|
||||
t.Logf("Extra secret names:\n%s", strings.Join(extraNames.List(), "\n"))
|
||||
t.Error("Extra secret names extracted. Verify VisitPVSecretNames() is correctly extracting secret names")
|
||||
}
|
||||
|
||||
expectedNamespacedNames := sets.NewString(
|
||||
"claimrefns/Spec.PersistentVolumeSource.AzureFile.SecretName",
|
||||
"Spec.PersistentVolumeSource.AzureFile.SecretNamespace/Spec.PersistentVolumeSource.AzureFile.SecretName",
|
||||
|
||||
"claimrefns/Spec.PersistentVolumeSource.CephFS.SecretRef",
|
||||
"cephfs/Spec.PersistentVolumeSource.CephFS.SecretRef",
|
||||
|
||||
"cinder/Spec.PersistentVolumeSource.Cinder.SecretRef",
|
||||
|
||||
"claimrefns/Spec.PersistentVolumeSource.FlexVolume.SecretRef",
|
||||
"flexns/Spec.PersistentVolumeSource.FlexVolume.SecretRef",
|
||||
|
||||
"claimrefns/Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
"rbdns/Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
|
||||
"claimrefns/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||
"scaleions/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||
|
||||
"claimrefns/Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||
"iscsi/Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||
|
||||
"storageosns/Spec.PersistentVolumeSource.StorageOS.SecretRef",
|
||||
|
||||
"csi/Spec.PersistentVolumeSource.CSI.ControllerPublishSecretRef",
|
||||
"csi/Spec.PersistentVolumeSource.CSI.NodePublishSecretRef",
|
||||
"csi/Spec.PersistentVolumeSource.CSI.NodeStageSecretRef",
|
||||
)
|
||||
if missingNames := expectedNamespacedNames.Difference(extractedNamesWithNamespace); len(missingNames) > 0 {
|
||||
t.Logf("Missing expected namespaced names:\n%s", strings.Join(missingNames.List(), "\n"))
|
||||
t.Error("Missing expected namespaced names. Verify the PV stub above includes these references, then verify VisitPVSecretNames() is correctly finding the missing names")
|
||||
}
|
||||
if extraNames := extractedNamesWithNamespace.Difference(expectedNamespacedNames); len(extraNames) > 0 {
|
||||
t.Logf("Extra namespaced names:\n%s", strings.Join(extraNames.List(), "\n"))
|
||||
t.Error("Extra namespaced names extracted. Verify VisitPVSecretNames() is correctly extracting secret names")
|
||||
}
|
||||
}
|
||||
|
||||
// collectSecretPaths traverses the object, computing all the struct paths that lead to fields with "secret" in the name.
|
||||
func collectSecretPaths(t *testing.T, path *field.Path, name string, tp reflect.Type) sets.String {
|
||||
secretPaths := sets.NewString()
|
||||
|
||||
if tp.Kind() == reflect.Ptr {
|
||||
secretPaths.Insert(collectSecretPaths(t, path, name, tp.Elem()).List()...)
|
||||
return secretPaths
|
||||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(name), "secret") {
|
||||
secretPaths.Insert(path.String())
|
||||
}
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Ptr:
|
||||
secretPaths.Insert(collectSecretPaths(t, path, name, tp.Elem()).List()...)
|
||||
case reflect.Struct:
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
field := tp.Field(i)
|
||||
secretPaths.Insert(collectSecretPaths(t, path.Child(field.Name), field.Name, field.Type).List()...)
|
||||
}
|
||||
case reflect.Interface:
|
||||
t.Errorf("cannot find secret fields in interface{} field %s", path.String())
|
||||
case reflect.Map:
|
||||
secretPaths.Insert(collectSecretPaths(t, path.Key("*"), "", tp.Elem()).List()...)
|
||||
case reflect.Slice:
|
||||
secretPaths.Insert(collectSecretPaths(t, path.Key("*"), "", tp.Elem()).List()...)
|
||||
default:
|
||||
// all primitive types
|
||||
}
|
||||
|
||||
return secretPaths
|
||||
}
|
||||
|
||||
func newHostPathType(pathType string) *corev1.HostPathType {
|
||||
hostPathType := new(corev1.HostPathType)
|
||||
*hostPathType = corev1.HostPathType(pathType)
|
||||
return hostPathType
|
||||
}
|
45
vendor/k8s.io/kubernetes/pkg/api/v1/pod/BUILD
generated
vendored
45
vendor/k8s.io/kubernetes/pkg/api/v1/pod/BUILD
generated
vendored
@ -1,45 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/pod",
|
||||
deps = [
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
304
vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go
generated
vendored
304
vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go
generated
vendored
@ -1,304 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// FindPort locates the container port for the given pod and portName. If the
|
||||
// targetPort is a number, use that. If the targetPort is a string, look that
|
||||
// string up in all named ports in all containers in the target pod. If no
|
||||
// match is found, fail.
|
||||
func FindPort(pod *v1.Pod, svcPort *v1.ServicePort) (int, error) {
|
||||
portName := svcPort.TargetPort
|
||||
switch portName.Type {
|
||||
case intstr.String:
|
||||
name := portName.StrVal
|
||||
for _, container := range pod.Spec.Containers {
|
||||
for _, port := range container.Ports {
|
||||
if port.Name == name && port.Protocol == svcPort.Protocol {
|
||||
return int(port.ContainerPort), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
case intstr.Int:
|
||||
return portName.IntValue(), nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no suitable port for manifest: %s", pod.UID)
|
||||
}
|
||||
|
||||
// Visitor is called with each object name, and returns true if visiting should continue
|
||||
type Visitor func(name string) (shouldContinue bool)
|
||||
|
||||
// VisitPodSecretNames invokes the visitor function with the name of every secret
|
||||
// referenced by the pod spec. If visitor returns false, visiting is short-circuited.
|
||||
// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
|
||||
// Returns true if visiting completed, false if visiting was short-circuited.
|
||||
func VisitPodSecretNames(pod *v1.Pod, visitor Visitor) bool {
|
||||
for _, reference := range pod.Spec.ImagePullSecrets {
|
||||
if !visitor(reference.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.InitContainers {
|
||||
if !visitContainerSecretNames(&pod.Spec.InitContainers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.Containers {
|
||||
if !visitContainerSecretNames(&pod.Spec.Containers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
var source *v1.VolumeSource
|
||||
|
||||
for i := range pod.Spec.Volumes {
|
||||
source = &pod.Spec.Volumes[i].VolumeSource
|
||||
switch {
|
||||
case source.AzureFile != nil:
|
||||
if len(source.AzureFile.SecretName) > 0 && !visitor(source.AzureFile.SecretName) {
|
||||
return false
|
||||
}
|
||||
case source.CephFS != nil:
|
||||
if source.CephFS.SecretRef != nil && !visitor(source.CephFS.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.Cinder != nil:
|
||||
if source.Cinder.SecretRef != nil && !visitor(source.Cinder.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.FlexVolume != nil:
|
||||
if source.FlexVolume.SecretRef != nil && !visitor(source.FlexVolume.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.Projected != nil:
|
||||
for j := range source.Projected.Sources {
|
||||
if source.Projected.Sources[j].Secret != nil {
|
||||
if !visitor(source.Projected.Sources[j].Secret.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case source.RBD != nil:
|
||||
if source.RBD.SecretRef != nil && !visitor(source.RBD.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.Secret != nil:
|
||||
if !visitor(source.Secret.SecretName) {
|
||||
return false
|
||||
}
|
||||
case source.ScaleIO != nil:
|
||||
if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.ISCSI != nil:
|
||||
if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
case source.StorageOS != nil:
|
||||
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func visitContainerSecretNames(container *v1.Container, visitor Visitor) bool {
|
||||
for _, env := range container.EnvFrom {
|
||||
if env.SecretRef != nil {
|
||||
if !visitor(env.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, envVar := range container.Env {
|
||||
if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil {
|
||||
if !visitor(envVar.ValueFrom.SecretKeyRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// VisitPodConfigmapNames invokes the visitor function with the name of every configmap
|
||||
// referenced by the pod spec. If visitor returns false, visiting is short-circuited.
|
||||
// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
|
||||
// Returns true if visiting completed, false if visiting was short-circuited.
|
||||
func VisitPodConfigmapNames(pod *v1.Pod, visitor Visitor) bool {
|
||||
for i := range pod.Spec.InitContainers {
|
||||
if !visitContainerConfigmapNames(&pod.Spec.InitContainers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.Containers {
|
||||
if !visitContainerConfigmapNames(&pod.Spec.Containers[i], visitor) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
var source *v1.VolumeSource
|
||||
for i := range pod.Spec.Volumes {
|
||||
source = &pod.Spec.Volumes[i].VolumeSource
|
||||
switch {
|
||||
case source.Projected != nil:
|
||||
for j := range source.Projected.Sources {
|
||||
if source.Projected.Sources[j].ConfigMap != nil {
|
||||
if !visitor(source.Projected.Sources[j].ConfigMap.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case source.ConfigMap != nil:
|
||||
if !visitor(source.ConfigMap.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func visitContainerConfigmapNames(container *v1.Container, visitor Visitor) bool {
|
||||
for _, env := range container.EnvFrom {
|
||||
if env.ConfigMapRef != nil {
|
||||
if !visitor(env.ConfigMapRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, envVar := range container.Env {
|
||||
if envVar.ValueFrom != nil && envVar.ValueFrom.ConfigMapKeyRef != nil {
|
||||
if !visitor(envVar.ValueFrom.ConfigMapKeyRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GetContainerStatus extracts the status of container "name" from "statuses".
|
||||
// It also returns if "name" exists.
|
||||
func GetContainerStatus(statuses []v1.ContainerStatus, name string) (v1.ContainerStatus, bool) {
|
||||
for i := range statuses {
|
||||
if statuses[i].Name == name {
|
||||
return statuses[i], true
|
||||
}
|
||||
}
|
||||
return v1.ContainerStatus{}, false
|
||||
}
|
||||
|
||||
// GetExistingContainerStatus extracts the status of container "name" from "statuses",
|
||||
// It also returns if "name" exists.
|
||||
func GetExistingContainerStatus(statuses []v1.ContainerStatus, name string) v1.ContainerStatus {
|
||||
status, _ := GetContainerStatus(statuses, name)
|
||||
return status
|
||||
}
|
||||
|
||||
// IsPodAvailable returns true if a pod is available; false otherwise.
|
||||
// Precondition for an available pod is that it must be ready. On top
|
||||
// of that, there are two cases when a pod can be considered available:
|
||||
// 1. minReadySeconds == 0, or
|
||||
// 2. LastTransitionTime (is set) + minReadySeconds < current time
|
||||
func IsPodAvailable(pod *v1.Pod, minReadySeconds int32, now metav1.Time) bool {
|
||||
if !IsPodReady(pod) {
|
||||
return false
|
||||
}
|
||||
|
||||
c := GetPodReadyCondition(pod.Status)
|
||||
minReadySecondsDuration := time.Duration(minReadySeconds) * time.Second
|
||||
if minReadySeconds == 0 || !c.LastTransitionTime.IsZero() && c.LastTransitionTime.Add(minReadySecondsDuration).Before(now.Time) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPodReady returns true if a pod is ready; false otherwise.
|
||||
func IsPodReady(pod *v1.Pod) bool {
|
||||
return IsPodReadyConditionTrue(pod.Status)
|
||||
}
|
||||
|
||||
// IsPodReadyConditionTrue returns true if a pod is ready; false otherwise.
|
||||
func IsPodReadyConditionTrue(status v1.PodStatus) bool {
|
||||
condition := GetPodReadyCondition(status)
|
||||
return condition != nil && condition.Status == v1.ConditionTrue
|
||||
}
|
||||
|
||||
// GetPodReadyCondition extracts the pod ready condition from the given status and returns that.
|
||||
// Returns nil if the condition is not present.
|
||||
func GetPodReadyCondition(status v1.PodStatus) *v1.PodCondition {
|
||||
_, condition := GetPodCondition(&status, v1.PodReady)
|
||||
return condition
|
||||
}
|
||||
|
||||
// GetPodCondition extracts the provided condition from the given status and returns that.
|
||||
// Returns nil and -1 if the condition is not present, and the index of the located condition.
|
||||
func GetPodCondition(status *v1.PodStatus, conditionType v1.PodConditionType) (int, *v1.PodCondition) {
|
||||
if status == nil {
|
||||
return -1, nil
|
||||
}
|
||||
return GetPodConditionFromList(status.Conditions, conditionType)
|
||||
}
|
||||
|
||||
// GetPodConditionFromList extracts the provided condition from the given list of condition and
|
||||
// returns the index of the condition and the condition. Returns -1 and nil if the condition is not present.
|
||||
func GetPodConditionFromList(conditions []v1.PodCondition, conditionType v1.PodConditionType) (int, *v1.PodCondition) {
|
||||
if conditions == nil {
|
||||
return -1, nil
|
||||
}
|
||||
for i := range conditions {
|
||||
if conditions[i].Type == conditionType {
|
||||
return i, &conditions[i]
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// UpdatePodCondition updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
|
||||
// status has changed.
|
||||
// Returns true if pod condition has changed or has been added.
|
||||
func UpdatePodCondition(status *v1.PodStatus, condition *v1.PodCondition) bool {
|
||||
condition.LastTransitionTime = metav1.Now()
|
||||
// Try to find this pod condition.
|
||||
conditionIndex, oldCondition := GetPodCondition(status, condition.Type)
|
||||
|
||||
if oldCondition == nil {
|
||||
// We are adding new pod condition.
|
||||
status.Conditions = append(status.Conditions, *condition)
|
||||
return true
|
||||
}
|
||||
// We are updating an existing condition, so we need to check if it has changed.
|
||||
if condition.Status == oldCondition.Status {
|
||||
condition.LastTransitionTime = oldCondition.LastTransitionTime
|
||||
}
|
||||
|
||||
isEqual := condition.Status == oldCondition.Status &&
|
||||
condition.Reason == oldCondition.Reason &&
|
||||
condition.Message == oldCondition.Message &&
|
||||
condition.LastProbeTime.Equal(&oldCondition.LastProbeTime) &&
|
||||
condition.LastTransitionTime.Equal(&oldCondition.LastTransitionTime)
|
||||
|
||||
status.Conditions[conditionIndex] = *condition
|
||||
// Return true if one of the fields have changed.
|
||||
return !isEqual
|
||||
}
|
602
vendor/k8s.io/kubernetes/pkg/api/v1/pod/util_test.go
generated
vendored
602
vendor/k8s.io/kubernetes/pkg/api/v1/pod/util_test.go
generated
vendored
@ -1,602 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pod
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func TestFindPort(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
containers []v1.Container
|
||||
port intstr.IntOrString
|
||||
expected int
|
||||
pass bool
|
||||
}{{
|
||||
name: "valid int, no ports",
|
||||
containers: []v1.Container{{}},
|
||||
port: intstr.FromInt(93),
|
||||
expected: 93,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "valid int, with ports",
|
||||
containers: []v1.Container{{Ports: []v1.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "TCP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: intstr.FromInt(93),
|
||||
expected: 93,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "valid str, no ports",
|
||||
containers: []v1.Container{{}},
|
||||
port: intstr.FromString("p"),
|
||||
expected: 0,
|
||||
pass: false,
|
||||
}, {
|
||||
name: "valid str, one ctr with ports",
|
||||
containers: []v1.Container{{Ports: []v1.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}, {
|
||||
Name: "q",
|
||||
ContainerPort: 33,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: intstr.FromString("q"),
|
||||
expected: 33,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "valid str, two ctr with ports",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}, {
|
||||
Name: "q",
|
||||
ContainerPort: 33,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: intstr.FromString("q"),
|
||||
expected: 33,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "valid str, two ctr with same port",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}, {
|
||||
Name: "q",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: intstr.FromString("q"),
|
||||
expected: 22,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "valid str, invalid protocol",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "a",
|
||||
ContainerPort: 11,
|
||||
Protocol: "snmp",
|
||||
},
|
||||
}}},
|
||||
port: intstr.FromString("a"),
|
||||
expected: 0,
|
||||
pass: false,
|
||||
}, {
|
||||
name: "valid hostPort",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "a",
|
||||
ContainerPort: 11,
|
||||
HostPort: 81,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
}}},
|
||||
port: intstr.FromString("a"),
|
||||
expected: 11,
|
||||
pass: true,
|
||||
},
|
||||
{
|
||||
name: "invalid hostPort",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "a",
|
||||
ContainerPort: 11,
|
||||
HostPort: -1,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
}}},
|
||||
port: intstr.FromString("a"),
|
||||
expected: 11,
|
||||
pass: true,
|
||||
//this should fail but passes.
|
||||
},
|
||||
{
|
||||
name: "invalid ContainerPort",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "a",
|
||||
ContainerPort: -1,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
}}},
|
||||
port: intstr.FromString("a"),
|
||||
expected: -1,
|
||||
pass: true,
|
||||
//this should fail but passes
|
||||
},
|
||||
{
|
||||
name: "HostIP Address",
|
||||
containers: []v1.Container{{}, {Ports: []v1.ContainerPort{{
|
||||
Name: "a",
|
||||
ContainerPort: 11,
|
||||
HostIP: "192.168.1.1",
|
||||
Protocol: "TCP",
|
||||
},
|
||||
}}},
|
||||
port: intstr.FromString("a"),
|
||||
expected: 11,
|
||||
pass: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
port, err := FindPort(&v1.Pod{Spec: v1.PodSpec{Containers: tc.containers}},
|
||||
&v1.ServicePort{Protocol: "TCP", TargetPort: tc.port})
|
||||
if err != nil && tc.pass {
|
||||
t.Errorf("unexpected error for %s: %v", tc.name, err)
|
||||
}
|
||||
if err == nil && !tc.pass {
|
||||
t.Errorf("unexpected non-error for %s: %d", tc.name, port)
|
||||
}
|
||||
if port != tc.expected {
|
||||
t.Errorf("wrong result for %s: expected %d, got %d", tc.name, tc.expected, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPodSecrets(t *testing.T) {
|
||||
// Stub containing all possible secret references in a pod.
|
||||
// The names of the referenced secrets match struct paths detected by reflection.
|
||||
pod := &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
EnvFrom: []v1.EnvFromSource{{
|
||||
SecretRef: &v1.SecretEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].EnvFrom[*].SecretRef"}}}},
|
||||
Env: []v1.EnvVar{{
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
SecretKeyRef: &v1.SecretKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].Env[*].ValueFrom.SecretKeyRef"}}}}}}},
|
||||
ImagePullSecrets: []v1.LocalObjectReference{{
|
||||
Name: "Spec.ImagePullSecrets"}},
|
||||
InitContainers: []v1.Container{{
|
||||
EnvFrom: []v1.EnvFromSource{{
|
||||
SecretRef: &v1.SecretEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].EnvFrom[*].SecretRef"}}}},
|
||||
Env: []v1.EnvVar{{
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
SecretKeyRef: &v1.SecretKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].Env[*].ValueFrom.SecretKeyRef"}}}}}}},
|
||||
Volumes: []v1.Volume{{
|
||||
VolumeSource: v1.VolumeSource{
|
||||
AzureFile: &v1.AzureFileVolumeSource{
|
||||
SecretName: "Spec.Volumes[*].VolumeSource.AzureFile.SecretName"}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
CephFS: &v1.CephFSVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.CephFS.SecretRef"}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Cinder: &v1.CinderVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.Cinder.SecretRef"}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
FlexVolume: &v1.FlexVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.FlexVolume.SecretRef"}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.Projected.Sources[*].Secret"}}}}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
RBD: &v1.RBDVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.RBD.SecretRef"}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: "Spec.Volumes[*].VolumeSource.Secret.SecretName"}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: "Spec.Volumes[*].VolumeSource.Secret"}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ScaleIO: &v1.ScaleIOVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef"}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ISCSI: &v1.ISCSIVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.ISCSI.SecretRef"}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
StorageOS: &v1.StorageOSVolumeSource{
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef"}}}}},
|
||||
},
|
||||
}
|
||||
extractedNames := sets.NewString()
|
||||
VisitPodSecretNames(pod, func(name string) bool {
|
||||
extractedNames.Insert(name)
|
||||
return true
|
||||
})
|
||||
|
||||
// excludedSecretPaths holds struct paths to fields with "secret" in the name that are not actually references to secret API objects
|
||||
excludedSecretPaths := sets.NewString(
|
||||
"Spec.Volumes[*].VolumeSource.CephFS.SecretFile",
|
||||
)
|
||||
// expectedSecretPaths holds struct paths to fields with "secret" in the name that are references to secret API objects.
|
||||
// every path here should be represented as an example in the Pod stub above, with the secret name set to the path.
|
||||
expectedSecretPaths := sets.NewString(
|
||||
"Spec.Containers[*].EnvFrom[*].SecretRef",
|
||||
"Spec.Containers[*].Env[*].ValueFrom.SecretKeyRef",
|
||||
"Spec.ImagePullSecrets",
|
||||
"Spec.InitContainers[*].EnvFrom[*].SecretRef",
|
||||
"Spec.InitContainers[*].Env[*].ValueFrom.SecretKeyRef",
|
||||
"Spec.Volumes[*].VolumeSource.AzureFile.SecretName",
|
||||
"Spec.Volumes[*].VolumeSource.CephFS.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.Cinder.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.FlexVolume.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.Projected.Sources[*].Secret",
|
||||
"Spec.Volumes[*].VolumeSource.RBD.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.Secret",
|
||||
"Spec.Volumes[*].VolumeSource.Secret.SecretName",
|
||||
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
|
||||
"Spec.Volumes[*].VolumeSource.StorageOS.SecretRef",
|
||||
)
|
||||
secretPaths := collectResourcePaths(t, "secret", nil, "", reflect.TypeOf(&v1.Pod{}))
|
||||
secretPaths = secretPaths.Difference(excludedSecretPaths)
|
||||
if missingPaths := expectedSecretPaths.Difference(secretPaths); len(missingPaths) > 0 {
|
||||
t.Logf("Missing expected secret paths:\n%s", strings.Join(missingPaths.List(), "\n"))
|
||||
t.Error("Missing expected secret paths. Verify VisitPodSecretNames() is correctly finding the missing paths, then correct expectedSecretPaths")
|
||||
}
|
||||
if extraPaths := secretPaths.Difference(expectedSecretPaths); len(extraPaths) > 0 {
|
||||
t.Logf("Extra secret paths:\n%s", strings.Join(extraPaths.List(), "\n"))
|
||||
t.Error("Extra fields with 'secret' in the name found. Verify VisitPodSecretNames() is including these fields if appropriate, then correct expectedSecretPaths")
|
||||
}
|
||||
|
||||
if missingNames := expectedSecretPaths.Difference(extractedNames); len(missingNames) > 0 {
|
||||
t.Logf("Missing expected secret names:\n%s", strings.Join(missingNames.List(), "\n"))
|
||||
t.Error("Missing expected secret names. Verify the pod stub above includes these references, then verify VisitPodSecretNames() is correctly finding the missing names")
|
||||
}
|
||||
if extraNames := extractedNames.Difference(expectedSecretPaths); len(extraNames) > 0 {
|
||||
t.Logf("Extra secret names:\n%s", strings.Join(extraNames.List(), "\n"))
|
||||
t.Error("Extra secret names extracted. Verify VisitPodSecretNames() is correctly extracting secret names")
|
||||
}
|
||||
}
|
||||
|
||||
// collectResourcePaths traverses the object, computing all the struct paths that lead to fields with resourcename in the name.
|
||||
func collectResourcePaths(t *testing.T, resourcename string, path *field.Path, name string, tp reflect.Type) sets.String {
|
||||
resourcename = strings.ToLower(resourcename)
|
||||
resourcePaths := sets.NewString()
|
||||
|
||||
if tp.Kind() == reflect.Ptr {
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...)
|
||||
return resourcePaths
|
||||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(name), resourcename) {
|
||||
resourcePaths.Insert(path.String())
|
||||
}
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Ptr:
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...)
|
||||
case reflect.Struct:
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
field := tp.Field(i)
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Child(field.Name), field.Name, field.Type).List()...)
|
||||
}
|
||||
case reflect.Interface:
|
||||
t.Errorf("cannot find %s fields in interface{} field %s", resourcename, path.String())
|
||||
case reflect.Map:
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...)
|
||||
case reflect.Slice:
|
||||
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...)
|
||||
default:
|
||||
// all primitive types
|
||||
}
|
||||
|
||||
return resourcePaths
|
||||
}
|
||||
|
||||
func TestPodConfigmaps(t *testing.T) {
|
||||
// Stub containing all possible ConfigMap references in a pod.
|
||||
// The names of the referenced ConfigMaps match struct paths detected by reflection.
|
||||
pod := &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
EnvFrom: []v1.EnvFromSource{{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].EnvFrom[*].ConfigMapRef"}}}},
|
||||
Env: []v1.EnvVar{{
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef"}}}}}}},
|
||||
InitContainers: []v1.Container{{
|
||||
EnvFrom: []v1.EnvFromSource{{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].EnvFrom[*].ConfigMapRef"}}}},
|
||||
Env: []v1.EnvVar{{
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef"}}}}}}},
|
||||
Volumes: []v1.Volume{{
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap"}}}}}}}, {
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "Spec.Volumes[*].VolumeSource.ConfigMap"}}}}},
|
||||
},
|
||||
}
|
||||
extractedNames := sets.NewString()
|
||||
VisitPodConfigmapNames(pod, func(name string) bool {
|
||||
extractedNames.Insert(name)
|
||||
return true
|
||||
})
|
||||
|
||||
// expectedPaths holds struct paths to fields with "ConfigMap" in the name that are references to ConfigMap API objects.
|
||||
// every path here should be represented as an example in the Pod stub above, with the ConfigMap name set to the path.
|
||||
expectedPaths := sets.NewString(
|
||||
"Spec.Containers[*].EnvFrom[*].ConfigMapRef",
|
||||
"Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef",
|
||||
"Spec.InitContainers[*].EnvFrom[*].ConfigMapRef",
|
||||
"Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef",
|
||||
"Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap",
|
||||
"Spec.Volumes[*].VolumeSource.ConfigMap",
|
||||
)
|
||||
collectPaths := collectResourcePaths(t, "ConfigMap", nil, "", reflect.TypeOf(&v1.Pod{}))
|
||||
if missingPaths := expectedPaths.Difference(collectPaths); len(missingPaths) > 0 {
|
||||
t.Logf("Missing expected paths:\n%s", strings.Join(missingPaths.List(), "\n"))
|
||||
t.Error("Missing expected paths. Verify VisitPodConfigmapNames() is correctly finding the missing paths, then correct expectedPaths")
|
||||
}
|
||||
if extraPaths := collectPaths.Difference(expectedPaths); len(extraPaths) > 0 {
|
||||
t.Logf("Extra paths:\n%s", strings.Join(extraPaths.List(), "\n"))
|
||||
t.Error("Extra fields with resource in the name found. Verify VisitPodConfigmapNames() is including these fields if appropriate, then correct expectedPaths")
|
||||
}
|
||||
|
||||
if missingNames := expectedPaths.Difference(extractedNames); len(missingNames) > 0 {
|
||||
t.Logf("Missing expected names:\n%s", strings.Join(missingNames.List(), "\n"))
|
||||
t.Error("Missing expected names. Verify the pod stub above includes these references, then verify VisitPodConfigmapNames() is correctly finding the missing names")
|
||||
}
|
||||
if extraNames := extractedNames.Difference(expectedPaths); len(extraNames) > 0 {
|
||||
t.Logf("Extra names:\n%s", strings.Join(extraNames.List(), "\n"))
|
||||
t.Error("Extra names extracted. Verify VisitPodConfigmapNames() is correctly extracting resource names")
|
||||
}
|
||||
}
|
||||
|
||||
func newPod(now metav1.Time, ready bool, beforeSec int) *v1.Pod {
|
||||
conditionStatus := v1.ConditionFalse
|
||||
if ready {
|
||||
conditionStatus = v1.ConditionTrue
|
||||
}
|
||||
return &v1.Pod{
|
||||
Status: v1.PodStatus{
|
||||
Conditions: []v1.PodCondition{
|
||||
{
|
||||
Type: v1.PodReady,
|
||||
LastTransitionTime: metav1.NewTime(now.Time.Add(-1 * time.Duration(beforeSec) * time.Second)),
|
||||
Status: conditionStatus,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPodAvailable(t *testing.T) {
|
||||
now := metav1.Now()
|
||||
tests := []struct {
|
||||
pod *v1.Pod
|
||||
minReadySeconds int32
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
pod: newPod(now, false, 0),
|
||||
minReadySeconds: 0,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
pod: newPod(now, true, 0),
|
||||
minReadySeconds: 1,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
pod: newPod(now, true, 0),
|
||||
minReadySeconds: 0,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pod: newPod(now, true, 51),
|
||||
minReadySeconds: 50,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
isAvailable := IsPodAvailable(test.pod, test.minReadySeconds, now)
|
||||
if isAvailable != test.expected {
|
||||
t.Errorf("[tc #%d] expected available pod: %t, got: %t", i, test.expected, isAvailable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetContainerStatus(t *testing.T) {
|
||||
type ExpectedStruct struct {
|
||||
status v1.ContainerStatus
|
||||
exists bool
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
status []v1.ContainerStatus
|
||||
name string
|
||||
expected ExpectedStruct
|
||||
desc string
|
||||
}{
|
||||
{
|
||||
status: []v1.ContainerStatus{{Name: "test1", Ready: false, Image: "image1"}, {Name: "test2", Ready: true, Image: "image1"}},
|
||||
name: "test1",
|
||||
expected: ExpectedStruct{status: v1.ContainerStatus{Name: "test1", Ready: false, Image: "image1"}, exists: true},
|
||||
desc: "retrieve ContainerStatus with Name=\"test1\"",
|
||||
},
|
||||
{
|
||||
status: []v1.ContainerStatus{{Name: "test2", Ready: false, Image: "image2"}},
|
||||
name: "test1",
|
||||
expected: ExpectedStruct{status: v1.ContainerStatus{}, exists: false},
|
||||
desc: "no matching ContainerStatus with Name=\"test1\"",
|
||||
},
|
||||
{
|
||||
status: []v1.ContainerStatus{{Name: "test3", Ready: false, Image: "image3"}},
|
||||
name: "",
|
||||
expected: ExpectedStruct{status: v1.ContainerStatus{}, exists: false},
|
||||
desc: "retrieve an empty ContainerStatus with container name empty",
|
||||
},
|
||||
{
|
||||
status: nil,
|
||||
name: "",
|
||||
expected: ExpectedStruct{status: v1.ContainerStatus{}, exists: false},
|
||||
desc: "retrieve an empty ContainerStatus with status nil",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
resultStatus, exists := GetContainerStatus(test.status, test.name)
|
||||
assert.Equal(t, test.expected.status, resultStatus, "GetContainerStatus: "+test.desc)
|
||||
assert.Equal(t, test.expected.exists, exists, "GetContainerStatus: "+test.desc)
|
||||
|
||||
resultStatus = GetExistingContainerStatus(test.status, test.name)
|
||||
assert.Equal(t, test.expected.status, resultStatus, "GetExistingContainerStatus: "+test.desc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdatePodCondition(t *testing.T) {
|
||||
time := metav1.Now()
|
||||
|
||||
podStatus := v1.PodStatus{
|
||||
Conditions: []v1.PodCondition{
|
||||
{
|
||||
Type: v1.PodReady,
|
||||
Status: v1.ConditionTrue,
|
||||
Reason: "successfully",
|
||||
Message: "sync pod successfully",
|
||||
LastProbeTime: time,
|
||||
LastTransitionTime: metav1.NewTime(time.Add(1000)),
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
status *v1.PodStatus
|
||||
conditions v1.PodCondition
|
||||
expected bool
|
||||
desc string
|
||||
}{
|
||||
{
|
||||
status: &podStatus,
|
||||
conditions: v1.PodCondition{
|
||||
Type: v1.PodReady,
|
||||
Status: v1.ConditionTrue,
|
||||
Reason: "successfully",
|
||||
Message: "sync pod successfully",
|
||||
LastProbeTime: time,
|
||||
LastTransitionTime: metav1.NewTime(time.Add(1000))},
|
||||
expected: false,
|
||||
desc: "all equal, no update",
|
||||
},
|
||||
{
|
||||
status: &podStatus,
|
||||
conditions: v1.PodCondition{
|
||||
Type: v1.PodScheduled,
|
||||
Status: v1.ConditionTrue,
|
||||
Reason: "successfully",
|
||||
Message: "sync pod successfully",
|
||||
LastProbeTime: time,
|
||||
LastTransitionTime: metav1.NewTime(time.Add(1000))},
|
||||
expected: true,
|
||||
desc: "not equal Type, should get updated",
|
||||
},
|
||||
{
|
||||
status: &podStatus,
|
||||
conditions: v1.PodCondition{
|
||||
Type: v1.PodReady,
|
||||
Status: v1.ConditionFalse,
|
||||
Reason: "successfully",
|
||||
Message: "sync pod successfully",
|
||||
LastProbeTime: time,
|
||||
LastTransitionTime: metav1.NewTime(time.Add(1000))},
|
||||
expected: true,
|
||||
desc: "not equal Status, should get updated",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
var resultStatus bool
|
||||
resultStatus = UpdatePodCondition(test.status, &test.conditions)
|
||||
|
||||
assert.Equal(t, test.expected, resultStatus, test.desc)
|
||||
}
|
||||
}
|
41
vendor/k8s.io/kubernetes/pkg/api/v1/resource/BUILD
generated
vendored
41
vendor/k8s.io/kubernetes/pkg/api/v1/resource/BUILD
generated
vendored
@ -1,41 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["helpers_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",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["helpers.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/resource",
|
||||
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"],
|
||||
tags = ["automanaged"],
|
||||
)
|
197
vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers.go
generated
vendored
197
vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers.go
generated
vendored
@ -1,197 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
// addResourceList adds the resources in newList to list
|
||||
func addResourceList(list, new v1.ResourceList) {
|
||||
for name, quantity := range new {
|
||||
if value, ok := list[name]; !ok {
|
||||
list[name] = *quantity.Copy()
|
||||
} else {
|
||||
value.Add(quantity)
|
||||
list[name] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maxResourceList sets list to the greater of list/newList for every resource
|
||||
// either list
|
||||
func maxResourceList(list, new v1.ResourceList) {
|
||||
for name, quantity := range new {
|
||||
if value, ok := list[name]; !ok {
|
||||
list[name] = *quantity.Copy()
|
||||
continue
|
||||
} else {
|
||||
if quantity.Cmp(value) > 0 {
|
||||
list[name] = *quantity.Copy()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
|
||||
// containers of the pod.
|
||||
func PodRequestsAndLimits(pod *v1.Pod) (reqs, limits v1.ResourceList) {
|
||||
reqs, limits = v1.ResourceList{}, v1.ResourceList{}
|
||||
for _, container := range pod.Spec.Containers {
|
||||
addResourceList(reqs, container.Resources.Requests)
|
||||
addResourceList(limits, container.Resources.Limits)
|
||||
}
|
||||
// init containers define the minimum of any resource
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
maxResourceList(reqs, container.Resources.Requests)
|
||||
maxResourceList(limits, container.Resources.Limits)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetResourceRequest finds and returns the request for a specific resource.
|
||||
func GetResourceRequest(pod *v1.Pod, resource v1.ResourceName) int64 {
|
||||
if resource == v1.ResourcePods {
|
||||
return 1
|
||||
}
|
||||
totalResources := int64(0)
|
||||
for _, container := range pod.Spec.Containers {
|
||||
if rQuantity, ok := container.Resources.Requests[resource]; ok {
|
||||
if resource == v1.ResourceCPU {
|
||||
totalResources += rQuantity.MilliValue()
|
||||
} else {
|
||||
totalResources += rQuantity.Value()
|
||||
}
|
||||
}
|
||||
}
|
||||
// take max_resource(sum_pod, any_init_container)
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
if rQuantity, ok := container.Resources.Requests[resource]; ok {
|
||||
if resource == v1.ResourceCPU && rQuantity.MilliValue() > totalResources {
|
||||
totalResources = rQuantity.MilliValue()
|
||||
} else if rQuantity.Value() > totalResources {
|
||||
totalResources = rQuantity.Value()
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalResources
|
||||
}
|
||||
|
||||
// ExtractResourceValueByContainerName extracts the value of a resource
|
||||
// by providing container name
|
||||
func ExtractResourceValueByContainerName(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string) (string, error) {
|
||||
container, err := findContainerInPod(pod, containerName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ExtractContainerResourceValue(fs, container)
|
||||
}
|
||||
|
||||
// ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource
|
||||
// by providing container name and node allocatable
|
||||
func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string, nodeAllocatable v1.ResourceList) (string, error) {
|
||||
realContainer, err := findContainerInPod(pod, containerName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
container := realContainer.DeepCopy()
|
||||
|
||||
MergeContainerResourceLimits(container, nodeAllocatable)
|
||||
|
||||
return ExtractContainerResourceValue(fs, container)
|
||||
}
|
||||
|
||||
// ExtractContainerResourceValue extracts the value of a resource
|
||||
// in an already known container
|
||||
func ExtractContainerResourceValue(fs *v1.ResourceFieldSelector, container *v1.Container) (string, error) {
|
||||
divisor := resource.Quantity{}
|
||||
if divisor.Cmp(fs.Divisor) == 0 {
|
||||
divisor = resource.MustParse("1")
|
||||
} else {
|
||||
divisor = fs.Divisor
|
||||
}
|
||||
|
||||
switch fs.Resource {
|
||||
case "limits.cpu":
|
||||
return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor)
|
||||
case "limits.memory":
|
||||
return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor)
|
||||
case "limits.ephemeral-storage":
|
||||
return convertResourceEphemeralStorageToString(container.Resources.Limits.StorageEphemeral(), divisor)
|
||||
case "requests.cpu":
|
||||
return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor)
|
||||
case "requests.memory":
|
||||
return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor)
|
||||
case "requests.ephemeral-storage":
|
||||
return convertResourceEphemeralStorageToString(container.Resources.Requests.StorageEphemeral(), divisor)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource)
|
||||
}
|
||||
|
||||
// convertResourceCPUToString converts cpu value to the format of divisor and returns
|
||||
// ceiling of the value.
|
||||
func convertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) {
|
||||
c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue())))
|
||||
return strconv.FormatInt(c, 10), nil
|
||||
}
|
||||
|
||||
// convertResourceMemoryToString converts memory value to the format of divisor and returns
|
||||
// ceiling of the value.
|
||||
func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) {
|
||||
m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value())))
|
||||
return strconv.FormatInt(m, 10), nil
|
||||
}
|
||||
|
||||
// convertResourceEphemeralStorageToString converts ephemeral storage value to the format of divisor and returns
|
||||
// ceiling of the value.
|
||||
func convertResourceEphemeralStorageToString(ephemeralStorage *resource.Quantity, divisor resource.Quantity) (string, error) {
|
||||
m := int64(math.Ceil(float64(ephemeralStorage.Value()) / float64(divisor.Value())))
|
||||
return strconv.FormatInt(m, 10), nil
|
||||
}
|
||||
|
||||
// findContainerInPod finds a container by its name in the provided pod
|
||||
func findContainerInPod(pod *v1.Pod, containerName string) (*v1.Container, error) {
|
||||
for _, container := range pod.Spec.Containers {
|
||||
if container.Name == containerName {
|
||||
return &container, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("container %s not found", containerName)
|
||||
}
|
||||
|
||||
// MergeContainerResourceLimits checks if a limit is applied for
|
||||
// the container, and if not, it sets the limit to the passed resource list.
|
||||
func MergeContainerResourceLimits(container *v1.Container,
|
||||
allocatable v1.ResourceList) {
|
||||
if container.Resources.Limits == nil {
|
||||
container.Resources.Limits = make(v1.ResourceList)
|
||||
}
|
||||
for _, resource := range []v1.ResourceName{v1.ResourceCPU, v1.ResourceMemory, v1.ResourceEphemeralStorage} {
|
||||
if quantity, exists := container.Resources.Limits[resource]; !exists || quantity.IsZero() {
|
||||
if cap, exists := allocatable[resource]; exists {
|
||||
container.Resources.Limits[resource] = *cap.Copy()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
180
vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers_test.go
generated
vendored
180
vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers_test.go
generated
vendored
@ -1,180 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
func TestResourceHelpers(t *testing.T) {
|
||||
cpuLimit := resource.MustParse("10")
|
||||
memoryLimit := resource.MustParse("10G")
|
||||
resourceSpec := v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: cpuLimit,
|
||||
v1.ResourceMemory: memoryLimit,
|
||||
},
|
||||
}
|
||||
if res := resourceSpec.Limits.Cpu(); res.Cmp(cpuLimit) != 0 {
|
||||
t.Errorf("expected cpulimit %v, got %v", cpuLimit, res)
|
||||
}
|
||||
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
|
||||
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
|
||||
}
|
||||
resourceSpec = v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceMemory: memoryLimit,
|
||||
},
|
||||
}
|
||||
if res := resourceSpec.Limits.Cpu(); res.Value() != 0 {
|
||||
t.Errorf("expected cpulimit %v, got %v", 0, res)
|
||||
}
|
||||
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
|
||||
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultResourceHelpers(t *testing.T) {
|
||||
resourceList := v1.ResourceList{}
|
||||
if resourceList.Cpu().Format != resource.DecimalSI {
|
||||
t.Errorf("expected %v, actual %v", resource.DecimalSI, resourceList.Cpu().Format)
|
||||
}
|
||||
if resourceList.Memory().Format != resource.BinarySI {
|
||||
t.Errorf("expected %v, actual %v", resource.BinarySI, resourceList.Memory().Format)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractResourceValue(t *testing.T) {
|
||||
cases := []struct {
|
||||
fs *v1.ResourceFieldSelector
|
||||
pod *v1.Pod
|
||||
cName string
|
||||
expectedValue string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "limits.cpu",
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "", "9", "", ""),
|
||||
expectedValue: "9",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "requests.cpu",
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "", "", "", ""),
|
||||
expectedValue: "0",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "requests.cpu",
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "8", "", "", ""),
|
||||
expectedValue: "8",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "requests.cpu",
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "100m", "", "", ""),
|
||||
expectedValue: "1",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "requests.cpu",
|
||||
Divisor: resource.MustParse("100m"),
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "1200m", "", "", ""),
|
||||
expectedValue: "12",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "requests.memory",
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "", "", "100Mi", ""),
|
||||
expectedValue: "104857600",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "requests.memory",
|
||||
Divisor: resource.MustParse("1Mi"),
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "", "", "100Mi", "1Gi"),
|
||||
expectedValue: "100",
|
||||
},
|
||||
{
|
||||
fs: &v1.ResourceFieldSelector{
|
||||
Resource: "limits.memory",
|
||||
},
|
||||
cName: "foo",
|
||||
pod: getPod("foo", "", "", "10Mi", "100Mi"),
|
||||
expectedValue: "104857600",
|
||||
},
|
||||
}
|
||||
as := assert.New(t)
|
||||
for idx, tc := range cases {
|
||||
actual, err := ExtractResourceValueByContainerName(tc.fs, tc.pod, tc.cName)
|
||||
if tc.expectedError != nil {
|
||||
as.Equal(tc.expectedError, err, "expected test case [%d] to fail with error %v; got %v", idx, tc.expectedError, err)
|
||||
} else {
|
||||
as.Nil(err, "expected test case [%d] to not return an error; got %v", idx, err)
|
||||
as.Equal(tc.expectedValue, actual, "expected test case [%d] to return %q; got %q instead", idx, tc.expectedValue, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *v1.Pod {
|
||||
resources := v1.ResourceRequirements{
|
||||
Limits: make(v1.ResourceList),
|
||||
Requests: make(v1.ResourceList),
|
||||
}
|
||||
if cpuLimit != "" {
|
||||
resources.Limits[v1.ResourceCPU] = resource.MustParse(cpuLimit)
|
||||
}
|
||||
if memoryLimit != "" {
|
||||
resources.Limits[v1.ResourceMemory] = resource.MustParse(memoryLimit)
|
||||
}
|
||||
if cpuRequest != "" {
|
||||
resources.Requests[v1.ResourceCPU] = resource.MustParse(cpuRequest)
|
||||
}
|
||||
if memoryRequest != "" {
|
||||
resources.Requests[v1.ResourceMemory] = resource.MustParse(memoryRequest)
|
||||
}
|
||||
return &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: cname,
|
||||
Resources: resources,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
40
vendor/k8s.io/kubernetes/pkg/api/v1/service/BUILD
generated
vendored
40
vendor/k8s.io/kubernetes/pkg/api/v1/service/BUILD
generated
vendored
@ -1,40 +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 = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/service",
|
||||
deps = [
|
||||
"//pkg/util/net/sets:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["util_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/util/net/sets:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
97
vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go
generated
vendored
97
vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go
generated
vendored
@ -1,97 +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 service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLoadBalancerSourceRanges = "0.0.0.0/0"
|
||||
)
|
||||
|
||||
// IsAllowAll checks whether the netsets.IPNet allows traffic from 0.0.0.0/0
|
||||
func IsAllowAll(ipnets netsets.IPNet) bool {
|
||||
for _, s := range ipnets.StringSlice() {
|
||||
if s == "0.0.0.0/0" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service.
|
||||
// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service,
|
||||
// extracting the source ranges to allow, and if not present returns a default (allow-all) value.
|
||||
func GetLoadBalancerSourceRanges(service *v1.Service) (netsets.IPNet, error) {
|
||||
var ipnets netsets.IPNet
|
||||
var err error
|
||||
// if SourceRange field is specified, ignore sourceRange annotation
|
||||
if len(service.Spec.LoadBalancerSourceRanges) > 0 {
|
||||
specs := service.Spec.LoadBalancerSourceRanges
|
||||
ipnets, err = netsets.ParseIPNets(specs...)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err)
|
||||
}
|
||||
} else {
|
||||
val := service.Annotations[v1.AnnotationLoadBalancerSourceRangesKey]
|
||||
val = strings.TrimSpace(val)
|
||||
if val == "" {
|
||||
val = defaultLoadBalancerSourceRanges
|
||||
}
|
||||
specs := strings.Split(val, ",")
|
||||
ipnets, err = netsets.ParseIPNets(specs...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", v1.AnnotationLoadBalancerSourceRangesKey, val)
|
||||
}
|
||||
}
|
||||
return ipnets, nil
|
||||
}
|
||||
|
||||
// RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic.
|
||||
func RequestsOnlyLocalTraffic(service *v1.Service) bool {
|
||||
if service.Spec.Type != v1.ServiceTypeLoadBalancer &&
|
||||
service.Spec.Type != v1.ServiceTypeNodePort {
|
||||
return false
|
||||
}
|
||||
return service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal
|
||||
}
|
||||
|
||||
// NeedsHealthCheck checks if service needs health check.
|
||||
func NeedsHealthCheck(service *v1.Service) bool {
|
||||
if service.Spec.Type != v1.ServiceTypeLoadBalancer {
|
||||
return false
|
||||
}
|
||||
return RequestsOnlyLocalTraffic(service)
|
||||
}
|
||||
|
||||
// GetServiceHealthCheckPathPort returns the path and nodePort programmed into the Cloud LB Health Check
|
||||
func GetServiceHealthCheckPathPort(service *v1.Service) (string, int32) {
|
||||
if !NeedsHealthCheck(service) {
|
||||
return "", 0
|
||||
}
|
||||
port := service.Spec.HealthCheckNodePort
|
||||
if port == 0 {
|
||||
return "", 0
|
||||
}
|
||||
return "/healthz", port
|
||||
}
|
216
vendor/k8s.io/kubernetes/pkg/api/v1/service/util_test.go
generated
vendored
216
vendor/k8s.io/kubernetes/pkg/api/v1/service/util_test.go
generated
vendored
@ -1,216 +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 service
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||
)
|
||||
|
||||
func TestGetLoadBalancerSourceRanges(t *testing.T) {
|
||||
checkError := func(v string) {
|
||||
annotations := make(map[string]string)
|
||||
annotations[v1.AnnotationLoadBalancerSourceRangesKey] = v
|
||||
svc := v1.Service{}
|
||||
svc.Annotations = annotations
|
||||
_, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error parsing: %q", v)
|
||||
}
|
||||
svc = v1.Service{}
|
||||
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
|
||||
_, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error parsing: %q", v)
|
||||
}
|
||||
}
|
||||
checkError("10.0.0.1/33")
|
||||
checkError("foo.bar")
|
||||
checkError("10.0.0.1/32,*")
|
||||
checkError("10.0.0.1/32,")
|
||||
checkError("10.0.0.1/32, ")
|
||||
checkError("10.0.0.1")
|
||||
|
||||
checkOK := func(v string) netsets.IPNet {
|
||||
annotations := make(map[string]string)
|
||||
annotations[v1.AnnotationLoadBalancerSourceRangesKey] = v
|
||||
svc := v1.Service{}
|
||||
svc.Annotations = annotations
|
||||
cidrs, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing: %q", v)
|
||||
}
|
||||
svc = v1.Service{}
|
||||
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
|
||||
cidrs, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing: %q", v)
|
||||
}
|
||||
return cidrs
|
||||
}
|
||||
cidrs := checkOK("192.168.0.1/32")
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK("192.168.0.1/32,192.168.0.1/32")
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR (after de-dup): %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK("192.168.0.1/32,192.168.0.2/32")
|
||||
if len(cidrs) != 2 {
|
||||
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK(" 192.168.0.1/32 , 192.168.0.2/32 ")
|
||||
if len(cidrs) != 2 {
|
||||
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
|
||||
}
|
||||
// check LoadBalancerSourceRanges not specified
|
||||
svc := v1.Service{}
|
||||
cidrs, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
if !IsAllowAll(cidrs) {
|
||||
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
|
||||
}
|
||||
// check SourceRanges annotation is empty
|
||||
annotations := make(map[string]string)
|
||||
annotations[v1.AnnotationLoadBalancerSourceRangesKey] = ""
|
||||
svc = v1.Service{}
|
||||
svc.Annotations = annotations
|
||||
cidrs, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
if !IsAllowAll(cidrs) {
|
||||
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowAll(t *testing.T) {
|
||||
checkAllowAll := func(allowAll bool, cidrs ...string) {
|
||||
ipnets, err := netsets.ParseIPNets(cidrs...)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing cidrs: %v", cidrs)
|
||||
}
|
||||
if allowAll != IsAllowAll(ipnets) {
|
||||
t.Errorf("IsAllowAll did not return expected value for %v", cidrs)
|
||||
}
|
||||
}
|
||||
checkAllowAll(false, "10.0.0.1/32")
|
||||
checkAllowAll(false, "10.0.0.1/32", "10.0.0.2/32")
|
||||
checkAllowAll(false, "10.0.0.1/32", "10.0.0.1/32")
|
||||
|
||||
checkAllowAll(true, "0.0.0.0/0")
|
||||
checkAllowAll(true, "192.168.0.0/0")
|
||||
checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0")
|
||||
}
|
||||
|
||||
func TestRequestsOnlyLocalTraffic(t *testing.T) {
|
||||
checkRequestsOnlyLocalTraffic := func(requestsOnlyLocalTraffic bool, service *v1.Service) {
|
||||
res := RequestsOnlyLocalTraffic(service)
|
||||
if res != requestsOnlyLocalTraffic {
|
||||
t.Errorf("Expected requests OnlyLocal traffic = %v, got %v",
|
||||
requestsOnlyLocalTraffic, res)
|
||||
}
|
||||
}
|
||||
|
||||
checkRequestsOnlyLocalTraffic(false, &v1.Service{})
|
||||
checkRequestsOnlyLocalTraffic(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeNodePort,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(true, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkRequestsOnlyLocalTraffic(true, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestNeedsHealthCheck(t *testing.T) {
|
||||
checkNeedsHealthCheck := func(needsHealthCheck bool, service *v1.Service) {
|
||||
res := NeedsHealthCheck(service)
|
||||
if res != needsHealthCheck {
|
||||
t.Errorf("Expected needs health check = %v, got %v",
|
||||
needsHealthCheck, res)
|
||||
}
|
||||
}
|
||||
|
||||
checkNeedsHealthCheck(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeNodePort,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(false, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
|
||||
},
|
||||
})
|
||||
checkNeedsHealthCheck(true, &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeLoadBalancer,
|
||||
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
|
||||
},
|
||||
})
|
||||
}
|
55
vendor/k8s.io/kubernetes/pkg/apis/OWNERS
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/apis/OWNERS
generated
vendored
@ -1,55 +0,0 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
filters:
|
||||
".*":
|
||||
approvers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- thockin
|
||||
- liggitt
|
||||
# - bgrant0607 # manual escalations only
|
||||
reviewers:
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- yujuhong
|
||||
- brendandburns
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- vishh
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- erictune
|
||||
- pmorie
|
||||
- sttts
|
||||
- dchen1107
|
||||
- saad-ali
|
||||
- luxas
|
||||
- janetkuo
|
||||
- justinsb
|
||||
- pwittrock
|
||||
- ncdc
|
||||
- tallclair
|
||||
- yifan-gu
|
||||
- eparis
|
||||
- mwielgus
|
||||
- feiskyer
|
||||
- soltysh
|
||||
- piosz
|
||||
- dims
|
||||
- errordeveloper
|
||||
- madhusudancs
|
||||
- krousey
|
||||
- rootfs
|
||||
- jszczepkowski
|
||||
|
||||
# examples:
|
||||
# pkg/apis/*/types.go
|
||||
# pkg/apis/*/*/types.go
|
||||
"[^/]+/([^/]+/)?(register|types)\\.go$":
|
||||
labels:
|
||||
- kind/api-change
|
42
vendor/k8s.io/kubernetes/pkg/apis/abac/BUILD
generated
vendored
42
vendor/k8s.io/kubernetes/pkg/apis/abac/BUILD
generated
vendored
@ -1,42 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/apis/abac",
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1: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/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/apis/abac/fuzzer:all-srcs",
|
||||
"//pkg/apis/abac/latest:all-srcs",
|
||||
"//pkg/apis/abac/v0:all-srcs",
|
||||
"//pkg/apis/abac/v1beta1:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
7
vendor/k8s.io/kubernetes/pkg/apis/abac/OWNERS
generated
vendored
7
vendor/k8s.io/kubernetes/pkg/apis/abac/OWNERS
generated
vendored
@ -1,7 +0,0 @@
|
||||
reviewers:
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- deads2k
|
||||
- liggitt
|
||||
- mbohlool
|
||||
- david-mcmahon
|
19
vendor/k8s.io/kubernetes/pkg/apis/abac/doc.go
generated
vendored
19
vendor/k8s.io/kubernetes/pkg/apis/abac/doc.go
generated
vendored
@ -1,19 +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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package abac
|
26
vendor/k8s.io/kubernetes/pkg/apis/abac/fuzzer/BUILD
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/apis/abac/fuzzer/BUILD
generated
vendored
@ -1,26 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fuzzer.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/apis/abac/fuzzer",
|
||||
deps = ["//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
26
vendor/k8s.io/kubernetes/pkg/apis/abac/fuzzer/fuzzer.go
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/apis/abac/fuzzer/fuzzer.go
generated
vendored
@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fuzzer
|
||||
|
||||
import (
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// Funcs returns the fuzzer functions for the abac api group.
|
||||
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{}
|
||||
}
|
30
vendor/k8s.io/kubernetes/pkg/apis/abac/latest/BUILD
generated
vendored
30
vendor/k8s.io/kubernetes/pkg/apis/abac/latest/BUILD
generated
vendored
@ -1,30 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["latest.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/apis/abac/latest",
|
||||
deps = [
|
||||
"//pkg/apis/abac:go_default_library",
|
||||
"//pkg/apis/abac/v0:go_default_library",
|
||||
"//pkg/apis/abac/v1beta1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
26
vendor/k8s.io/kubernetes/pkg/apis/abac/latest/latest.go
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/apis/abac/latest/latest.go
generated
vendored
@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 latest
|
||||
|
||||
import (
|
||||
_ "k8s.io/kubernetes/pkg/apis/abac"
|
||||
_ "k8s.io/kubernetes/pkg/apis/abac/v0"
|
||||
_ "k8s.io/kubernetes/pkg/apis/abac/v1beta1"
|
||||
)
|
||||
|
||||
// TODO: this file is totally wrong, it should look like other latest files.
|
||||
// lavalamp is in the middle of fixing this code, so wait for the new way of doing things..
|
55
vendor/k8s.io/kubernetes/pkg/apis/abac/register.go
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/apis/abac/register.go
generated
vendored
@ -1,55 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package abac
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// GroupName is the API group for abac
|
||||
const GroupName = "abac.authorization.kubernetes.io"
|
||||
|
||||
// SchemeGroupVersion is the API group version used to register abac internal
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// Scheme is the default instance of runtime.Scheme to which types in the abac API group are api.Registry.
|
||||
// TODO: remove this, abac should not have its own scheme.
|
||||
var Scheme = runtime.NewScheme()
|
||||
|
||||
// Codecs provides access to encoding and decoding for the scheme
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
|
||||
func init() {
|
||||
// TODO: delete this, abac should not have its own scheme.
|
||||
addKnownTypes(Scheme)
|
||||
}
|
||||
|
||||
var (
|
||||
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
// AddToScheme is a common registration function for mapping packaged scoped group & version keys to a scheme
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Policy{},
|
||||
)
|
||||
return nil
|
||||
}
|
74
vendor/k8s.io/kubernetes/pkg/apis/abac/types.go
generated
vendored
74
vendor/k8s.io/kubernetes/pkg/apis/abac/types.go
generated
vendored
@ -1,74 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package abac
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Policy contains a single ABAC policy rule
|
||||
type Policy struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// Spec describes the policy rule
|
||||
Spec PolicySpec
|
||||
}
|
||||
|
||||
// PolicySpec contains the attributes for a policy rule
|
||||
type PolicySpec struct {
|
||||
|
||||
// User is the username this rule applies to.
|
||||
// Either user or group is required to match the request.
|
||||
// "*" matches all users.
|
||||
User string
|
||||
|
||||
// Group is the group this rule applies to.
|
||||
// Either user or group is required to match the request.
|
||||
// "*" matches all groups.
|
||||
Group string
|
||||
|
||||
// Readonly matches readonly requests when true, and all requests when false
|
||||
Readonly bool
|
||||
|
||||
// APIGroup is the name of an API group. APIGroup, Resource, and Namespace are required to match resource requests.
|
||||
// "*" matches all API groups
|
||||
APIGroup string
|
||||
|
||||
// Resource is the name of a resource. APIGroup, Resource, and Namespace are required to match resource requests.
|
||||
// "*" matches all resources
|
||||
Resource string
|
||||
|
||||
// Namespace is the name of a namespace. APIGroup, Resource, and Namespace are required to match resource requests.
|
||||
// "*" matches all namespaces (including unnamespaced requests)
|
||||
Namespace string
|
||||
|
||||
// NonResourcePath matches non-resource request paths.
|
||||
// "*" matches all paths
|
||||
// "/foo/*" matches all subpaths of foo
|
||||
NonResourcePath string
|
||||
|
||||
// TODO: "expires" string in RFC3339 format.
|
||||
|
||||
// TODO: want a way to allow some users to restart containers of a pod but
|
||||
// not delete or modify it.
|
||||
|
||||
// TODO: want a way to allow a controller to create a pod based only on a
|
||||
// certain podTemplates.
|
||||
|
||||
}
|
49
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/BUILD
generated
vendored
49
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/BUILD
generated
vendored
@ -1,49 +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 = [
|
||||
"conversion.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/apis/abac/v0",
|
||||
deps = [
|
||||
"//pkg/apis/abac:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["conversion_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/abac:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
68
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/conversion.go
generated
vendored
68
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/conversion.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v0
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
api "k8s.io/kubernetes/pkg/apis/abac"
|
||||
)
|
||||
|
||||
// allAuthenticated matches k8s.io/apiserver/pkg/authentication/user.AllAuthenticated,
|
||||
// but we don't want an client library (which must include types), depending on a server library
|
||||
const allAuthenticated = "system:authenticated"
|
||||
|
||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
return scheme.AddConversionFuncs(
|
||||
func(in *Policy, out *api.Policy, s conversion.Scope) error {
|
||||
// Begin by copying all fields
|
||||
out.Spec.User = in.User
|
||||
out.Spec.Group = in.Group
|
||||
out.Spec.Namespace = in.Namespace
|
||||
out.Spec.Resource = in.Resource
|
||||
out.Spec.Readonly = in.Readonly
|
||||
|
||||
// In v0, unspecified user and group matches all authenticated subjects
|
||||
if len(in.User) == 0 && len(in.Group) == 0 {
|
||||
out.Spec.Group = allAuthenticated
|
||||
}
|
||||
// In v0, user or group of * matches all authenticated subjects
|
||||
if in.User == "*" || in.Group == "*" {
|
||||
out.Spec.Group = allAuthenticated
|
||||
out.Spec.User = ""
|
||||
}
|
||||
|
||||
// In v0, leaving namespace empty matches all namespaces
|
||||
if len(in.Namespace) == 0 {
|
||||
out.Spec.Namespace = "*"
|
||||
}
|
||||
// In v0, leaving resource empty matches all resources
|
||||
if len(in.Resource) == 0 {
|
||||
out.Spec.Resource = "*"
|
||||
}
|
||||
// Any rule in v0 should match all API groups
|
||||
out.Spec.APIGroup = "*"
|
||||
|
||||
// In v0, leaving namespace and resource blank allows non-resource paths
|
||||
if len(in.Namespace) == 0 && len(in.Resource) == 0 {
|
||||
out.Spec.NonResourcePath = "*"
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
88
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/conversion_test.go
generated
vendored
88
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/conversion_test.go
generated
vendored
@ -1,88 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v0_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/kubernetes/pkg/apis/abac"
|
||||
"k8s.io/kubernetes/pkg/apis/abac/v0"
|
||||
)
|
||||
|
||||
func TestV0Conversion(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
old *v0.Policy
|
||||
expected *abac.Policy
|
||||
}{
|
||||
// a completely empty policy rule allows everything to all users
|
||||
"empty": {
|
||||
old: &v0.Policy{},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}},
|
||||
},
|
||||
|
||||
// specifying a user is preserved
|
||||
"user": {
|
||||
old: &v0.Policy{User: "bob"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{User: "bob", Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}},
|
||||
},
|
||||
|
||||
// specifying a group is preserved (and no longer matches all users)
|
||||
"group": {
|
||||
old: &v0.Policy{Group: "mygroup"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: "mygroup", Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}},
|
||||
},
|
||||
|
||||
// specifying * for user or group maps to all authenticated subjects
|
||||
"* user": {
|
||||
old: &v0.Policy{User: "*"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}},
|
||||
},
|
||||
"* group": {
|
||||
old: &v0.Policy{Group: "*"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}},
|
||||
},
|
||||
|
||||
// specifying a namespace removes the * match on non-resource path
|
||||
"namespace": {
|
||||
old: &v0.Policy{Namespace: "myns"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "", Namespace: "myns", Resource: "*", APIGroup: "*"}},
|
||||
},
|
||||
|
||||
// specifying a resource removes the * match on non-resource path
|
||||
"resource": {
|
||||
old: &v0.Policy{Resource: "myresource"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "", Namespace: "*", Resource: "myresource", APIGroup: "*"}},
|
||||
},
|
||||
|
||||
// specifying a namespace+resource removes the * match on non-resource path
|
||||
"namespace+resource": {
|
||||
old: &v0.Policy{Namespace: "myns", Resource: "myresource"},
|
||||
expected: &abac.Policy{Spec: abac.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "", Namespace: "myns", Resource: "myresource", APIGroup: "*"}},
|
||||
},
|
||||
}
|
||||
for k, tc := range testcases {
|
||||
internal := &abac.Policy{}
|
||||
if err := abac.Scheme.Convert(tc.old, internal, nil); err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
}
|
||||
if !reflect.DeepEqual(internal, tc.expected) {
|
||||
t.Errorf("%s: expected\n\t%#v, got \n\t%#v", k, tc.expected, internal)
|
||||
}
|
||||
}
|
||||
}
|
21
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/doc.go
generated
vendored
21
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/doc.go
generated
vendored
@ -1,21 +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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
// +groupName=abac.authorization.kubernetes.io
|
||||
|
||||
package v0 // import "k8s.io/kubernetes/pkg/apis/abac/v0"
|
67
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/register.go
generated
vendored
67
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/register.go
generated
vendored
@ -1,67 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v0
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/apis/abac"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "abac.authorization.kubernetes.io"
|
||||
|
||||
// SchemeGroupVersion is the API group version used to register abac v0
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v0"}
|
||||
|
||||
func init() {
|
||||
// TODO: Delete this init function, abac should not have its own scheme.
|
||||
if err := addKnownTypes(abac.Scheme); err != nil {
|
||||
// Programmer error.
|
||||
panic(err)
|
||||
}
|
||||
if err := addConversionFuncs(abac.Scheme); err != nil {
|
||||
// Programmer error.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
|
||||
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
// localSchemeBuilder ïs a pointer to SchemeBuilder instance. Using localSchemeBuilder
|
||||
// defaulting and conversion init funcs are registered as well.
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
// AddToScheme is a common registration function for mapping packaged scoped group & version keys to a scheme
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes, addConversionFuncs)
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Policy{},
|
||||
)
|
||||
return nil
|
||||
}
|
56
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/types.go
generated
vendored
56
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/types.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
|
||||
package v0
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Policy contains a single ABAC policy rule
|
||||
type Policy struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// User is the username this rule applies to.
|
||||
// Either user or group is required to match the request.
|
||||
// "*" matches all users.
|
||||
// +optional
|
||||
User string `json:"user,omitempty"`
|
||||
|
||||
// Group is the group this rule applies to.
|
||||
// Either user or group is required to match the request.
|
||||
// "*" matches all groups.
|
||||
// +optional
|
||||
Group string `json:"group,omitempty"`
|
||||
|
||||
// Readonly matches readonly requests when true, and all requests when false
|
||||
// +optional
|
||||
Readonly bool `json:"readonly,omitempty"`
|
||||
|
||||
// Resource is the name of a resource
|
||||
// "*" matches all resources
|
||||
// +optional
|
||||
Resource string `json:"resource,omitempty"`
|
||||
|
||||
// Namespace is the name of a namespace
|
||||
// "*" matches all namespaces (including unnamespaced requests)
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
50
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/zz_generated.deepcopy.go
generated
vendored
50
vendor/k8s.io/kubernetes/pkg/apis/abac/v0/zz_generated.deepcopy.go
generated
vendored
@ -1,50 +0,0 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v0
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Policy) DeepCopyInto(out *Policy) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy.
|
||||
func (in *Policy) DeepCopy() *Policy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Policy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Policy) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
51
vendor/k8s.io/kubernetes/pkg/apis/abac/v1beta1/BUILD
generated
vendored
51
vendor/k8s.io/kubernetes/pkg/apis/abac/v1beta1/BUILD
generated
vendored
@ -1,51 +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 = [
|
||||
"conversion.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/apis/abac/v1beta1",
|
||||
deps = [
|
||||
"//pkg/apis/abac:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["conversion_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/abac:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
46
vendor/k8s.io/kubernetes/pkg/apis/abac/v1beta1/conversion.go
generated
vendored
46
vendor/k8s.io/kubernetes/pkg/apis/abac/v1beta1/conversion.go
generated
vendored
@ -1,46 +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 v1beta1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
api "k8s.io/kubernetes/pkg/apis/abac"
|
||||
)
|
||||
|
||||
// allAuthenticated matches k8s.io/apiserver/pkg/authentication/user.AllAuthenticated,
|
||||
// but we don't want an client library (which must include types), depending on a server library
|
||||
const allAuthenticated = "system:authenticated"
|
||||
|
||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
return scheme.AddConversionFuncs(
|
||||
func(in *Policy, out *api.Policy, s conversion.Scope) error {
|
||||
// Begin by copying all fields
|
||||
if err := autoConvert_v1beta1_Policy_To_abac_Policy(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// In v1beta1, * user or group maps to all authenticated subjects
|
||||
if in.Spec.User == "*" || in.Spec.Group == "*" {
|
||||
out.Spec.Group = allAuthenticated
|
||||
out.Spec.User = ""
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user