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  }