Fresh dep ensure

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

View File

@ -1,4 +1,17 @@
approvers:
- api-approvers
reviewers:
- api-reviewers
# 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

View File

@ -13,7 +13,7 @@ go_library(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/util/hash:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
],
)
@ -23,8 +23,8 @@ go_test(
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",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
],
)

View File

@ -38,12 +38,12 @@ func RepackSubsets(subsets []api.EndpointSubset) []api.EndpointSubset {
allAddrs := map[addressKey]*api.EndpointAddress{}
portToAddrReadyMap := map[api.EndpointPort]addressSet{}
for i := range subsets {
for _, port := range subsets[i].Ports {
for k := range subsets[i].Addresses {
mapAddressByPort(&subsets[i].Addresses[k], port, true, allAddrs, portToAddrReadyMap)
}
for k := range subsets[i].NotReadyAddresses {
mapAddressByPort(&subsets[i].NotReadyAddresses[k], port, false, allAddrs, portToAddrReadyMap)
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)
}
}
}
@ -58,7 +58,14 @@ func RepackSubsets(subsets []api.EndpointSubset) []api.EndpointSubset {
for port, addrs := range portToAddrReadyMap {
key := keyString(hashAddresses(addrs))
keyToAddrReadyMap[key] = addrs
addrReadyMapKeyToPorts[key] = append(addrReadyMapKeyToPorts[key], port)
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.
@ -85,7 +92,17 @@ type addressKey struct {
uid types.UID
}
// mapAddressByPort adds an address into a map by its ports, registering the address with a unique pointer, and preserving
// 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
@ -154,6 +171,7 @@ 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 {
@ -173,8 +191,8 @@ func LessEndpointAddress(a, b *api.EndpointAddress) bool {
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(addrsByIPAndUID(ss.Addresses))
sort.Sort(addrsByIPAndUID(ss.NotReadyAddresses))
sort.Sort(portsByHash(ss.Ports))
}
sort.Sort(subsetsByHash(subsets))
@ -197,11 +215,11 @@ func (sl subsetsByHash) Less(i, j int) bool {
return bytes.Compare(h1, h2) < 0
}
type addrsByIpAndUID []api.EndpointAddress
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 {
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])
}

View File

@ -51,11 +51,11 @@ func TestPackSubsets(t *testing.T) {
}, {
name: "empty ports",
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []api.EndpointPort{}}},
expect: []api.EndpointSubset{},
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{},
expect: []api.EndpointSubset{{NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: nil}},
}, {
name: "one set, one ip, one port",
given: []api.EndpointSubset{{

View File

@ -1,37 +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 = ["sorted_event_list.go"],
importpath = "k8s.io/kubernetes/pkg/api/events",
deps = ["//pkg/apis/core:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["sorted_event_list_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,2 +0,0 @@
reviewers:
- gmarek

View File

@ -1,66 +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 events
import (
"sort"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kubernetes/pkg/apis/core"
)
func TestSortableEvents(t *testing.T) {
// Arrange
list := SortableEvents([]api.Event{
{
Source: api.EventSource{Component: "kubelet"},
Message: "Item 1",
FirstTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
LastTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
Count: 1,
Type: api.EventTypeNormal,
},
{
Source: api.EventSource{Component: "scheduler"},
Message: "Item 2",
FirstTimestamp: metav1.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)),
LastTimestamp: metav1.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)),
Count: 1,
Type: api.EventTypeNormal,
},
{
Source: api.EventSource{Component: "kubelet"},
Message: "Item 3",
FirstTimestamp: metav1.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)),
LastTimestamp: metav1.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)),
Count: 1,
Type: api.EventTypeNormal,
},
})
// Act
sort.Sort(list)
// Assert
if list[0].Message != "Item 2" ||
list[1].Message != "Item 3" ||
list[2].Message != "Item 1" {
t.Fatal("List is not sorted by time. List: ", list)
}
}

View File

@ -6,8 +6,8 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/api/legacyscheme",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
],
)

View File

@ -1,10 +1,6 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
@ -13,7 +9,7 @@ go_library(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)
@ -37,8 +33,8 @@ go_test(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature: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",
],
)

View File

@ -22,123 +22,22 @@ import (
"k8s.io/kubernetes/pkg/features"
)
func getClaimRefNamespace(pv *api.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 *api.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
}
// DropDisabledAlphaFields removes disabled fields from the pv spec.
// DropDisabledFields removes disabled fields from the pv spec.
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pv spec.
func DropDisabledAlphaFields(pvSpec *api.PersistentVolumeSpec) {
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
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
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.
@ -20,307 +20,136 @@ import (
"reflect"
"testing"
"strings"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
"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 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 := []*api.PersistentVolume{
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
AzureFile: &api.AzureFilePersistentVolumeSource{
SecretName: "Spec.PersistentVolumeSource.AzureFile.SecretName"}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
AzureFile: &api.AzureFilePersistentVolumeSource{
SecretName: "Spec.PersistentVolumeSource.AzureFile.SecretName",
SecretNamespace: &secretNamespace}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
CephFS: &api.CephFSPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.CephFS.SecretRef",
Namespace: "cephfs"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
CephFS: &api.CephFSPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.CephFS.SecretRef"}}}}},
{Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Cinder: &api.CinderPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.Cinder.SecretRef",
Namespace: "cinder"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
FlexVolume: &api.FlexPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.FlexVolume.SecretRef",
Namespace: "flexns"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
FlexVolume: &api.FlexPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.FlexVolume.SecretRef"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
RBD: &api.RBDPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.RBD.SecretRef"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
RBD: &api.RBDPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.RBD.SecretRef",
Namespace: "rbdns"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
ScaleIO: &api.ScaleIOPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
ScaleIO: &api.ScaleIOPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef",
Namespace: "scaleions"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
ISCSI: &api.ISCSIPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef",
Namespace: "iscsi"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
ISCSI: &api.ISCSIPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
StorageOS: &api.StorageOSPersistentVolumeSource{
SecretRef: &api.ObjectReference{
Name: "Spec.PersistentVolumeSource.StorageOS.SecretRef",
Namespace: "storageosns"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
CSI: &api.CSIPersistentVolumeSource{
ControllerPublishSecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.CSI.ControllerPublishSecretRef",
Namespace: "csi"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
CSI: &api.CSIPersistentVolumeSource{
NodePublishSecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.CSI.NodePublishSecretRef",
Namespace: "csi"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
CSI: &api.CSIPersistentVolumeSource{
NodeStageSecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.CSI.NodeStageSecretRef",
Namespace: "csi"}}}}},
func TestDropDisabledFields(t *testing.T) {
specWithCSI := func() *api.PersistentVolumeSpec {
return &api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{CSI: &api.CSIPersistentVolumeSource{}}}
}
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
})
specWithoutCSI := func() *api.PersistentVolumeSpec {
return &api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{CSI: nil}}
}
specWithMode := func(mode *api.PersistentVolumeMode) *api.PersistentVolumeSpec {
return &api.PersistentVolumeSpec{VolumeMode: mode}
}
// 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")
}
modeBlock := api.PersistentVolumeBlock
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")
}
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(),
},
expectedNamespacedNames := sets.NewString(
"claimrefns/Spec.PersistentVolumeSource.AzureFile.SecretName",
"Spec.PersistentVolumeSource.AzureFile.SecretNamespace/Spec.PersistentVolumeSource.AzureFile.SecretName",
"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(),
},
"claimrefns/Spec.PersistentVolumeSource.CephFS.SecretRef",
"cephfs/Spec.PersistentVolumeSource.CephFS.SecretRef",
"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),
},
"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) *api.HostPathType {
hostPathType := new(api.HostPathType)
*hostPathType = api.HostPathType(pathType)
return hostPathType
}
func TestDropAlphaPVVolumeMode(t *testing.T) {
vmode := api.PersistentVolumeFilesystem
// PersistentVolume with VolumeMode set
pv := api.PersistentVolume{
Spec: api.PersistentVolumeSpec{
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{
Path: "/foo",
Type: newHostPathType(string(api.HostPathDirectory)),
},
},
StorageClassName: "test-storage-class",
VolumeMode: &vmode,
"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),
},
}
// Enable alpha feature BlockVolume
err1 := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
if err1 != nil {
t.Fatalf("Failed to enable feature gate for BlockVolume: %v", err1)
}
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)()
// now test dropping the fields - should not be dropped
DropDisabledAlphaFields(&pv.Spec)
// check to make sure VolumeDevices is still present
// if featureset is set to true
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
if pv.Spec.VolumeMode == nil {
t.Error("VolumeMode in pv.Spec should not have been dropped based on feature-gate")
}
}
// Disable alpha feature BlockVolume
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
if err != nil {
t.Fatalf("Failed to disable feature gate for BlockVolume: %v", err)
}
// now test dropping the fields
DropDisabledAlphaFields(&pv.Spec)
// check to make sure VolumeDevices is nil
// if featureset is set to false
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
if pv.Spec.VolumeMode != nil {
t.Error("DropDisabledAlphaFields VolumeMode for pv.Spec failed")
}
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))
}
})
}
}

View File

@ -13,7 +13,7 @@ go_library(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)
@ -32,11 +32,15 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["util_test.go"],
srcs = [
"main_test.go",
"util_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature: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",
],
)

View File

@ -1,5 +1,5 @@
/*
Copyright 2014 The Kubernetes Authors.
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.
@ -14,23 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package events
package persistentvolumeclaim
import (
api "k8s.io/kubernetes/pkg/apis/core"
"testing"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
_ "k8s.io/kubernetes/pkg/features"
)
// SortableEvents implements sort.Interface for []api.Event based on the Timestamp field
type SortableEvents []api.Event
func (list SortableEvents) Len() int {
return len(list)
}
func (list SortableEvents) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
func (list SortableEvents) Less(i, j int) bool {
return list[i].LastTimestamp.Time.Before(list[j].LastTimestamp.Time)
func TestMain(m *testing.M) {
utilfeaturetesting.VerifyFeatureGatesUnchanged(utilfeature.DefaultFeatureGate, m.Run)
}

View File

@ -20,6 +20,7 @@ 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"
)
@ -36,36 +37,24 @@ func TestDropAlphaPVCVolumeMode(t *testing.T) {
}
// Enable alpha feature BlockVolume
err1 := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
if err1 != nil {
t.Fatalf("Failed to enable feature gate for BlockVolume: %v", err1)
}
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 utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
if pvc.Spec.VolumeMode == nil {
t.Error("VolumeMode in pvc.Spec should not have been dropped based on feature-gate")
}
if pvc.Spec.VolumeMode == nil {
t.Error("VolumeMode in pvc.Spec should not have been dropped based on feature-gate")
}
// Disable alpha feature BlockVolume
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
if err != nil {
t.Fatalf("Failed to disable feature gate for BlockVolume: %v", err)
}
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 !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
if pvc.Spec.VolumeMode != nil {
t.Error("DropDisabledAlphaFields VolumeMode for pvc.Spec failed")
}
if pvc.Spec.VolumeMode != nil {
t.Error("DropDisabledAlphaFields VolumeMode for pvc.Spec failed")
}
}

View File

@ -13,8 +13,8 @@ go_library(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature: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",
],
)
@ -33,13 +33,17 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["util_test.go"],
srcs = [
"main_test.go",
"util_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature: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",
],
)

29
vendor/k8s.io/kubernetes/pkg/api/pod/main_test.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
/*
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)
}

View File

@ -248,20 +248,15 @@ func DropDisabledAlphaFields(podSpec *api.PodSpec) {
}
}
if !utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) && podSpec.SecurityContext != nil {
podSpec.SecurityContext.ShareProcessNamespace = nil
}
for i := range podSpec.Containers {
DropDisabledVolumeMountsAlphaFields(podSpec.Containers[i].VolumeMounts)
}
for i := range podSpec.InitContainers {
DropDisabledVolumeMountsAlphaFields(podSpec.InitContainers[i].VolumeMounts)
}
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
@ -284,12 +279,20 @@ func DropDisabledRunAsGroupField(podSpec *api.PodSpec) {
}
}
// DropDisabledVolumeMountsAlphaFields removes disabled fields from []VolumeMount.
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a VolumeMount
func DropDisabledVolumeMountsAlphaFields(volumeMounts []api.VolumeMount) {
if !utilfeature.DefaultFeatureGate.Enabled(features.MountPropagation) {
for i := range volumeMounts {
volumeMounts[i].MountPropagation = 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
}
}
}
}

View File

@ -18,13 +18,13 @@ package pod
import (
"reflect"
"testing"
"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"
)
@ -304,42 +304,32 @@ func TestDropAlphaVolumeDevices(t *testing.T) {
}
// Enable alpha feature BlockVolume
err1 := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
if err1 != nil {
t.Fatalf("Failed to enable feature gate for BlockVolume: %v", err1)
}
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 utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
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")
}
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
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
if err != nil {
t.Fatalf("Failed to disable feature gate for BlockVolume: %v", err)
}
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 !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
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")
}
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")
}
}

View File

@ -0,0 +1,47 @@
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 Executable file
View File

@ -0,0 +1,3 @@
reviewers:
- smarterclayton
- jessfraz

View File

@ -0,0 +1,29 @@
/*
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)
}

View File

@ -0,0 +1,34 @@
/*
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
}
}

View File

@ -0,0 +1,69 @@
/*
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")
}
}
}

View File

@ -13,9 +13,10 @@ go_test(
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema: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",
],
)
@ -25,9 +26,9 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/api/ref",
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime: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",
],
)

View File

@ -28,8 +28,8 @@ import (
api "k8s.io/kubernetes/pkg/apis/core"
)
// Errors that could be returned by GetReference.
var (
// Errors that could be returned by GetReference.
ErrNilObject = errors.New("can't reference a nil object")
ErrNoSelfLink = errors.New("selfLink was empty, can't make reference")
)
@ -80,12 +80,12 @@ func GetReference(scheme *runtime.Scheme, obj runtime.Object) (*api.ObjectRefere
if len(selfLink) == 0 {
return nil, ErrNoSelfLink
}
selfLinkUrl, err := url.Parse(selfLink)
selfLinkURL, err := url.Parse(selfLink)
if err != nil {
return nil, err
}
// example paths: /<prefix>/<version>/*
parts := strings.Split(selfLinkUrl.Path, "/")
parts := strings.Split(selfLinkURL.Path, "/")
if len(parts) < 3 {
return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", selfLink, version)
}

View File

@ -20,6 +20,8 @@ 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"
@ -53,7 +55,7 @@ func TestGetReference(t *testing.T) {
// 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 {
api.AddToScheme(legacyscheme.Scheme)
require.NoError(t, api.AddToScheme(legacyscheme.Scheme))
}
table := map[string]struct {

View File

@ -12,7 +12,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/api/resource",
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
],
)
@ -35,6 +35,8 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource: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",
],
)

View File

@ -25,50 +25,45 @@ import (
api "k8s.io/kubernetes/pkg/apis/core"
)
// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
// containers of the pod.
func PodRequestsAndLimits(pod *api.Pod) (reqs map[api.ResourceName]resource.Quantity, limits map[api.ResourceName]resource.Quantity) {
reqs, limits = map[api.ResourceName]resource.Quantity{}, map[api.ResourceName]resource.Quantity{}
for _, container := range pod.Spec.Containers {
for name, quantity := range container.Resources.Requests {
if value, ok := reqs[name]; !ok {
reqs[name] = *quantity.Copy()
} else {
value.Add(quantity)
reqs[name] = value
}
// 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
}
for name, quantity := range container.Resources.Limits {
if value, ok := limits[name]; !ok {
limits[name] = *quantity.Copy()
} else {
value.Add(quantity)
limits[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 {
for name, quantity := range container.Resources.Requests {
value, ok := reqs[name]
if !ok {
reqs[name] = *quantity.Copy()
continue
}
if quantity.Cmp(value) > 0 {
reqs[name] = *quantity.Copy()
}
}
for name, quantity := range container.Resources.Limits {
value, ok := limits[name]
if !ok {
limits[name] = *quantity.Copy()
continue
}
if quantity.Cmp(value) > 0 {
limits[name] = *quantity.Copy()
}
}
maxResourceList(reqs, container.Resources.Requests)
maxResourceList(limits, container.Resources.Limits)
}
return
}

View File

@ -17,9 +17,12 @@ 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"
)
@ -60,3 +63,184 @@ func TestDefaultResourceHelpers(t *testing.T) {
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),
},
},
}
}

View File

@ -151,25 +151,25 @@ func TestRequestsOnlyLocalTraffic(t *testing.T) {
})
checkRequestsOnlyLocalTraffic(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkRequestsOnlyLocalTraffic(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
checkRequestsOnlyLocalTraffic(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkRequestsOnlyLocalTraffic(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
@ -191,25 +191,25 @@ func TestNeedsHealthCheck(t *testing.T) {
})
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkNeedsHealthCheck(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})

View File

@ -18,6 +18,8 @@ go_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",
@ -27,7 +29,8 @@ go_library(
"//pkg/apis/batch/install:go_default_library",
"//pkg/apis/certificates:go_default_library",
"//pkg/apis/certificates/install:go_default_library",
"//pkg/apis/componentconfig/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",
@ -48,9 +51,9 @@ go_library(
"//pkg/apis/settings/install:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/install:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer: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",
],
)
@ -59,8 +62,8 @@ go_test(
srcs = ["testapi_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime: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",
],
)

View File

@ -16,5 +16,4 @@ reviewers:
- markturansky
- mml
- david-mcmahon
- ericchiang
- jianhuiz

View File

@ -37,10 +37,12 @@ import (
"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"
@ -52,15 +54,17 @@ import (
"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/componentconfig/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"
@ -73,6 +77,7 @@ import (
_ "k8s.io/kubernetes/pkg/apis/storage/install"
)
// Variables to store GroupName
var (
Groups = make(map[string]TestGroup)
Default TestGroup
@ -89,6 +94,7 @@ var (
storageSerializer runtime.SerializerInfo
)
// TestGroup contains GroupVersion to uniquely identify the API
type TestGroup struct {
externalGroupVersion schema.GroupVersion
}
@ -257,6 +263,18 @@ func init() {
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]
@ -269,6 +287,7 @@ func init() {
Admission = Groups[admission.GroupName]
}
// GroupVersion makes copy of schema.GroupVersion
func (g TestGroup) GroupVersion() *schema.GroupVersion {
copyOfGroupVersion := g.externalGroupVersion
return &copyOfGroupVersion
@ -283,6 +302,7 @@ func (g TestGroup) Codec() runtime.Codec {
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")
}
@ -315,14 +335,13 @@ func (g TestGroup) SelfLink(resource, name string) string {
return fmt.Sprintf("/api/%s/%s", g.externalGroupVersion.Version, resource)
}
return fmt.Sprintf("/api/%s/%s/%s", g.externalGroupVersion.Version, resource, name)
} else {
// 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)
}
// 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.

View File

@ -18,27 +18,29 @@ go_library(
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:go_default_library",
"//pkg/apis/extensions/fuzzer:go_default_library",
"//pkg/apis/extensions/v1beta1: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",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
],
)
@ -76,34 +78,37 @@ go_test(
"//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",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
],
)

View File

@ -11,9 +11,9 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/api/testing/compat",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field: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",
],
)

View File

@ -31,11 +31,10 @@ import (
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
//
// 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,

View File

@ -20,10 +20,11 @@ import (
"testing"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// TestSelectableFieldLabelConversions verifies that given resource have field
// 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.
@ -38,6 +39,13 @@ func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string,
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)
}
@ -46,7 +54,7 @@ func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string,
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(apiVersion, kind, label, value)
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 {
@ -64,7 +72,7 @@ func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string,
}
for _, label := range badFieldLabels {
_, _, err := legacyscheme.Scheme.ConvertFieldLabel(apiVersion, kind, label, "value")
_, _, err := legacyscheme.Scheme.ConvertFieldLabel(gvk, label, "value")
if err == nil {
t.Errorf("kind=%s label=%s: got unexpected non-error", kind, label)
}

View File

@ -21,8 +21,8 @@ import (
"math/rand"
"testing"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"

View File

@ -24,8 +24,8 @@ import (
"github.com/google/gofuzz"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
"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"

View File

@ -37,7 +37,7 @@ func parseTimeOrDie(ts string) metav1.Time {
return metav1.Time{Time: t}
}
var benchmarkPod api.Pod = api.Pod{
var benchmarkPod = api.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",

View File

@ -26,7 +26,7 @@ import (
apiv1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
roundtrip "k8s.io/apimachinery/pkg/api/testing/roundtrip"
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"
@ -88,9 +88,6 @@ func TestDefaulting(t *testing.T) {
{Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {},
{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequest"}: {},
{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequestList"}: {},
{Group: "componentconfig", Version: "v1alpha1", Kind: "KubeProxyConfiguration"}: {},
{Group: "componentconfig", Version: "v1alpha1", Kind: "KubeSchedulerConfiguration"}: {},
{Group: "componentconfig", Version: "v1alpha1", Kind: "KubeletConfiguration"}: {},
{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.
@ -139,6 +136,8 @@ func TestDefaulting(t *testing.T) {
{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"}: {},

View File

@ -21,22 +21,23 @@ import (
fuzz "github.com/google/gofuzz"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
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"
"k8s.io/kubernetes/pkg/apis/extensions"
extensionsfuzzer "k8s.io/kubernetes/pkg/apis/extensions/fuzzer"
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
networkingfuzzer "k8s.io/kubernetes/pkg/apis/networking/fuzzer"
policyfuzzer "k8s.io/kubernetes/pkg/apis/policy/fuzzer"
rbacfuzzer "k8s.io/kubernetes/pkg/apis/rbac/fuzzer"
@ -64,14 +65,14 @@ func overrideGenericFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
},
func(r *runtime.RawExtension, c fuzz.Continue) {
// Pick an arbitrary type and fuzz it
types := []runtime.Object{&api.Pod{}, &extensions.Deployment{}, &api.Service{}}
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 *extensions.Deployment:
codec = apitesting.TestCodec(codecs, extensionsv1beta1.SchemeGroupVersion)
case *apps.Deployment:
codec = apitesting.TestCodec(codecs, appsv1.SchemeGroupVersion)
default:
codec = apitesting.TestCodec(codecs, v1.SchemeGroupVersion)
}
@ -88,6 +89,7 @@ func overrideGenericFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
}
}
// FuzzerFuncs is a list of fuzzer functions
var FuzzerFuncs = fuzzer.MergeFuzzerFuncs(
genericfuzzer.Funcs,
overrideGenericFuncs,
@ -100,6 +102,7 @@ var FuzzerFuncs = fuzzer.MergeFuzzerFuncs(
policyfuzzer.Funcs,
certificatesfuzzer.Funcs,
admissionregistrationfuzzer.Funcs,
auditregistrationfuzzer.Funcs,
storagefuzzer.Funcs,
networkingfuzzer.Funcs,
)

View File

@ -26,8 +26,8 @@ import (
"github.com/gogo/protobuf/proto"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"

View File

@ -19,7 +19,7 @@ package testing
import (
"bytes"
"encoding/hex"
"encoding/json"
gojson "encoding/json"
"io/ioutil"
"math/rand"
"reflect"
@ -27,27 +27,27 @@ import (
jsoniter "github.com/json-iterator/go"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
"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"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
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_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
"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"
"k8s.io/kubernetes/pkg/apis/extensions"
k8s_v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
)
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
@ -65,14 +65,14 @@ func fuzzInternalObject(t *testing.T, forVersion schema.GroupVersion, item runti
return item
}
func Convert_v1beta1_ReplicaSet_to_api_ReplicationController(in *v1beta1.ReplicaSet, out *api.ReplicationController, s conversion.Scope) error {
intermediate1 := &extensions.ReplicaSet{}
if err := k8s_v1beta1.Convert_v1beta1_ReplicaSet_To_extensions_ReplicaSet(in, intermediate1, s); err != nil {
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_extensions_ReplicaSet_to_v1_ReplicationController(intermediate1, intermediate2, s); err != nil {
if err := k8s_api_v1.Convert_apps_ReplicaSet_To_v1_ReplicationController(intermediate1, intermediate2, s); err != nil {
return err
}
@ -80,17 +80,17 @@ func Convert_v1beta1_ReplicaSet_to_api_ReplicationController(in *v1beta1.Replica
}
func TestSetControllerConversion(t *testing.T) {
if err := legacyscheme.Scheme.AddConversionFuncs(Convert_v1beta1_ReplicaSet_to_api_ReplicationController); err != nil {
if err := legacyscheme.Scheme.AddConversionFuncs(ConvertV1ReplicaSetToAPIReplicationController); err != nil {
t.Fatal(err)
}
rs := &extensions.ReplicaSet{}
rs := &apps.ReplicaSet{}
rc := &api.ReplicationController{}
extGroup := testapi.Extensions
extGroup := testapi.Apps
defaultGroup := testapi.Default
fuzzInternalObject(t, schema.GroupVersion{Group: "extensions", Version: runtime.APIVersionInternal}, rs, rand.Int63())
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)
@ -101,7 +101,7 @@ func TestSetControllerConversion(t *testing.T) {
},
}
t.Logf("rs._internal.extensions -> rs.v1beta1.extensions")
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)
@ -116,7 +116,7 @@ func TestSetControllerConversion(t *testing.T) {
),
)
t.Logf("rs.v1beta1.extensions -> rc._internal")
t.Logf("rs.v1.apps -> rc._internal")
if err := runtime.DecodeInto(decoder, data, rc); err != nil {
t.Fatalf("unexpected decoding error: %v", err)
}
@ -127,7 +127,7 @@ func TestSetControllerConversion(t *testing.T) {
t.Fatalf("unexpected encoding error: %v", err)
}
t.Logf("rc.v1 -> rs._internal.extensions")
t.Logf("rc.v1 -> rs._internal.apps")
if err := runtime.DecodeInto(decoder, data, rs); err != nil {
t.Fatalf("unexpected decoding error: %v", err)
}
@ -138,7 +138,7 @@ func TestSetControllerConversion(t *testing.T) {
func TestSpecificKind(t *testing.T) {
// Uncomment the following line to enable logging of which conversions
// legacyscheme.Scheme.Log(t)
internalGVK := schema.GroupVersionKind{Group: "extensions", Version: runtime.APIVersionInternal, Kind: "DaemonSet"}
internalGVK := schema.GroupVersionKind{Group: "apps", Version: runtime.APIVersionInternal, Kind: "DaemonSet"}
seed := rand.Int63()
fuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs)
@ -156,11 +156,13 @@ var nonRoundTrippableTypes = sets.NewString(
"WatchEvent",
// ListOptions is now part of the meta group
"ListOptions",
// Delete options is only read in metav1
// DeleteOptions, CreateOptions and UpdateOptions are only read in metav1
"DeleteOptions",
"CreateOptions",
"UpdateOptions",
)
var commonKinds = []string{"Status", "ListOptions", "DeleteOptions", "ExportOptions"}
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.
@ -203,11 +205,7 @@ func TestCommonKindsRegistered(t *testing.T) {
func TestRoundTripTypes(t *testing.T) {
seed := rand.Int63()
fuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(seed), legacyscheme.Codecs)
nonRoundTrippableTypes := map[schema.GroupVersionKind]bool{
{Group: "componentconfig", Version: runtime.APIVersionInternal, Kind: "KubeProxyConfiguration"}: true,
{Group: "componentconfig", Version: runtime.APIVersionInternal, Kind: "KubeSchedulerConfiguration"}: true,
}
nonRoundTrippableTypes := map[schema.GroupVersionKind]bool{}
roundtrip.RoundTripTypes(t, legacyscheme.Scheme, legacyscheme.Codecs, fuzzer, nonRoundTrippableTypes)
}
@ -216,6 +214,7 @@ func TestRoundTripTypes(t *testing.T) {
// 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"},
@ -226,8 +225,9 @@ func TestEncodePtr(t *testing.T) {
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
SchedulerName: api.DefaultSchedulerName,
SecurityContext: &api.PodSecurityContext{},
SchedulerName: api.DefaultSchedulerName,
EnableServiceLinks: &enableServiceLinks,
},
}
obj := runtime.Object(pod)
@ -244,6 +244,29 @@ func TestEncodePtr(t *testing.T) {
}
}
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) {
@ -437,7 +460,7 @@ func BenchmarkEncodeJSONMarshal(b *testing.B) {
width := len(items)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(&items[i%width]); err != nil {
if _, err := gojson.Marshal(&items[i%width]); err != nil {
b.Fatal(err)
}
}
@ -529,7 +552,7 @@ func BenchmarkDecodeIntoJSON(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
obj := v1.Pod{}
if err := json.Unmarshal(encoded[i%width], &obj); err != nil {
if err := gojson.Unmarshal(encoded[i%width], &obj); err != nil {
b.Fatal(err)
}
}
@ -579,7 +602,7 @@ func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testi
}
b.ResetTimer()
iter := k8s_json.CaseSensitiveJsonIterator()
iter := json.CaseSensitiveJsonIterator()
for i := 0; i < b.N; i++ {
obj := v1.Pod{}
if err := iter.Unmarshal(encoded[i%width], &obj); err != nil {

View File

@ -24,9 +24,9 @@ import (
"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"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metaunstruct "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"

View File

@ -12,8 +12,8 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/api/v1/endpoints",
deps = [
"//pkg/util/hash:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
],
)
@ -22,9 +22,9 @@ go_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",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
],
)

View File

@ -38,12 +38,12 @@ func RepackSubsets(subsets []v1.EndpointSubset) []v1.EndpointSubset {
allAddrs := map[addressKey]*v1.EndpointAddress{}
portToAddrReadyMap := map[v1.EndpointPort]addressSet{}
for i := range subsets {
for _, port := range subsets[i].Ports {
for k := range subsets[i].Addresses {
mapAddressByPort(&subsets[i].Addresses[k], port, true, allAddrs, portToAddrReadyMap)
}
for k := range subsets[i].NotReadyAddresses {
mapAddressByPort(&subsets[i].NotReadyAddresses[k], port, false, allAddrs, portToAddrReadyMap)
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)
}
}
}
@ -58,7 +58,14 @@ func RepackSubsets(subsets []v1.EndpointSubset) []v1.EndpointSubset {
for port, addrs := range portToAddrReadyMap {
key := keyString(hashAddresses(addrs))
keyToAddrReadyMap[key] = addrs
addrReadyMapKeyToPorts[key] = append(addrReadyMapKeyToPorts[key], port)
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.
@ -85,7 +92,17 @@ type addressKey struct {
uid types.UID
}
// mapAddressByPort adds an address into a map by its ports, registering the address with a unique pointer, and preserving
// 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
@ -155,6 +172,7 @@ 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 {
@ -174,8 +192,8 @@ func LessEndpointAddress(a, b *v1.EndpointAddress) bool {
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(addrsByIPAndUID(ss.Addresses))
sort.Sort(addrsByIPAndUID(ss.NotReadyAddresses))
sort.Sort(portsByHash(ss.Ports))
}
sort.Sort(subsetsByHash(subsets))
@ -198,11 +216,11 @@ func (sl subsetsByHash) Less(i, j int) bool {
return bytes.Compare(h1, h2) < 0
}
type addrsByIpAndUID []v1.EndpointAddress
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 {
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])
}

View File

@ -51,11 +51,11 @@ func TestPackSubsets(t *testing.T) {
}, {
name: "empty ports",
given: []v1.EndpointSubset{{Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []v1.EndpointPort{}}},
expect: []v1.EndpointSubset{},
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{},
expect: []v1.EndpointSubset{{NotReadyAddresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: nil}},
}, {
name: "one set, one ip, one port",
given: []v1.EndpointSubset{{

View File

@ -9,7 +9,7 @@ go_library(
name = "go_default_library",
srcs = ["util.go"],
importpath = "k8s.io/kubernetes/pkg/api/v1/node",
deps = ["//vendor/k8s.io/api/core/v1:go_default_library"],
deps = ["//staging/src/k8s.io/api/core/v1:go_default_library"],
)
filegroup(

View File

@ -0,0 +1,35 @@
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"],
)

View File

@ -0,0 +1,134 @@
/*
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
}

View File

@ -0,0 +1,272 @@
/*
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
}

View File

@ -11,9 +11,9 @@ go_library(
srcs = ["util.go"],
importpath = "k8s.io/kubernetes/pkg/api/v1/pod",
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//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",
],
)
@ -22,12 +22,12 @@ go_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",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)

View File

@ -209,14 +209,10 @@ func GetContainerStatus(statuses []v1.ContainerStatus, name string) (v1.Containe
}
// GetExistingContainerStatus extracts the status of container "name" from "statuses",
// and returns empty status if "name" does not exist.
// It also returns if "name" exists.
func GetExistingContainerStatus(statuses []v1.ContainerStatus, name string) v1.ContainerStatus {
for i := range statuses {
if statuses[i].Name == name {
return statuses[i]
}
}
return v1.ContainerStatus{}
status, _ := GetContainerStatus(statuses, name)
return status
}
// IsPodAvailable returns true if a pod is available; false otherwise.
@ -242,13 +238,13 @@ func IsPodReady(pod *v1.Pod) bool {
return IsPodReadyConditionTrue(pod.Status)
}
// IsPodReady returns true if a pod is ready; false otherwise.
// 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
}
// Extracts the pod ready condition from the given status and returns that.
// 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)
@ -278,7 +274,7 @@ func GetPodConditionFromList(conditions []v1.PodCondition, conditionType v1.PodC
return -1, nil
}
// Updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
// 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 {
@ -290,20 +286,19 @@ func UpdatePodCondition(status *v1.PodStatus, condition *v1.PodCondition) bool {
// We are adding new pod condition.
status.Conditions = append(status.Conditions, *condition)
return true
} else {
// 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
}
// 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
}

View File

@ -301,7 +301,7 @@ func TestPodSecrets(t *testing.T) {
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
"Spec.Volumes[*].VolumeSource.StorageOS.SecretRef",
)
secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&v1.Pod{}))
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"))
@ -322,38 +322,113 @@ func TestPodSecrets(t *testing.T) {
}
}
// 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()
// 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 {
secretPaths.Insert(collectSecretPaths(t, path, name, tp.Elem()).List()...)
return secretPaths
resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...)
return resourcePaths
}
if strings.Contains(strings.ToLower(name), "secret") {
secretPaths.Insert(path.String())
if strings.Contains(strings.ToLower(name), resourcename) {
resourcePaths.Insert(path.String())
}
switch tp.Kind() {
case reflect.Ptr:
secretPaths.Insert(collectSecretPaths(t, path, name, tp.Elem()).List()...)
resourcePaths.Insert(collectResourcePaths(t, resourcename, 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()...)
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Child(field.Name), field.Name, field.Type).List()...)
}
case reflect.Interface:
t.Errorf("cannot find secret fields in interface{} field %s", path.String())
t.Errorf("cannot find %s fields in interface{} field %s", resourcename, path.String())
case reflect.Map:
secretPaths.Insert(collectSecretPaths(t, path.Key("*"), "", tp.Elem()).List()...)
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...)
case reflect.Slice:
secretPaths.Insert(collectSecretPaths(t, path.Key("*"), "", tp.Elem()).List()...)
resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...)
default:
// all primitive types
}
return secretPaths
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 {

View File

@ -11,9 +11,9 @@ go_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",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
],
)
@ -22,8 +22,8 @@ go_library(
srcs = ["helpers.go"],
importpath = "k8s.io/kubernetes/pkg/api/v1/resource",
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
],
)

View File

@ -25,55 +25,50 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)
// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
// containers of the pod.
func PodRequestsAndLimits(pod *v1.Pod) (reqs map[v1.ResourceName]resource.Quantity, limits map[v1.ResourceName]resource.Quantity) {
reqs, limits = map[v1.ResourceName]resource.Quantity{}, map[v1.ResourceName]resource.Quantity{}
for _, container := range pod.Spec.Containers {
for name, quantity := range container.Resources.Requests {
if value, ok := reqs[name]; !ok {
reqs[name] = *quantity.Copy()
} else {
value.Add(quantity)
reqs[name] = value
}
// 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
}
for name, quantity := range container.Resources.Limits {
if value, ok := limits[name]; !ok {
limits[name] = *quantity.Copy()
} else {
value.Add(quantity)
limits[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 {
for name, quantity := range container.Resources.Requests {
value, ok := reqs[name]
if !ok {
reqs[name] = *quantity.Copy()
continue
}
if quantity.Cmp(value) > 0 {
reqs[name] = *quantity.Copy()
}
}
for name, quantity := range container.Resources.Limits {
value, ok := limits[name]
if !ok {
limits[name] = *quantity.Copy()
continue
}
if quantity.Cmp(value) > 0 {
limits[name] = *quantity.Copy()
}
}
maxResourceList(reqs, container.Resources.Requests)
maxResourceList(limits, container.Resources.Limits)
}
return
}
// finds and returns the request for a specific resource.
// 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

View File

@ -12,7 +12,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/api/v1/service",
deps = [
"//pkg/util/net/sets:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
],
)
@ -22,7 +22,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/util/net/sets:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
],
)

View File

@ -151,25 +151,25 @@ func TestRequestsOnlyLocalTraffic(t *testing.T) {
})
checkRequestsOnlyLocalTraffic(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
Type: v1.ServiceTypeNodePort,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkRequestsOnlyLocalTraffic(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
Type: v1.ServiceTypeNodePort,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
},
})
checkRequestsOnlyLocalTraffic(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
Type: v1.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkRequestsOnlyLocalTraffic(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
Type: v1.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
},
})
@ -191,25 +191,25 @@ func TestNeedsHealthCheck(t *testing.T) {
})
checkNeedsHealthCheck(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
Type: v1.ServiceTypeNodePort,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkNeedsHealthCheck(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
Type: v1.ServiceTypeNodePort,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
},
})
checkNeedsHealthCheck(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
Type: v1.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkNeedsHealthCheck(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
Type: v1.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal,
},
})