resource.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package resource
  14. import (
  15. "fmt"
  16. "math"
  17. "strconv"
  18. "strings"
  19. corev1 "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/api/resource"
  21. "k8s.io/apimachinery/pkg/util/sets"
  22. )
  23. // PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
  24. // containers of the pod.
  25. func PodRequestsAndLimits(pod *corev1.Pod) (reqs, limits corev1.ResourceList) {
  26. reqs, limits = corev1.ResourceList{}, corev1.ResourceList{}
  27. for _, container := range pod.Spec.Containers {
  28. addResourceList(reqs, container.Resources.Requests)
  29. addResourceList(limits, container.Resources.Limits)
  30. }
  31. // init containers define the minimum of any resource
  32. for _, container := range pod.Spec.InitContainers {
  33. maxResourceList(reqs, container.Resources.Requests)
  34. maxResourceList(limits, container.Resources.Limits)
  35. }
  36. return
  37. }
  38. // addResourceList adds the resources in newList to list
  39. func addResourceList(list, new corev1.ResourceList) {
  40. for name, quantity := range new {
  41. if value, ok := list[name]; !ok {
  42. list[name] = *quantity.Copy()
  43. } else {
  44. value.Add(quantity)
  45. list[name] = value
  46. }
  47. }
  48. }
  49. // maxResourceList sets list to the greater of list/newList for every resource
  50. // either list
  51. func maxResourceList(list, new corev1.ResourceList) {
  52. for name, quantity := range new {
  53. if value, ok := list[name]; !ok {
  54. list[name] = *quantity.Copy()
  55. continue
  56. } else {
  57. if quantity.Cmp(value) > 0 {
  58. list[name] = *quantity.Copy()
  59. }
  60. }
  61. }
  62. }
  63. // ExtractContainerResourceValue extracts the value of a resource
  64. // in an already known container
  65. func ExtractContainerResourceValue(fs *corev1.ResourceFieldSelector, container *corev1.Container) (string, error) {
  66. divisor := resource.Quantity{}
  67. if divisor.Cmp(fs.Divisor) == 0 {
  68. divisor = resource.MustParse("1")
  69. } else {
  70. divisor = fs.Divisor
  71. }
  72. switch fs.Resource {
  73. case "limits.cpu":
  74. return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor)
  75. case "limits.memory":
  76. return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor)
  77. case "limits.ephemeral-storage":
  78. return convertResourceEphemeralStorageToString(container.Resources.Limits.StorageEphemeral(), divisor)
  79. case "requests.cpu":
  80. return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor)
  81. case "requests.memory":
  82. return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor)
  83. case "requests.ephemeral-storage":
  84. return convertResourceEphemeralStorageToString(container.Resources.Requests.StorageEphemeral(), divisor)
  85. }
  86. return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource)
  87. }
  88. // convertResourceCPUToString converts cpu value to the format of divisor and returns
  89. // ceiling of the value.
  90. func convertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) {
  91. c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue())))
  92. return strconv.FormatInt(c, 10), nil
  93. }
  94. // convertResourceMemoryToString converts memory value to the format of divisor and returns
  95. // ceiling of the value.
  96. func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) {
  97. m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value())))
  98. return strconv.FormatInt(m, 10), nil
  99. }
  100. // convertResourceEphemeralStorageToString converts ephemeral storage value to the format of divisor and returns
  101. // ceiling of the value.
  102. func convertResourceEphemeralStorageToString(ephemeralStorage *resource.Quantity, divisor resource.Quantity) (string, error) {
  103. m := int64(math.Ceil(float64(ephemeralStorage.Value()) / float64(divisor.Value())))
  104. return strconv.FormatInt(m, 10), nil
  105. }
  106. var standardContainerResources = sets.NewString(
  107. string(corev1.ResourceCPU),
  108. string(corev1.ResourceMemory),
  109. string(corev1.ResourceEphemeralStorage),
  110. )
  111. // IsStandardContainerResourceName returns true if the container can make a resource request
  112. // for the specified resource
  113. func IsStandardContainerResourceName(str string) bool {
  114. return standardContainerResources.Has(str) || IsHugePageResourceName(corev1.ResourceName(str))
  115. }
  116. // IsHugePageResourceName returns true if the resource name has the huge page
  117. // resource prefix.
  118. func IsHugePageResourceName(name corev1.ResourceName) bool {
  119. return strings.HasPrefix(string(name), corev1.ResourceHugePagesPrefix)
  120. }