github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/api/genericresource/resource_management.go (about) 1 package genericresource 2 3 import ( 4 "fmt" 5 6 "github.com/docker/swarmkit/api" 7 ) 8 9 // Claim assigns GenericResources to a task by taking them from the 10 // node's GenericResource list and storing them in the task's available list 11 func Claim(nodeAvailableResources, taskAssigned *[]*api.GenericResource, 12 taskReservations []*api.GenericResource) error { 13 var resSelected []*api.GenericResource 14 15 for _, res := range taskReservations { 16 tr := res.GetDiscreteResourceSpec() 17 if tr == nil { 18 return fmt.Errorf("task should only hold Discrete type") 19 } 20 21 // Select the resources 22 nrs, err := selectNodeResources(*nodeAvailableResources, tr) 23 if err != nil { 24 return err 25 } 26 27 resSelected = append(resSelected, nrs...) 28 } 29 30 ClaimResources(nodeAvailableResources, taskAssigned, resSelected) 31 return nil 32 } 33 34 // ClaimResources adds the specified resources to the task's list 35 // and removes them from the node's generic resource list 36 func ClaimResources(nodeAvailableResources, taskAssigned *[]*api.GenericResource, 37 resSelected []*api.GenericResource) { 38 *taskAssigned = append(*taskAssigned, resSelected...) 39 ConsumeNodeResources(nodeAvailableResources, resSelected) 40 } 41 42 func selectNodeResources(nodeRes []*api.GenericResource, 43 tr *api.DiscreteGenericResource) ([]*api.GenericResource, error) { 44 var nrs []*api.GenericResource 45 46 for _, res := range nodeRes { 47 if Kind(res) != tr.Kind { 48 continue 49 } 50 51 switch nr := res.Resource.(type) { 52 case *api.GenericResource_DiscreteResourceSpec: 53 if nr.DiscreteResourceSpec.Value >= tr.Value && tr.Value != 0 { 54 nrs = append(nrs, NewDiscrete(tr.Kind, tr.Value)) 55 } 56 57 return nrs, nil 58 case *api.GenericResource_NamedResourceSpec: 59 nrs = append(nrs, res.Copy()) 60 61 if int64(len(nrs)) == tr.Value { 62 return nrs, nil 63 } 64 } 65 } 66 67 if len(nrs) == 0 { 68 return nil, fmt.Errorf("not enough resources available for task reservations: %+v", tr) 69 } 70 71 return nrs, nil 72 } 73 74 // Reclaim adds the resources taken by the task to the node's store 75 func Reclaim(nodeAvailableResources *[]*api.GenericResource, taskAssigned, nodeRes []*api.GenericResource) error { 76 err := reclaimResources(nodeAvailableResources, taskAssigned) 77 if err != nil { 78 return err 79 } 80 81 sanitize(nodeRes, nodeAvailableResources) 82 83 return nil 84 } 85 86 func reclaimResources(nodeAvailableResources *[]*api.GenericResource, taskAssigned []*api.GenericResource) error { 87 // The node could have been updated 88 if nodeAvailableResources == nil { 89 return fmt.Errorf("node no longer has any resources") 90 } 91 92 for _, res := range taskAssigned { 93 switch tr := res.Resource.(type) { 94 case *api.GenericResource_DiscreteResourceSpec: 95 nrs := GetResource(tr.DiscreteResourceSpec.Kind, *nodeAvailableResources) 96 97 // If the resource went down to 0 it's no longer in the 98 // available list 99 if len(nrs) == 0 { 100 *nodeAvailableResources = append(*nodeAvailableResources, res.Copy()) 101 } 102 103 if len(nrs) != 1 { 104 continue // Type change 105 } 106 107 nr := nrs[0].GetDiscreteResourceSpec() 108 if nr == nil { 109 continue // Type change 110 } 111 112 nr.Value += tr.DiscreteResourceSpec.Value 113 case *api.GenericResource_NamedResourceSpec: 114 *nodeAvailableResources = append(*nodeAvailableResources, res.Copy()) 115 } 116 } 117 118 return nil 119 } 120 121 // sanitize checks that nodeAvailableResources does not add resources unknown 122 // to the nodeSpec (nodeRes) or goes over the integer bound specified 123 // by the spec. 124 // Note this is because the user is able to update a node's resources 125 func sanitize(nodeRes []*api.GenericResource, nodeAvailableResources *[]*api.GenericResource) { 126 // - We add the sanitized resources at the end, after 127 // having removed the elements from the list 128 129 // - When a set changes to a Discrete we also need 130 // to make sure that we don't add the Discrete multiple 131 // time hence, the need of a map to remember that 132 var sanitized []*api.GenericResource 133 kindSanitized := make(map[string]struct{}) 134 w := 0 135 136 for _, na := range *nodeAvailableResources { 137 ok, nrs := sanitizeResource(nodeRes, na) 138 if !ok { 139 if _, ok = kindSanitized[Kind(na)]; ok { 140 continue 141 } 142 143 kindSanitized[Kind(na)] = struct{}{} 144 sanitized = append(sanitized, nrs...) 145 146 continue 147 } 148 149 (*nodeAvailableResources)[w] = na 150 w++ 151 } 152 153 *nodeAvailableResources = (*nodeAvailableResources)[:w] 154 *nodeAvailableResources = append(*nodeAvailableResources, sanitized...) 155 } 156 157 // Returns true if the element is in nodeRes and "sane" 158 // Returns false if the element isn't in nodeRes and "sane" and the element(s) that should be replacing it 159 func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource) (ok bool, nrs []*api.GenericResource) { 160 switch na := res.Resource.(type) { 161 case *api.GenericResource_DiscreteResourceSpec: 162 nrs := GetResource(na.DiscreteResourceSpec.Kind, nodeRes) 163 164 // Type change or removed: reset 165 if len(nrs) != 1 { 166 return false, nrs 167 } 168 169 // Type change: reset 170 nr := nrs[0].GetDiscreteResourceSpec() 171 if nr == nil { 172 return false, nrs 173 } 174 175 // Amount change: reset 176 if na.DiscreteResourceSpec.Value > nr.Value { 177 return false, nrs 178 } 179 case *api.GenericResource_NamedResourceSpec: 180 nrs := GetResource(na.NamedResourceSpec.Kind, nodeRes) 181 182 // Type change 183 if len(nrs) == 0 { 184 return false, nrs 185 } 186 187 for _, nr := range nrs { 188 // Type change: reset 189 if nr.GetDiscreteResourceSpec() != nil { 190 return false, nrs 191 } 192 193 if na.NamedResourceSpec.Value == nr.GetNamedResourceSpec().Value { 194 return true, nil 195 } 196 } 197 198 // Removed 199 return false, nil 200 } 201 202 return true, nil 203 }