aboutsummaryrefslogtreecommitdiffstats
path: root/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CmsoOptimizerClient.java
diff options
context:
space:
mode:
Diffstat (limited to 'cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CmsoOptimizerClient.java')
-rw-r--r--cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CmsoOptimizerClient.java401
1 files changed, 401 insertions, 0 deletions
diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CmsoOptimizerClient.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CmsoOptimizerClient.java
new file mode 100644
index 0000000..d81c293
--- /dev/null
+++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CmsoOptimizerClient.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright © 2017-2019 AT&T Intellectual Property. Modifications Copyright © 2018 IBM.
+ *
+ * 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.
+ *
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed under the Creative
+ * Commons License, Attribution 4.0 Intl. (the "License"); you may not use this documentation except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation 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.
+ */
+
+package org.onap.optf.cmso.optimizer;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.ResponseProcessingException;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.onap.observations.Mdc;
+import org.onap.observations.Observation;
+import org.onap.optf.cmso.common.BasicAuthenticatorFilter;
+import org.onap.optf.cmso.common.CMSStatusEnum;
+import org.onap.optf.cmso.common.LogMessages;
+import org.onap.optf.cmso.common.PropertiesManagement;
+import org.onap.optf.cmso.filters.CmsoClientFilters;
+import org.onap.optf.cmso.model.DomainData;
+import org.onap.optf.cmso.model.Schedule;
+import org.onap.optf.cmso.model.dao.ScheduleDAO;
+import org.onap.optf.cmso.optimizer.model.OptimizerRequest;
+import org.onap.optf.cmso.optimizer.model.OptimizerResponse;
+import org.onap.optf.cmso.service.rs.models.HealthCheckComponent;
+import org.onap.optf.cmso.service.rs.models.v2.NameValue;
+import org.onap.optf.cmso.service.rs.models.v2.SchedulingData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * The Class CmsoOptimizerClient.
+ */
+@Component
+public class CmsoOptimizerClient {
+ private static EELFLogger debug = EELFManager.getInstance().getDebugLogger();
+
+ @Autowired
+ ScheduleDAO scheduleDAO;
+
+ @Autowired
+ Environment env;
+
+ @Autowired
+ PropertiesManagement pm;
+
+ @Autowired
+ CmsoOptimizerHandler optimizerHandler;
+
+ /**
+ * Schedule optimization.
+ *
+ * @param uuid - non empty
+ */
+ public void scheduleOptimization(UUID uuid) {
+ Map<String, String> mdcSave = Mdc.save();
+ try {
+ // Ensure that only one cmso is requsting this call to optimizer
+ Schedule schedule = scheduleDAO.lockOne(uuid);
+ if (schedule.getStatus().equals(CMSStatusEnum.PendingSchedule.toString())) {
+ scheduleNewOptimization(schedule);
+ }
+ if (schedule.getStatus().equals(CMSStatusEnum.OptimizationInProgress.toString())) {
+ pollOptimizer(schedule);
+ }
+ return;
+ } catch (Exception e) {
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage());
+ } finally {
+ Mdc.restore(mdcSave);
+ }
+ }
+
+ /**
+ * Schedule New Optimization.
+ *
+ * @param schedule - schedule
+ */
+ public void scheduleNewOptimization(Schedule schedule) {
+ try {
+ Integer maxAttempts = env.getProperty("cmso.optimizer.maxAttempts", Integer.class, 20);
+ //
+ // Only 'successfully' process one schedule per invocation
+ // If a schedule attemp fails and it could be because of the data in the
+ // message, try the next one. We don't want bad data to
+ //
+ if (schedule.getOptimizerAttemptsToSchedule() >= maxAttempts) {
+ schedule.setStatus(CMSStatusEnum.OptimizationFailed.toString());
+ schedule.setOptimizerMessage("Maximum number of attempts exceeded " + maxAttempts);
+ updateScheduleStatus(schedule);
+ return;
+ }
+ OptimizerRequest cmReq = null;
+ try {
+ cmReq = buildRequestMessage(schedule);
+ if (cmReq == null) {
+ return;
+ }
+ } catch (Exception e) {
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage());
+ schedule.setStatus(CMSStatusEnum.OptimizationFailed.toString());
+ schedule.setOptimizerMessage("Unexpected exception: " + e.getMessage());
+ updateScheduleStatus(schedule);
+ return;
+ }
+ initiateOptimization(schedule, cmReq);
+ } catch (Exception e) {
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage());
+ }
+ }
+
+ private void initiateOptimization(Schedule schedule, OptimizerRequest cmReq) {
+ try {
+ String optimizerurl = env.getProperty("cmso.optimizer.request.url");
+ String username = env.getProperty("mechid.user");
+ String password = pm.getProperty("mechid.pass", "");
+ // This service will call optimizer for each PendingSchedule
+ // If the request is successfully scheduled in optimizer, status will be
+ // updated to OptimizationInProgress.
+ Client client = ClientBuilder.newClient();
+ client.register(new BasicAuthenticatorFilter(username, password));
+ client.register(new CmsoClientFilters());
+ WebTarget optimizerTarget = client.target(optimizerurl);
+ Invocation.Builder invocationBuilder = optimizerTarget.request(MediaType.APPLICATION_JSON);
+ try {
+ //
+ // First, push OptimizationInProgress to the DB (flush()) assuming a 202 status,
+ // in case the optimizer callback is received prior to the
+ // commit of this transaction.
+ // optimizer Callback will throw an error if it receives a response in the incorrect
+ // state.
+ //
+ schedule.setOptimizerTransactionId(cmReq.getRequestId());
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setStatus(CMSStatusEnum.OptimizationInProgress.toString());
+ updateScheduleStatus(schedule);
+ debug.debug("optimizer url / user: " + optimizerurl + " / " + username);
+ debug.debug("optimizer Request: " + new ObjectMapper().writeValueAsString(cmReq));
+ Observation.report(LogMessages.OPTIMIZER_REQUEST, "Begin", schedule.getScheduleId(), optimizerurl);
+ Response response = invocationBuilder.post(Entity.json(cmReq));
+ Observation.report(LogMessages.OPTIMIZER_REQUEST, "End", schedule.getScheduleId(), optimizerurl);
+ switch (response.getStatus()) {
+ case 202:
+ debug.debug("Successfully scheduled optimization: " + schedule.getScheduleId());
+ // Scheduled with optimizer
+ break;
+ case 400: // Bad request
+ {
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setOptimizerStatus("HTTP Status: " + response.getStatus());
+ String message = response.readEntity(String.class);
+ schedule.setOptimizerMessage(message);
+ schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString());
+ // Need to understand the cause of this error. May be teh same as optimizer
+ // down.
+ int tries = schedule.getOptimizerAttemptsToSchedule();
+ tries++;
+ schedule.setOptimizerAttemptsToSchedule(tries);
+ updateScheduleStatus(schedule);
+ Observation.report(LogMessages.OPTIMIZER_EXCEPTION, message);
+ }
+ break;
+ case 500:
+ default: {
+ String message = response.readEntity(String.class);
+ // SHould probably track the number of retries.
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ int tries = schedule.getOptimizerAttemptsToSchedule();
+ tries++;
+ schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString());
+ schedule.setOptimizerAttemptsToSchedule(tries);
+ schedule.setOptimizerMessage(message);
+ updateScheduleStatus(schedule);
+ /// Got processing error response
+ // may be transient, wait for next cycle.
+ Observation.report(LogMessages.OPTIMIZER_EXCEPTION, message);
+ // Wait until next cycle and try again.
+ }
+ }
+ } catch (ResponseProcessingException e) {
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setOptimizerStatus("Failed to parse optimizer response");
+ schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString());
+ // Need to understand the cause of this error. May be teh same as optimizer down.
+ int tries = schedule.getOptimizerAttemptsToSchedule();
+ tries++;
+ schedule.setOptimizerAttemptsToSchedule(tries);
+ updateScheduleStatus(schedule);
+ // Getting invalid response from optimizer.
+ // May be data related.
+ Observation.report(LogMessages.OPTIMIZER_EXCEPTION, e, e.getMessage());
+ } catch (ProcessingException e) {
+ // Don't track number of retries on IO error (optimizer is down)
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setStatus(CMSStatusEnum.PendingSchedule.toString());
+ updateScheduleStatus(schedule);
+ /// Cannot connect to optimizer
+ Observation.report(LogMessages.OPTIMIZER_EXCEPTION, e, e.getMessage());
+ // Wait until next cycle
+ }
+ } catch (Exception e) {
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage());
+ }
+
+ }
+
+ /**
+ * Poll the optimizer.
+ *
+ * @param schedule - schedule
+ */
+ public void pollOptimizer(Schedule schedule) {
+ try {
+ String optimizerurl = env.getProperty("cmso.optimizer.status.url");
+ String username = env.getProperty("mechid.user");
+ String password = pm.getProperty("mechid.pass", "");
+ Long timeout = env.getProperty("cmso.optimizer.request.timeout.secs", Long.class);
+ if (timeout == null) {
+ timeout = 3600L;
+ }
+ if (!optimizerurl.endsWith("/")) {
+ optimizerurl += "/";
+ }
+ Long now = System.currentTimeMillis();
+ if (now > schedule.getOptimizerDateTimeMillis() + (timeout * 1000)) {
+ schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString());
+ updateScheduleStatus(schedule);
+ return;
+ }
+
+ optimizerurl += schedule.getOptimizerTransactionId();
+ // This service will call optimizer for each PendingSchedule
+ // If the request is successfully scheduled in optimizer, status will be
+ // updated to OptimizationInProgress.
+ Client client = ClientBuilder.newClient();
+ client.register(new BasicAuthenticatorFilter(username, password));
+ client.register(new CmsoClientFilters());
+ WebTarget optimizerTarget = client.target(optimizerurl);
+ Invocation.Builder invocationBuilder = optimizerTarget.request(MediaType.APPLICATION_JSON);
+ debug.debug("optimizer url / user: " + optimizerurl + " / " + username);
+ Observation.report(LogMessages.OPTIMIZER_REQUEST, "Begin", schedule.getScheduleId(), optimizerurl);
+ Response response = invocationBuilder.get();
+ Observation.report(LogMessages.OPTIMIZER_REQUEST, "End", schedule.getScheduleId(), optimizerurl);
+ switch (response.getStatus()) {
+ case 200:
+
+ String optimizerResponseString = response.readEntity(String.class);
+ ObjectMapper om = new ObjectMapper();
+ OptimizerResponse optimizerResponse =
+ om.readValue(optimizerResponseString, OptimizerResponse.class);
+ debug.debug("Successfully retrieved optimization: " + schedule.getScheduleId());
+ optimizerHandler.handleOptimizerResponse(optimizerResponse, schedule);
+ break;
+ default: // Bad request
+ {
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setOptimizerStatus("HTTP Status: " + response.getStatus());
+ String message = response.readEntity(String.class);
+ schedule.setOptimizerMessage(message);
+ schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString());
+ updateScheduleStatus(schedule);
+ Observation.report(LogMessages.OPTIMIZER_EXCEPTION, message);
+ }
+ }
+ } catch (Exception e) {
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage());
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setOptimizerMessage(e.getMessage());
+ schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString());
+ updateScheduleStatus(schedule);
+ }
+ }
+
+ private OptimizerRequest buildRequestMessage(Schedule schedule) {
+ String request = schedule.getScheduleInfo();
+ ObjectMapper om = new ObjectMapper();
+ try {
+ SchedulingData info = om.readValue(request, SchedulingData.class);
+ OptimizerRequest orequest = new OptimizerRequest();
+ orequest.setChangeWindows(info.getChangeWindows());
+ orequest.setPolicies(info.getPolicies());
+ orequest.setRequestId(schedule.getScheduleId());
+ orequest.setCommonData(marshallCommonData(schedule));
+ orequest.setElements(info.getElements());
+ orequest.setAdditionalDuration(info.getAdditionalDurationInSeconds());
+ orequest.setNormalDuration(info.getNormalDurationInSeconds());
+ orequest.setConcurrencyLimit(info.getConcurrencyLimit());
+ return orequest;
+ } catch (Exception e) {
+ // Parsing should work here because this was a toString on the original object.
+ // We may have an issue when upgrading....
+ // Perhaps We create ChangeManagementSchedulingInfoV1, ...V2, etc.
+ // ANd try them one after another....
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, "Unable to parse message. Format changed?");
+ schedule.setOptimizerStatus("Failed to parse optimizer request");
+ schedule.setOptimizerDateTimeMillis(System.currentTimeMillis());
+ schedule.setStatus(CMSStatusEnum.OptimizationFailed.toString());
+ scheduleDAO.save(schedule);
+ }
+ return null;
+ }
+
+ private List<NameValue> marshallCommonData(Schedule schedule) {
+ List<NameValue> nvList = new ArrayList<>();
+ List<DomainData> ddList = schedule.getDomainData();
+ for (DomainData dd : ddList) {
+ NameValue nv = new NameValue();
+ nv.setName(dd.getName());
+ // TODO: handle other than String values
+ nv.setValue(dd.getValue());
+ nvList.add(nv);
+ }
+ return nvList;
+ }
+
+ /**
+ * Update schedule status.
+ *
+ * @param schedule the schedule
+ */
+ @Transactional
+ public void updateScheduleStatus(Schedule schedule) {
+ scheduleDAO.save(schedule);
+ }
+
+ /**
+ * Health check.
+ * @return
+ */
+ public HealthCheckComponent healthCheck() {
+ Map<String, String> mdcSave = Mdc.save();
+ HealthCheckComponent hcc = new HealthCheckComponent();
+ hcc.setName("OPtimizer Interface");
+ String optimizerurl = env.getProperty("cmso.optimizer.health.url");
+ String username = env.getProperty("mechid.user");
+ String password = pm.getProperty("mechid.pass", "");
+ hcc.setUrl(optimizerurl);
+ try {
+ Client client = ClientBuilder.newClient();
+ client.register(new BasicAuthenticatorFilter(username, password));
+ client.register(new CmsoClientFilters());
+
+ WebTarget optimizerTarget = client.target(optimizerurl);
+ Invocation.Builder invocationBuilder = optimizerTarget.request(MediaType.APPLICATION_JSON);
+ debug.debug("Optimizer url / user: " + optimizerurl + " / " + username);
+ Response response = invocationBuilder.get();
+ Observation.report(LogMessages.OPTIMIZER_REQUEST, "End", "healthcheck", optimizerurl);
+ String message = response.getStatus() + ":" + response.readEntity(String.class);
+ switch (response.getStatus()) {
+ case 200:
+ debug.debug("Successful optimizer healthcheck");
+ hcc.setHealthy(true);
+ break;
+ case 400:
+ default:
+ hcc.setStatus(message);
+ break;
+ }
+ } catch (Exception e) {
+ Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e.toString());
+ hcc.setStatus(e.toString());
+ } finally {
+ Mdc.restore(mdcSave);
+ }
+ return hcc;
+ }
+}