1 package genericresource
5 "github.com/docker/swarmkit/api"
8 // Claim assigns GenericResources to a task by taking them from the
9 // node's GenericResource list and storing them in the task's available list
10 func Claim(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
11 taskReservations []*api.GenericResource) error {
12 var resSelected []*api.GenericResource
14 for _, res := range taskReservations {
15 tr := res.GetDiscrete()
17 return fmt.Errorf("task should only hold Discrete type")
20 // Select the resources
21 nrs, err := selectNodeResources(*nodeAvailableResources, tr)
26 resSelected = append(resSelected, nrs...)
29 ClaimResources(nodeAvailableResources, taskAssigned, resSelected)
33 // ClaimResources adds the specified resources to the task's list
34 // and removes them from the node's generic resource list
35 func ClaimResources(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
36 resSelected []*api.GenericResource) {
37 *taskAssigned = append(*taskAssigned, resSelected...)
38 ConsumeNodeResources(nodeAvailableResources, resSelected)
41 func selectNodeResources(nodeRes []*api.GenericResource,
42 tr *api.GenericDiscrete) ([]*api.GenericResource, error) {
43 var nrs []*api.GenericResource
45 for _, res := range nodeRes {
46 if Kind(res) != tr.Kind {
50 switch nr := res.Resource.(type) {
51 case *api.GenericResource_Discrete:
52 if nr.Discrete.Value >= tr.Value && tr.Value != 0 {
53 nrs = append(nrs, NewDiscrete(tr.Kind, tr.Value))
57 case *api.GenericResource_Str:
58 nrs = append(nrs, res.Copy())
60 if int64(len(nrs)) == tr.Value {
67 return nil, fmt.Errorf("not enough resources available for task reservations: %+v", tr)
73 // Reclaim adds the resources taken by the task to the node's store
74 func Reclaim(nodeAvailableResources *[]*api.GenericResource, taskAssigned, nodeRes []*api.GenericResource) error {
75 err := reclaimResources(nodeAvailableResources, taskAssigned)
80 sanitize(nodeRes, nodeAvailableResources)
85 func reclaimResources(nodeAvailableResources *[]*api.GenericResource, taskAssigned []*api.GenericResource) error {
86 // The node could have been updated
87 if nodeAvailableResources == nil {
88 return fmt.Errorf("node no longer has any resources")
91 for _, res := range taskAssigned {
92 switch tr := res.Resource.(type) {
93 case *api.GenericResource_Discrete:
94 nrs := GetResource(tr.Discrete.Kind, *nodeAvailableResources)
96 // If the resource went down to 0 it's no longer in the
99 *nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
103 continue // Type change
106 nr := nrs[0].GetDiscrete()
108 continue // Type change
111 nr.Value += tr.Discrete.Value
112 case *api.GenericResource_Str:
113 *nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
120 // sanitize checks that nodeAvailableResources does not add resources unknown
121 // to the nodeSpec (nodeRes) or goes over the integer bound specified
123 // Note this is because the user is able to update a node's resources
124 func sanitize(nodeRes []*api.GenericResource, nodeAvailableResources *[]*api.GenericResource) {
125 // - We add the sanitized resources at the end, after
126 // having removed the elements from the list
128 // - When a set changes to a Discrete we also need
129 // to make sure that we don't add the Discrete multiple
130 // time hence, the need of a map to remember that
131 var sanitized []*api.GenericResource
132 kindSanitized := make(map[string]struct{})
135 for _, na := range *nodeAvailableResources {
136 ok, nrs := sanitizeResource(nodeRes, na)
138 if _, ok = kindSanitized[Kind(na)]; ok {
142 kindSanitized[Kind(na)] = struct{}{}
143 sanitized = append(sanitized, nrs...)
148 (*nodeAvailableResources)[w] = na
152 *nodeAvailableResources = (*nodeAvailableResources)[:w]
153 *nodeAvailableResources = append(*nodeAvailableResources, sanitized...)
156 // Returns true if the element is in nodeRes and "sane"
157 // Returns false if the element isn't in nodeRes and "sane" and the element(s) that should be replacing it
158 func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource) (ok bool, nrs []*api.GenericResource) {
159 switch na := res.Resource.(type) {
160 case *api.GenericResource_Discrete:
161 nrs := GetResource(na.Discrete.Kind, nodeRes)
163 // Type change or removed: reset
168 // Type change: reset
169 nr := nrs[0].GetDiscrete()
174 // Amount change: reset
175 if na.Discrete.Value > nr.Value {
178 case *api.GenericResource_Str:
179 nrs := GetResource(na.Str.Kind, nodeRes)
186 for _, nr := range nrs {
187 // Type change: reset
188 if nr.GetDiscrete() != nil {
192 if na.Str.Value == nr.GetStr().Value {