placement.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. Copyright 2018 The Rook Authors. All rights reserved.
  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 v1
  14. import (
  15. v1 "k8s.io/api/core/v1"
  16. )
  17. func (p PlacementSpec) All() Placement {
  18. return p[KeyAll]
  19. }
  20. // ApplyToPodSpec adds placement to a pod spec
  21. func (p Placement) ApplyToPodSpec(t *v1.PodSpec) {
  22. if t.Affinity == nil {
  23. t.Affinity = &v1.Affinity{}
  24. }
  25. if p.NodeAffinity != nil {
  26. t.Affinity.NodeAffinity = p.mergeNodeAffinity(t.Affinity.NodeAffinity)
  27. }
  28. if p.PodAffinity != nil {
  29. t.Affinity.PodAffinity = p.PodAffinity.DeepCopy()
  30. }
  31. if p.PodAntiAffinity != nil {
  32. t.Affinity.PodAntiAffinity = p.PodAntiAffinity.DeepCopy()
  33. }
  34. if p.Tolerations != nil {
  35. t.Tolerations = p.mergeTolerations(t.Tolerations)
  36. }
  37. if p.TopologySpreadConstraints != nil {
  38. t.TopologySpreadConstraints = p.TopologySpreadConstraints
  39. }
  40. }
  41. func (p Placement) mergeNodeAffinity(nodeAffinity *v1.NodeAffinity) *v1.NodeAffinity {
  42. // no node affinity is specified yet, so return the placement's nodeAffinity
  43. result := p.NodeAffinity.DeepCopy()
  44. if nodeAffinity == nil {
  45. return result
  46. }
  47. // merge the preferred node affinity that was already specified, and the placement's nodeAffinity
  48. result.PreferredDuringSchedulingIgnoredDuringExecution = append(
  49. nodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution,
  50. p.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution...)
  51. // nothing to merge if no affinity was passed in
  52. if nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil {
  53. return result
  54. }
  55. // take the desired affinity if there was none on the placement
  56. if p.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil {
  57. result.RequiredDuringSchedulingIgnoredDuringExecution = nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution
  58. return result
  59. }
  60. // take the desired affinity node selectors without the need to merge
  61. if len(nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms) == 0 {
  62. return result
  63. }
  64. // take the placement affinity node selectors without the need to merge
  65. if len(p.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms) == 0 {
  66. // take the placement from the first option since the second isn't specified
  67. result.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms =
  68. nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms
  69. return result
  70. }
  71. // merge the match expressions together since they are defined in both placements
  72. // this will only work if we want an "and" between all the expressions, more complex conditions won't work with this merge
  73. var nodeTerm v1.NodeSelectorTerm
  74. nodeTerm.MatchExpressions = append(
  75. nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions,
  76. p.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions...)
  77. nodeTerm.MatchFields = append(
  78. nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchFields,
  79. p.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchFields...)
  80. result.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0] = nodeTerm
  81. return result
  82. }
  83. func (p Placement) mergeTolerations(tolerations []v1.Toleration) []v1.Toleration {
  84. // no toleration is specified yet, return placement's toleration
  85. if tolerations == nil {
  86. return p.Tolerations
  87. }
  88. return append(p.Tolerations, tolerations...)
  89. }
  90. // Merge returns a Placement which results from merging the attributes of the
  91. // original Placement with the attributes of the supplied one. The supplied
  92. // Placement's attributes will override the original ones if defined.
  93. func (p Placement) Merge(with Placement) Placement {
  94. ret := p
  95. if with.NodeAffinity != nil {
  96. ret.NodeAffinity = with.NodeAffinity
  97. }
  98. if with.PodAffinity != nil {
  99. ret.PodAffinity = with.PodAffinity
  100. }
  101. if with.PodAntiAffinity != nil {
  102. ret.PodAntiAffinity = with.PodAntiAffinity
  103. }
  104. if with.Tolerations != nil {
  105. ret.Tolerations = ret.mergeTolerations(with.Tolerations)
  106. }
  107. if with.TopologySpreadConstraints != nil {
  108. ret.TopologySpreadConstraints = with.TopologySpreadConstraints
  109. }
  110. return ret
  111. }
  112. // GetMgrPlacement returns the placement for the MGR service
  113. func GetMgrPlacement(p PlacementSpec) Placement {
  114. return p.All().Merge(p[KeyMgr])
  115. }
  116. // GetMonPlacement returns the placement for the MON service
  117. func GetMonPlacement(p PlacementSpec) Placement {
  118. return p.All().Merge(p[KeyMon])
  119. }
  120. // GetArbiterPlacement returns the placement for the arbiter MON service
  121. func GetArbiterPlacement(p PlacementSpec) Placement {
  122. // If the mon is the arbiter in a stretch cluster and its placement is specified, return it
  123. // without merging with the "all" placement so it can be handled separately from all other daemons
  124. return p[KeyMonArbiter]
  125. }
  126. // GetOSDPlacement returns the placement for the OSD service
  127. func GetOSDPlacement(p PlacementSpec) Placement {
  128. return p.All().Merge(p[KeyOSD])
  129. }