mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-05 23:47:50 +00:00
Merge pull request #44296 from caesarxuchao/move-api-helpers.go
Automatic merge from submit-queue
Move api helpers.go to a subpackage
Part of https://github.com/kubernetes/kubernetes/issues/44065.
This PR moves the pkg/api/helpers.go to its own subpackage. It's mostly a mechanic move, except that
* I removed ConversionError in helpers.go, it's not used by anyone
* I moved the 3 methods of Taint and Toleration to pkg/api/methods.go, and left a TODO saying refactoring these methods to functions.
I'll send a few more PRs to make the k8s.io/kubernetes/pkg/api package only contains the code we want in the k8s.io/api repo, then we can run a [script](a0015fd1be (diff-7a2fbb4371972350ee414c6b88aee1c8)) to cut the new repo.
This commit is contained in:
@@ -15,8 +15,8 @@ go_library(
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"field_constants.go",
|
||||
"helpers.go",
|
||||
"json.go",
|
||||
"methods.go",
|
||||
"ref.go",
|
||||
"register.go",
|
||||
"resource_helpers.go",
|
||||
@@ -25,7 +25,6 @@ go_library(
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/davecgh/go-spew/spew",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apimachinery/announced",
|
||||
@@ -37,17 +36,15 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer",
|
||||
"//vendor:k8s.io/apimachinery/pkg/selection",
|
||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"helpers_test.go",
|
||||
"methods_test.go",
|
||||
"ref_test.go",
|
||||
"resource_helpers_test.go",
|
||||
],
|
||||
@@ -56,7 +53,6 @@ go_test(
|
||||
deps = [
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
],
|
||||
@@ -120,6 +116,7 @@ filegroup(
|
||||
"//pkg/api/endpoints:all-srcs",
|
||||
"//pkg/api/errors:all-srcs",
|
||||
"//pkg/api/events:all-srcs",
|
||||
"//pkg/api/helper:all-srcs",
|
||||
"//pkg/api/install:all-srcs",
|
||||
"//pkg/api/meta:all-srcs",
|
||||
"//pkg/api/pod:all-srcs",
|
||||
|
||||
@@ -64,4 +64,7 @@ const (
|
||||
// in the Annotations of a Pod.
|
||||
// TODO: remove when alpha support for affinity is removed
|
||||
AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
|
||||
|
||||
// annotation key prefix used to identify non-convertible json paths.
|
||||
NonConvertibleAnnotationPrefix = "non-convertible.kubernetes.io"
|
||||
)
|
||||
|
||||
51
pkg/api/helper/BUILD
Normal file
51
pkg/api/helper/BUILD
Normal file
@@ -0,0 +1,51 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["helpers_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["helpers.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
||||
"//vendor:k8s.io/apimachinery/pkg/fields",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/selection",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
@@ -14,18 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
package helper
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
@@ -34,25 +31,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// Conversion error conveniently packages up errors in conversions.
|
||||
type ConversionError struct {
|
||||
In, Out interface{}
|
||||
Message string
|
||||
}
|
||||
|
||||
// Return a helpful string about the error
|
||||
func (c *ConversionError) Error() string {
|
||||
return spew.Sprintf(
|
||||
"Conversion error: %s. (in: %v(%+v) out: %v)",
|
||||
c.Message, reflect.TypeOf(c.In), c.In, reflect.TypeOf(c.Out),
|
||||
)
|
||||
}
|
||||
|
||||
const (
|
||||
// annotation key prefix used to identify non-convertible json paths.
|
||||
NonConvertibleAnnotationPrefix = "non-convertible.kubernetes.io"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// NonConvertibleFields iterates over the provided map and filters out all but
|
||||
@@ -60,7 +39,7 @@ const (
|
||||
func NonConvertibleFields(annotations map[string]string) map[string]string {
|
||||
nonConvertibleKeys := map[string]string{}
|
||||
for key, value := range annotations {
|
||||
if strings.HasPrefix(key, NonConvertibleAnnotationPrefix) {
|
||||
if strings.HasPrefix(key, api.NonConvertibleAnnotationPrefix) {
|
||||
nonConvertibleKeys[key] = value
|
||||
}
|
||||
}
|
||||
@@ -89,10 +68,10 @@ var Semantic = conversion.EqualitiesOrDie(
|
||||
)
|
||||
|
||||
var standardResourceQuotaScopes = sets.NewString(
|
||||
string(ResourceQuotaScopeTerminating),
|
||||
string(ResourceQuotaScopeNotTerminating),
|
||||
string(ResourceQuotaScopeBestEffort),
|
||||
string(ResourceQuotaScopeNotBestEffort),
|
||||
string(api.ResourceQuotaScopeTerminating),
|
||||
string(api.ResourceQuotaScopeNotTerminating),
|
||||
string(api.ResourceQuotaScopeBestEffort),
|
||||
string(api.ResourceQuotaScopeNotBestEffort),
|
||||
)
|
||||
|
||||
// IsStandardResourceQuotaScope returns true if the scope is a standard value
|
||||
@@ -101,24 +80,24 @@ func IsStandardResourceQuotaScope(str string) bool {
|
||||
}
|
||||
|
||||
var podObjectCountQuotaResources = sets.NewString(
|
||||
string(ResourcePods),
|
||||
string(api.ResourcePods),
|
||||
)
|
||||
|
||||
var podComputeQuotaResources = sets.NewString(
|
||||
string(ResourceCPU),
|
||||
string(ResourceMemory),
|
||||
string(ResourceLimitsCPU),
|
||||
string(ResourceLimitsMemory),
|
||||
string(ResourceRequestsCPU),
|
||||
string(ResourceRequestsMemory),
|
||||
string(api.ResourceCPU),
|
||||
string(api.ResourceMemory),
|
||||
string(api.ResourceLimitsCPU),
|
||||
string(api.ResourceLimitsMemory),
|
||||
string(api.ResourceRequestsCPU),
|
||||
string(api.ResourceRequestsMemory),
|
||||
)
|
||||
|
||||
// IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope
|
||||
func IsResourceQuotaScopeValidForResource(scope ResourceQuotaScope, resource string) bool {
|
||||
func IsResourceQuotaScopeValidForResource(scope api.ResourceQuotaScope, resource string) bool {
|
||||
switch scope {
|
||||
case ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeNotBestEffort:
|
||||
case api.ResourceQuotaScopeTerminating, api.ResourceQuotaScopeNotTerminating, api.ResourceQuotaScopeNotBestEffort:
|
||||
return podObjectCountQuotaResources.Has(resource) || podComputeQuotaResources.Has(resource)
|
||||
case ResourceQuotaScopeBestEffort:
|
||||
case api.ResourceQuotaScopeBestEffort:
|
||||
return podObjectCountQuotaResources.Has(resource)
|
||||
default:
|
||||
return true
|
||||
@@ -126,8 +105,8 @@ func IsResourceQuotaScopeValidForResource(scope ResourceQuotaScope, resource str
|
||||
}
|
||||
|
||||
var standardContainerResources = sets.NewString(
|
||||
string(ResourceCPU),
|
||||
string(ResourceMemory),
|
||||
string(api.ResourceCPU),
|
||||
string(api.ResourceMemory),
|
||||
)
|
||||
|
||||
// IsStandardContainerResourceName returns true if the container can make a resource request
|
||||
@@ -138,24 +117,24 @@ func IsStandardContainerResourceName(str string) bool {
|
||||
|
||||
// IsOpaqueIntResourceName returns true if the resource name has the opaque
|
||||
// integer resource prefix.
|
||||
func IsOpaqueIntResourceName(name ResourceName) bool {
|
||||
return strings.HasPrefix(string(name), ResourceOpaqueIntPrefix)
|
||||
func IsOpaqueIntResourceName(name api.ResourceName) bool {
|
||||
return strings.HasPrefix(string(name), api.ResourceOpaqueIntPrefix)
|
||||
}
|
||||
|
||||
// OpaqueIntResourceName returns a ResourceName with the canonical opaque
|
||||
// integer prefix prepended. If the argument already has the prefix, it is
|
||||
// returned unmodified.
|
||||
func OpaqueIntResourceName(name string) ResourceName {
|
||||
if IsOpaqueIntResourceName(ResourceName(name)) {
|
||||
return ResourceName(name)
|
||||
func OpaqueIntResourceName(name string) api.ResourceName {
|
||||
if IsOpaqueIntResourceName(api.ResourceName(name)) {
|
||||
return api.ResourceName(name)
|
||||
}
|
||||
return ResourceName(fmt.Sprintf("%s%s", ResourceOpaqueIntPrefix, name))
|
||||
return api.ResourceName(fmt.Sprintf("%s%s", api.ResourceOpaqueIntPrefix, name))
|
||||
}
|
||||
|
||||
var standardLimitRangeTypes = sets.NewString(
|
||||
string(LimitTypePod),
|
||||
string(LimitTypeContainer),
|
||||
string(LimitTypePersistentVolumeClaim),
|
||||
string(api.LimitTypePod),
|
||||
string(api.LimitTypeContainer),
|
||||
string(api.LimitTypePersistentVolumeClaim),
|
||||
)
|
||||
|
||||
// IsStandardLimitRangeType returns true if the type is Pod or Container
|
||||
@@ -164,22 +143,22 @@ func IsStandardLimitRangeType(str string) bool {
|
||||
}
|
||||
|
||||
var standardQuotaResources = sets.NewString(
|
||||
string(ResourceCPU),
|
||||
string(ResourceMemory),
|
||||
string(ResourceRequestsCPU),
|
||||
string(ResourceRequestsMemory),
|
||||
string(ResourceRequestsStorage),
|
||||
string(ResourceLimitsCPU),
|
||||
string(ResourceLimitsMemory),
|
||||
string(ResourcePods),
|
||||
string(ResourceQuotas),
|
||||
string(ResourceServices),
|
||||
string(ResourceReplicationControllers),
|
||||
string(ResourceSecrets),
|
||||
string(ResourcePersistentVolumeClaims),
|
||||
string(ResourceConfigMaps),
|
||||
string(ResourceServicesNodePorts),
|
||||
string(ResourceServicesLoadBalancers),
|
||||
string(api.ResourceCPU),
|
||||
string(api.ResourceMemory),
|
||||
string(api.ResourceRequestsCPU),
|
||||
string(api.ResourceRequestsMemory),
|
||||
string(api.ResourceRequestsStorage),
|
||||
string(api.ResourceLimitsCPU),
|
||||
string(api.ResourceLimitsMemory),
|
||||
string(api.ResourcePods),
|
||||
string(api.ResourceQuotas),
|
||||
string(api.ResourceServices),
|
||||
string(api.ResourceReplicationControllers),
|
||||
string(api.ResourceSecrets),
|
||||
string(api.ResourcePersistentVolumeClaims),
|
||||
string(api.ResourceConfigMaps),
|
||||
string(api.ResourceServicesNodePorts),
|
||||
string(api.ResourceServicesLoadBalancers),
|
||||
)
|
||||
|
||||
// IsStandardQuotaResourceName returns true if the resource is known to
|
||||
@@ -189,21 +168,21 @@ func IsStandardQuotaResourceName(str string) bool {
|
||||
}
|
||||
|
||||
var standardResources = sets.NewString(
|
||||
string(ResourceCPU),
|
||||
string(ResourceMemory),
|
||||
string(ResourceRequestsCPU),
|
||||
string(ResourceRequestsMemory),
|
||||
string(ResourceLimitsCPU),
|
||||
string(ResourceLimitsMemory),
|
||||
string(ResourcePods),
|
||||
string(ResourceQuotas),
|
||||
string(ResourceServices),
|
||||
string(ResourceReplicationControllers),
|
||||
string(ResourceSecrets),
|
||||
string(ResourceConfigMaps),
|
||||
string(ResourcePersistentVolumeClaims),
|
||||
string(ResourceStorage),
|
||||
string(ResourceRequestsStorage),
|
||||
string(api.ResourceCPU),
|
||||
string(api.ResourceMemory),
|
||||
string(api.ResourceRequestsCPU),
|
||||
string(api.ResourceRequestsMemory),
|
||||
string(api.ResourceLimitsCPU),
|
||||
string(api.ResourceLimitsMemory),
|
||||
string(api.ResourcePods),
|
||||
string(api.ResourceQuotas),
|
||||
string(api.ResourceServices),
|
||||
string(api.ResourceReplicationControllers),
|
||||
string(api.ResourceSecrets),
|
||||
string(api.ResourceConfigMaps),
|
||||
string(api.ResourcePersistentVolumeClaims),
|
||||
string(api.ResourceStorage),
|
||||
string(api.ResourceRequestsStorage),
|
||||
)
|
||||
|
||||
// IsStandardResourceName returns true if the resource is known to the system
|
||||
@@ -212,50 +191,50 @@ func IsStandardResourceName(str string) bool {
|
||||
}
|
||||
|
||||
var integerResources = sets.NewString(
|
||||
string(ResourcePods),
|
||||
string(ResourceQuotas),
|
||||
string(ResourceServices),
|
||||
string(ResourceReplicationControllers),
|
||||
string(ResourceSecrets),
|
||||
string(ResourceConfigMaps),
|
||||
string(ResourcePersistentVolumeClaims),
|
||||
string(ResourceServicesNodePorts),
|
||||
string(ResourceServicesLoadBalancers),
|
||||
string(api.ResourcePods),
|
||||
string(api.ResourceQuotas),
|
||||
string(api.ResourceServices),
|
||||
string(api.ResourceReplicationControllers),
|
||||
string(api.ResourceSecrets),
|
||||
string(api.ResourceConfigMaps),
|
||||
string(api.ResourcePersistentVolumeClaims),
|
||||
string(api.ResourceServicesNodePorts),
|
||||
string(api.ResourceServicesLoadBalancers),
|
||||
)
|
||||
|
||||
// IsIntegerResourceName returns true if the resource is measured in integer values
|
||||
func IsIntegerResourceName(str string) bool {
|
||||
return integerResources.Has(str) || IsOpaqueIntResourceName(ResourceName(str))
|
||||
return integerResources.Has(str) || IsOpaqueIntResourceName(api.ResourceName(str))
|
||||
}
|
||||
|
||||
// this function aims to check if the service's ClusterIP is set or not
|
||||
// the objective is not to perform validation here
|
||||
func IsServiceIPSet(service *Service) bool {
|
||||
return service.Spec.ClusterIP != ClusterIPNone && service.Spec.ClusterIP != ""
|
||||
func IsServiceIPSet(service *api.Service) bool {
|
||||
return service.Spec.ClusterIP != api.ClusterIPNone && service.Spec.ClusterIP != ""
|
||||
}
|
||||
|
||||
// this function aims to check if the service's cluster IP is requested or not
|
||||
func IsServiceIPRequested(service *Service) bool {
|
||||
func IsServiceIPRequested(service *api.Service) bool {
|
||||
// ExternalName services are CNAME aliases to external ones. Ignore the IP.
|
||||
if service.Spec.Type == ServiceTypeExternalName {
|
||||
if service.Spec.Type == api.ServiceTypeExternalName {
|
||||
return false
|
||||
}
|
||||
return service.Spec.ClusterIP == ""
|
||||
}
|
||||
|
||||
var standardFinalizers = sets.NewString(
|
||||
string(FinalizerKubernetes),
|
||||
string(api.FinalizerKubernetes),
|
||||
metav1.FinalizerOrphanDependents,
|
||||
)
|
||||
|
||||
// HasAnnotation returns a bool if passed in annotation exists
|
||||
func HasAnnotation(obj ObjectMeta, ann string) bool {
|
||||
func HasAnnotation(obj api.ObjectMeta, ann string) bool {
|
||||
_, found := obj.Annotations[ann]
|
||||
return found
|
||||
}
|
||||
|
||||
// SetMetaDataAnnotation sets the annotation and value
|
||||
func SetMetaDataAnnotation(obj *ObjectMeta, ann string, value string) {
|
||||
func SetMetaDataAnnotation(obj *api.ObjectMeta, ann string, value string) {
|
||||
if obj.Annotations == nil {
|
||||
obj.Annotations = make(map[string]string)
|
||||
}
|
||||
@@ -268,7 +247,7 @@ func IsStandardFinalizerName(str string) bool {
|
||||
|
||||
// AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice,
|
||||
// only if they do not already exist
|
||||
func AddToNodeAddresses(addresses *[]NodeAddress, addAddresses ...NodeAddress) {
|
||||
func AddToNodeAddresses(addresses *[]api.NodeAddress, addAddresses ...api.NodeAddress) {
|
||||
for _, add := range addAddresses {
|
||||
exists := false
|
||||
for _, existing := range *addresses {
|
||||
@@ -292,11 +271,11 @@ func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) {
|
||||
}
|
||||
|
||||
// TODO: make method on LoadBalancerStatus?
|
||||
func LoadBalancerStatusEqual(l, r *LoadBalancerStatus) bool {
|
||||
func LoadBalancerStatusEqual(l, r *api.LoadBalancerStatus) bool {
|
||||
return ingressSliceEqual(l.Ingress, r.Ingress)
|
||||
}
|
||||
|
||||
func ingressSliceEqual(lhs, rhs []LoadBalancerIngress) bool {
|
||||
func ingressSliceEqual(lhs, rhs []api.LoadBalancerIngress) bool {
|
||||
if len(lhs) != len(rhs) {
|
||||
return false
|
||||
}
|
||||
@@ -308,7 +287,7 @@ func ingressSliceEqual(lhs, rhs []LoadBalancerIngress) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func ingressEqual(lhs, rhs *LoadBalancerIngress) bool {
|
||||
func ingressEqual(lhs, rhs *api.LoadBalancerIngress) bool {
|
||||
if lhs.IP != rhs.IP {
|
||||
return false
|
||||
}
|
||||
@@ -319,9 +298,9 @@ func ingressEqual(lhs, rhs *LoadBalancerIngress) bool {
|
||||
}
|
||||
|
||||
// TODO: make method on LoadBalancerStatus?
|
||||
func LoadBalancerStatusDeepCopy(lb *LoadBalancerStatus) *LoadBalancerStatus {
|
||||
c := &LoadBalancerStatus{}
|
||||
c.Ingress = make([]LoadBalancerIngress, len(lb.Ingress))
|
||||
func LoadBalancerStatusDeepCopy(lb *api.LoadBalancerStatus) *api.LoadBalancerStatus {
|
||||
c := &api.LoadBalancerStatus{}
|
||||
c.Ingress = make([]api.LoadBalancerIngress, len(lb.Ingress))
|
||||
for i := range lb.Ingress {
|
||||
c.Ingress[i] = lb.Ingress[i]
|
||||
}
|
||||
@@ -330,42 +309,42 @@ func LoadBalancerStatusDeepCopy(lb *LoadBalancerStatus) *LoadBalancerStatus {
|
||||
|
||||
// GetAccessModesAsString returns a string representation of an array of access modes.
|
||||
// modes, when present, are always in the same order: RWO,ROX,RWX.
|
||||
func GetAccessModesAsString(modes []PersistentVolumeAccessMode) string {
|
||||
func GetAccessModesAsString(modes []api.PersistentVolumeAccessMode) string {
|
||||
modes = removeDuplicateAccessModes(modes)
|
||||
modesStr := []string{}
|
||||
if containsAccessMode(modes, ReadWriteOnce) {
|
||||
if containsAccessMode(modes, api.ReadWriteOnce) {
|
||||
modesStr = append(modesStr, "RWO")
|
||||
}
|
||||
if containsAccessMode(modes, ReadOnlyMany) {
|
||||
if containsAccessMode(modes, api.ReadOnlyMany) {
|
||||
modesStr = append(modesStr, "ROX")
|
||||
}
|
||||
if containsAccessMode(modes, ReadWriteMany) {
|
||||
if containsAccessMode(modes, api.ReadWriteMany) {
|
||||
modesStr = append(modesStr, "RWX")
|
||||
}
|
||||
return strings.Join(modesStr, ",")
|
||||
}
|
||||
|
||||
// GetAccessModesAsString returns an array of AccessModes from a string created by GetAccessModesAsString
|
||||
func GetAccessModesFromString(modes string) []PersistentVolumeAccessMode {
|
||||
func GetAccessModesFromString(modes string) []api.PersistentVolumeAccessMode {
|
||||
strmodes := strings.Split(modes, ",")
|
||||
accessModes := []PersistentVolumeAccessMode{}
|
||||
accessModes := []api.PersistentVolumeAccessMode{}
|
||||
for _, s := range strmodes {
|
||||
s = strings.Trim(s, " ")
|
||||
switch {
|
||||
case s == "RWO":
|
||||
accessModes = append(accessModes, ReadWriteOnce)
|
||||
accessModes = append(accessModes, api.ReadWriteOnce)
|
||||
case s == "ROX":
|
||||
accessModes = append(accessModes, ReadOnlyMany)
|
||||
accessModes = append(accessModes, api.ReadOnlyMany)
|
||||
case s == "RWX":
|
||||
accessModes = append(accessModes, ReadWriteMany)
|
||||
accessModes = append(accessModes, api.ReadWriteMany)
|
||||
}
|
||||
}
|
||||
return accessModes
|
||||
}
|
||||
|
||||
// removeDuplicateAccessModes returns an array of access modes without any duplicates
|
||||
func removeDuplicateAccessModes(modes []PersistentVolumeAccessMode) []PersistentVolumeAccessMode {
|
||||
accessModes := []PersistentVolumeAccessMode{}
|
||||
func removeDuplicateAccessModes(modes []api.PersistentVolumeAccessMode) []api.PersistentVolumeAccessMode {
|
||||
accessModes := []api.PersistentVolumeAccessMode{}
|
||||
for _, m := range modes {
|
||||
if !containsAccessMode(accessModes, m) {
|
||||
accessModes = append(accessModes, m)
|
||||
@@ -374,7 +353,7 @@ func removeDuplicateAccessModes(modes []PersistentVolumeAccessMode) []Persistent
|
||||
return accessModes
|
||||
}
|
||||
|
||||
func containsAccessMode(modes []PersistentVolumeAccessMode, mode PersistentVolumeAccessMode) bool {
|
||||
func containsAccessMode(modes []api.PersistentVolumeAccessMode, mode api.PersistentVolumeAccessMode) bool {
|
||||
for _, m := range modes {
|
||||
if m == mode {
|
||||
return true
|
||||
@@ -397,7 +376,7 @@ func ParseRFC3339(s string, nowFn func() metav1.Time) (metav1.Time, error) {
|
||||
|
||||
// NodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements
|
||||
// labels.Selector.
|
||||
func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.Selector, error) {
|
||||
func NodeSelectorRequirementsAsSelector(nsm []api.NodeSelectorRequirement) (labels.Selector, error) {
|
||||
if len(nsm) == 0 {
|
||||
return labels.Nothing(), nil
|
||||
}
|
||||
@@ -405,17 +384,17 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
|
||||
for _, expr := range nsm {
|
||||
var op selection.Operator
|
||||
switch expr.Operator {
|
||||
case NodeSelectorOpIn:
|
||||
case api.NodeSelectorOpIn:
|
||||
op = selection.In
|
||||
case NodeSelectorOpNotIn:
|
||||
case api.NodeSelectorOpNotIn:
|
||||
op = selection.NotIn
|
||||
case NodeSelectorOpExists:
|
||||
case api.NodeSelectorOpExists:
|
||||
op = selection.Exists
|
||||
case NodeSelectorOpDoesNotExist:
|
||||
case api.NodeSelectorOpDoesNotExist:
|
||||
op = selection.DoesNotExist
|
||||
case NodeSelectorOpGt:
|
||||
case api.NodeSelectorOpGt:
|
||||
op = selection.GreaterThan
|
||||
case NodeSelectorOpLt:
|
||||
case api.NodeSelectorOpLt:
|
||||
op = selection.LessThan
|
||||
default:
|
||||
return nil, fmt.Errorf("%q is not a valid node selector operator", expr.Operator)
|
||||
@@ -431,10 +410,10 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
|
||||
|
||||
// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
|
||||
// and converts it to the []Toleration type in api.
|
||||
func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
|
||||
var tolerations []Toleration
|
||||
if len(annotations) > 0 && annotations[TolerationsAnnotationKey] != "" {
|
||||
err := json.Unmarshal([]byte(annotations[TolerationsAnnotationKey]), &tolerations)
|
||||
func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]api.Toleration, error) {
|
||||
var tolerations []api.Toleration
|
||||
if len(annotations) > 0 && annotations[api.TolerationsAnnotationKey] != "" {
|
||||
err := json.Unmarshal([]byte(annotations[api.TolerationsAnnotationKey]), &tolerations)
|
||||
if err != nil {
|
||||
return tolerations, err
|
||||
}
|
||||
@@ -444,10 +423,10 @@ func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Tolerati
|
||||
|
||||
// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list.
|
||||
// Returns true if something was updated, false otherwise.
|
||||
func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) bool {
|
||||
func AddOrUpdateTolerationInPod(pod *api.Pod, toleration *api.Toleration) bool {
|
||||
podTolerations := pod.Spec.Tolerations
|
||||
|
||||
var newTolerations []Toleration
|
||||
var newTolerations []api.Toleration
|
||||
updated := false
|
||||
for i := range podTolerations {
|
||||
if toleration.MatchToleration(&podTolerations[i]) {
|
||||
@@ -470,18 +449,8 @@ func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MatchToleration checks if the toleration matches tolerationToMatch. Tolerations are unique by <key,effect,operator,value>,
|
||||
// if the two tolerations have same <key,effect,operator,value> combination, regard as they match.
|
||||
// TODO: uniqueness check for tolerations in api validations.
|
||||
func (t *Toleration) MatchToleration(tolerationToMatch *Toleration) bool {
|
||||
return t.Key == tolerationToMatch.Key &&
|
||||
t.Effect == tolerationToMatch.Effect &&
|
||||
t.Operator == tolerationToMatch.Operator &&
|
||||
t.Value == tolerationToMatch.Value
|
||||
}
|
||||
|
||||
// TolerationToleratesTaint checks if the toleration tolerates the taint.
|
||||
func TolerationToleratesTaint(toleration *Toleration, taint *Taint) bool {
|
||||
func TolerationToleratesTaint(toleration *api.Toleration, taint *api.Taint) bool {
|
||||
if len(toleration.Effect) != 0 && toleration.Effect != taint.Effect {
|
||||
return false
|
||||
}
|
||||
@@ -490,17 +459,17 @@ func TolerationToleratesTaint(toleration *Toleration, taint *Taint) bool {
|
||||
return false
|
||||
}
|
||||
// TODO: Use proper defaulting when Toleration becomes a field of PodSpec
|
||||
if (len(toleration.Operator) == 0 || toleration.Operator == TolerationOpEqual) && toleration.Value == taint.Value {
|
||||
if (len(toleration.Operator) == 0 || toleration.Operator == api.TolerationOpEqual) && toleration.Value == taint.Value {
|
||||
return true
|
||||
}
|
||||
if toleration.Operator == TolerationOpExists {
|
||||
if toleration.Operator == api.TolerationOpExists {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TaintToleratedByTolerations checks if taint is tolerated by any of the tolerations.
|
||||
func TaintToleratedByTolerations(taint *Taint, tolerations []Toleration) bool {
|
||||
func TaintToleratedByTolerations(taint *api.Taint, tolerations []api.Toleration) bool {
|
||||
tolerated := false
|
||||
for i := range tolerations {
|
||||
if TolerationToleratesTaint(&tolerations[i], taint) {
|
||||
@@ -511,28 +480,14 @@ func TaintToleratedByTolerations(taint *Taint, tolerations []Toleration) bool {
|
||||
return tolerated
|
||||
}
|
||||
|
||||
// MatchTaint checks if the taint matches taintToMatch. Taints are unique by key:effect,
|
||||
// if the two taints have same key:effect, regard as they match.
|
||||
func (t *Taint) MatchTaint(taintToMatch Taint) bool {
|
||||
return t.Key == taintToMatch.Key && t.Effect == taintToMatch.Effect
|
||||
}
|
||||
|
||||
// taint.ToString() converts taint struct to string in format key=value:effect or key:effect.
|
||||
func (t *Taint) ToString() string {
|
||||
if len(t.Value) == 0 {
|
||||
return fmt.Sprintf("%v:%v", t.Key, t.Effect)
|
||||
}
|
||||
return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect)
|
||||
}
|
||||
|
||||
// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations
|
||||
// and converts it to the []Taint type in api.
|
||||
func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]Taint, error) {
|
||||
var taints []Taint
|
||||
if len(annotations) > 0 && annotations[TaintsAnnotationKey] != "" {
|
||||
err := json.Unmarshal([]byte(annotations[TaintsAnnotationKey]), &taints)
|
||||
func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]api.Taint, error) {
|
||||
var taints []api.Taint
|
||||
if len(annotations) > 0 && annotations[api.TaintsAnnotationKey] != "" {
|
||||
err := json.Unmarshal([]byte(annotations[api.TaintsAnnotationKey]), &taints)
|
||||
if err != nil {
|
||||
return []Taint{}, err
|
||||
return []api.Taint{}, err
|
||||
}
|
||||
}
|
||||
return taints, nil
|
||||
@@ -541,12 +496,12 @@ func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]Taint, error
|
||||
// SysctlsFromPodAnnotations parses the sysctl annotations into a slice of safe Sysctls
|
||||
// and a slice of unsafe Sysctls. This is only a convenience wrapper around
|
||||
// SysctlsFromPodAnnotation.
|
||||
func SysctlsFromPodAnnotations(a map[string]string) ([]Sysctl, []Sysctl, error) {
|
||||
safe, err := SysctlsFromPodAnnotation(a[SysctlsPodAnnotationKey])
|
||||
func SysctlsFromPodAnnotations(a map[string]string) ([]api.Sysctl, []api.Sysctl, error) {
|
||||
safe, err := SysctlsFromPodAnnotation(a[api.SysctlsPodAnnotationKey])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
unsafe, err := SysctlsFromPodAnnotation(a[UnsafeSysctlsPodAnnotationKey])
|
||||
unsafe, err := SysctlsFromPodAnnotation(a[api.UnsafeSysctlsPodAnnotationKey])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -555,13 +510,13 @@ func SysctlsFromPodAnnotations(a map[string]string) ([]Sysctl, []Sysctl, error)
|
||||
}
|
||||
|
||||
// SysctlsFromPodAnnotation parses an annotation value into a slice of Sysctls.
|
||||
func SysctlsFromPodAnnotation(annotation string) ([]Sysctl, error) {
|
||||
func SysctlsFromPodAnnotation(annotation string) ([]api.Sysctl, error) {
|
||||
if len(annotation) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
kvs := strings.Split(annotation, ",")
|
||||
sysctls := make([]Sysctl, len(kvs))
|
||||
sysctls := make([]api.Sysctl, len(kvs))
|
||||
for i, kv := range kvs {
|
||||
cs := strings.Split(kv, "=")
|
||||
if len(cs) != 2 || len(cs[0]) == 0 {
|
||||
@@ -574,7 +529,7 @@ func SysctlsFromPodAnnotation(annotation string) ([]Sysctl, error) {
|
||||
}
|
||||
|
||||
// PodAnnotationsFromSysctls creates an annotation value for a slice of Sysctls.
|
||||
func PodAnnotationsFromSysctls(sysctls []Sysctl) string {
|
||||
func PodAnnotationsFromSysctls(sysctls []api.Sysctl) string {
|
||||
if len(sysctls) == 0 {
|
||||
return ""
|
||||
}
|
||||
@@ -589,10 +544,10 @@ func PodAnnotationsFromSysctls(sysctls []Sysctl) string {
|
||||
// GetAffinityFromPodAnnotations gets the json serialized affinity data from Pod.Annotations
|
||||
// and converts it to the Affinity type in api.
|
||||
// TODO: remove when alpha support for affinity is removed
|
||||
func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) {
|
||||
if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" {
|
||||
var affinity Affinity
|
||||
err := json.Unmarshal([]byte(annotations[AffinityAnnotationKey]), &affinity)
|
||||
func GetAffinityFromPodAnnotations(annotations map[string]string) (*api.Affinity, error) {
|
||||
if len(annotations) > 0 && annotations[api.AffinityAnnotationKey] != "" {
|
||||
var affinity api.Affinity
|
||||
err := json.Unmarshal([]byte(annotations[api.AffinityAnnotationKey]), &affinity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -602,9 +557,9 @@ func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, er
|
||||
}
|
||||
|
||||
// GetPersistentVolumeClass returns StorageClassName.
|
||||
func GetPersistentVolumeClass(volume *PersistentVolume) string {
|
||||
func GetPersistentVolumeClass(volume *api.PersistentVolume) string {
|
||||
// Use beta annotation first
|
||||
if class, found := volume.Annotations[BetaStorageClassAnnotation]; found {
|
||||
if class, found := volume.Annotations[api.BetaStorageClassAnnotation]; found {
|
||||
return class
|
||||
}
|
||||
|
||||
@@ -613,9 +568,9 @@ func GetPersistentVolumeClass(volume *PersistentVolume) string {
|
||||
|
||||
// GetPersistentVolumeClaimClass returns StorageClassName. If no storage class was
|
||||
// requested, it returns "".
|
||||
func GetPersistentVolumeClaimClass(claim *PersistentVolumeClaim) string {
|
||||
func GetPersistentVolumeClaimClass(claim *api.PersistentVolumeClaim) string {
|
||||
// Use beta annotation first
|
||||
if class, found := claim.Annotations[BetaStorageClassAnnotation]; found {
|
||||
if class, found := claim.Annotations[api.BetaStorageClassAnnotation]; found {
|
||||
return class
|
||||
}
|
||||
|
||||
@@ -627,9 +582,9 @@ func GetPersistentVolumeClaimClass(claim *PersistentVolumeClaim) string {
|
||||
}
|
||||
|
||||
// PersistentVolumeClaimHasClass returns true if given claim has set StorageClassName field.
|
||||
func PersistentVolumeClaimHasClass(claim *PersistentVolumeClaim) bool {
|
||||
func PersistentVolumeClaimHasClass(claim *api.PersistentVolumeClaim) bool {
|
||||
// Use beta annotation first
|
||||
if _, found := claim.Annotations[BetaStorageClassAnnotation]; found {
|
||||
if _, found := claim.Annotations[api.BetaStorageClassAnnotation]; found {
|
||||
return true
|
||||
}
|
||||
|
||||
268
pkg/api/helper/helpers_test.go
Normal file
268
pkg/api/helper/helpers_test.go
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package helper
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
func TestSemantic(t *testing.T) {
|
||||
table := []struct {
|
||||
a, b interface{}
|
||||
shouldEqual bool
|
||||
}{
|
||||
{resource.MustParse("0"), resource.Quantity{}, true},
|
||||
{resource.Quantity{}, resource.MustParse("0"), true},
|
||||
{resource.Quantity{}, resource.MustParse("1m"), false},
|
||||
{
|
||||
resource.NewQuantity(5, resource.BinarySI),
|
||||
resource.NewQuantity(5, resource.DecimalSI),
|
||||
true,
|
||||
},
|
||||
{resource.MustParse("2m"), resource.MustParse("1m"), false},
|
||||
}
|
||||
|
||||
for index, item := range table {
|
||||
if e, a := item.shouldEqual, Semantic.DeepEqual(item.a, item.b); e != a {
|
||||
t.Errorf("case[%d], expected %v, got %v.", index, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsStandardResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
output bool
|
||||
}{
|
||||
{"cpu", true},
|
||||
{"memory", true},
|
||||
{"disk", false},
|
||||
{"blah", false},
|
||||
{"x.y.z", false},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
if IsStandardResourceName(tc.input) != tc.output {
|
||||
t.Errorf("case[%d], expected: %t, got: %t", i, tc.output, !tc.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddToNodeAddresses(t *testing.T) {
|
||||
testCases := []struct {
|
||||
existing []api.NodeAddress
|
||||
toAdd []api.NodeAddress
|
||||
expected []api.NodeAddress
|
||||
}{
|
||||
{
|
||||
existing: []api.NodeAddress{},
|
||||
toAdd: []api.NodeAddress{},
|
||||
expected: []api.NodeAddress{},
|
||||
},
|
||||
{
|
||||
existing: []api.NodeAddress{},
|
||||
toAdd: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: api.NodeHostName, Address: "localhost"},
|
||||
},
|
||||
expected: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: api.NodeHostName, Address: "localhost"},
|
||||
},
|
||||
},
|
||||
{
|
||||
existing: []api.NodeAddress{},
|
||||
toAdd: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
},
|
||||
expected: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
existing: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: api.NodeInternalIP, Address: "10.1.1.1"},
|
||||
},
|
||||
toAdd: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: api.NodeHostName, Address: "localhost"},
|
||||
},
|
||||
expected: []api.NodeAddress{
|
||||
{Type: api.NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: api.NodeInternalIP, Address: "10.1.1.1"},
|
||||
{Type: api.NodeHostName, Address: "localhost"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
AddToNodeAddresses(&tc.existing, tc.toAdd...)
|
||||
if !Semantic.DeepEqual(tc.expected, tc.existing) {
|
||||
t.Errorf("case[%d], expected: %v, got: %v", i, tc.expected, tc.existing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccessModesFromString(t *testing.T) {
|
||||
modes := GetAccessModesFromString("ROX")
|
||||
if !containsAccessMode(modes, api.ReadOnlyMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", api.ReadOnlyMany, modes)
|
||||
}
|
||||
|
||||
modes = GetAccessModesFromString("ROX,RWX")
|
||||
if !containsAccessMode(modes, api.ReadOnlyMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", api.ReadOnlyMany, modes)
|
||||
}
|
||||
if !containsAccessMode(modes, api.ReadWriteMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", api.ReadWriteMany, modes)
|
||||
}
|
||||
|
||||
modes = GetAccessModesFromString("RWO,ROX,RWX")
|
||||
if !containsAccessMode(modes, api.ReadOnlyMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", api.ReadOnlyMany, modes)
|
||||
}
|
||||
if !containsAccessMode(modes, api.ReadWriteMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", api.ReadWriteMany, modes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveDuplicateAccessModes(t *testing.T) {
|
||||
modes := []api.PersistentVolumeAccessMode{
|
||||
api.ReadWriteOnce, api.ReadOnlyMany, api.ReadOnlyMany, api.ReadOnlyMany,
|
||||
}
|
||||
modes = removeDuplicateAccessModes(modes)
|
||||
if len(modes) != 2 {
|
||||
t.Errorf("Expected 2 distinct modes in set but found %v", len(modes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeSelectorRequirementsAsSelector(t *testing.T) {
|
||||
matchExpressions := []api.NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpIn,
|
||||
Values: []string{"bar", "baz"},
|
||||
}}
|
||||
mustParse := func(s string) labels.Selector {
|
||||
out, e := labels.Parse(s)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return out
|
||||
}
|
||||
tc := []struct {
|
||||
in []api.NodeSelectorRequirement
|
||||
out labels.Selector
|
||||
expectErr bool
|
||||
}{
|
||||
{in: nil, out: labels.Nothing()},
|
||||
{in: []api.NodeSelectorRequirement{}, out: labels.Nothing()},
|
||||
{
|
||||
in: matchExpressions,
|
||||
out: mustParse("foo in (baz,bar)"),
|
||||
},
|
||||
{
|
||||
in: []api.NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpExists,
|
||||
Values: []string{"bar", "baz"},
|
||||
}},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
in: []api.NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpGt,
|
||||
Values: []string{"1"},
|
||||
}},
|
||||
out: mustParse("foo>1"),
|
||||
},
|
||||
{
|
||||
in: []api.NodeSelectorRequirement{{
|
||||
Key: "bar",
|
||||
Operator: api.NodeSelectorOpLt,
|
||||
Values: []string{"7"},
|
||||
}},
|
||||
out: mustParse("bar<7"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tc {
|
||||
out, err := NodeSelectorRequirementsAsSelector(tc.in)
|
||||
if err == nil && tc.expectErr {
|
||||
t.Errorf("[%v]expected error but got none.", i)
|
||||
}
|
||||
if err != nil && !tc.expectErr {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.out) {
|
||||
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSysctlsFromPodAnnotation(t *testing.T) {
|
||||
type Test struct {
|
||||
annotation string
|
||||
expectValue []api.Sysctl
|
||||
expectErr bool
|
||||
}
|
||||
for i, test := range []Test{
|
||||
{
|
||||
annotation: "",
|
||||
expectValue: nil,
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
annotation: "=123",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=",
|
||||
expectValue: []api.Sysctl{{Name: "foo.bar", Value: ""}},
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=42",
|
||||
expectValue: []api.Sysctl{{Name: "foo.bar", Value: "42"}},
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=42,",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=42,abc.def=1",
|
||||
expectValue: []api.Sysctl{{Name: "foo.bar", Value: "42"}, {Name: "abc.def", Value: "1"}},
|
||||
},
|
||||
} {
|
||||
sysctls, err := SysctlsFromPodAnnotation(test.annotation)
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("[%v]expected error but got none", i)
|
||||
} else if !test.expectErr && err != nil {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
} else if !reflect.DeepEqual(sysctls, test.expectValue) {
|
||||
t.Errorf("[%v]expect value %v but got %v", i, test.expectValue, sysctls)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func TestConversionError(t *testing.T) {
|
||||
var i int
|
||||
var s string
|
||||
i = 3
|
||||
s = "foo"
|
||||
c := ConversionError{
|
||||
In: &i, Out: &s,
|
||||
Message: "Can't make x into y, silly",
|
||||
}
|
||||
var e error
|
||||
e = &c // ensure it implements error
|
||||
msg := e.Error()
|
||||
t.Logf("Message is %v", msg)
|
||||
for _, part := range []string{"3", "int", "string", "Can't"} {
|
||||
if !strings.Contains(msg, part) {
|
||||
t.Errorf("didn't find %v", part)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSemantic(t *testing.T) {
|
||||
table := []struct {
|
||||
a, b interface{}
|
||||
shouldEqual bool
|
||||
}{
|
||||
{resource.MustParse("0"), resource.Quantity{}, true},
|
||||
{resource.Quantity{}, resource.MustParse("0"), true},
|
||||
{resource.Quantity{}, resource.MustParse("1m"), false},
|
||||
{
|
||||
resource.NewQuantity(5, resource.BinarySI),
|
||||
resource.NewQuantity(5, resource.DecimalSI),
|
||||
true,
|
||||
},
|
||||
{resource.MustParse("2m"), resource.MustParse("1m"), false},
|
||||
}
|
||||
|
||||
for index, item := range table {
|
||||
if e, a := item.shouldEqual, Semantic.DeepEqual(item.a, item.b); e != a {
|
||||
t.Errorf("case[%d], expected %v, got %v.", index, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsStandardResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
output bool
|
||||
}{
|
||||
{"cpu", true},
|
||||
{"memory", true},
|
||||
{"disk", false},
|
||||
{"blah", false},
|
||||
{"x.y.z", false},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
if IsStandardResourceName(tc.input) != tc.output {
|
||||
t.Errorf("case[%d], expected: %t, got: %t", i, tc.output, !tc.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddToNodeAddresses(t *testing.T) {
|
||||
testCases := []struct {
|
||||
existing []NodeAddress
|
||||
toAdd []NodeAddress
|
||||
expected []NodeAddress
|
||||
}{
|
||||
{
|
||||
existing: []NodeAddress{},
|
||||
toAdd: []NodeAddress{},
|
||||
expected: []NodeAddress{},
|
||||
},
|
||||
{
|
||||
existing: []NodeAddress{},
|
||||
toAdd: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: NodeHostName, Address: "localhost"},
|
||||
},
|
||||
expected: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: NodeHostName, Address: "localhost"},
|
||||
},
|
||||
},
|
||||
{
|
||||
existing: []NodeAddress{},
|
||||
toAdd: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
},
|
||||
expected: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
existing: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: NodeInternalIP, Address: "10.1.1.1"},
|
||||
},
|
||||
toAdd: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: NodeHostName, Address: "localhost"},
|
||||
},
|
||||
expected: []NodeAddress{
|
||||
{Type: NodeExternalIP, Address: "1.1.1.1"},
|
||||
{Type: NodeInternalIP, Address: "10.1.1.1"},
|
||||
{Type: NodeHostName, Address: "localhost"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
AddToNodeAddresses(&tc.existing, tc.toAdd...)
|
||||
if !Semantic.DeepEqual(tc.expected, tc.existing) {
|
||||
t.Errorf("case[%d], expected: %v, got: %v", i, tc.expected, tc.existing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccessModesFromString(t *testing.T) {
|
||||
modes := GetAccessModesFromString("ROX")
|
||||
if !containsAccessMode(modes, ReadOnlyMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", ReadOnlyMany, modes)
|
||||
}
|
||||
|
||||
modes = GetAccessModesFromString("ROX,RWX")
|
||||
if !containsAccessMode(modes, ReadOnlyMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", ReadOnlyMany, modes)
|
||||
}
|
||||
if !containsAccessMode(modes, ReadWriteMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", ReadWriteMany, modes)
|
||||
}
|
||||
|
||||
modes = GetAccessModesFromString("RWO,ROX,RWX")
|
||||
if !containsAccessMode(modes, ReadOnlyMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", ReadOnlyMany, modes)
|
||||
}
|
||||
if !containsAccessMode(modes, ReadWriteMany) {
|
||||
t.Errorf("Expected mode %s, but got %+v", ReadWriteMany, modes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveDuplicateAccessModes(t *testing.T) {
|
||||
modes := []PersistentVolumeAccessMode{
|
||||
ReadWriteOnce, ReadOnlyMany, ReadOnlyMany, ReadOnlyMany,
|
||||
}
|
||||
modes = removeDuplicateAccessModes(modes)
|
||||
if len(modes) != 2 {
|
||||
t.Errorf("Expected 2 distinct modes in set but found %v", len(modes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeSelectorRequirementsAsSelector(t *testing.T) {
|
||||
matchExpressions := []NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: NodeSelectorOpIn,
|
||||
Values: []string{"bar", "baz"},
|
||||
}}
|
||||
mustParse := func(s string) labels.Selector {
|
||||
out, e := labels.Parse(s)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return out
|
||||
}
|
||||
tc := []struct {
|
||||
in []NodeSelectorRequirement
|
||||
out labels.Selector
|
||||
expectErr bool
|
||||
}{
|
||||
{in: nil, out: labels.Nothing()},
|
||||
{in: []NodeSelectorRequirement{}, out: labels.Nothing()},
|
||||
{
|
||||
in: matchExpressions,
|
||||
out: mustParse("foo in (baz,bar)"),
|
||||
},
|
||||
{
|
||||
in: []NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: NodeSelectorOpExists,
|
||||
Values: []string{"bar", "baz"},
|
||||
}},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
in: []NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: NodeSelectorOpGt,
|
||||
Values: []string{"1"},
|
||||
}},
|
||||
out: mustParse("foo>1"),
|
||||
},
|
||||
{
|
||||
in: []NodeSelectorRequirement{{
|
||||
Key: "bar",
|
||||
Operator: NodeSelectorOpLt,
|
||||
Values: []string{"7"},
|
||||
}},
|
||||
out: mustParse("bar<7"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tc {
|
||||
out, err := NodeSelectorRequirementsAsSelector(tc.in)
|
||||
if err == nil && tc.expectErr {
|
||||
t.Errorf("[%v]expected error but got none.", i)
|
||||
}
|
||||
if err != nil && !tc.expectErr {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.out) {
|
||||
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaintToString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
taint *Taint
|
||||
expectedString string
|
||||
}{
|
||||
{
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectedString: "foo=bar:NoSchedule",
|
||||
},
|
||||
{
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectedString: "foo:NoSchedule",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
if tc.expectedString != tc.taint.ToString() {
|
||||
t.Errorf("[%v] expected taint %v converted to %s, got %s", i, tc.taint, tc.expectedString, tc.taint.ToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchTaint(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
taint *Taint
|
||||
taintToMatch Taint
|
||||
expectMatch bool
|
||||
}{
|
||||
{
|
||||
description: "two taints with the same key,value,effect should match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
description: "two taints with the same key,effect but different value should match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "foo",
|
||||
Value: "different-value",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
description: "two taints with the different key cannot match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "different-key",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectMatch: false,
|
||||
},
|
||||
{
|
||||
description: "two taints with the different effect cannot match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectPreferNoSchedule,
|
||||
},
|
||||
expectMatch: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if tc.expectMatch != tc.taint.MatchTaint(tc.taintToMatch) {
|
||||
t.Errorf("[%s] expect taint %s match taint %s", tc.description, tc.taint.ToString(), tc.taintToMatch.ToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSysctlsFromPodAnnotation(t *testing.T) {
|
||||
type Test struct {
|
||||
annotation string
|
||||
expectValue []Sysctl
|
||||
expectErr bool
|
||||
}
|
||||
for i, test := range []Test{
|
||||
{
|
||||
annotation: "",
|
||||
expectValue: nil,
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
annotation: "=123",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=",
|
||||
expectValue: []Sysctl{{Name: "foo.bar", Value: ""}},
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=42",
|
||||
expectValue: []Sysctl{{Name: "foo.bar", Value: "42"}},
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=42,",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
annotation: "foo.bar=42,abc.def=1",
|
||||
expectValue: []Sysctl{{Name: "foo.bar", Value: "42"}, {Name: "abc.def", Value: "1"}},
|
||||
},
|
||||
} {
|
||||
sysctls, err := SysctlsFromPodAnnotation(test.annotation)
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("[%v]expected error but got none", i)
|
||||
} else if !test.expectErr && err != nil {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
} else if !reflect.DeepEqual(sysctls, test.expectValue) {
|
||||
t.Errorf("[%v]expect value %v but got %v", i, test.expectValue, sysctls)
|
||||
}
|
||||
}
|
||||
}
|
||||
46
pkg/api/methods.go
Normal file
46
pkg/api/methods.go
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
//TODO: consider making these methods functions, because we don't want helper
|
||||
//functions in the k8s.io/api repo.
|
||||
|
||||
package api
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MatchToleration checks if the toleration matches tolerationToMatch. Tolerations are unique by <key,effect,operator,value>,
|
||||
// if the two tolerations have same <key,effect,operator,value> combination, regard as they match.
|
||||
// TODO: uniqueness check for tolerations in api validations.
|
||||
func (t *Toleration) MatchToleration(tolerationToMatch *Toleration) bool {
|
||||
return t.Key == tolerationToMatch.Key &&
|
||||
t.Effect == tolerationToMatch.Effect &&
|
||||
t.Operator == tolerationToMatch.Operator &&
|
||||
t.Value == tolerationToMatch.Value
|
||||
}
|
||||
|
||||
// MatchTaint checks if the taint matches taintToMatch. Taints are unique by key:effect,
|
||||
// if the two taints have same key:effect, regard as they match.
|
||||
func (t *Taint) MatchTaint(taintToMatch Taint) bool {
|
||||
return t.Key == taintToMatch.Key && t.Effect == taintToMatch.Effect
|
||||
}
|
||||
|
||||
// taint.ToString() converts taint struct to string in format key=value:effect or key:effect.
|
||||
func (t *Taint) ToString() string {
|
||||
if len(t.Value) == 0 {
|
||||
return fmt.Sprintf("%v:%v", t.Key, t.Effect)
|
||||
}
|
||||
return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect)
|
||||
}
|
||||
120
pkg/api/methods_test.go
Normal file
120
pkg/api/methods_test.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTaintToString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
taint *Taint
|
||||
expectedString string
|
||||
}{
|
||||
{
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectedString: "foo=bar:NoSchedule",
|
||||
},
|
||||
{
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectedString: "foo:NoSchedule",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
if tc.expectedString != tc.taint.ToString() {
|
||||
t.Errorf("[%v] expected taint %v converted to %s, got %s", i, tc.taint, tc.expectedString, tc.taint.ToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchTaint(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
taint *Taint
|
||||
taintToMatch Taint
|
||||
expectMatch bool
|
||||
}{
|
||||
{
|
||||
description: "two taints with the same key,value,effect should match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
description: "two taints with the same key,effect but different value should match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "foo",
|
||||
Value: "different-value",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
description: "two taints with the different key cannot match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "different-key",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
expectMatch: false,
|
||||
},
|
||||
{
|
||||
description: "two taints with the different effect cannot match",
|
||||
taint: &Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectNoSchedule,
|
||||
},
|
||||
taintToMatch: Taint{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: TaintEffectPreferNoSchedule,
|
||||
},
|
||||
expectMatch: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if tc.expectMatch != tc.taint.MatchTaint(tc.taintToMatch) {
|
||||
t.Errorf("[%s] expect taint %s match taint %s", tc.description, tc.taint.ToString(), tc.taintToMatch.ToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/helper:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/util:go_default_library",
|
||||
"//pkg/util/parsers:go_default_library",
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
)
|
||||
|
||||
// IsOpaqueIntResourceName returns true if the resource name has the opaque
|
||||
@@ -285,7 +286,7 @@ func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) bool {
|
||||
updated := false
|
||||
for i := range podTolerations {
|
||||
if toleration.MatchToleration(&podTolerations[i]) {
|
||||
if api.Semantic.DeepEqual(toleration, podTolerations[i]) {
|
||||
if helper.Semantic.DeepEqual(toleration, podTolerations[i]) {
|
||||
return false
|
||||
}
|
||||
newTolerations = append(newTolerations, *toleration)
|
||||
@@ -527,7 +528,7 @@ func AddOrUpdateTaint(node *Node, taint *Taint) (*Node, bool, error) {
|
||||
updated := false
|
||||
for i := range nodeTaints {
|
||||
if taint.MatchTaint(&nodeTaints[i]) {
|
||||
if api.Semantic.DeepEqual(taint, nodeTaints[i]) {
|
||||
if helper.Semantic.DeepEqual(taint, nodeTaints[i]) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
newTaints = append(newTaints, *taint)
|
||||
|
||||
@@ -12,7 +12,7 @@ go_library(
|
||||
srcs = ["validation.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/helper:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath
|
||||
func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := validateResourceName(value, fldPath)
|
||||
if len(strings.Split(value, "/")) == 1 {
|
||||
if !api.IsStandardContainerResourceName(value) {
|
||||
if !helper.IsStandardContainerResourceName(value) {
|
||||
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers"))
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func validateContainerResourceName(value string, fldPath *field.Path) field.Erro
|
||||
func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
|
||||
if api.IsIntegerResourceName(resource) {
|
||||
if helper.IsIntegerResourceName(resource) {
|
||||
if value.MilliValue()%int64(1000) != int64(0) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, value, isNotIntegerErrorMsg))
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
}
|
||||
|
||||
if len(strings.Split(value, "/")) == 1 {
|
||||
if !api.IsStandardResourceName(value) {
|
||||
if !helper.IsStandardResourceName(value) {
|
||||
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/helper:go_default_library",
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/api/util:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
@@ -67,6 +68,7 @@ go_test(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/helper:go_default_library",
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/testing:go_default_library",
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
apiservice "k8s.io/kubernetes/pkg/api/service"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/capabilities"
|
||||
@@ -115,13 +116,13 @@ func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.Pod
|
||||
allErrs = append(allErrs, ValidateSeccompPodAnnotations(annotations, fldPath)...)
|
||||
allErrs = append(allErrs, ValidateAppArmorPodAnnotations(annotations, spec, fldPath)...)
|
||||
|
||||
sysctls, err := api.SysctlsFromPodAnnotation(annotations[api.SysctlsPodAnnotationKey])
|
||||
sysctls, err := helper.SysctlsFromPodAnnotation(annotations[api.SysctlsPodAnnotationKey])
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Key(api.SysctlsPodAnnotationKey), annotations[api.SysctlsPodAnnotationKey], err.Error()))
|
||||
} else {
|
||||
allErrs = append(allErrs, validateSysctls(sysctls, fldPath.Key(api.SysctlsPodAnnotationKey))...)
|
||||
}
|
||||
unsafeSysctls, err := api.SysctlsFromPodAnnotation(annotations[api.UnsafeSysctlsPodAnnotationKey])
|
||||
unsafeSysctls, err := helper.SysctlsFromPodAnnotation(annotations[api.UnsafeSysctlsPodAnnotationKey])
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Key(api.UnsafeSysctlsPodAnnotationKey), annotations[api.UnsafeSysctlsPodAnnotationKey], err.Error()))
|
||||
} else {
|
||||
@@ -139,7 +140,7 @@ func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.Pod
|
||||
func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
tolerations, err := api.GetTolerationsFromPodAnnotations(annotations)
|
||||
tolerations, err := helper.GetTolerationsFromPodAnnotations(annotations)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, api.TolerationsAnnotationKey, err.Error()))
|
||||
return allErrs
|
||||
@@ -156,7 +157,7 @@ func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath
|
||||
func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
affinity, err := api.GetAffinityFromPodAnnotations(annotations)
|
||||
affinity, err := helper.GetAffinityFromPodAnnotations(annotations)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, api.AffinityAnnotationKey, err.Error()))
|
||||
return allErrs
|
||||
@@ -2625,7 +2626,7 @@ func validateServiceFields(service *api.Service) field.ErrorList {
|
||||
allErrs = append(allErrs, field.NotSupported(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List()))
|
||||
}
|
||||
|
||||
if api.IsServiceIPSet(service) {
|
||||
if helper.IsServiceIPSet(service) {
|
||||
if ip := net.ParseIP(service.Spec.ClusterIP); ip == nil {
|
||||
allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty, 'None', or a valid IP address"))
|
||||
}
|
||||
@@ -2958,7 +2959,7 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path)
|
||||
func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
taints, err := api.GetTaintsFromNodeAnnotations(annotations)
|
||||
taints, err := helper.GetTaintsFromNodeAnnotations(annotations)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, api.TaintsAnnotationKey, err.Error()))
|
||||
return allErrs
|
||||
@@ -3115,7 +3116,7 @@ func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
}
|
||||
|
||||
if len(strings.Split(value, "/")) == 1 {
|
||||
if !api.IsStandardResourceName(value) {
|
||||
if !helper.IsStandardResourceName(value) {
|
||||
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified"))
|
||||
}
|
||||
}
|
||||
@@ -3128,7 +3129,7 @@ func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := validateResourceName(value, fldPath)
|
||||
if len(strings.Split(value, "/")) == 1 {
|
||||
if !api.IsStandardContainerResourceName(value) {
|
||||
if !helper.IsStandardContainerResourceName(value) {
|
||||
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers"))
|
||||
}
|
||||
}
|
||||
@@ -3140,7 +3141,7 @@ func validateContainerResourceName(value string, fldPath *field.Path) field.Erro
|
||||
func ValidateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := validateResourceName(value, fldPath)
|
||||
if len(strings.Split(value, "/")) == 1 {
|
||||
if !api.IsStandardQuotaResourceName(value) {
|
||||
if !helper.IsStandardQuotaResourceName(value) {
|
||||
return append(allErrs, field.Invalid(fldPath, value, isInvalidQuotaResource))
|
||||
}
|
||||
}
|
||||
@@ -3158,7 +3159,7 @@ func validateLimitRangeTypeName(value string, fldPath *field.Path) field.ErrorLi
|
||||
}
|
||||
|
||||
if len(strings.Split(value, "/")) == 1 {
|
||||
if !api.IsStandardLimitRangeType(value) {
|
||||
if !helper.IsStandardLimitRangeType(value) {
|
||||
return append(allErrs, field.Invalid(fldPath, value, "must be a standard limit type or fully qualified"))
|
||||
}
|
||||
}
|
||||
@@ -3494,11 +3495,11 @@ func validateResourceQuotaScopes(resourceQuotaSpec *api.ResourceQuotaSpec, fld *
|
||||
fldPath := fld.Child("scopes")
|
||||
scopeSet := sets.NewString()
|
||||
for _, scope := range resourceQuotaSpec.Scopes {
|
||||
if !api.IsStandardResourceQuotaScope(string(scope)) {
|
||||
if !helper.IsStandardResourceQuotaScope(string(scope)) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope"))
|
||||
}
|
||||
for _, k := range hardLimits.List() {
|
||||
if api.IsStandardQuotaResourceName(k) && !api.IsResourceQuotaScopeValidForResource(scope, k) {
|
||||
if helper.IsStandardQuotaResourceName(k) && !helper.IsResourceQuotaScopeValidForResource(scope, k) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope applied to resource"))
|
||||
}
|
||||
}
|
||||
@@ -3563,7 +3564,7 @@ func ValidateResourceQuotaSpec(resourceQuotaSpec *api.ResourceQuotaSpec, fld *fi
|
||||
func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
|
||||
if api.IsIntegerResourceName(resource) {
|
||||
if helper.IsIntegerResourceName(resource) {
|
||||
if value.MilliValue()%int64(1000) != int64(0) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, value, isNotIntegerErrorMsg))
|
||||
}
|
||||
@@ -3641,7 +3642,7 @@ func validateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorL
|
||||
func validateKubeFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(strings.Split(stringValue, "/")) == 1 {
|
||||
if !api.IsStandardFinalizerName(stringValue) {
|
||||
if !helper.IsStandardFinalizerName(stringValue) {
|
||||
return append(allErrs, field.Invalid(fldPath, stringValue, "name is neither a standard finalizer name nor is it fully qualified"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
"k8s.io/kubernetes/pkg/api/service"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/capabilities"
|
||||
@@ -3712,10 +3713,10 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("10"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("10"),
|
||||
},
|
||||
Limits: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("20"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("20"),
|
||||
},
|
||||
},
|
||||
TerminationMessagePolicy: "File",
|
||||
@@ -3737,10 +3738,10 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("10"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("10"),
|
||||
},
|
||||
Limits: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("20"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("20"),
|
||||
},
|
||||
},
|
||||
TerminationMessagePolicy: "File",
|
||||
@@ -4211,10 +4212,10 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("2"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("2"),
|
||||
},
|
||||
Limits: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("1"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4233,7 +4234,7 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("500m"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("500m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4252,7 +4253,7 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("500m"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("500m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4272,10 +4273,10 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
},
|
||||
Limits: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("2.5"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("2.5"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4294,10 +4295,10 @@ func TestValidatePod(t *testing.T) {
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
},
|
||||
Limits: api.ResourceList{
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("2.5"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("2.5"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -6739,8 +6740,8 @@ func TestValidateNodeUpdate(t *testing.T) {
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
api.OpaqueIntResourceName("B"): resource.MustParse("10"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
helper.OpaqueIntResourceName("B"): resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
}, true},
|
||||
@@ -6756,7 +6757,7 @@ func TestValidateNodeUpdate(t *testing.T) {
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("500m"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("500m"),
|
||||
},
|
||||
},
|
||||
}, false},
|
||||
@@ -6772,12 +6773,12 @@ func TestValidateNodeUpdate(t *testing.T) {
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("5"),
|
||||
},
|
||||
Allocatable: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
|
||||
api.OpaqueIntResourceName("A"): resource.MustParse("4.5"),
|
||||
helper.OpaqueIntResourceName("A"): resource.MustParse("4.5"),
|
||||
},
|
||||
},
|
||||
}, false},
|
||||
|
||||
@@ -65,7 +65,6 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ContainerStateTerminated, InType: reflect.TypeOf(&ContainerStateTerminated{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ContainerStateWaiting, InType: reflect.TypeOf(&ContainerStateWaiting{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ContainerStatus, InType: reflect.TypeOf(&ContainerStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConversionError, InType: reflect.TypeOf(&ConversionError{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DaemonEndpoint, InType: reflect.TypeOf(&DaemonEndpoint{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeleteOptions, InType: reflect.TypeOf(&DeleteOptions{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DownwardAPIProjection, InType: reflect.TypeOf(&DownwardAPIProjection{})},
|
||||
@@ -707,31 +706,6 @@ func DeepCopy_api_ContainerStatus(in interface{}, out interface{}, c *conversion
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ConversionError(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ConversionError)
|
||||
out := out.(*ConversionError)
|
||||
*out = *in
|
||||
// in.In is kind 'Interface'
|
||||
if in.In != nil {
|
||||
if newVal, err := c.DeepCopy(&in.In); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.In = *newVal.(*interface{})
|
||||
}
|
||||
}
|
||||
// in.Out is kind 'Interface'
|
||||
if in.Out != nil {
|
||||
if newVal, err := c.DeepCopy(&in.Out); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.Out = *newVal.(*interface{})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_DaemonEndpoint(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*DaemonEndpoint)
|
||||
|
||||
Reference in New Issue
Block a user