node_info.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /*
  2. Copyright 2015 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 nodeinfo
  14. import (
  15. "errors"
  16. "fmt"
  17. "sync"
  18. "sync/atomic"
  19. v1 "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/api/resource"
  21. utilfeature "k8s.io/apiserver/pkg/util/feature"
  22. "k8s.io/klog"
  23. v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
  24. "k8s.io/kubernetes/pkg/features"
  25. schedutil "k8s.io/kubernetes/pkg/scheduler/util"
  26. )
  27. var (
  28. emptyResource = Resource{}
  29. generation int64
  30. )
  31. // ImageStateSummary provides summarized information about the state of an image.
  32. type ImageStateSummary struct {
  33. // Size of the image
  34. Size int64
  35. // Used to track how many nodes have this image
  36. NumNodes int
  37. }
  38. // NodeInfo is node level aggregated information.
  39. type NodeInfo struct {
  40. // Overall node information.
  41. node *v1.Node
  42. pods []*v1.Pod
  43. podsWithAffinity []*v1.Pod
  44. usedPorts HostPortInfo
  45. // Total requested resources of all pods on this node. This includes assumed
  46. // pods, which scheduler has sent for binding, but may not be scheduled yet.
  47. requestedResource *Resource
  48. // Total requested resources of all pods on this node with a minimum value
  49. // applied to each container's CPU and memory requests. This does not reflect
  50. // the actual resource requests for this node, but is used to avoid scheduling
  51. // many zero-request pods onto one node.
  52. nonzeroRequest *Resource
  53. // We store allocatedResources (which is Node.Status.Allocatable.*) explicitly
  54. // as int64, to avoid conversions and accessing map.
  55. allocatableResource *Resource
  56. // Cached taints of the node for faster lookup.
  57. taints []v1.Taint
  58. taintsErr error
  59. // imageStates holds the entry of an image if and only if this image is on the node. The entry can be used for
  60. // checking an image's existence and advanced usage (e.g., image locality scheduling policy) based on the image
  61. // state information.
  62. imageStates map[string]*ImageStateSummary
  63. // TransientInfo holds the information pertaining to a scheduling cycle. This will be destructed at the end of
  64. // scheduling cycle.
  65. // TODO: @ravig. Remove this once we have a clear approach for message passing across predicates and priorities.
  66. TransientInfo *TransientSchedulerInfo
  67. // Cached conditions of node for faster lookup.
  68. memoryPressureCondition v1.ConditionStatus
  69. diskPressureCondition v1.ConditionStatus
  70. pidPressureCondition v1.ConditionStatus
  71. // Whenever NodeInfo changes, generation is bumped.
  72. // This is used to avoid cloning it if the object didn't change.
  73. generation int64
  74. }
  75. //initializeNodeTransientInfo initializes transient information pertaining to node.
  76. func initializeNodeTransientInfo() nodeTransientInfo {
  77. return nodeTransientInfo{AllocatableVolumesCount: 0, RequestedVolumes: 0}
  78. }
  79. // nextGeneration: Let's make sure history never forgets the name...
  80. // Increments the generation number monotonically ensuring that generation numbers never collide.
  81. // Collision of the generation numbers would be particularly problematic if a node was deleted and
  82. // added back with the same name. See issue#63262.
  83. func nextGeneration() int64 {
  84. return atomic.AddInt64(&generation, 1)
  85. }
  86. // nodeTransientInfo contains transient node information while scheduling.
  87. type nodeTransientInfo struct {
  88. // AllocatableVolumesCount contains number of volumes that could be attached to node.
  89. AllocatableVolumesCount int
  90. // Requested number of volumes on a particular node.
  91. RequestedVolumes int
  92. }
  93. // TransientSchedulerInfo is a transient structure which is destructed at the end of each scheduling cycle.
  94. // It consists of items that are valid for a scheduling cycle and is used for message passing across predicates and
  95. // priorities. Some examples which could be used as fields are number of volumes being used on node, current utilization
  96. // on node etc.
  97. // IMPORTANT NOTE: Make sure that each field in this structure is documented along with usage. Expand this structure
  98. // only when absolutely needed as this data structure will be created and destroyed during every scheduling cycle.
  99. type TransientSchedulerInfo struct {
  100. TransientLock sync.Mutex
  101. // NodeTransInfo holds the information related to nodeTransientInformation. NodeName is the key here.
  102. TransNodeInfo nodeTransientInfo
  103. }
  104. // NewTransientSchedulerInfo returns a new scheduler transient structure with initialized values.
  105. func NewTransientSchedulerInfo() *TransientSchedulerInfo {
  106. tsi := &TransientSchedulerInfo{
  107. TransNodeInfo: initializeNodeTransientInfo(),
  108. }
  109. return tsi
  110. }
  111. // ResetTransientSchedulerInfo resets the TransientSchedulerInfo.
  112. func (transientSchedInfo *TransientSchedulerInfo) ResetTransientSchedulerInfo() {
  113. transientSchedInfo.TransientLock.Lock()
  114. defer transientSchedInfo.TransientLock.Unlock()
  115. // Reset TransientNodeInfo.
  116. transientSchedInfo.TransNodeInfo.AllocatableVolumesCount = 0
  117. transientSchedInfo.TransNodeInfo.RequestedVolumes = 0
  118. }
  119. // Resource is a collection of compute resource.
  120. type Resource struct {
  121. MilliCPU int64
  122. Memory int64
  123. EphemeralStorage int64
  124. // We store allowedPodNumber (which is Node.Status.Allocatable.Pods().Value())
  125. // explicitly as int, to avoid conversions and improve performance.
  126. AllowedPodNumber int
  127. // ScalarResources
  128. ScalarResources map[v1.ResourceName]int64
  129. }
  130. // NewResource creates a Resource from ResourceList
  131. func NewResource(rl v1.ResourceList) *Resource {
  132. r := &Resource{}
  133. r.Add(rl)
  134. return r
  135. }
  136. // Add adds ResourceList into Resource.
  137. func (r *Resource) Add(rl v1.ResourceList) {
  138. if r == nil {
  139. return
  140. }
  141. for rName, rQuant := range rl {
  142. switch rName {
  143. case v1.ResourceCPU:
  144. r.MilliCPU += rQuant.MilliValue()
  145. case v1.ResourceMemory:
  146. r.Memory += rQuant.Value()
  147. case v1.ResourcePods:
  148. r.AllowedPodNumber += int(rQuant.Value())
  149. case v1.ResourceEphemeralStorage:
  150. r.EphemeralStorage += rQuant.Value()
  151. default:
  152. if v1helper.IsScalarResourceName(rName) {
  153. r.AddScalar(rName, rQuant.Value())
  154. }
  155. }
  156. }
  157. }
  158. // ResourceList returns a resource list of this resource.
  159. func (r *Resource) ResourceList() v1.ResourceList {
  160. result := v1.ResourceList{
  161. v1.ResourceCPU: *resource.NewMilliQuantity(r.MilliCPU, resource.DecimalSI),
  162. v1.ResourceMemory: *resource.NewQuantity(r.Memory, resource.BinarySI),
  163. v1.ResourcePods: *resource.NewQuantity(int64(r.AllowedPodNumber), resource.BinarySI),
  164. v1.ResourceEphemeralStorage: *resource.NewQuantity(r.EphemeralStorage, resource.BinarySI),
  165. }
  166. for rName, rQuant := range r.ScalarResources {
  167. if v1helper.IsHugePageResourceName(rName) {
  168. result[rName] = *resource.NewQuantity(rQuant, resource.BinarySI)
  169. } else {
  170. result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI)
  171. }
  172. }
  173. return result
  174. }
  175. // Clone returns a copy of this resource.
  176. func (r *Resource) Clone() *Resource {
  177. res := &Resource{
  178. MilliCPU: r.MilliCPU,
  179. Memory: r.Memory,
  180. AllowedPodNumber: r.AllowedPodNumber,
  181. EphemeralStorage: r.EphemeralStorage,
  182. }
  183. if r.ScalarResources != nil {
  184. res.ScalarResources = make(map[v1.ResourceName]int64)
  185. for k, v := range r.ScalarResources {
  186. res.ScalarResources[k] = v
  187. }
  188. }
  189. return res
  190. }
  191. // AddScalar adds a resource by a scalar value of this resource.
  192. func (r *Resource) AddScalar(name v1.ResourceName, quantity int64) {
  193. r.SetScalar(name, r.ScalarResources[name]+quantity)
  194. }
  195. // SetScalar sets a resource by a scalar value of this resource.
  196. func (r *Resource) SetScalar(name v1.ResourceName, quantity int64) {
  197. // Lazily allocate scalar resource map.
  198. if r.ScalarResources == nil {
  199. r.ScalarResources = map[v1.ResourceName]int64{}
  200. }
  201. r.ScalarResources[name] = quantity
  202. }
  203. // SetMaxResource compares with ResourceList and takes max value for each Resource.
  204. func (r *Resource) SetMaxResource(rl v1.ResourceList) {
  205. if r == nil {
  206. return
  207. }
  208. for rName, rQuantity := range rl {
  209. switch rName {
  210. case v1.ResourceMemory:
  211. if mem := rQuantity.Value(); mem > r.Memory {
  212. r.Memory = mem
  213. }
  214. case v1.ResourceCPU:
  215. if cpu := rQuantity.MilliValue(); cpu > r.MilliCPU {
  216. r.MilliCPU = cpu
  217. }
  218. case v1.ResourceEphemeralStorage:
  219. if ephemeralStorage := rQuantity.Value(); ephemeralStorage > r.EphemeralStorage {
  220. r.EphemeralStorage = ephemeralStorage
  221. }
  222. default:
  223. if v1helper.IsScalarResourceName(rName) {
  224. value := rQuantity.Value()
  225. if value > r.ScalarResources[rName] {
  226. r.SetScalar(rName, value)
  227. }
  228. }
  229. }
  230. }
  231. }
  232. // NewNodeInfo returns a ready to use empty NodeInfo object.
  233. // If any pods are given in arguments, their information will be aggregated in
  234. // the returned object.
  235. func NewNodeInfo(pods ...*v1.Pod) *NodeInfo {
  236. ni := &NodeInfo{
  237. requestedResource: &Resource{},
  238. nonzeroRequest: &Resource{},
  239. allocatableResource: &Resource{},
  240. TransientInfo: NewTransientSchedulerInfo(),
  241. generation: nextGeneration(),
  242. usedPorts: make(HostPortInfo),
  243. imageStates: make(map[string]*ImageStateSummary),
  244. }
  245. for _, pod := range pods {
  246. ni.AddPod(pod)
  247. }
  248. return ni
  249. }
  250. // Node returns overall information about this node.
  251. func (n *NodeInfo) Node() *v1.Node {
  252. if n == nil {
  253. return nil
  254. }
  255. return n.node
  256. }
  257. // Pods return all pods scheduled (including assumed to be) on this node.
  258. func (n *NodeInfo) Pods() []*v1.Pod {
  259. if n == nil {
  260. return nil
  261. }
  262. return n.pods
  263. }
  264. // SetPods sets all pods scheduled (including assumed to be) on this node.
  265. func (n *NodeInfo) SetPods(pods []*v1.Pod) {
  266. n.pods = pods
  267. }
  268. // UsedPorts returns used ports on this node.
  269. func (n *NodeInfo) UsedPorts() HostPortInfo {
  270. if n == nil {
  271. return nil
  272. }
  273. return n.usedPorts
  274. }
  275. // SetUsedPorts sets the used ports on this node.
  276. func (n *NodeInfo) SetUsedPorts(newUsedPorts HostPortInfo) {
  277. n.usedPorts = newUsedPorts
  278. }
  279. // ImageStates returns the state information of all images.
  280. func (n *NodeInfo) ImageStates() map[string]*ImageStateSummary {
  281. if n == nil {
  282. return nil
  283. }
  284. return n.imageStates
  285. }
  286. // SetImageStates sets the state information of all images.
  287. func (n *NodeInfo) SetImageStates(newImageStates map[string]*ImageStateSummary) {
  288. n.imageStates = newImageStates
  289. }
  290. // PodsWithAffinity return all pods with (anti)affinity constraints on this node.
  291. func (n *NodeInfo) PodsWithAffinity() []*v1.Pod {
  292. if n == nil {
  293. return nil
  294. }
  295. return n.podsWithAffinity
  296. }
  297. // AllowedPodNumber returns the number of the allowed pods on this node.
  298. func (n *NodeInfo) AllowedPodNumber() int {
  299. if n == nil || n.allocatableResource == nil {
  300. return 0
  301. }
  302. return n.allocatableResource.AllowedPodNumber
  303. }
  304. // Taints returns the taints list on this node.
  305. func (n *NodeInfo) Taints() ([]v1.Taint, error) {
  306. if n == nil {
  307. return nil, nil
  308. }
  309. return n.taints, n.taintsErr
  310. }
  311. // SetTaints sets the taints list on this node.
  312. func (n *NodeInfo) SetTaints(newTaints []v1.Taint) {
  313. n.taints = newTaints
  314. }
  315. // RequestedResource returns aggregated resource request of pods on this node.
  316. func (n *NodeInfo) RequestedResource() Resource {
  317. if n == nil {
  318. return emptyResource
  319. }
  320. return *n.requestedResource
  321. }
  322. // SetRequestedResource sets the aggregated resource request of pods on this node.
  323. func (n *NodeInfo) SetRequestedResource(newResource *Resource) {
  324. n.requestedResource = newResource
  325. }
  326. // NonZeroRequest returns aggregated nonzero resource request of pods on this node.
  327. func (n *NodeInfo) NonZeroRequest() Resource {
  328. if n == nil {
  329. return emptyResource
  330. }
  331. return *n.nonzeroRequest
  332. }
  333. // SetNonZeroRequest sets the aggregated nonzero resource request of pods on this node.
  334. func (n *NodeInfo) SetNonZeroRequest(newResource *Resource) {
  335. n.nonzeroRequest = newResource
  336. }
  337. // AllocatableResource returns allocatable resources on a given node.
  338. func (n *NodeInfo) AllocatableResource() Resource {
  339. if n == nil {
  340. return emptyResource
  341. }
  342. return *n.allocatableResource
  343. }
  344. // SetAllocatableResource sets the allocatableResource information of given node.
  345. func (n *NodeInfo) SetAllocatableResource(allocatableResource *Resource) {
  346. n.allocatableResource = allocatableResource
  347. n.generation = nextGeneration()
  348. }
  349. // GetGeneration returns the generation on this node.
  350. func (n *NodeInfo) GetGeneration() int64 {
  351. if n == nil {
  352. return 0
  353. }
  354. return n.generation
  355. }
  356. // SetGeneration sets the generation on this node. This is for testing only.
  357. func (n *NodeInfo) SetGeneration(newGeneration int64) {
  358. n.generation = newGeneration
  359. }
  360. // Clone returns a copy of this node.
  361. func (n *NodeInfo) Clone() *NodeInfo {
  362. clone := &NodeInfo{
  363. node: n.node,
  364. requestedResource: n.requestedResource.Clone(),
  365. nonzeroRequest: n.nonzeroRequest.Clone(),
  366. allocatableResource: n.allocatableResource.Clone(),
  367. taintsErr: n.taintsErr,
  368. TransientInfo: n.TransientInfo,
  369. memoryPressureCondition: n.memoryPressureCondition,
  370. diskPressureCondition: n.diskPressureCondition,
  371. pidPressureCondition: n.pidPressureCondition,
  372. usedPorts: make(HostPortInfo),
  373. imageStates: n.imageStates,
  374. generation: n.generation,
  375. }
  376. if len(n.pods) > 0 {
  377. clone.pods = append([]*v1.Pod(nil), n.pods...)
  378. }
  379. if len(n.usedPorts) > 0 {
  380. // HostPortInfo is a map-in-map struct
  381. // make sure it's deep copied
  382. for ip, portMap := range n.usedPorts {
  383. clone.usedPorts[ip] = make(map[ProtocolPort]struct{})
  384. for protocolPort, v := range portMap {
  385. clone.usedPorts[ip][protocolPort] = v
  386. }
  387. }
  388. }
  389. if len(n.podsWithAffinity) > 0 {
  390. clone.podsWithAffinity = append([]*v1.Pod(nil), n.podsWithAffinity...)
  391. }
  392. if len(n.taints) > 0 {
  393. clone.taints = append([]v1.Taint(nil), n.taints...)
  394. }
  395. return clone
  396. }
  397. // VolumeLimits returns volume limits associated with the node
  398. func (n *NodeInfo) VolumeLimits() map[v1.ResourceName]int64 {
  399. volumeLimits := map[v1.ResourceName]int64{}
  400. for k, v := range n.AllocatableResource().ScalarResources {
  401. if v1helper.IsAttachableVolumeResourceName(k) {
  402. volumeLimits[k] = v
  403. }
  404. }
  405. return volumeLimits
  406. }
  407. // String returns representation of human readable format of this NodeInfo.
  408. func (n *NodeInfo) String() string {
  409. podKeys := make([]string, len(n.pods))
  410. for i, pod := range n.pods {
  411. podKeys[i] = pod.Name
  412. }
  413. return fmt.Sprintf("&NodeInfo{Pods:%v, RequestedResource:%#v, NonZeroRequest: %#v, UsedPort: %#v, AllocatableResource:%#v}",
  414. podKeys, n.requestedResource, n.nonzeroRequest, n.usedPorts, n.allocatableResource)
  415. }
  416. func hasPodAffinityConstraints(pod *v1.Pod) bool {
  417. affinity := pod.Spec.Affinity
  418. return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil)
  419. }
  420. // AddPod adds pod information to this NodeInfo.
  421. func (n *NodeInfo) AddPod(pod *v1.Pod) {
  422. res, non0CPU, non0Mem := calculateResource(pod)
  423. n.requestedResource.MilliCPU += res.MilliCPU
  424. n.requestedResource.Memory += res.Memory
  425. n.requestedResource.EphemeralStorage += res.EphemeralStorage
  426. if n.requestedResource.ScalarResources == nil && len(res.ScalarResources) > 0 {
  427. n.requestedResource.ScalarResources = map[v1.ResourceName]int64{}
  428. }
  429. for rName, rQuant := range res.ScalarResources {
  430. n.requestedResource.ScalarResources[rName] += rQuant
  431. }
  432. n.nonzeroRequest.MilliCPU += non0CPU
  433. n.nonzeroRequest.Memory += non0Mem
  434. n.pods = append(n.pods, pod)
  435. if hasPodAffinityConstraints(pod) {
  436. n.podsWithAffinity = append(n.podsWithAffinity, pod)
  437. }
  438. // Consume ports when pods added.
  439. n.UpdateUsedPorts(pod, true)
  440. n.generation = nextGeneration()
  441. }
  442. // RemovePod subtracts pod information from this NodeInfo.
  443. func (n *NodeInfo) RemovePod(pod *v1.Pod) error {
  444. k1, err := GetPodKey(pod)
  445. if err != nil {
  446. return err
  447. }
  448. for i := range n.podsWithAffinity {
  449. k2, err := GetPodKey(n.podsWithAffinity[i])
  450. if err != nil {
  451. klog.Errorf("Cannot get pod key, err: %v", err)
  452. continue
  453. }
  454. if k1 == k2 {
  455. // delete the element
  456. n.podsWithAffinity[i] = n.podsWithAffinity[len(n.podsWithAffinity)-1]
  457. n.podsWithAffinity = n.podsWithAffinity[:len(n.podsWithAffinity)-1]
  458. break
  459. }
  460. }
  461. for i := range n.pods {
  462. k2, err := GetPodKey(n.pods[i])
  463. if err != nil {
  464. klog.Errorf("Cannot get pod key, err: %v", err)
  465. continue
  466. }
  467. if k1 == k2 {
  468. // delete the element
  469. n.pods[i] = n.pods[len(n.pods)-1]
  470. n.pods = n.pods[:len(n.pods)-1]
  471. // reduce the resource data
  472. res, non0CPU, non0Mem := calculateResource(pod)
  473. n.requestedResource.MilliCPU -= res.MilliCPU
  474. n.requestedResource.Memory -= res.Memory
  475. n.requestedResource.EphemeralStorage -= res.EphemeralStorage
  476. if len(res.ScalarResources) > 0 && n.requestedResource.ScalarResources == nil {
  477. n.requestedResource.ScalarResources = map[v1.ResourceName]int64{}
  478. }
  479. for rName, rQuant := range res.ScalarResources {
  480. n.requestedResource.ScalarResources[rName] -= rQuant
  481. }
  482. n.nonzeroRequest.MilliCPU -= non0CPU
  483. n.nonzeroRequest.Memory -= non0Mem
  484. // Release ports when remove Pods.
  485. n.UpdateUsedPorts(pod, false)
  486. n.generation = nextGeneration()
  487. n.resetSlicesIfEmpty()
  488. return nil
  489. }
  490. }
  491. return fmt.Errorf("no corresponding pod %s in pods of node %s", pod.Name, n.node.Name)
  492. }
  493. // resets the slices to nil so that we can do DeepEqual in unit tests.
  494. func (n *NodeInfo) resetSlicesIfEmpty() {
  495. if len(n.podsWithAffinity) == 0 {
  496. n.podsWithAffinity = nil
  497. }
  498. if len(n.pods) == 0 {
  499. n.pods = nil
  500. }
  501. }
  502. func calculateResource(pod *v1.Pod) (res Resource, non0CPU int64, non0Mem int64) {
  503. resPtr := &res
  504. for _, c := range pod.Spec.Containers {
  505. resPtr.Add(c.Resources.Requests)
  506. non0CPUReq, non0MemReq := schedutil.GetNonzeroRequests(&c.Resources.Requests)
  507. non0CPU += non0CPUReq
  508. non0Mem += non0MemReq
  509. // No non-zero resources for GPUs or opaque resources.
  510. }
  511. // If Overhead is being utilized, add to the total requests for the pod
  512. if pod.Spec.Overhead != nil && utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) {
  513. resPtr.Add(pod.Spec.Overhead)
  514. if _, found := pod.Spec.Overhead[v1.ResourceCPU]; found {
  515. non0CPU += pod.Spec.Overhead.Cpu().MilliValue()
  516. }
  517. if _, found := pod.Spec.Overhead[v1.ResourceMemory]; found {
  518. non0Mem += pod.Spec.Overhead.Memory().Value()
  519. }
  520. }
  521. return
  522. }
  523. // UpdateUsedPorts updates the UsedPorts of NodeInfo.
  524. func (n *NodeInfo) UpdateUsedPorts(pod *v1.Pod, add bool) {
  525. for j := range pod.Spec.Containers {
  526. container := &pod.Spec.Containers[j]
  527. for k := range container.Ports {
  528. podPort := &container.Ports[k]
  529. if add {
  530. n.usedPorts.Add(podPort.HostIP, string(podPort.Protocol), podPort.HostPort)
  531. } else {
  532. n.usedPorts.Remove(podPort.HostIP, string(podPort.Protocol), podPort.HostPort)
  533. }
  534. }
  535. }
  536. }
  537. // SetNode sets the overall node information.
  538. func (n *NodeInfo) SetNode(node *v1.Node) error {
  539. n.node = node
  540. n.allocatableResource = NewResource(node.Status.Allocatable)
  541. n.taints = node.Spec.Taints
  542. for i := range node.Status.Conditions {
  543. cond := &node.Status.Conditions[i]
  544. switch cond.Type {
  545. case v1.NodeMemoryPressure:
  546. n.memoryPressureCondition = cond.Status
  547. case v1.NodeDiskPressure:
  548. n.diskPressureCondition = cond.Status
  549. case v1.NodePIDPressure:
  550. n.pidPressureCondition = cond.Status
  551. default:
  552. // We ignore other conditions.
  553. }
  554. }
  555. n.TransientInfo = NewTransientSchedulerInfo()
  556. n.generation = nextGeneration()
  557. return nil
  558. }
  559. // FilterOutPods receives a list of pods and filters out those whose node names
  560. // are equal to the node of this NodeInfo, but are not found in the pods of this NodeInfo.
  561. //
  562. // Preemption logic simulates removal of pods on a node by removing them from the
  563. // corresponding NodeInfo. In order for the simulation to work, we call this method
  564. // on the pods returned from SchedulerCache, so that predicate functions see
  565. // only the pods that are not removed from the NodeInfo.
  566. func (n *NodeInfo) FilterOutPods(pods []*v1.Pod) []*v1.Pod {
  567. node := n.Node()
  568. if node == nil {
  569. return pods
  570. }
  571. filtered := make([]*v1.Pod, 0, len(pods))
  572. for _, p := range pods {
  573. if p.Spec.NodeName != node.Name {
  574. filtered = append(filtered, p)
  575. continue
  576. }
  577. // If pod is on the given node, add it to 'filtered' only if it is present in nodeInfo.
  578. podKey, err := GetPodKey(p)
  579. if err != nil {
  580. continue
  581. }
  582. for _, np := range n.Pods() {
  583. npodkey, _ := GetPodKey(np)
  584. if npodkey == podKey {
  585. filtered = append(filtered, p)
  586. break
  587. }
  588. }
  589. }
  590. return filtered
  591. }
  592. // GetPodKey returns the string key of a pod.
  593. func GetPodKey(pod *v1.Pod) (string, error) {
  594. uid := string(pod.UID)
  595. if len(uid) == 0 {
  596. return "", errors.New("Cannot get cache key for pod with empty UID")
  597. }
  598. return uid, nil
  599. }
  600. // Filter implements PodFilter interface. It returns false only if the pod node name
  601. // matches NodeInfo.node and the pod is not found in the pods list. Otherwise,
  602. // returns true.
  603. func (n *NodeInfo) Filter(pod *v1.Pod) bool {
  604. if pod.Spec.NodeName != n.node.Name {
  605. return true
  606. }
  607. for _, p := range n.pods {
  608. if p.Name == pod.Name && p.Namespace == pod.Namespace {
  609. return true
  610. }
  611. }
  612. return false
  613. }