ffaeeb96a1e4038fc4fa659ec24ffcd838bb8c4a
[optf/cmso.git] /
1 /*
2  *  ============LICENSE_START==============================================
3  *  Copyright (c) 2019 AT&T Intellectual Property.
4  *  =======================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
6  *  not use this file except in compliance with the License. You may obtain a
7  *  copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing
15  * permissions and limitations under the License.
16  * ============LICENSE_END=================================================
17  */
18
19 package org.onap.optf.cmso.optimizer.clients.optimizer;
20
21 import com.google.ical.compat.jodatime.DateTimeIterator;
22 import java.text.ParseException;
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.TreeMap;
29 import org.joda.time.DateTime;
30 import org.onap.optf.cmso.optimizer.availability.policies.model.TimeLimitAndVerticalTopology;
31 import org.onap.optf.cmso.optimizer.availability.timewindows.RecurringWindows;
32 import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerParameters;
33 import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse;
34 import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.TicketData;
35 import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyElementInfo;
36 import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse;
37 import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow;
38 import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest;
39
40 public class ElementAvailability extends ElementWindowMapping{
41
42     private List<TimeLimitAndVerticalTopology> policies;
43     private ActiveTicketsResponse ticketResponse;
44
45     private OptimizerParameters parameters = null;
46
47     private List<List<ChangeWindow>> globalRelativeAvailability = new ArrayList<>();
48
49     private Map<String, List<TicketData>> nodeUnAvailability = new TreeMap<>();
50
51     public ElementAvailability(List<TimeLimitAndVerticalTopology> policies, OptimizerRequest optimizerRequest,
52                     TopologyResponse topologyResponse, ActiveTicketsResponse ticketResponse) throws ParseException {
53         super(optimizerRequest, topologyResponse);
54         this.policies         = policies;
55         this.ticketResponse   = ticketResponse;
56     }
57
58     public void populate(OptimizerParameters parameters) throws ParseException {
59         this.parameters = parameters;
60         for (ChangeWindow changeWindow : optimizerRequest.getChangeWindows()) {
61             if  (policies.size() > 0) {
62                 globalRelativeAvailability
63                                 .add(RecurringWindows.getAvailabilityWindowsForPolicies(policies, changeWindow));
64             } else {
65                 List<ChangeWindow> wholeWindow = new ArrayList<>();
66                 wholeWindow.add(changeWindow);
67                 globalRelativeAvailability.add(wholeWindow);
68             }
69         }
70         for (String id : nodeInfo.keySet()) {
71             calculateNodeAvailability(nodeInfo.get(id));
72         }
73         setNoConflicts();
74         parameters.setMaxTime(new Long(parameters.getNoConflict().get(0).size()));
75         parameters.setNumElements(new Long(parameters.getNoConflict().size()));
76
77         // for now we have 1 loader with unlimited capacity
78         parameters.setNumLoaders(1L);
79         Long loaderCapacity = parameters.getNumElements();
80         List<Long> capacity =  new ArrayList<>();
81         for (Long slot =0L ; slot < parameters.getMaxTime() ; slot++) {
82             capacity.add(loaderCapacity);
83         }
84         parameters.getLoaderCapacity().add(capacity);
85
86         // For now every slot has the same concurrency limit
87         capacity =  new ArrayList<>();
88         Long limit = new Long(optimizerRequest.getConcurrencyLimit());
89         if (limit > parameters.getNumElements()) {
90             limit = parameters.getNumElements();
91         }
92
93         for (Long slot =0L ; slot < parameters.getMaxTime() ; slot++) {
94             capacity.add(limit);
95         }
96         parameters.setElementSlotCapacity(capacity);
97
98     }
99
100     private void setNoConflicts() throws ParseException {
101         // Only support 1 change window for now
102         ChangeWindow window = optimizerRequest.getChangeWindows().get(0);
103         Long duration = new Long(optimizerRequest.getNormalDuration());
104         if (optimizerRequest.getAdditionalDuration() != null) {
105             duration += optimizerRequest.getAdditionalDuration();
106         }
107         for (String elementId : nodeInfo.keySet()) {
108
109             TopologyElementInfo info = nodeInfo.get(elementId);
110             // Library for lat/lon to timzezone is MIT license.
111             // We must provided
112             String timeZone = "GMT";
113             if (info.getElementLocation() != null && info.getElementLocation().getTimezone() != null
114                             && !info.getElementLocation().getTimezone().equals("")) {
115                 timeZone = info.getElementLocation().getTimezone();
116             }
117             DateTimeIterator recur = getRecurringIterator();
118             List<Boolean> element = new ArrayList<>();
119             // calculate number time slots
120             long numberOfTimeSlots = calculateNumberOfSlotsInWindow(window, duration);
121             while (recur.hasNext() && element.size() < numberOfTimeSlots) {
122                 DateTime next = recur.next();
123                 if (next.isAfter(window.getEndTime().getTime())) {
124                     break;
125                 }
126                 ChangeWindow slot = new ChangeWindow();
127                 slot.setStartTime(next.toDate());
128                 slot.setEndTime(next.plus(duration).toDate());
129                 if (slotIsAvailable(slot, timeZone, nodeUnAvailability.get(elementId))) {
130                     element.add(true);
131                 } else {
132                     element.add(false);
133                 }
134             }
135             parameters.getNoConflict().add(element);
136         }
137
138     }
139
140     private long calculateNumberOfSlotsInWindow(ChangeWindow window, Long duration)
141     {
142         long windowSize = window.getEndTime().getTime() - window.getStartTime().getTime();
143         long numberOfSlots = windowSize /duration;
144         return numberOfSlots;
145     }
146
147     private boolean slotIsAvailable(ChangeWindow slot, String timeZone, List<TicketData> tickets) {
148         if (isGloballyAvailable(slot, timeZone) && isNotRestricted(slot, tickets)) {
149             return true;
150         }
151         return false;
152     }
153
154     private boolean isNotRestricted(ChangeWindow slot, List<TicketData> tickets) {
155         if (tickets != null) {
156             for (TicketData ticket : tickets) {
157                 ChangeWindow window = new ChangeWindow();
158                 window.setStartTime(ticket.getStartTime());
159                 window.setEndTime(ticket.getEndTime());
160                 if (slot.overlaps(window)) {
161                     return false;
162                 }
163             }
164         }
165         return true;
166     }
167
168     //
169     // Globally availability are generally maintenance window definitions
170     // which are UTC times that are treated as relative to the local time zone.
171     // The slot is an absolute UTCT time as well.
172     // When we test to see if the slot is 'globally' available we must adjust it
173     // to the local time of the element to see it it matches the relative
174     // Consider
175     // slot UTC time is 06:00-07:00
176     // global availability (maintenance window) 00:00-06:00
177     // the slot for an element in US/Eastern
178     // time would be converted to 01:00-02:00
179     // and would fit in the local maintenance window
180     //
181     private boolean isGloballyAvailable(ChangeWindow slot, String timeZone) {
182         boolean available = false;
183         for (ChangeWindow global : globalRelativeAvailability.get(0)) {
184             if (global.containsInTimeZone(slot, timeZone)) {
185                 available = true;
186             }
187         }
188         return available;
189     }
190
191     private void calculateNodeAvailability(TopologyElementInfo info) {
192         Set<String> requiredElements = new HashSet<>();
193         requiredElements.add(info.getElementId());
194         if (info.getRequiredElements() != null) {
195             requiredElements.addAll(info.getRequiredElements());
196         }
197         if (ticketResponse.getElements() != null) {
198             List<TicketData> tickets = ticketResponse.getElements();
199             for (TicketData data : tickets) {
200                 for (String id : data.getElementIds()) {
201                     if (requiredElements.contains(id)) {
202                         updateNodeAvailability(id, data);
203                         break;
204                     }
205                 }
206             }
207         }
208     }
209
210     private void updateNodeAvailability(String elementId, TicketData data) {
211         List<TicketData> list = nodeUnAvailability.get(elementId);
212         if (list == null) {
213             list = new ArrayList<>();
214             nodeUnAvailability.put(elementId, list);
215         }
216         list.add(data);
217     }
218
219 }