Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / swarmkit / api / genericresource / resource_management.go
1 package genericresource
2
3 import (
4         "fmt"
5         "github.com/docker/swarmkit/api"
6 )
7
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
13
14         for _, res := range taskReservations {
15                 tr := res.GetDiscrete()
16                 if tr == nil {
17                         return fmt.Errorf("task should only hold Discrete type")
18                 }
19
20                 // Select the resources
21                 nrs, err := selectNodeResources(*nodeAvailableResources, tr)
22                 if err != nil {
23                         return err
24                 }
25
26                 resSelected = append(resSelected, nrs...)
27         }
28
29         ClaimResources(nodeAvailableResources, taskAssigned, resSelected)
30         return nil
31 }
32
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)
39 }
40
41 func selectNodeResources(nodeRes []*api.GenericResource,
42         tr *api.GenericDiscrete) ([]*api.GenericResource, error) {
43         var nrs []*api.GenericResource
44
45         for _, res := range nodeRes {
46                 if Kind(res) != tr.Kind {
47                         continue
48                 }
49
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))
54                         }
55
56                         return nrs, nil
57                 case *api.GenericResource_Str:
58                         nrs = append(nrs, res.Copy())
59
60                         if int64(len(nrs)) == tr.Value {
61                                 return nrs, nil
62                         }
63                 }
64         }
65
66         if len(nrs) == 0 {
67                 return nil, fmt.Errorf("not enough resources available for task reservations: %+v", tr)
68         }
69
70         return nrs, nil
71 }
72
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)
76         if err != nil {
77                 return err
78         }
79
80         sanitize(nodeRes, nodeAvailableResources)
81
82         return nil
83 }
84
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")
89         }
90
91         for _, res := range taskAssigned {
92                 switch tr := res.Resource.(type) {
93                 case *api.GenericResource_Discrete:
94                         nrs := GetResource(tr.Discrete.Kind, *nodeAvailableResources)
95
96                         // If the resource went down to 0 it's no longer in the
97                         // available list
98                         if len(nrs) == 0 {
99                                 *nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
100                         }
101
102                         if len(nrs) != 1 {
103                                 continue // Type change
104                         }
105
106                         nr := nrs[0].GetDiscrete()
107                         if nr == nil {
108                                 continue // Type change
109                         }
110
111                         nr.Value += tr.Discrete.Value
112                 case *api.GenericResource_Str:
113                         *nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
114                 }
115         }
116
117         return nil
118 }
119
120 // sanitize checks that nodeAvailableResources does not add resources unknown
121 // to the nodeSpec (nodeRes) or goes over the integer bound specified
122 // by the spec.
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
127
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{})
133         w := 0
134
135         for _, na := range *nodeAvailableResources {
136                 ok, nrs := sanitizeResource(nodeRes, na)
137                 if !ok {
138                         if _, ok = kindSanitized[Kind(na)]; ok {
139                                 continue
140                         }
141
142                         kindSanitized[Kind(na)] = struct{}{}
143                         sanitized = append(sanitized, nrs...)
144
145                         continue
146                 }
147
148                 (*nodeAvailableResources)[w] = na
149                 w++
150         }
151
152         *nodeAvailableResources = (*nodeAvailableResources)[:w]
153         *nodeAvailableResources = append(*nodeAvailableResources, sanitized...)
154 }
155
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)
162
163                 // Type change or removed: reset
164                 if len(nrs) != 1 {
165                         return false, nrs
166                 }
167
168                 // Type change: reset
169                 nr := nrs[0].GetDiscrete()
170                 if nr == nil {
171                         return false, nrs
172                 }
173
174                 // Amount change: reset
175                 if na.Discrete.Value > nr.Value {
176                         return false, nrs
177                 }
178         case *api.GenericResource_Str:
179                 nrs := GetResource(na.Str.Kind, nodeRes)
180
181                 // Type change
182                 if len(nrs) == 0 {
183                         return false, nrs
184                 }
185
186                 for _, nr := range nrs {
187                         // Type change: reset
188                         if nr.GetDiscrete() != nil {
189                                 return false, nrs
190                         }
191
192                         if na.Str.Value == nr.GetStr().Value {
193                                 return true, nil
194                         }
195                 }
196
197                 // Removed
198                 return false, nil
199         }
200
201         return true, nil
202 }