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  }