0f5335443b1d536053b52fbcafdb10b794a82ead
[ccsdk/sli/adaptors.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                         reserved.
7  * ================================================================================
8  * Modifications Copyright (C) 2018 IBM.
9  * ================================================================================
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.ccsdk.sli.adaptors.rm.comp;
25
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Set;
32 import java.util.SortedSet;
33 import java.util.TreeSet;
34 import org.onap.ccsdk.sli.adaptors.lock.comp.LockHelper;
35 import org.onap.ccsdk.sli.adaptors.lock.comp.ResourceLockedException;
36 import org.onap.ccsdk.sli.adaptors.lock.comp.SynchronizedFunction;
37 import org.onap.ccsdk.sli.adaptors.rm.dao.ResourceDao;
38 import org.onap.ccsdk.sli.adaptors.rm.data.AllocationOutcome;
39 import org.onap.ccsdk.sli.adaptors.rm.data.AllocationRequest;
40 import org.onap.ccsdk.sli.adaptors.rm.data.AllocationStatus;
41 import org.onap.ccsdk.sli.adaptors.rm.data.LabelAllocationOutcome;
42 import org.onap.ccsdk.sli.adaptors.rm.data.LabelAllocationRequest;
43 import org.onap.ccsdk.sli.adaptors.rm.data.LabelResource;
44 import org.onap.ccsdk.sli.adaptors.rm.data.LimitAllocationOutcome;
45 import org.onap.ccsdk.sli.adaptors.rm.data.LimitAllocationRequest;
46 import org.onap.ccsdk.sli.adaptors.rm.data.LimitResource;
47 import org.onap.ccsdk.sli.adaptors.rm.data.MultiAssetAllocationOutcome;
48 import org.onap.ccsdk.sli.adaptors.rm.data.MultiAssetAllocationRequest;
49 import org.onap.ccsdk.sli.adaptors.rm.data.MultiResourceAllocationOutcome;
50 import org.onap.ccsdk.sli.adaptors.rm.data.MultiResourceAllocationRequest;
51 import org.onap.ccsdk.sli.adaptors.rm.data.Range;
52 import org.onap.ccsdk.sli.adaptors.rm.data.RangeAllocationOutcome;
53 import org.onap.ccsdk.sli.adaptors.rm.data.RangeAllocationRequest;
54 import org.onap.ccsdk.sli.adaptors.rm.data.RangeResource;
55 import org.onap.ccsdk.sli.adaptors.rm.data.Resource;
56 import org.onap.ccsdk.sli.adaptors.rm.data.ResourceKey;
57 import org.onap.ccsdk.sli.adaptors.rm.data.ResourceType;
58 import org.onap.ccsdk.sli.adaptors.rm.util.LabelUtil;
59 import org.onap.ccsdk.sli.adaptors.rm.util.LimitUtil;
60 import org.onap.ccsdk.sli.adaptors.rm.util.RangeUtil;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 class AllocationFunction extends SynchronizedFunction {
65
66     @SuppressWarnings("unused")
67     private static final Logger log = LoggerFactory.getLogger(AllocationFunction.class);
68
69     private ResourceDao resourceDao;
70
71     private AllocationRequest request;
72     private AllocationOutcome outcome;
73
74     private List<Resource> updateList = new ArrayList<>();
75
76     public AllocationFunction(LockHelper lockHelper, ResourceDao resourceDao, AllocationRequest request,
77             int lockTimeout) {
78         super(lockHelper, getLockNames(request), lockTimeout);
79         this.resourceDao = resourceDao;
80         this.request = request;
81     }
82
83     private static Collection<String> getLockNames(AllocationRequest request) {
84         Set<String> lockResourceNames = new HashSet<>();
85         addLockNames(lockResourceNames, request);
86         return lockResourceNames;
87     }
88
89     private static void addLockNames(Set<String> lockResourceNames, AllocationRequest request) {
90         if (request instanceof MultiAssetAllocationRequest) {
91             MultiAssetAllocationRequest req = (MultiAssetAllocationRequest) request;
92             if (req.assetIdList != null) {
93                 lockResourceNames.addAll(req.assetIdList);
94             }
95         } else if (request instanceof MultiResourceAllocationRequest) {
96             MultiResourceAllocationRequest req = (MultiResourceAllocationRequest) request;
97             if (req.allocationRequestList != null) {
98                 for (AllocationRequest request1 : req.allocationRequestList) {
99                     addLockNames(lockResourceNames, request1);
100                 }
101             }
102         } else if (request.assetId != null) {
103             lockResourceNames.add(request.assetId);
104         }
105     }
106
107     @Override
108     public void _exec() throws ResourceLockedException {
109         outcome = allocate(request);
110
111         if ((outcome!=null) && (outcome.status == AllocationStatus.Success)) {
112             for (Resource r : updateList) {
113                 resourceDao.saveResource(r);
114             }
115         }
116     }
117
118     private AllocationOutcome allocate(AllocationRequest allocationRequest) throws ResourceLockedException {
119         if (allocationRequest instanceof MultiAssetAllocationRequest) {
120             return allocateMultiAsset((MultiAssetAllocationRequest) allocationRequest);
121         }
122         if (allocationRequest instanceof MultiResourceAllocationRequest) {
123             return allocateMultiResource((MultiResourceAllocationRequest) allocationRequest);
124         }
125         if (allocationRequest instanceof LimitAllocationRequest) {
126             return allocateLimit((LimitAllocationRequest) allocationRequest);
127         }
128         if (allocationRequest instanceof LabelAllocationRequest) {
129             return allocateLabel((LabelAllocationRequest) allocationRequest);
130         }
131         if (allocationRequest instanceof RangeAllocationRequest) {
132             return allocateRange((RangeAllocationRequest) allocationRequest);
133         }
134         return null;
135     }
136
137     private MultiAssetAllocationOutcome allocateMultiAsset(MultiAssetAllocationRequest req) {
138
139         return null;
140     }
141
142     private MultiResourceAllocationOutcome allocateMultiResource(MultiResourceAllocationRequest req) {
143         MultiResourceAllocationOutcome out = new MultiResourceAllocationOutcome();
144         out.request = req;
145         out.allocationOutcomeList = new ArrayList<>();
146         out.status = AllocationStatus.Success;
147
148         if (req.allocationRequestList != null) {
149             for (AllocationRequest req1 : req.allocationRequestList) {
150                 AllocationOutcome out1 = allocate(req1);
151                 out.allocationOutcomeList.add(out1);
152                 if (out1.status != AllocationStatus.Success) {
153                     out.status = AllocationStatus.Failure;
154                 }
155             }
156         }
157
158         return out;
159     }
160
161     private LimitAllocationOutcome allocateLimit(LimitAllocationRequest req) {
162         LimitAllocationOutcome out = new LimitAllocationOutcome();
163         out.request = req;
164
165         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
166         if (r == null) {
167             r = new LimitResource();
168             r.resourceKey = new ResourceKey();
169             r.resourceKey.assetId = req.assetId;
170             r.resourceKey.resourceName = req.resourceName;
171             r.resourceType = ResourceType.Limit;
172         } else {
173             if (r.resourceType != ResourceType.Limit) {
174                 out.status = AllocationStatus.ResourceNotFound;
175                 return out;
176             }
177             LimitUtil.recalculate((LimitResource) r);
178         }
179
180         LimitResource l = (LimitResource) r;
181         if (LimitUtil.checkLimit(l, req)) {
182             out.status = AllocationStatus.Success;
183             if (req.allocateCount > 0) {
184                 out.allocatedCount = LimitUtil.allocateLimit(l, req);
185                 updateList.add(l);
186             }
187         } else {
188             out.status = AllocationStatus.Failure;
189         }
190
191         out.used = l.used;
192         out.limit = req.checkLimit;
193
194         return out;
195     }
196
197     private LabelAllocationOutcome allocateLabel(LabelAllocationRequest req) {
198         LabelAllocationOutcome out = new LabelAllocationOutcome();
199
200         out.request = req;
201
202         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
203         if (r == null) {
204             r = new LabelResource();
205             r.resourceKey = new ResourceKey();
206             r.resourceKey.assetId = req.assetId;
207             r.resourceKey.resourceName = req.resourceName;
208             r.resourceType = ResourceType.Label;
209         } else {
210             if (r.resourceType != ResourceType.Label) {
211                 out.status = AllocationStatus.ResourceNotFound;
212                 return out;
213             }
214             LabelUtil.recalculate((LabelResource) r);
215         }
216
217         LabelResource l = (LabelResource) r;
218         if (LabelUtil.checkLabel(l, req)) {
219             out.status = AllocationStatus.Success;
220             out.currentLabel = l.label;
221             if (req.allocate) {
222                 out.allocatedLabel = LabelUtil.allocateLabel(l, req);
223                 updateList.add(l);
224             }
225         } else {
226             out.status = AllocationStatus.Failure;
227         }
228
229         return out;
230     }
231
232     private RangeAllocationOutcome allocateRange(RangeAllocationRequest req) {
233         RangeAllocationOutcome out = new RangeAllocationOutcome();
234
235         out.request = req;
236
237         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
238         if (r == null) {
239             r = new RangeResource();
240             r.resourceKey = new ResourceKey();
241             r.resourceKey.assetId = req.assetId;
242             r.resourceKey.resourceName = req.resourceName;
243             r.resourceType = ResourceType.Range;
244         } else {
245             if (r.resourceType != ResourceType.Range) {
246                 out.status = AllocationStatus.ResourceNotFound;
247                 return out;
248             }
249             RangeUtil.recalculate((RangeResource) r);
250         }
251
252         RangeResource rr = (RangeResource) r;
253         SortedSet<Integer> foundNumbers = null;
254         if (!req.check) {
255             out.status = AllocationStatus.Success;
256             foundNumbers = req.requestedNumbers;
257         } else {
258             if (req.requestedNumbers != null && !req.requestedNumbers.isEmpty()) {
259                 foundNumbers = req.requestedNumbers;
260                 out.status = AllocationStatus.Success;
261                 for (int n : foundNumbers) {
262                     if (!RangeUtil.checkRange(rr, req, n)) {
263                         out.status = AllocationStatus.Failure;
264                         break;
265                     }
266                 }
267             } else {
268                 foundNumbers = new TreeSet<>();
269                 int foundCount = 0;
270
271                 // First try to reuse the numbers already taken by the same resource union
272                 SortedSet<Integer> uu = RangeUtil.getUsed(rr, req.resourceUnionId);
273                 if (uu != null && !uu.isEmpty() && req.replace && !req.forceNewNumbers) {
274                     if (uu.size() >= req.requestedCount) {
275                         // Just take the first req.requestedCount numbers from uu
276                         Iterator<Integer> i = uu.iterator();
277                         while (foundCount < req.requestedCount) {
278                             foundNumbers.add(i.next());
279                             foundCount++;
280                         }
281                     } else {
282                         // Additional numbers are requested. Try to find them starting from
283                         // the minimum we have in uu (the first element) towards the min
284                         // parameter, and then starting from the maximum in uu (the last
285                         // element) towards the max parameter.
286                         // NOTE: In case of request for sequential numbers, the parameters
287                         // alignBlockSize and alignModulus are ignored. It would be harder
288                         // to take them into account, and currently it is not needed.
289
290                         // Request may contain multiple ranges. We will find the range from the request
291                         // that contains the currently used numbers (the first one). We will only look
292                         // for additional numbers in that range.
293
294                         Range range = null;
295                         if (req.rangeList != null) {
296                             for (Range range1 : req.rangeList) {
297                                 if (uu.first() >= range1.min && uu.first() <= range1.max) {
298                                     range = range1;
299                                     break;
300                                 }
301                             }
302                         }
303
304                         if (range != null) {
305                             int uumin = uu.first() - 1;
306                             int uumax = uu.last() + 1;
307                             foundNumbers.addAll(uu);
308                             foundCount = uu.size();
309                             for (int n = uumin; foundCount < req.requestedCount && n >= range.min; n--) {
310                                 if (RangeUtil.checkRange(rr, req, n)) {
311                                     foundNumbers.add(n);
312                                     foundCount++;
313                                 } else if (req.sequential) {
314                                     break;
315                                 }
316                             }
317                             for (int n = uumax; foundCount < req.requestedCount && n <= range.max; n++) {
318                                 if (RangeUtil.checkRange(rr, req, n)) {
319                                     foundNumbers.add(n);
320                                     foundCount++;
321                                 } else if (req.sequential) {
322                                     break;
323                                 }
324                             }
325                         }
326
327                         // If we could not find enough numbers trying to reuse currently
328                         // allocated, reset foundNumbers and foundCount, continue with
329                         // the normal allocation of new numbers.
330                         if (foundCount < req.requestedCount) {
331                             foundNumbers = new TreeSet<>();
332                             foundCount = 0;
333                         }
334                     }
335                 }
336
337                 if (req.rangeList != null) {
338                     if (req.reverseOrder) {
339                         for (int i = req.rangeList.size() - 1; i >= 0; i--) {
340                             Range range = req.rangeList.get(i);
341                             for (int n = range.max; foundCount < req.requestedCount && n >= range.min; n--) {
342                                 if (RangeUtil.checkRange(rr, req, n)) {
343                                     foundNumbers.add(n);
344                                     foundCount++;
345                                 } else if (req.sequential) {
346                                     foundCount = 0;
347                                 }
348                             }
349                         }
350                     } else {
351                         for (Range range : req.rangeList) {
352                             for (int n = range.min; foundCount < req.requestedCount && n <= range.max; n++) {
353                                 if (RangeUtil.checkRange(rr, req, n)) {
354                                     foundNumbers.add(n);
355                                     foundCount++;
356                                 } else if (req.sequential) {
357                                     foundCount = 0;
358                                 }
359                             }
360                         }
361                     }
362                 }
363
364                 out.status = foundCount == req.requestedCount ? AllocationStatus.Success : AllocationStatus.Failure;
365             }
366         }
367
368         if (out.status == AllocationStatus.Success) {
369             out.allocated = foundNumbers;
370             if (req.allocate) {
371                 RangeUtil.allocateRange(rr, out.allocated, req);
372                 updateList.add(rr);
373             }
374         } else {
375             out.allocated = new TreeSet<>();
376         }
377
378         out.used = rr.used;
379
380         return out;
381     }
382
383     public AllocationOutcome getAllocationOutcome() {
384         return outcome;
385     }
386 }