github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/api/helpers.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package api 18 19 import ( 20 "crypto/md5" 21 "encoding/json" 22 "fmt" 23 "reflect" 24 "strings" 25 "time" 26 27 "k8s.io/kubernetes/pkg/api/resource" 28 "k8s.io/kubernetes/pkg/api/unversioned" 29 "k8s.io/kubernetes/pkg/conversion" 30 "k8s.io/kubernetes/pkg/fields" 31 "k8s.io/kubernetes/pkg/labels" 32 "k8s.io/kubernetes/pkg/runtime" 33 "k8s.io/kubernetes/pkg/types" 34 "k8s.io/kubernetes/pkg/util/sets" 35 36 "github.com/davecgh/go-spew/spew" 37 ) 38 39 // Conversion error conveniently packages up errors in conversions. 40 type ConversionError struct { 41 In, Out interface{} 42 Message string 43 } 44 45 // Return a helpful string about the error 46 func (c *ConversionError) Error() string { 47 return spew.Sprintf( 48 "Conversion error: %s. (in: %v(%+v) out: %v)", 49 c.Message, reflect.TypeOf(c.In), c.In, reflect.TypeOf(c.Out), 50 ) 51 } 52 53 // Semantic can do semantic deep equality checks for api objects. 54 // Example: api.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true 55 var Semantic = conversion.EqualitiesOrDie( 56 func(a, b resource.Quantity) bool { 57 // Ignore formatting, only care that numeric value stayed the same. 58 // TODO: if we decide it's important, it should be safe to start comparing the format. 59 // 60 // Uninitialized quantities are equivalent to 0 quantities. 61 if a.Amount == nil && b.MilliValue() == 0 { 62 return true 63 } 64 if b.Amount == nil && a.MilliValue() == 0 { 65 return true 66 } 67 if a.Amount == nil || b.Amount == nil { 68 return false 69 } 70 return a.Amount.Cmp(b.Amount) == 0 71 }, 72 func(a, b unversioned.Time) bool { 73 return a.UTC() == b.UTC() 74 }, 75 func(a, b labels.Selector) bool { 76 return a.String() == b.String() 77 }, 78 func(a, b fields.Selector) bool { 79 return a.String() == b.String() 80 }, 81 ) 82 83 var standardResourceQuotaScopes = sets.NewString( 84 string(ResourceQuotaScopeTerminating), 85 string(ResourceQuotaScopeNotTerminating), 86 string(ResourceQuotaScopeBestEffort), 87 string(ResourceQuotaScopeNotBestEffort), 88 ) 89 90 // IsStandardResourceQuotaScope returns true if the scope is a standard value 91 func IsStandardResourceQuotaScope(str string) bool { 92 return standardResourceQuotaScopes.Has(str) 93 } 94 95 var podObjectCountQuotaResources = sets.NewString( 96 string(ResourcePods), 97 ) 98 99 var podComputeQuotaResources = sets.NewString( 100 string(ResourceCPU), 101 string(ResourceMemory), 102 string(ResourceLimitsCPU), 103 string(ResourceLimitsMemory), 104 string(ResourceRequestsCPU), 105 string(ResourceRequestsMemory), 106 ) 107 108 // IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope 109 func IsResourceQuotaScopeValidForResource(scope ResourceQuotaScope, resource string) bool { 110 switch scope { 111 case ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeNotBestEffort: 112 return podObjectCountQuotaResources.Has(resource) || podComputeQuotaResources.Has(resource) 113 case ResourceQuotaScopeBestEffort: 114 return podObjectCountQuotaResources.Has(resource) 115 default: 116 return true 117 } 118 } 119 120 var standardContainerResources = sets.NewString( 121 string(ResourceCPU), 122 string(ResourceMemory), 123 ) 124 125 // IsStandardContainerResourceName returns true if the container can make a resource request 126 // for the specified resource 127 func IsStandardContainerResourceName(str string) bool { 128 return standardContainerResources.Has(str) 129 } 130 131 var standardLimitRangeTypes = sets.NewString( 132 string(LimitTypePod), 133 string(LimitTypeContainer), 134 ) 135 136 // IsStandardLimitRangeType returns true if the type is Pod or Container 137 func IsStandardLimitRangeType(str string) bool { 138 return standardLimitRangeTypes.Has(str) 139 } 140 141 var standardQuotaResources = sets.NewString( 142 string(ResourceCPU), 143 string(ResourceMemory), 144 string(ResourceRequestsCPU), 145 string(ResourceRequestsMemory), 146 string(ResourceLimitsCPU), 147 string(ResourceLimitsMemory), 148 string(ResourcePods), 149 string(ResourceQuotas), 150 string(ResourceServices), 151 string(ResourceReplicationControllers), 152 string(ResourceSecrets), 153 string(ResourcePersistentVolumeClaims), 154 string(ResourceConfigMaps), 155 string(ResourceServicesNodePorts), 156 string(ResourceServicesLoadBalancers), 157 ) 158 159 // IsStandardQuotaResourceName returns true if the resource is known to 160 // the quota tracking system 161 func IsStandardQuotaResourceName(str string) bool { 162 return standardQuotaResources.Has(str) 163 } 164 165 var standardResources = sets.NewString( 166 string(ResourceCPU), 167 string(ResourceMemory), 168 string(ResourceRequestsCPU), 169 string(ResourceRequestsMemory), 170 string(ResourceLimitsCPU), 171 string(ResourceLimitsMemory), 172 string(ResourcePods), 173 string(ResourceQuotas), 174 string(ResourceServices), 175 string(ResourceReplicationControllers), 176 string(ResourceSecrets), 177 string(ResourceConfigMaps), 178 string(ResourcePersistentVolumeClaims), 179 string(ResourceStorage), 180 ) 181 182 // IsStandardResourceName returns true if the resource is known to the system 183 func IsStandardResourceName(str string) bool { 184 return standardResources.Has(str) 185 } 186 187 var integerResources = sets.NewString( 188 string(ResourcePods), 189 string(ResourceQuotas), 190 string(ResourceServices), 191 string(ResourceReplicationControllers), 192 string(ResourceSecrets), 193 string(ResourceConfigMaps), 194 string(ResourcePersistentVolumeClaims), 195 string(ResourceServicesNodePorts), 196 string(ResourceServicesLoadBalancers), 197 ) 198 199 // IsIntegerResourceName returns true if the resource is measured in integer values 200 func IsIntegerResourceName(str string) bool { 201 return integerResources.Has(str) 202 } 203 204 // NewDeleteOptions returns a DeleteOptions indicating the resource should 205 // be deleted within the specified grace period. Use zero to indicate 206 // immediate deletion. If you would prefer to use the default grace period, 207 // use &api.DeleteOptions{} directly. 208 func NewDeleteOptions(grace int64) *DeleteOptions { 209 return &DeleteOptions{GracePeriodSeconds: &grace} 210 } 211 212 // NewPreconditionDeleteOptions returns a DeleteOptions with a UID precondition set. 213 func NewPreconditionDeleteOptions(uid string) *DeleteOptions { 214 u := types.UID(uid) 215 p := Preconditions{UID: &u} 216 return &DeleteOptions{Preconditions: &p} 217 } 218 219 // NewUIDPreconditions returns a Preconditions with UID set. 220 func NewUIDPreconditions(uid string) *Preconditions { 221 u := types.UID(uid) 222 return &Preconditions{UID: &u} 223 } 224 225 // this function aims to check if the service's ClusterIP is set or not 226 // the objective is not to perform validation here 227 func IsServiceIPSet(service *Service) bool { 228 return service.Spec.ClusterIP != ClusterIPNone && service.Spec.ClusterIP != "" 229 } 230 231 // this function aims to check if the service's cluster IP is requested or not 232 func IsServiceIPRequested(service *Service) bool { 233 return service.Spec.ClusterIP == "" 234 } 235 236 var standardFinalizers = sets.NewString( 237 string(FinalizerKubernetes)) 238 239 func IsStandardFinalizerName(str string) bool { 240 return standardFinalizers.Has(str) 241 } 242 243 // SingleObject returns a ListOptions for watching a single object. 244 func SingleObject(meta ObjectMeta) ListOptions { 245 return ListOptions{ 246 FieldSelector: fields.OneTermEqualSelector("metadata.name", meta.Name), 247 ResourceVersion: meta.ResourceVersion, 248 } 249 } 250 251 // AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice, 252 // only if they do not already exist 253 func AddToNodeAddresses(addresses *[]NodeAddress, addAddresses ...NodeAddress) { 254 for _, add := range addAddresses { 255 exists := false 256 for _, existing := range *addresses { 257 if existing.Address == add.Address && existing.Type == add.Type { 258 exists = true 259 break 260 } 261 } 262 if !exists { 263 *addresses = append(*addresses, add) 264 } 265 } 266 } 267 268 func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) { 269 data, err := runtime.Encode(codec, obj) 270 if err != nil { 271 return "", err 272 } 273 return fmt.Sprintf("%x", md5.Sum(data)), nil 274 } 275 276 // TODO: make method on LoadBalancerStatus? 277 func LoadBalancerStatusEqual(l, r *LoadBalancerStatus) bool { 278 return ingressSliceEqual(l.Ingress, r.Ingress) 279 } 280 281 func ingressSliceEqual(lhs, rhs []LoadBalancerIngress) bool { 282 if len(lhs) != len(rhs) { 283 return false 284 } 285 for i := range lhs { 286 if !ingressEqual(&lhs[i], &rhs[i]) { 287 return false 288 } 289 } 290 return true 291 } 292 293 func ingressEqual(lhs, rhs *LoadBalancerIngress) bool { 294 if lhs.IP != rhs.IP { 295 return false 296 } 297 if lhs.Hostname != rhs.Hostname { 298 return false 299 } 300 return true 301 } 302 303 // TODO: make method on LoadBalancerStatus? 304 func LoadBalancerStatusDeepCopy(lb *LoadBalancerStatus) *LoadBalancerStatus { 305 c := &LoadBalancerStatus{} 306 c.Ingress = make([]LoadBalancerIngress, len(lb.Ingress)) 307 for i := range lb.Ingress { 308 c.Ingress[i] = lb.Ingress[i] 309 } 310 return c 311 } 312 313 // GetAccessModesAsString returns a string representation of an array of access modes. 314 // modes, when present, are always in the same order: RWO,ROX,RWX. 315 func GetAccessModesAsString(modes []PersistentVolumeAccessMode) string { 316 modes = removeDuplicateAccessModes(modes) 317 modesStr := []string{} 318 if containsAccessMode(modes, ReadWriteOnce) { 319 modesStr = append(modesStr, "RWO") 320 } 321 if containsAccessMode(modes, ReadOnlyMany) { 322 modesStr = append(modesStr, "ROX") 323 } 324 if containsAccessMode(modes, ReadWriteMany) { 325 modesStr = append(modesStr, "RWX") 326 } 327 return strings.Join(modesStr, ",") 328 } 329 330 // GetAccessModesAsString returns an array of AccessModes from a string created by GetAccessModesAsString 331 func GetAccessModesFromString(modes string) []PersistentVolumeAccessMode { 332 strmodes := strings.Split(modes, ",") 333 accessModes := []PersistentVolumeAccessMode{} 334 for _, s := range strmodes { 335 s = strings.Trim(s, " ") 336 switch { 337 case s == "RWO": 338 accessModes = append(accessModes, ReadWriteOnce) 339 case s == "ROX": 340 accessModes = append(accessModes, ReadOnlyMany) 341 case s == "RWX": 342 accessModes = append(accessModes, ReadWriteMany) 343 } 344 } 345 return accessModes 346 } 347 348 // removeDuplicateAccessModes returns an array of access modes without any duplicates 349 func removeDuplicateAccessModes(modes []PersistentVolumeAccessMode) []PersistentVolumeAccessMode { 350 accessModes := []PersistentVolumeAccessMode{} 351 for _, m := range modes { 352 if !containsAccessMode(accessModes, m) { 353 accessModes = append(accessModes, m) 354 } 355 } 356 return accessModes 357 } 358 359 func containsAccessMode(modes []PersistentVolumeAccessMode, mode PersistentVolumeAccessMode) bool { 360 for _, m := range modes { 361 if m == mode { 362 return true 363 } 364 } 365 return false 366 } 367 368 // ParseRFC3339 parses an RFC3339 date in either RFC3339Nano or RFC3339 format. 369 func ParseRFC3339(s string, nowFn func() unversioned.Time) (unversioned.Time, error) { 370 if t, timeErr := time.Parse(time.RFC3339Nano, s); timeErr == nil { 371 return unversioned.Time{Time: t}, nil 372 } 373 t, err := time.Parse(time.RFC3339, s) 374 if err != nil { 375 return unversioned.Time{}, err 376 } 377 return unversioned.Time{Time: t}, nil 378 } 379 380 // NodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements 381 // labels.Selector. 382 func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.Selector, error) { 383 if len(nsm) == 0 { 384 return labels.Nothing(), nil 385 } 386 selector := labels.NewSelector() 387 for _, expr := range nsm { 388 var op labels.Operator 389 switch expr.Operator { 390 case NodeSelectorOpIn: 391 op = labels.InOperator 392 case NodeSelectorOpNotIn: 393 op = labels.NotInOperator 394 case NodeSelectorOpExists: 395 op = labels.ExistsOperator 396 case NodeSelectorOpDoesNotExist: 397 op = labels.DoesNotExistOperator 398 case NodeSelectorOpGt: 399 op = labels.GreaterThanOperator 400 case NodeSelectorOpLt: 401 op = labels.LessThanOperator 402 default: 403 return nil, fmt.Errorf("%q is not a valid node selector operator", expr.Operator) 404 } 405 r, err := labels.NewRequirement(expr.Key, op, sets.NewString(expr.Values...)) 406 if err != nil { 407 return nil, err 408 } 409 selector = selector.Add(*r) 410 } 411 return selector, nil 412 } 413 414 // AffinityAnnotationKey represents the key of affinity data (json serialized) 415 // in the Annotations of a Pod. 416 const AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity" 417 418 // GetAffinityFromPod gets the json serialized affinity data from Pod.Annotations 419 // and converts it to the Affinity type in api. 420 func GetAffinityFromPodAnnotations(annotations map[string]string) (Affinity, error) { 421 var affinity Affinity 422 if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" { 423 err := json.Unmarshal([]byte(annotations[AffinityAnnotationKey]), &affinity) 424 if err != nil { 425 return affinity, err 426 } 427 } 428 return affinity, nil 429 }