diff options
Diffstat (limited to 'cmso-optimizer')
29 files changed, 2114 insertions, 32 deletions
diff --git a/cmso-optimizer/etc/config/optimizer.properties b/cmso-optimizer/etc/config/optimizer.properties index ac39ec8..641bbeb 100644 --- a/cmso-optimizer/etc/config/optimizer.properties +++ b/cmso-optimizer/etc/config/optimizer.properties @@ -46,4 +46,9 @@ logging.level.org.hibernate=TRACE cmso.topology.create.request.url=http://127.0.0.1:7998/topology/v1/current cmso.ticket.create.request.url=http://127.0.0.1:7999/ticketmgt/v1/activetickets -cmso.local.policy.folder=data/policies
\ No newline at end of file +cmso.local.policy.folder=data/policies + +cmso.minizinc.command.exe="C:/Program Files/MiniZinc IDE (bundled)/minizinc.exe" +cmso.minizinc.command.solver=OSICBC +cmso.minizinc.command.timelimit=60000 +cmso.minizinc.command.mzn=scripts/minizinc/generic_attributes.mzn diff --git a/cmso-optimizer/pom.xml b/cmso-optimizer/pom.xml index 8db7eb2..2ede9e7 100644 --- a/cmso-optimizer/pom.xml +++ b/cmso-optimizer/pom.xml @@ -141,6 +141,11 @@ <artifactId>httpclient</artifactId> </dependency> <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.6</version> + </dependency> + <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <scope>test</scope> @@ -205,6 +210,11 @@ </exclusions> </dependency> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + </dependency> + <!-- <dependency> <groupId>org.onap.aaf.authz</groupId> <artifactId>aaf-cadi-aaf</artifactId> <version>2.1.1</version> </dependency> --> <dependency> diff --git a/cmso-optimizer/scripts/minizinc/generic_attributes.mzn b/cmso-optimizer/scripts/minizinc/generic_attributes.mzn new file mode 100644 index 0000000..af38df9 --- /dev/null +++ b/cmso-optimizer/scripts/minizinc/generic_attributes.mzn @@ -0,0 +1,199 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% element scheduling problem +%% Modified on Mar 08, 2019 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Parameters +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Required (core) parameters +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Number of elements. +int: numElements; + +% Number of loaders/engineers. +int: numLoaders; + +% Index of last possible time-slot for scheduling These time slots can be +% minutes, hours, or nights. E.g., if scheduling happens at the granularity of +% nights, 1st night is counted as 1, 2nd night counted as 2, and so on. OTOH, +% if we have 6 hours each night and we are scheduling at the granularity of +% hours, 1st hour of 1st night is 1, 1st hour of 2nd night is 7, and so on. +int: maxTime; + +% TRUE, if i-th element does NOT have a conflict on j-th timeslot/night. +array[1..numElements, 1..maxTime] of bool: noConflict; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Optional parameters (defined via policy) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Each attribute is composed of 3 parameters that must be supplied. When an +% attribute is selected, all parameters related to it must be given. + +%%%%%%%%%%%%%%%%%%%% +% Timeslots / nights capacities +%%%%%%%%%%%%%%%%%%%% + +% Maximum number of elements that can be scheduled on j-th timeslot/night. +array[1..maxTime] of 0..numElements: elementSlotCapacity; + +%%%%%%%%%%%%%%%%%%%% +% Loader capacities +%%%%%%%%%%%%%%%%%%%% + +% Maximum number of elements that can be assigned to the j-th loader per +% timeslot/night. +array[1..numLoaders, 1..maxTime] of 0..numElements: loaderCapacity; + +%%%%%%%%%%%%%%%%%%%% +% Attribute matrix +%%%%%%%%%%%%%%%%%%%% + +% Number of attributes for wach node, e.g., hardware, software, oss, market, +% pool, etc. +int: numAttributes; + +% Assume that i-th attribute has a range 0..attribute_range[i]. +% Assume that 0 indicates NA. E.g, we may have pools and a node +% that does not belong to any pools will have 'pool attribute = 0 +% when we write constraints, we only consider attribute values >= 1. +array[1..numAttributes] of int: attributesRange; + +% The attribute matrix that holds values of each attribute for a element. +array[1..numElements, 1..numAttributes] of int: attributes; + +% Maximum number of nodes per time-slot that match on a given attribute. +array[1..numAttributes, 1..maxTime] of int: attributeConcurrencyLimit; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Variables +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% TRUE, if i-th element gets scheduled on j-th night. +array[1..numElements, 1..maxTime] of var bool: ELEMENT2TIMESLOT; + +% TRUE, if i-th element gets scheduled to j-th loader. +array[1..numElements, 1..numLoaders] of var bool: ELEMENT2LOADER; + +% Indicates the time slot (nigth) in which the elements were scheduled. +array[1..numElements] of var 0..maxTime: SCHEDULED_SLOT = + [sum(j in 1..maxTime)(j * bool2int(ELEMENT2TIMESLOT[i,j])) | i in 1..numElements]; + +% Indicates the loader for which the elements were scheduled. +array[1..numElements] of var 0..numLoaders: SCHEDULED_LOADER = + [sum(l in 1..numLoaders)(l * bool2int(ELEMENT2LOADER[i,l])) | i in 1..numElements]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Constraints +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Required (core) constraints +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Schedule only on noConclict nights. +constraint +forall(i in 1..numElements, j in 1..maxTime)( + ELEMENT2TIMESLOT[i,j] -> noConflict[i,j] +); + +% Schedule a element to a loader +constraint +forall(i in 1..numElements)( + sum(t in 1..maxTime)(bool2int(ELEMENT2TIMESLOT[i,t])) == + sum(l in 1..numLoaders)(bool2int(ELEMENT2LOADER[i,l])) +); + +% Schedule each element exactly one timeslot/night (or none). +constraint +forall(i in 1..numElements)( + sum(j in 1..maxTime)(bool2int(ELEMENT2TIMESLOT[i,j])) <= 1 +); + +% Schedule each element exactly one loader (or none). +constraint +forall(i in 1..numElements)( + sum(j in 1..numLoaders)(bool2int(ELEMENT2LOADER[i,j])) <= 1 +); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Optional constraints (defined via policy) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%These constraints are defined via policy and require sets of parameters also +%defined via policy. They must be both available. + +%%%%%%%%%%%%%%%%%%%% +% General capacity constraints +%%%%%%%%%%%%%%%%%%%% + +% Satisfy element timeslot/nightly capacity. +constraint +forall(j in 1..maxTime)( + sum(i in 1..numElements)(bool2int(ELEMENT2TIMESLOT[i,j])) <= elementSlotCapacity[j] +); + +% Satisfy loader/timeslot capacity. +constraint +forall(l in 1..numLoaders, t in 1..maxTime)( + sum(i in 1..numElements)( + bool2int(ELEMENT2LOADER[i,l] /\ ELEMENT2TIMESLOT[i,t]) + ) <= loaderCapacity[l,t] +); + +%%%%%%%%%%%%%%%%%%%% +% Attribute capacity constraints +%%%%%%%%%%%%%%%%%%%% + +% For attribute a and timeslot/night t, limits the number of elements having +% the same value for attribute k, scheduled in the same timeslot/night t. +constraint +forall(t in 1..maxTime, a in 1..numAttributes)( + forall(m in 1..attributesRange[a])( + sum(i in 1..numElements)( + bool2int(attributes[i,a] == m /\ ELEMENT2TIMESLOT[i,t]) + ) <= attributeConcurrencyLimit[a,t] + ) +); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Objective function +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Computes the number of scheduled elements. +var int: NUM_SCHEDULED = sum(i in 1..numElements)(bool2int(SCHEDULED_SLOT[i] > 0)); + +% Computes the (average) completion time of all elements. Note that average is +% just a simple division by a constant, and it can be dropped from the model +% for robusteness. +var int: TOTAL_COMPLETION_TIME = sum(i in 1..numElements)(SCHEDULED_SLOT[i]); + +% First, maximize the number of scheduled elements (using a heavy weight) +% and then minimize the (average) completion time for all elements. +solve maximize maxTime * numElements * NUM_SCHEDULED - TOTAL_COMPLETION_TIME; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Output +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +output +["results:"] ++ +["\n -"] ++ +["\n num_scheduled: " ++ show(NUM_SCHEDULED)] ++ +["\n total_completion_time: " ++ show(TOTAL_COMPLETION_TIME)] ++ +["\n element_slot_loader: |"] ++ +[ + "\n " ++ show(element) ++ "," ++ show(SCHEDULED_SLOT[element]) ++ "," ++ + show(SCHEDULED_LOADER[element]) +| element in 1..numElements +] + +%output +%["\n - num_scheduled: " ++ show(NUM_SCHEDULED)] ++ +%["\n total_completion_time: " ++ show(TOTAL_COMPLETION_TIME)] ++ +%["\n elementSlotLoader |"] ++ +%[ "\n " ++ show(element) ++ "," ++ +%show(SCHEDULED_SLOT[element]) ++ "," ++ show(SCHEDULED_LOADER[element]) | element in +%1..numElements ] diff --git a/cmso-optimizer/src/main/docker/assembly/cmso-files.xml b/cmso-optimizer/src/main/docker/assembly/cmso-files.xml index 37804ec..2e3f19e 100644 --- a/cmso-optimizer/src/main/docker/assembly/cmso-files.xml +++ b/cmso-optimizer/src/main/docker/assembly/cmso-files.xml @@ -1,5 +1,4 @@ <!-- ============LICENSE_START======================================================= - ECOMP CMSO ================================================================================ Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy diff --git a/cmso-optimizer/src/main/java/org/onap/observations/Mdc.java b/cmso-optimizer/src/main/java/org/onap/observations/Mdc.java index 0686f59..5dea5aa 100644 --- a/cmso-optimizer/src/main/java/org/onap/observations/Mdc.java +++ b/cmso-optimizer/src/main/java/org/onap/observations/Mdc.java @@ -53,7 +53,7 @@ import org.onap.observations.MessageHeaders.HeadersEnum; import org.slf4j.MDC; /** - * ECOMP EELF logging MDC fields not defined in the MDC Configuration (i.e. MDC_ALERT_SEVERITY) + * EELF logging MDC fields not defined in the MDC Configuration (i.e. MDC_ALERT_SEVERITY) **/ public class Mdc { diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java index dce64b4..23e3ad8 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java @@ -32,7 +32,6 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -212,5 +211,17 @@ public class RecurringWindows { return instant.plus(date.toEpochMilli(), ChronoUnit.MILLIS); } + public static DateTimeIterator getRecurringListForChangeWindow(ChangeWindow window, Long durationInSeconds) + throws ParseException { + + String rdata = "RRULE:FREQ=MINUTELY;INTERVAL=" + durationInSeconds/60; + DateTime start = new DateTime(window.getStartTime().toInstant().toEpochMilli()); + DateTimeIterator recur = + DateTimeIteratorFactory.createDateTimeIterator(rdata, start, DateTimeZone.UTC, true); + return recur; + } + + + } diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java new file mode 100644 index 0000000..4766db2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java @@ -0,0 +1,197 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.google.ical.compat.jodatime.DateTimeIterator; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import org.joda.time.DateTime; +import org.onap.optf.cmso.optimizer.availability.policies.model.TimeLimitAndVerticalTopology; +import org.onap.optf.cmso.optimizer.availability.timewindows.RecurringWindows; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerParameters; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.TicketData; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyElementInfo; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.springframework.expression.spel.ast.OpInc; + +public class ElementAvailability extends ElementWindowMapping{ + + private List<TimeLimitAndVerticalTopology> policies; + private ActiveTicketsResponse ticketResponse; + + private OptimizerParameters parameters = null; + + private List<List<ChangeWindow>> globalRelativeAvailability = new ArrayList<>(); + + private Map<String, List<TicketData>> nodeUnAvailability = new TreeMap<>(); + + public ElementAvailability(List<TimeLimitAndVerticalTopology> policies, OptimizerRequest optimizerRequest, + TopologyResponse topologyResponse, ActiveTicketsResponse ticketResponse) throws ParseException + { + super(optimizerRequest, topologyResponse); + this.policies = policies; + this.ticketResponse = ticketResponse; + } + + public void populate(OptimizerParameters parameters) throws ParseException { + this.parameters = parameters; + for (ChangeWindow changeWindow : optimizerRequest.getChangeWindows()) { + if (policies.size() > 0) { + globalRelativeAvailability.add(RecurringWindows.getAvailabilityWindowsForPolicies(policies, changeWindow)); + } + else { + List<ChangeWindow> wholeWindow = new ArrayList<>(); + wholeWindow.add(changeWindow); + globalRelativeAvailability.add(wholeWindow); + } + } + for (String id : nodeInfo.keySet()) { + calculateNodeAvailability(nodeInfo.get(id)); + } + setNoConflicts(); + parameters.setMaxTime(new Long(parameters.getNoConflict().get(0).size())); + parameters.setNumElements(new Long(parameters.getNoConflict().size())); + + // for now we have 1 loader with unlimited capacity + parameters.setNumLoaders(1L); + Long loaderCapacity = parameters.getNumElements(); + List<Long> capacity = new ArrayList<>(); + for (Long slot =0L ; slot < parameters.getMaxTime() ; slot++) { + capacity.add(loaderCapacity); + } + parameters.getLoaderCapacity().add(capacity); + + // For now every slot has the same concurrency limit + capacity = new ArrayList<>(); + Long limit = new Long(optimizerRequest.getConcurrencyLimit()); + if (limit > parameters.getNumElements()) { + limit = parameters.getNumElements(); + } + + for (Long slot =0L ; slot < parameters.getMaxTime() ; slot++) { + capacity.add(limit); + } + parameters.setElementSlotCapacity(capacity); + + } + + private void setNoConflicts() throws ParseException { + // Only support 1 change window for now + ChangeWindow window = optimizerRequest.getChangeWindows().get(0); + Long duration = new Long(optimizerRequest.getNormalDuration()); + if (optimizerRequest.getAdditionalDuration() != null) { + duration += optimizerRequest.getAdditionalDuration(); + } + for (String elementId : nodeInfo.keySet()) { + + TopologyElementInfo info = nodeInfo.get(elementId); + Long timeZoneOffset = getTimeZoneOffset(info); + DateTimeIterator recur = getRecurringIterator(); + List<Boolean> element = new ArrayList<>(); + while (recur.hasNext()) { + DateTime next = recur.next(); + if (next.isAfter(window.getEndTime().getTime())) { + break; + } + ChangeWindow slot = new ChangeWindow(); + slot.setStartTime(next.toDate()); + slot.setEndTime(next.plus(duration).toDate()); + if (slotIsAvailable(slot, timeZoneOffset, nodeUnAvailability.get(elementId))) { + element.add(true); + } else { + element.add(false); + } + } + parameters.getNoConflict().add(element); + } + + } + + private boolean slotIsAvailable(ChangeWindow slot, Long timeZoneOffset, List<TicketData> tickets) { + if (isGloballyAvailable(slot, timeZoneOffset) && isNotRestricted(slot, tickets)) { + return true; + } + return false; + } + + private boolean isNotRestricted(ChangeWindow slot, List<TicketData> tickets) { + if (tickets != null) { + for (TicketData ticket : tickets) { + ChangeWindow window = new ChangeWindow(); + window.setStartTime(ticket.getStartTime()); + window.setEndTime(ticket.getEndTime()); + if (slot.overlaps(window)) { + return false; + } + } + } + return true; + } + + private boolean isGloballyAvailable(ChangeWindow slot, Long timeZoneOffset) { + for (ChangeWindow global : globalRelativeAvailability.get(0)) { + if (global.containsInTimeZone(slot, timeZoneOffset)) { + return true; + } + } + return false; + } + + private Long getTimeZoneOffset(TopologyElementInfo info) { + // TODO Auto-generated method stub + return 0L; + } + + private void calculateNodeAvailability(TopologyElementInfo info) { + Set<String> requiredElements = new HashSet<>(); + requiredElements.add(info.getElementId()); + if (info.getRequiredElements() != null) { + requiredElements.addAll(info.getRequiredElements()); + } + if (ticketResponse.getElements() != null) { + List<TicketData> tickets = ticketResponse.getElements(); + for (TicketData data : tickets) { + for (String id : data.getElementIds()) { + if (requiredElements.contains(id)) { + updateNodeAvailability(id, data); + break; + } + } + } + } + } + + private void updateNodeAvailability(String elementId, TicketData data) { + List<TicketData> list = nodeUnAvailability.get(elementId); + if (list == null) { + list = new ArrayList<>(); + nodeUnAvailability.put(elementId, list); + } + list.add(data); + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java new file mode 100644 index 0000000..42c69a2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java @@ -0,0 +1,148 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.google.ical.compat.jodatime.DateTimeIterator; +import java.text.ParseException; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; +import org.joda.time.DateTime; +import org.onap.optf.cmso.optimizer.availability.timewindows.RecurringWindows; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.ElementSlot; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerSchedule; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyElementInfo; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerScheduleInfo; +import org.onap.optf.cmso.optimizer.service.rs.models.ScheduledElement; +import org.onap.optf.cmso.optimizer.service.rs.models.ScheduledElement.ScheduleType; +import org.onap.optf.cmso.optimizer.service.rs.models.UnScheduledElement; +import org.onap.optf.cmso.optimizer.service.rs.models.UnScheduledElement.NotScheduledReason; + +// This class ensures that the node indices nodes and the time slots are the +// same when processing the optimizer engine response as when initiating. +public class ElementWindowMapping { + + protected OptimizerRequest optimizerRequest; + protected TopologyResponse topologyResponse; + + protected Map<String, TopologyElementInfo> nodeInfo = new TreeMap<>(); + private List<TopologyElementInfo> nodeArray = null; + + public ElementWindowMapping(OptimizerRequest optimizerRequest, TopologyResponse topologyResponse) + throws ParseException { + this.optimizerRequest = optimizerRequest; + this.topologyResponse = topologyResponse; + initialize(); + + } + + private void initialize() throws ParseException { + List<TopologyElementInfo> elements = topologyResponse.getElements(); + for (TopologyElementInfo info : elements) { + nodeInfo.put(info.getElementId(), info); + } + } + + protected DateTimeIterator getRecurringIterator() throws ParseException { + // Only support 1 change window for now + ChangeWindow window = optimizerRequest.getChangeWindows().get(0); + Long duration = new Long(optimizerRequest.getNormalDuration()); + if (optimizerRequest.getAdditionalDuration() != null) { + duration += optimizerRequest.getAdditionalDuration(); + } + DateTimeIterator recur = RecurringWindows.getRecurringListForChangeWindow(window, duration); + return recur; + } + + public void initializeForProcessResult() + { + // we need nodeInfo to be an array to speed up the result processing. + // but we need it sorted by elementId as when we created it.... + nodeArray = nodeInfo.values().stream().collect(Collectors.toList()); + nodeInfo.clear(); + + } + public OptimizerScheduleInfo processResult(OptimizerSchedule result) throws ParseException { + // When considering the memory vs performance + // 5 minute duration for a month long change window is 8928 slots + // The assumption is that there were be fewer allocated slots + // than potential slots. + List<ElementSlot> elements = result.getElementSlotLoader(); + Map<Integer, List<ElementSlot>> mapSlotToElement = elements.stream(). + collect(Collectors.groupingBy(ElementSlot::getSlot)); + DateTimeIterator iter = getRecurringIterator(); + // TODO - supporting only 1 change window at the moment..... + Long endWindow = optimizerRequest.getChangeWindows().get(0).getEndTime().getTime(); + Integer slotIndex = 1; + while (iter.hasNext()) { + DateTime dateTime = iter.next(); + if (dateTime.isAfter(endWindow)) + break; + List<ElementSlot> list = mapSlotToElement.get(slotIndex); + if (list != null) { + list.stream().forEach(x -> x.setTime(dateTime.getMillis())); + } + slotIndex++; + } + // + // All assigned ElementSlots now have corresponding UTC time + // + OptimizerScheduleInfo info = new OptimizerScheduleInfo(); + for (ElementSlot slot : elements) + { + updateInfo(slot, info); + } + return info; + } + + private void updateInfo(ElementSlot slot, OptimizerScheduleInfo info) + { + TopologyElementInfo element = nodeArray.get(slot.getElementIndex()-1); + if (slot.getSlot() > 0) + { + ScheduledElement scheduled = new ScheduledElement(); + Integer durationInSeconds = optimizerRequest.getNormalDuration(); + if (optimizerRequest.getAdditionalDuration() != null) { + durationInSeconds += optimizerRequest.getAdditionalDuration(); + } + scheduled.setDurationSeconds(durationInSeconds.longValue()); + scheduled.setElementId(element.getElementId()); + scheduled.setStartTime(new Date(slot.getTime())); + scheduled.setEndTime(new Date(slot.getTime() + (durationInSeconds*1000))); + scheduled.setScheduleType(ScheduleType.INDIVIDUAL); + info.getScheduledElements().add(scheduled); + } + else + { + UnScheduledElement unscheduled = new UnScheduledElement(); + unscheduled.setElementId(element.getElementId()); + unscheduled.setGroupId("unknown"); + unscheduled.getNotScheduledReaons().add(NotScheduledReason.Other); + unscheduled.getNotScheduledMessages().add("Unknown"); + info.getUnScheduledElements().add(unscheduled); + } + } + + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java new file mode 100644 index 0000000..514097e --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java @@ -0,0 +1,279 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + * + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.apache.commons.io.IOUtils; +import org.onap.observations.Observation; +import org.onap.optf.cmso.common.PropertiesManagement; +import org.onap.optf.cmso.common.exceptions.CmsoException; +import org.onap.optf.cmso.optimizer.availability.policies.PolicyManager; +import org.onap.optf.cmso.optimizer.availability.policies.model.TimeLimitAndVerticalTopology; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse.OptimizerEngineResponseStatus; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerParameters; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerResponseUtility; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerResults; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.TicketMgtRequestManager; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse; +import org.onap.optf.cmso.optimizer.clients.topology.TopologyRequestManager; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.common.LogMessages; +import org.onap.optf.cmso.optimizer.model.Optimizer; +import org.onap.optf.cmso.optimizer.model.Request; +import org.onap.optf.cmso.optimizer.model.Ticket; +import org.onap.optf.cmso.optimizer.model.Topology; +import org.onap.optf.cmso.optimizer.model.dao.OptimizerDao; +import org.onap.optf.cmso.optimizer.model.dao.RequestDao; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerResponse.OptimizeScheduleStatus; +import org.onap.optf.cmso.optimizer.service.rs.models.PolicyInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * The Class OptimizerClient. + */ +@Component +public class OptimizerClient { + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + Environment env; + + @Autowired + PropertiesManagement pm; + + @Autowired + RequestDao requestDao; + + @Autowired + TopologyRequestManager topologyRequestManager; + + @Autowired + TicketMgtRequestManager ticketMgtRequestManager; + + @Autowired + OptimizerDao optimizerDao; + + @Autowired + PolicyManager policyManager; + + /** + * Make request. + * + * @param request the request + * @param optimizer the Optimizer + * @return the Optimizer response + */ + public OptimizerEngineResponse makeRequest(Request request, Optimizer optimizer) { + Integer maxAttempts = env.getProperty("cmso.optimizer.maxAttempts", Integer.class, 20); + OptimizerEngineResponse apiResponse = new OptimizerEngineResponse(); + if (optimizer.getOptimizeRetries() >= maxAttempts) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage(LogMessages.EXCEEDED_RETRY_LIMIT.format("Optimizer", maxAttempts.toString())); + Observation.report(LogMessages.EXCEEDED_RETRY_LIMIT, "Optimizer", maxAttempts.toString()); + return apiResponse; + } + OptimizerRequest optimizerRequest = null; + TopologyResponse topologyResponse = null; + ActiveTicketsResponse ticketResponse = null; + try { + optimizerRequest = getOptimizerRequest(request); + topologyResponse = getTopologyResponse(request.getUuid()); + ticketResponse = getTicketResponse(request.getUuid()); + OptimizerParameters optimizerParameters = + buildOptimizerParameters(optimizerRequest, topologyResponse, ticketResponse); + apiResponse = initiateOptimizer(optimizerParameters, request); + } catch (Exception e) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage(LogMessages.UNEXPECTED_EXCEPTION.format(e.getMessage())); + Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + return apiResponse; + } + + private OptimizerParameters buildOptimizerParameters(OptimizerRequest optimizerRequest, + TopologyResponse topologyResponse, ActiveTicketsResponse ticketResponse) throws ParseException { + List<TimeLimitAndVerticalTopology> policies = getPolicies(optimizerRequest); + OptimizerParameters parameters = new OptimizerParameters(); + ElementAvailability elementAvailability = + new ElementAvailability(policies, optimizerRequest, topologyResponse, ticketResponse); + elementAvailability.populate(parameters); + + // Policies for this are undefined... + parameters.setAttributes(getAttributes(policies, optimizerRequest)); + parameters.setAttributesRange(getAttributesRange(policies, optimizerRequest)); + parameters.setAttributeConcurrencyLimit(getAttributeConcrrencyLimit(policies, optimizerRequest)); + parameters.setNumAttributes(new Long(parameters.getAttributesRange().size())); + return parameters; + } + + private List<List<Long>> getAttributeConcrrencyLimit(List<TimeLimitAndVerticalTopology> policies, + OptimizerRequest optimizerRequest) { + List<List<Long>> list = new ArrayList<>(); + return list; + } + + private List<Long> getAttributesRange(List<TimeLimitAndVerticalTopology> policies, + OptimizerRequest optimizerRequest) { + List<Long> list = new ArrayList<>(); + return list; + } + + private List<List<Long>> getAttributes(List<TimeLimitAndVerticalTopology> policies, + OptimizerRequest optimizerRequest) { + List<List<Long>> list = new ArrayList<>(); + return list; + } + + + private List<TimeLimitAndVerticalTopology> getPolicies(OptimizerRequest optimizerRequest) { + List<TimeLimitAndVerticalTopology> list = new ArrayList<>(); + for (PolicyInfo policyInfo : optimizerRequest.getPolicies()) { + TimeLimitAndVerticalTopology policy = + policyManager.getTimeLimitAndVerticalTopologyByName(policyInfo.getPolicyName()); + list.add(policy); + } + return list; + } + + private ActiveTicketsResponse getTicketResponse(UUID uuid) + throws JsonParseException, JsonMappingException, IOException { + Ticket ticketRow = ticketMgtRequestManager.getExistingTickets(uuid); + String ticketString = ticketRow.getTickets(); + ObjectMapper om = new ObjectMapper(); + return om.readValue(ticketString, ActiveTicketsResponse.class); + } + + private TopologyResponse getTopologyResponse(UUID uuid) + throws JsonParseException, JsonMappingException, IOException { + Topology topologyRow = topologyRequestManager.getExistingTopology(uuid); + String topologyString = topologyRow.getTopology(); + ObjectMapper om = new ObjectMapper(); + return om.readValue(topologyString, TopologyResponse.class); + } + + private OptimizerRequest getOptimizerRequest(Request request) + throws JsonParseException, JsonMappingException, IOException { + String requestString = request.getRequest(); + ObjectMapper om = new ObjectMapper(); + return om.readValue(requestString, OptimizerRequest.class); + } + + + private OptimizerEngineResponse initiateOptimizer(OptimizerParameters request, Request requestRow) + throws CmsoException, JsonProcessingException { + + + UUID uuid = requestRow.getUuid(); + OptimizerEngineResponse apiResponse = new OptimizerEngineResponse(); + apiResponse.setRequestId(uuid.toString()); + + String workingFolderString = env.getProperty("cmso.optimizer.engine.working.folder", "data/engine"); + File workingFolder = new File(workingFolderString + File.separator + requestRow.getUuid().toString()); + workingFolder.mkdirs(); + Long timeLimit = env.getProperty("cmso.minizinc.command.timelimit", Long.class); + // TODO calculate time limit + Process p = null; + try { + Path inputFileName = Paths.get(workingFolder.getAbsolutePath(), "input.dzn"); + Path outputFileName = Paths.get(workingFolder.getAbsolutePath(), "results.yaml"); + String dzn = request.toMiniZinc(); + Files.write(inputFileName, dzn.getBytes()); + List<String> command = buildCommand(inputFileName, outputFileName, timeLimit.toString()); + debug.debug("engine command=", command.toString()); + ProcessBuilder pb = new ProcessBuilder(command); + p = pb.start(); + String stdout = IOUtils.toString(p.getInputStream(), "UTF-8"); + String stderr = IOUtils.toString(p.getErrorStream(), "UTF-8"); + debug.debug("stdout=" + stdout); + debug.debug("stderr=" + stderr); + if (p.isAlive()) { + p.wait(); + } + OptimizerResponseUtility responseUtility = new OptimizerResponseUtility(); + OptimizerResults optimizerResults = responseUtility.parseOptimizerResult(outputFileName.toFile()); + apiResponse.setOptimizerResults(optimizerResults); + apiResponse.setStatus(OptimizerEngineResponseStatus.COMPLETED); + + } catch (InterruptedException e) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage( + LogMessages.OPTIMIZER_REQUEST_TIMEOUT.format(uuid.toString(), timeLimit.toString())); + Observation.report(LogMessages.OPTIMIZER_REQUEST_TIMEOUT, uuid.toString(), timeLimit.toString()); + p.destroyForcibly(); + } catch (Exception e) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage(LogMessages.UNEXPECTED_EXCEPTION.format(e.getMessage())); + Observation.report(LogMessages.UNEXPECTED_RESPONSE, e, e.getMessage()); + } finally { + if (workingFolder.exists()) { + workingFolder.delete(); + } + } + return apiResponse; + } + + private List<String> buildCommand(Path inputFileName, Path outputFileName, String timeLimit) { + List<String> command = new ArrayList<>(); + String minizinc = env.getProperty("cmso.minizinc.command.exe", "minizinc"); + String solver = env.getProperty("cmso.minizinc.command.solver", "OSICBC"); + String additional = env.getProperty("cmso.minizinc.command.additional", ""); + String script = env.getProperty("cmso.minizinc.command.mzn", "scripts/minizinc/generic_attributes.mzn"); + + command.add(minizinc); + command.add("--solver"); + command.add(solver); + command.add("--time-limit"); + command.add(timeLimit); + command.add("--time-limit"); + command.add(timeLimit); + command.add("--soln-sep"); + command.add("\"\""); + command.add("--search-complete-msg"); + command.add("\"\""); + for (String add : additional.split(" ")) { + command.add(add); + } + command.add("-o"); + command.add(outputFileName.toString()); + command.add(script); + command.add(inputFileName.toString()); + return command; + } + + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerRequestManager.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerRequestManager.java new file mode 100644 index 0000000..34de3df --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerRequestManager.java @@ -0,0 +1,185 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + * + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.onap.observations.Observation; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse.OptimizerEngineResponseStatus; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerResults; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerSchedule; +import org.onap.optf.cmso.optimizer.clients.topology.TopologyRequestManager; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.common.LogMessages; +import org.onap.optf.cmso.optimizer.model.Optimizer; +import org.onap.optf.cmso.optimizer.model.Request; +import org.onap.optf.cmso.optimizer.model.Response; +import org.onap.optf.cmso.optimizer.model.dao.OptimizerDao; +import org.onap.optf.cmso.optimizer.model.dao.RequestDao; +import org.onap.optf.cmso.optimizer.model.dao.ResponseDao; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerResponse; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerResponse.OptimizeScheduleStatus; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerScheduleInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * The Class OPtimizerRequestManager. + */ +@Component +public class OptimizerRequestManager { + + @Autowired + Environment env; + + @Autowired + RequestDao requestDao; + + @Autowired + OptimizerDao optimizerDao; + + @Autowired + ResponseDao responseDao; + + @Autowired + OptimizerClient optimizerClient; + + @Autowired + TopologyRequestManager topologyRequestManager; + + /** + * Creates the Optimizer request. + * + * @param requestRow the request row + * @return the Optimizer response + */ + public OptimizerEngineResponse createOptimizerRequest(Request requestRow) { + // + if (okToDispatch()) { + Optimizer optimizer = getExistingOptmizer(requestRow.getUuid()); + if (optimizer == null) { + optimizer = new Optimizer(); + optimizer.setUuid(requestRow.getUuid()); + optimizer.setOptimizeRetries(0); + } + optimizer.setOptimizeStart(System.currentTimeMillis()); + OptimizerEngineResponse apiResponse = optimizerClient.makeRequest(requestRow, optimizer); + if (apiResponse.getStatus() == OptimizerEngineResponseStatus.COMPLETED) { + optimizer.setOptimizeEnd(System.currentTimeMillis()); + optimizer.setOptimizeResponse(""); // Perhaps we do not need to persist... + buildFinalResponse(requestRow, apiResponse); + } + optimizerDao.save(optimizer); + return apiResponse; + } else { + OptimizerEngineResponse apiResponse = new OptimizerEngineResponse(); + apiResponse.setRequestId(requestRow.getUuid().toString()); + apiResponse.setStatus(OptimizerEngineResponseStatus.IN_QUEUE); + apiResponse.setPollingSeconds(60); + return apiResponse; + } + } + + + private void buildFinalResponse(Request requestRow, OptimizerEngineResponse apiResponse) { + Optional<Response> opt = responseDao.findById(requestRow.getUuid()); + Response responseRow = null; + if (opt.isPresent()) + { + responseRow = opt.get(); + } + if (responseRow == null) + { + responseRow = new Response(); + responseRow.setUuid(requestRow.getUuid()); + } + + try + { + OptimizerResults results = apiResponse.getOptimizerResults(); + OptimizerResponse response = new OptimizerResponse(); + response.setRequestId(requestRow.getUuid().toString()); + + String optString = requestRow.getRequest(); + + OptimizerRequest optimizerResquest = new ObjectMapper().readValue(optString, OptimizerRequest.class); + TopologyResponse topologyResponse = topologyRequestManager.getTopologyResponse(requestRow.getUuid()); + ElementWindowMapping ewm = new ElementWindowMapping(optimizerResquest, topologyResponse); + ewm.initializeForProcessResult(); + for (OptimizerSchedule result : results.getSchedules()) { + OptimizerScheduleInfo info = ewm.processResult(result); + if (info != null) { + response.getSchedules().add(info); + } + } + responseRow.setRepsonse(new ObjectMapper().writeValueAsString(response)); + requestRow.setStatus(OptimizeScheduleStatus.COMPLETED.toString()); + responseDao.save(responseRow); + requestDao.save(requestRow); + } + catch (Exception e) + { + Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + requestRow.setStatus(OptimizeScheduleStatus.FAILED.toString()); + requestRow.setMessage(e.getMessage()); + responseRow.setRepsonse(""); + responseDao.save(responseRow); + requestDao.save(requestRow); + } + } + + + + private boolean okToDispatch() { + // TODO Auto-generated method stub + + // Will probably change to @Async on makeRequest to queue requests in a different thread. + return true; + } + + + /** + * Gets the existing optimizer row. + * + * @param uuid the uuid + * @return the existing optmizer row + */ + public Optimizer getExistingOptmizer(UUID uuid) { + Optional<Optimizer> oppt = optimizerDao.findById(uuid); + if (oppt.isPresent()) { + return oppt.get(); + } + return null; + } + + + public List<OptimizerScheduleInfo> getScheduleInfo(Response responseRow) { + // TODO Auto-generated method stub + return null; + } + + + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/ElementSlot.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/ElementSlot.java new file mode 100644 index 0000000..8f76b10 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/ElementSlot.java @@ -0,0 +1,106 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +/** + * The Class ElementSlot. + */ +/* + 1,0,1 + 2,0,1 + 3,0,1 + 4,0,1 + 5,0,1 + */ +public class ElementSlot { + private Integer elementIndex = 0; + private Integer slot = 0; + private Integer loader = 0; + private Long time = 0L; + + public Integer getElementIndex() { + return elementIndex; + } + + public void setElementIndex(Integer elementIndex) { + this.elementIndex = elementIndex; + } + + /** + * Gets the slot. + * + * @return the slot + */ + public Integer getSlot() { + return slot; + } + + /** + * Sets the slot. + * + * @param slot the new slot + */ + public void setSlot(Integer slot) { + this.slot = slot; + } + + /** + * Gets the loader. + * + * @return the loader + */ + public Integer getLoader() { + return loader; + } + + /** + * Sets the loader. + * + * @param loader the new loader + */ + public void setLoader(Integer loader) { + this.loader = loader; + } + + /** + * Instantiates a new element slot. + * + * @param cols the values + */ + public ElementSlot(String[] cols) { + if (cols.length > 0) { + elementIndex = Integer.valueOf(cols[0]); + } + if (cols.length > 1) { + slot = Integer.valueOf(cols[1]); + } + if (cols.length > 2) { + loader = Integer.valueOf(cols[2]); + } + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } +} + diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerEngineResponse.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerEngineResponse.java new file mode 100644 index 0000000..7315b31 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerEngineResponse.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +public class OptimizerEngineResponse +{ + + public enum OptimizerEngineResponseStatus { + IN_PROGRESS, COMPLETED, FAILED, IN_QUEUE, + } + + private String requestId; + private OptimizerResults optimizerResults; + private OptimizerEngineResponseStatus status; + private Integer pollingSeconds; + private String errorMessage; + public String getRequestId() { + return requestId; + } + public void setRequestId(String requestId) { + this.requestId = requestId; + } + public OptimizerResults getOptimizerResults() { + return optimizerResults; + } + public void setOptimizerResults(OptimizerResults oprimizerResults) { + this.optimizerResults = oprimizerResults; + } + public OptimizerEngineResponseStatus getStatus() { + return status; + } + public void setStatus(OptimizerEngineResponseStatus status) { + this.status = status; + } + public Integer getPollingSeconds() { + return pollingSeconds; + } + public void setPollingSeconds(Integer pollingSeconds) { + this.pollingSeconds = pollingSeconds; + } + public String getErrorMessage() { + return errorMessage; + } + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutResults.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutResults.java new file mode 100644 index 0000000..2c1c777 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutResults.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import java.util.List; + +/* + + */ +public class OptimizerOutResults { + private Long elapsedMillis; + private List<OptimizerOutSchedule> results; + + public Long getElapsedMillis() { + return elapsedMillis; + } + + public void setElapsedMillis(Long elapsed_millis) { + this.elapsedMillis = elapsed_millis; + } + + public List<OptimizerOutSchedule> getResults() { + return results; + } + + public void setResults(List<OptimizerOutSchedule> schedules) { + this.results = schedules; + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutSchedule.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutSchedule.java new file mode 100644 index 0000000..abcebf2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutSchedule.java @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +/* +num_scheduled: 0 +total_completion_time: 0 +element_slot_loader: | + 1,0,1 + 2,0,1 + 3,0,1 + 4,0,1 + 5,0,1 + */ +public class OptimizerOutSchedule { + private Long numScheduled; + private Long totalCompletionTime; + private String elementSlotLoader; + + public Long getNumScheduled() { + return numScheduled; + } + + public void setNumScheduled(Long numScheduled) { + this.numScheduled = numScheduled; + } + + public Long getTotalCompletionTime() { + return totalCompletionTime; + } + + public void setTotalCompletionTime(Long totalCompletionTime) { + this.totalCompletionTime = totalCompletionTime; + } + + public String getElementSlotLoader() { + return elementSlotLoader; + } + + public void setElementSlotLoader(String elementSlotLoader) { + this.elementSlotLoader = elementSlotLoader; + } +} + diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutYaml.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutYaml.java new file mode 100644 index 0000000..c9c16cb --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerOutYaml.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +/* +results: + result: + num_scheduled: 0 + total_completion_time: 0 + element_slot_loader: | + 1,0,1 + 2,0,1 + 3,0,1 + 4,0,1 + 5,0,1 + result: + num_scheduled: 1 + total_completion_time: 2 + element_slot_loader: | + 1,0,1 + 2,0,1 + 3,2,1 + 4,0,1 + 5,0,1 + result: + num_scheduled: 4 + total_completion_time: 8 + element_slot_loader: | + 1,2,1 + 2,1,1 + 3,2,1 + 4,0,1 + 5,3,1 + elapsed_millis: 3400 + + */ +public class OptimizerOutYaml { + + private OptimizerOutResults results; + + public OptimizerOutResults getResults() { + return results; + } + + public void setResults(OptimizerOutResults results) { + this.results = results; + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerParameters.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerParameters.java new file mode 100644 index 0000000..be74e37 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerParameters.java @@ -0,0 +1,225 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import java.util.ArrayList; +import java.util.List; + + +/* + * numElements = 5; +maxTime = 5; +numLoaders = 1; +noConflict = [| true , true , true , true , true + | true , true , true , true , true + | false , true , false , true , false + | false , false , false , false , false + | true , false , true , false , true + |]; +slotCapacity = [5, 5, 5, 5, 5]; +loaderCapacity = [| +5, 5, 5, 5, 5 +|]; + + +numAttributes = 0; +attributesRange = []; +attributes = []; +attributeConcurrencyLimit = []; + */ +public class OptimizerParameters { + private Long numElements; + private Long numLoaders; + private List<Long> elementSlotCapacity = new ArrayList<>(); + private Long maxTime; + private List<List<Boolean>> noConflict = new ArrayList<>(); + private List<List<Long>> loaderCapacity = new ArrayList<>(); + + private Long numAttributes; + private List<Long> attributesRange = new ArrayList<>(); + private List<List<Long>> attributes = new ArrayList<>(); + private List<List<Long>> attributeConcurrencyLimit = new ArrayList<>(); + + public Long getNumElements() { + return numElements; + } + + public void setNumElements(Long numElements) { + this.numElements = numElements; + } + + public Long getMaxTime() { + return maxTime; + } + + public void setMaxTime(Long maxTime) { + this.maxTime = maxTime; + } + + public Long getNumLoaders() { + return numLoaders; + } + + public void setNumLoaders(Long numLoaders) { + this.numLoaders = numLoaders; + } + + public List<List<Boolean>> getNoConflict() { + return noConflict; + } + + public void setNoConflict(List<List<Boolean>> noConflict) { + this.noConflict = noConflict; + } + + public List<Long> getElementSlotCapacity() { + return elementSlotCapacity; + } + + public void setElementSlotCapacity(List<Long> slotCapacity) { + this.elementSlotCapacity = slotCapacity; + } + + public List<List<Long>> getLoaderCapacity() { + return loaderCapacity; + } + + public void setLoaderCapacity(List<List<Long>> loaderCapacity) { + this.loaderCapacity = loaderCapacity; + } + + public Long getNumAttributes() { + return numAttributes; + } + + public void setNumAttributes(Long numAttributes) { + this.numAttributes = numAttributes; + } + + public List<Long> getAttributesRange() { + return attributesRange; + } + + public void setAttributesRange(List<Long> attributesRange) { + this.attributesRange = attributesRange; + } + + public List<List<Long>> getAttributes() { + return attributes; + } + + public void setAttributes(List<List<Long>> attributes) { + this.attributes = attributes; + } + + public List<List<Long>> getAttributeConcurrencyLimit() { + return attributeConcurrencyLimit; + } + + public void setAttributeConcurrencyLimit(List<List<Long>> attributeConcurrencyLimit) { + this.attributeConcurrencyLimit = attributeConcurrencyLimit; + } + + + + public String toMiniZinc() { + StringBuilder sb = new StringBuilder(); + appendAttribute(sb, "numElements", numElements.toString()); + appendAttribute(sb, "maxTime", maxTime.toString()); + appendAttribute(sb, "numLoaders", numLoaders.toString()); + appendAttribute(sb, "numAttributes", numAttributes.toString()); + + appendAttribute(sb, "noConflict", "[|\n" + formatBooleanRows(noConflict) + "|]"); + appendAttribute(sb, "elementSlotCapacity", "[" + formatLongList(elementSlotCapacity) + "]"); + appendAttribute(sb, "loaderCapacity", "[|\n" + formatLongRows(loaderCapacity) + "|]"); + + + if (attributesRange.size() > 0) { + appendAttribute(sb, "attributesRange", "[" + formatLongList(attributesRange) + "]"); + } + else { + appendAttribute(sb, "attributesRange", "[]"); + } + if (attributes.size() > 0) { + appendAttribute(sb, "attributes", "[|\n" + formatLongRows(attributes) + "|]"); + } + else { + appendAttribute(sb, "attributes", "array2d(1..numElements, 1..numAttributes, [])"); + } + if (attributeConcurrencyLimit.size() > 0) { + appendAttribute(sb, "attributeConcurrencyLimit", "[|\n" + formatLongRows(attributeConcurrencyLimit) + "|]"); + } + else + { + appendAttribute(sb, "attributeConcurrencyLimit", "array2d(1..numAttributes, 1..maxTime, [])"); + } + return sb.toString(); + } + + private void appendAttribute(StringBuilder sb, String name, String value) { + sb.append(name).append(" = ").append(value).append(";\n"); + } + + // Methods to dump minizinc parameters. THese may be very large + // + private String formatBooleanRows(List<List<Boolean>> list) { + StringBuilder sb = new StringBuilder(); + String row = ""; + for (List<Boolean> objectList : list) { + sb.append(row).append(formatBooleanList(objectList)); + row = "| "; + } + sb.append("\n"); + return sb.toString(); + } + + private String formatBooleanList(List<Boolean> list) { + StringBuilder sb = new StringBuilder(); + String comma = ""; + for (Object object : list) { + sb.append(comma).append(object.toString()); + comma = ", "; + } + return sb.toString(); + } + + private String formatLongRows(List<List<Long>> list) { + StringBuilder sb = new StringBuilder(); + String row = ""; + for (List<Long> objectList : list) { + sb.append(row).append(formatLongList(objectList)); + row = "| "; + } + sb.append("\n"); + return sb.toString(); + } + + private String formatLongList(List<Long> list) { + StringBuilder sb = new StringBuilder(); + String comma = ""; + for (Object object : list) { + sb.append(comma).append(object.toString()); + comma = ", "; + } + return sb.toString(); + } + +} + + diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerResponseUtility.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerResponseUtility.java new file mode 100644 index 0000000..89208b2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerResponseUtility.java @@ -0,0 +1,82 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import com.google.common.base.CaseFormat; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.onap.observations.Observation; +import org.onap.optf.cmso.optimizer.common.LogMessages; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.introspector.PropertyUtils; + +public class OptimizerResponseUtility extends PropertyUtils { + + public OptimizerResults parseOptimizerResult(File resultsFile) { + OptimizerResults results = null; + try (InputStream input = new FileInputStream(resultsFile)) { + Constructor constructor = new Constructor(OptimizerOutResults.class); + constructor.setPropertyUtils(this); + Yaml yaml = new Yaml(constructor); + OptimizerOutResults optimizerOut = yaml.load(input); + results = marshall(optimizerOut); + } catch (Exception e) { + Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + return results; + } + + private OptimizerResults marshall(OptimizerOutResults optimizerOut) { + OptimizerResults results = new OptimizerResults(); + results.setElapsedMillis(optimizerOut.getElapsedMillis()); + List<OptimizerSchedule> schedules = new ArrayList<>(); + results.setSchedules(schedules); + for (OptimizerOutSchedule sch : optimizerOut.getResults()) { + schedules.add(marshall(sch)); + } + return results; + } + + private OptimizerSchedule marshall(OptimizerOutSchedule sch) { + OptimizerSchedule optimizerSchedule = new OptimizerSchedule(); + optimizerSchedule.setNumScheduled(sch.getNumScheduled()); + optimizerSchedule.setTotalCompletionTime(sch.getTotalCompletionTime()); + String[] rows = sch.getElementSlotLoader().split("\n"); + List<ElementSlot> slots = new ArrayList<>(); + optimizerSchedule.setElementSlotLoader(slots); + for (String row : rows) { + String[] cols = row.split(","); + ElementSlot slot = new ElementSlot(cols); + slots.add(slot); + } + return optimizerSchedule; + } + + @Override + public Property getProperty(Class<? extends Object> type, String name) { + name = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name); + return super.getProperty(type, name); + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerResults.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerResults.java new file mode 100644 index 0000000..9c31a9f --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerResults.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import java.util.List; + +/* + + */ +public class OptimizerResults { + private Long elapsedMillis; + private List<OptimizerSchedule> schedules; + + public Long getElapsedMillis() { + return elapsedMillis; + } + + public void setElapsedMillis(Long elapsed_millis) { + this.elapsedMillis = elapsed_millis; + } + + public List<OptimizerSchedule> getSchedules() { + return schedules; + } + + public void setSchedules(List<OptimizerSchedule> schedules) { + this.schedules = schedules; + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerSchedule.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerSchedule.java new file mode 100644 index 0000000..d4bc008 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/OptimizerSchedule.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import java.util.List; + +/* +num_scheduled: 0 +total_completion_time: 0 +element_slot_loader: | + 1,0,1 + 2,0,1 + 3,0,1 + 4,0,1 + 5,0,1 + */ +public class OptimizerSchedule { + private Long numScheduled; + private Long totalCompletionTime; + private List<ElementSlot> elementSlotLoader; + + public Long getNumScheduled() { + return numScheduled; + } + + public void setNumScheduled(Long numScheduled) { + this.numScheduled = numScheduled; + } + + public Long getTotalCompletionTime() { + return totalCompletionTime; + } + + public void setTotalCompletionTime(Long totalCompletionTime) { + this.totalCompletionTime = totalCompletionTime; + } + + public List<ElementSlot> getElementSlotLoader() { + return elementSlotLoader; + } + + public void setElementSlotLoader(List<ElementSlot> elementSlotLoader) { + this.elementSlotLoader = elementSlotLoader; + } + +} + diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/Results.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/Results.java new file mode 100644 index 0000000..402bdf2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/Results.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import java.util.List; + +/* + + */ +public class Results { + private Long elapsedMillis; + private List<OptimizerSchedule> schedules; + + public Long getElapsedMillis() { + return elapsedMillis; + } + + public void setElapsedMillis(Long elapsed_millis) { + this.elapsedMillis = elapsed_millis; + } + + public List<OptimizerSchedule> getSchedules() { + return schedules; + } + + public void setSchedules(List<OptimizerSchedule> schedules) { + this.schedules = schedules; + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/ticketmgt/TicketMgtRequestManager.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/ticketmgt/TicketMgtRequestManager.java index 8c7dfb6..8520809 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/ticketmgt/TicketMgtRequestManager.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/ticketmgt/TicketMgtRequestManager.java @@ -20,11 +20,13 @@ package org.onap.optf.cmso.optimizer.clients.ticketmgt; import java.util.Optional; +import java.util.UUID; import org.onap.observations.Observation; import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse; import org.onap.optf.cmso.optimizer.common.LogMessages; import org.onap.optf.cmso.optimizer.model.Request; import org.onap.optf.cmso.optimizer.model.Ticket; +import org.onap.optf.cmso.optimizer.model.Topology; import org.onap.optf.cmso.optimizer.model.dao.RequestDao; import org.onap.optf.cmso.optimizer.model.dao.TicketDao; import org.springframework.beans.factory.annotation.Autowired; @@ -53,13 +55,12 @@ public class TicketMgtRequestManager { TicketMgtClient ticketmgtClient; /** - * Creates the topology request. + * Creates the tickets request. * * @param requestRow the uuid * @return the active tickets response */ public ActiveTicketsResponse createTicketsRequest(Request requestRow) { - try { Ticket row = null; Optional<Ticket> rowOpt = ticketDao.findById(requestRow.getUuid()); if (rowOpt.isPresent()) { @@ -72,22 +73,21 @@ public class TicketMgtRequestManager { row.setTicketsRetries(0); } ActiveTicketsResponse apiResponse = ticketmgtClient.makeRequest(requestRow, row); - switch (apiResponse.getStatus()) { - case COMPLETED: - break; - case FAILED: - break; - case IN_PROGRESS: - break; - default: - break; - } + ticketDao.save(row); return apiResponse; - } catch (Exception e) { - Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + /** + * Gets the existing tickets. + * + * @param uuid the uuid + * @return the existing tickets + */ + public Ticket getExistingTickets(UUID uuid) { + Optional<Ticket> opt = ticketDao.findById(uuid); + if (opt.isPresent()) { + return opt.get(); } return null; - } } diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/topology/TopologyRequestManager.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/topology/TopologyRequestManager.java index ce0d583..a1cb51d 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/topology/TopologyRequestManager.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/topology/TopologyRequestManager.java @@ -19,6 +19,10 @@ package org.onap.optf.cmso.optimizer.clients.topology; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; import java.util.Optional; import java.util.UUID; import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; @@ -81,4 +85,15 @@ public class TopologyRequestManager { } return null; } + + + public TopologyResponse getTopologyResponse(UUID uuid) throws JsonParseException, JsonMappingException, IOException { + Topology row = getExistingTopology(uuid); + if (row != null) + { + String responseString = row.getTopology(); + return new ObjectMapper().readValue(responseString, TopologyResponse.class); + } + return null; + } } diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/common/LogMessages.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/common/LogMessages.java index f36caee..f8d23eb 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/common/LogMessages.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/common/LogMessages.java @@ -85,6 +85,8 @@ public enum LogMessages implements ObservationInterface { Level.ERROR), FAILED_TO_CREATE_OPTIMIZER_REQUEST("Failed to create optimizer request for id={0}", Status.INTERNAL_SERVER_ERROR, Level.ERROR), + OPTIMIZER_REQUEST_TIMEOUT("Optimizer engine request timed out id={0} timelimit={1}", Status.INTERNAL_SERVER_ERROR, + Level.ERROR), ; private final String defaultId; diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/core/OptimizerManager.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/core/OptimizerManager.java index 43ecf3f..eabebec 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/core/OptimizerManager.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/core/OptimizerManager.java @@ -26,13 +26,17 @@ import java.util.Optional; import java.util.UUID; import javax.ws.rs.core.Response.Status; import org.onap.optf.cmso.common.exceptions.CmsoException; +import org.onap.optf.cmso.optimizer.clients.optimizer.OptimizerRequestManager; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse; import org.onap.optf.cmso.optimizer.clients.ticketmgt.TicketMgtRequestManager; import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse; import org.onap.optf.cmso.optimizer.clients.topology.TopologyRequestManager; import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; import org.onap.optf.cmso.optimizer.common.LogMessages; import org.onap.optf.cmso.optimizer.model.Request; +import org.onap.optf.cmso.optimizer.model.Response; import org.onap.optf.cmso.optimizer.model.dao.RequestDao; +import org.onap.optf.cmso.optimizer.model.dao.ResponseDao; import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow; import org.onap.optf.cmso.optimizer.service.rs.models.ElementInfo; import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; @@ -51,11 +55,17 @@ public class OptimizerManager { RequestDao requestDao; @Autowired + ResponseDao responseDao; + + @Autowired TopologyRequestManager topologyRequestManager; @Autowired TicketMgtRequestManager ticketMgtRequestManager; + @Autowired + OptimizerRequestManager optimizerRequestManager; + /** * Validate optimizer request. * @@ -147,13 +157,22 @@ public class OptimizerManager { } catch (JsonProcessingException e) { throw new CmsoException(Status.BAD_REQUEST, LogMessages.INVALID_REQUEST, e.getMessage()); } - requestRow.setStatus(OptimizeScheduleStatus.FAILED.toString()); + requestRow.setStatus(OptimizeScheduleStatus.PENDING_TOPOLOGY.toString()); requestDao.save(requestRow); initiateDataGathering(requestRow); requestDao.save(requestRow); OptimizeScheduleStatus status = OptimizeScheduleStatus.valueOf(requestRow.getStatus()); - optimizerResponse.setStatus(status); - optimizerResponse.setErrorMessage(""); + if (status == OptimizeScheduleStatus.COMPLETED) + { + // COmpletely synchronous optimization + optimizerResponse = getCompletedOptimizerResponse(uuid); + } + else + { + // One or more steps are asynchronous + optimizerResponse.setStatus(status); + optimizerResponse.setErrorMessage(""); + } return optimizerResponse; } @@ -174,8 +193,8 @@ public class OptimizerManager { return; case IN_PROGRESS: requestRow.setRequestStart(System.currentTimeMillis()); - requestRow.setStatus(OptimizeScheduleStatus.PENDING_TOPOLOGY.toString()); - break; + requestRow.setStatus(OptimizeScheduleStatus.TOPOLOGY_IN_PROGRESS.toString()); + return; default: break; } @@ -192,17 +211,17 @@ public class OptimizerManager { requestRow.setRequestStart(System.currentTimeMillis()); requestRow.setStatus(OptimizeScheduleStatus.PENDING_OPTIMIZER.toString()); initiateOptimizer(requestRow); - break; + return; case FAILED: requestRow.setRequestStart(System.currentTimeMillis()); requestRow.setRequestEnd(System.currentTimeMillis()); requestRow.setStatus(OptimizeScheduleStatus.FAILED.toString()); requestRow.setMessage(apiResponse.getErrorMessage()); - break; + return; case IN_PROGRESS: requestRow.setRequestStart(System.currentTimeMillis()); - requestRow.setStatus(OptimizeScheduleStatus.PENDING_TICKETS.toString()); - break; + requestRow.setStatus(OptimizeScheduleStatus.TICKETS_IN_PROGRESS.toString()); + return; default: break; } @@ -212,9 +231,54 @@ public class OptimizerManager { } - private void initiateOptimizer(Request requestRow) { - // TODO Auto-generated method stub + private void initiateOptimizer(Request requestRow) throws CmsoException { + OptimizerEngineResponse apiResponse = optimizerRequestManager.createOptimizerRequest(requestRow); + if (apiResponse != null) { + switch (apiResponse.getStatus()) { + case COMPLETED: + requestRow.setRequestEnd(System.currentTimeMillis()); + requestRow.setStatus(OptimizeScheduleStatus.COMPLETED.toString()); + return; + case FAILED: + requestRow.setRequestStart(System.currentTimeMillis()); + requestRow.setRequestEnd(System.currentTimeMillis()); + requestRow.setStatus(OptimizeScheduleStatus.FAILED.toString()); + requestRow.setMessage(apiResponse.getErrorMessage()); + return; + case IN_PROGRESS: + case IN_QUEUE: + requestRow.setRequestStart(System.currentTimeMillis()); + requestRow.setStatus(OptimizeScheduleStatus.OPTIMIZER_IN_PROGRESS.toString()); + return; + default: + break; + } + } + throw new CmsoException(Status.INTERNAL_SERVER_ERROR, LogMessages.FAILED_TO_CREATE_TICKET_REQUEST, + requestRow.getUuid().toString()); + } + public OptimizerResponse getCompletedOptimizerResponse(UUID uuid) + { + OptimizerResponse response = new OptimizerResponse(); + response.setRequestId(uuid.toString()); + response.setStatus(OptimizeScheduleStatus.COMPLETED); + Response responseRow = getResponseRow(uuid); + if (responseRow != null) + { + response.setSchedules(optimizerRequestManager.getScheduleInfo(responseRow)); + } + return response; + } + + public Response getResponseRow(UUID uuid) + { + Optional<Response> opt = responseDao.findById(uuid); + if (opt.isPresent()) + { + return opt.get(); + } + return null; } @SuppressWarnings("unused") @@ -225,7 +289,7 @@ public class OptimizerManager { return requestOptional.get(); } throw new CmsoException(Status.INTERNAL_SERVER_ERROR, LogMessages.EXPECTED_DATA_NOT_FOUND, - requestRow.toString(), "Request table"); + uuid.toString(), "Request table"); } diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindow.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindow.java index d0af5c4..4eb6824 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindow.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindow.java @@ -33,6 +33,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; +import java.time.Instant; import java.util.Date; import org.springframework.format.annotation.DateTimeFormat; @@ -111,6 +112,38 @@ public class ChangeWindow implements Serializable { } /** + * Test if this window contains the passed window. + * + * @param test the test + * @return true, if this change window contains the passed change window + */ + public boolean contains(ChangeWindow test) { + if (!test.getStartTime().before(getStartTime()) && !test.getEndTime().after(getEndTime())) { + return true; + } + return false; + } + + /** + * Passed slot time (test) is within this change window adjusted for the time zone of the element. + * This is used to interpret global relative availability (maintenance) windows as opposed to + * absolute UTC times provided in tickets which should already be adjusted for time zone. + * + * @param test the test + * @param timeZoneOffset the time zone offset + * @return true, if successful + */ + public boolean containsInTimeZone(ChangeWindow test, Long timeZoneOffset) { + Instant startInstant = startTime.toInstant().plusMillis(timeZoneOffset); + Instant endInstant = endTime.toInstant().plusMillis(timeZoneOffset); + if (!test.getStartTime().toInstant().isBefore(startInstant) + && !test.getEndTime().toInstant().isAfter(endInstant)) { + return true; + } + return false; + } + + /** * Absorb if overlapping window. * * @param test the test window @@ -145,4 +178,5 @@ public class ChangeWindow implements Serializable { return ""; } + } diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/OptimizerResponse.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/OptimizerResponse.java index 2f8e705..b8b5a21 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/OptimizerResponse.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/service/rs/models/OptimizerResponse.java @@ -42,7 +42,16 @@ public class OptimizerResponse implements Serializable { private static EELFLogger log = EELFManager.getInstance().getLogger(OptimizerResponse.class); public enum OptimizeScheduleStatus { - CREATED, PENDING_TOPOLOGY, PENDING_TICKETS, PENDING_OPTIMIZER, COMPLETED, FAILED, DELETED, + CREATED, + PENDING_TOPOLOGY, + TOPOLOGY_IN_PROGRESS, + PENDING_TICKETS, + TICKETS_IN_PROGRESS, + PENDING_OPTIMIZER, + OPTIMIZER_IN_PROGRESS, + COMPLETED, + FAILED, + DELETED, } @ApiModelProperty(value = "Unique Id of the request") diff --git a/cmso-optimizer/src/test/data/resultsTest001.yaml b/cmso-optimizer/src/test/data/resultsTest001.yaml new file mode 100644 index 0000000..1c7eed6 --- /dev/null +++ b/cmso-optimizer/src/test/data/resultsTest001.yaml @@ -0,0 +1,28 @@ +results: + - num_scheduled: 0 + total_completion_time: 0 + element_slot_loader: | + 1,0,1 + 2,0,1 + 3,0,1 + 4,0,1 + 5,0,1 + - + num_scheduled: 1 + total_completion_time: 2 + element_slot_loader: | + 1,0,1 + 2,0,1 + 3,2,1 + 4,0,1 + 5,0,1 + - + num_scheduled: 4 + total_completion_time: 8 + element_slot_loader: | + 1,2,1 + 2,1,1 + 3,2,1 + 4,0,1 + 5,3,1 +elapsed_millis: 3400
\ No newline at end of file diff --git a/cmso-optimizer/src/test/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/ResultsTest.java b/cmso-optimizer/src/test/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/ResultsTest.java new file mode 100644 index 0000000..ddbee2f --- /dev/null +++ b/cmso-optimizer/src/test/java/org/onap/optf/cmso/optimizer/clients/optimizer/models/ResultsTest.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer.models; + +import java.io.File; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.yaml.snakeyaml.introspector.PropertyUtils; + +@RunWith(MockitoJUnitRunner.class) +public class ResultsTest extends PropertyUtils { + @Test + public void yamlTests() { + OptimizerResponseUtility util = new OptimizerResponseUtility(); + File resultsFile = new File("src/test/data/resultsTest001.yaml"); + OptimizerResults results = util.parseOptimizerResult(resultsFile); + Assert.assertTrue(results != null); + + } + + +} diff --git a/cmso-optimizer/src/test/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindowTest.java b/cmso-optimizer/src/test/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindowTest.java new file mode 100644 index 0000000..b1309fb --- /dev/null +++ b/cmso-optimizer/src/test/java/org/onap/optf/cmso/optimizer/service/rs/models/ChangeWindowTest.java @@ -0,0 +1,53 @@ +package org.onap.optf.cmso.optimizer.service.rs.models; + +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + * + */ + +import java.time.Instant; +import java.util.Date; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ChangeWindowTest { + + + @Test + public void chagneWindowTest() { + ChangeWindow window = new ChangeWindow(); + window.setStartTime(Date.from(Instant.parse("2019-03-08T00:00:00.00Z"))); + window.setEndTime(Date.from(Instant.parse("2019-03-12T00:00:00.00Z"))); + testContains(window, "2019-03-08T00:00:00.00Z", "2019-03-12T00:00:00.00Z", true); + testContains(window, "2019-03-07T23:59:59Z", "2019-03-12T00:00:00.00Z", false); + testContains(window, "2019-03-09T23:59:59Z", "2019-03-11T00:00:00.00Z", true); + testContains(window, "2019-03-06T23:59:59Z", "2019-03-06T23:59:59Z", false); + testContains(window, "2019-03-12T23:59:59Z", "2019-03-13T00:00:00.00Z", false); + + } + + private void testContains(ChangeWindow window, String from, String to, boolean contains) { + ChangeWindow test = new ChangeWindow(); + test.setStartTime(Date.from(Instant.parse(from))); + test.setEndTime(Date.from(Instant.parse(to))); + Assert.assertTrue(window.contains(test) == contains); + } + +} |