github.com/timstclair/heapster@v0.20.0-alpha1/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 "fmt" 22 "reflect" 23 "strings" 24 "time" 25 26 "k8s.io/kubernetes/pkg/api/resource" 27 "k8s.io/kubernetes/pkg/api/unversioned" 28 "k8s.io/kubernetes/pkg/conversion" 29 "k8s.io/kubernetes/pkg/fields" 30 "k8s.io/kubernetes/pkg/labels" 31 "k8s.io/kubernetes/pkg/runtime" 32 "k8s.io/kubernetes/pkg/util/sets" 33 34 "github.com/davecgh/go-spew/spew" 35 ) 36 37 // Conversion error conveniently packages up errors in conversions. 38 type ConversionError struct { 39 In, Out interface{} 40 Message string 41 } 42 43 // Return a helpful string about the error 44 func (c *ConversionError) Error() string { 45 return spew.Sprintf( 46 "Conversion error: %s. (in: %v(%+v) out: %v)", 47 c.Message, reflect.TypeOf(c.In), c.In, reflect.TypeOf(c.Out), 48 ) 49 } 50 51 // Semantic can do semantic deep equality checks for api objects. 52 // Example: api.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true 53 var Semantic = conversion.EqualitiesOrDie( 54 func(a, b resource.Quantity) bool { 55 // Ignore formatting, only care that numeric value stayed the same. 56 // TODO: if we decide it's important, it should be safe to start comparing the format. 57 // 58 // Uninitialized quantities are equivalent to 0 quantities. 59 if a.Amount == nil && b.MilliValue() == 0 { 60 return true 61 } 62 if b.Amount == nil && a.MilliValue() == 0 { 63 return true 64 } 65 if a.Amount == nil || b.Amount == nil { 66 return false 67 } 68 return a.Amount.Cmp(b.Amount) == 0 69 }, 70 func(a, b unversioned.Time) bool { 71 return a.UTC() == b.UTC() 72 }, 73 func(a, b labels.Selector) bool { 74 return a.String() == b.String() 75 }, 76 func(a, b fields.Selector) bool { 77 return a.String() == b.String() 78 }, 79 ) 80 81 var standardResources = sets.NewString( 82 string(ResourceCPU), 83 string(ResourceMemory), 84 string(ResourcePods), 85 string(ResourceQuotas), 86 string(ResourceServices), 87 string(ResourceReplicationControllers), 88 string(ResourceSecrets), 89 string(ResourcePersistentVolumeClaims), 90 string(ResourceStorage), 91 ) 92 93 // IsStandardResourceName returns true if the resource is known to the system 94 func IsStandardResourceName(str string) bool { 95 return standardResources.Has(str) 96 } 97 98 var integerResources = sets.NewString( 99 string(ResourcePods), 100 string(ResourceQuotas), 101 string(ResourceServices), 102 string(ResourceReplicationControllers), 103 string(ResourceSecrets), 104 string(ResourcePersistentVolumeClaims), 105 ) 106 107 // IsIntegerResourceName returns true if the resource is measured in integer values 108 func IsIntegerResourceName(str string) bool { 109 return integerResources.Has(str) 110 } 111 112 // NewDeleteOptions returns a DeleteOptions indicating the resource should 113 // be deleted within the specified grace period. Use zero to indicate 114 // immediate deletion. If you would prefer to use the default grace period, 115 // use &api.DeleteOptions{} directly. 116 func NewDeleteOptions(grace int64) *DeleteOptions { 117 return &DeleteOptions{GracePeriodSeconds: &grace} 118 } 119 120 // this function aims to check if the service's ClusterIP is set or not 121 // the objective is not to perform validation here 122 func IsServiceIPSet(service *Service) bool { 123 return service.Spec.ClusterIP != ClusterIPNone && service.Spec.ClusterIP != "" 124 } 125 126 // this function aims to check if the service's cluster IP is requested or not 127 func IsServiceIPRequested(service *Service) bool { 128 return service.Spec.ClusterIP == "" 129 } 130 131 var standardFinalizers = sets.NewString( 132 string(FinalizerKubernetes)) 133 134 func IsStandardFinalizerName(str string) bool { 135 return standardFinalizers.Has(str) 136 } 137 138 // AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice, 139 // only if they do not already exist 140 func AddToNodeAddresses(addresses *[]NodeAddress, addAddresses ...NodeAddress) { 141 for _, add := range addAddresses { 142 exists := false 143 for _, existing := range *addresses { 144 if existing.Address == add.Address && existing.Type == add.Type { 145 exists = true 146 break 147 } 148 } 149 if !exists { 150 *addresses = append(*addresses, add) 151 } 152 } 153 } 154 155 func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) { 156 data, err := codec.Encode(obj) 157 if err != nil { 158 return "", err 159 } 160 return fmt.Sprintf("%x", md5.Sum(data)), nil 161 } 162 163 // TODO: make method on LoadBalancerStatus? 164 func LoadBalancerStatusEqual(l, r *LoadBalancerStatus) bool { 165 return ingressSliceEqual(l.Ingress, r.Ingress) 166 } 167 168 func ingressSliceEqual(lhs, rhs []LoadBalancerIngress) bool { 169 if len(lhs) != len(rhs) { 170 return false 171 } 172 for i := range lhs { 173 if !ingressEqual(&lhs[i], &rhs[i]) { 174 return false 175 } 176 } 177 return true 178 } 179 180 func ingressEqual(lhs, rhs *LoadBalancerIngress) bool { 181 if lhs.IP != rhs.IP { 182 return false 183 } 184 if lhs.Hostname != rhs.Hostname { 185 return false 186 } 187 return true 188 } 189 190 // TODO: make method on LoadBalancerStatus? 191 func LoadBalancerStatusDeepCopy(lb *LoadBalancerStatus) *LoadBalancerStatus { 192 c := &LoadBalancerStatus{} 193 c.Ingress = make([]LoadBalancerIngress, len(lb.Ingress)) 194 for i := range lb.Ingress { 195 c.Ingress[i] = lb.Ingress[i] 196 } 197 return c 198 } 199 200 // GetAccessModesAsString returns a string representation of an array of access modes. 201 // modes, when present, are always in the same order: RWO,ROX,RWX. 202 func GetAccessModesAsString(modes []PersistentVolumeAccessMode) string { 203 modes = removeDuplicateAccessModes(modes) 204 modesStr := []string{} 205 if containsAccessMode(modes, ReadWriteOnce) { 206 modesStr = append(modesStr, "RWO") 207 } 208 if containsAccessMode(modes, ReadOnlyMany) { 209 modesStr = append(modesStr, "ROX") 210 } 211 if containsAccessMode(modes, ReadWriteMany) { 212 modesStr = append(modesStr, "RWX") 213 } 214 return strings.Join(modesStr, ",") 215 } 216 217 // GetAccessModesAsString returns an array of AccessModes from a string created by GetAccessModesAsString 218 func GetAccessModesFromString(modes string) []PersistentVolumeAccessMode { 219 strmodes := strings.Split(modes, ",") 220 accessModes := []PersistentVolumeAccessMode{} 221 for _, s := range strmodes { 222 s = strings.Trim(s, " ") 223 switch { 224 case s == "RWO": 225 accessModes = append(accessModes, ReadWriteOnce) 226 case s == "ROX": 227 accessModes = append(accessModes, ReadOnlyMany) 228 case s == "RWX": 229 accessModes = append(accessModes, ReadWriteMany) 230 } 231 } 232 return accessModes 233 } 234 235 // removeDuplicateAccessModes returns an array of access modes without any duplicates 236 func removeDuplicateAccessModes(modes []PersistentVolumeAccessMode) []PersistentVolumeAccessMode { 237 accessModes := []PersistentVolumeAccessMode{} 238 for _, m := range modes { 239 if !containsAccessMode(accessModes, m) { 240 accessModes = append(accessModes, m) 241 } 242 } 243 return accessModes 244 } 245 246 func containsAccessMode(modes []PersistentVolumeAccessMode, mode PersistentVolumeAccessMode) bool { 247 for _, m := range modes { 248 if m == mode { 249 return true 250 } 251 } 252 return false 253 } 254 255 // ParseRFC3339 parses an RFC3339 date in either RFC3339Nano or RFC3339 format. 256 func ParseRFC3339(s string, nowFn func() unversioned.Time) (unversioned.Time, error) { 257 if t, timeErr := time.Parse(time.RFC3339Nano, s); timeErr == nil { 258 return unversioned.Time{t}, nil 259 } 260 t, err := time.Parse(time.RFC3339, s) 261 if err != nil { 262 return unversioned.Time{}, err 263 } 264 return unversioned.Time{t}, nil 265 }