From 93c1a756bc483c4dae1350820a78cb72d052f2cf Mon Sep 17 00:00:00 2001 From: "RamaPrasad Amaranarayana (ra5425)" Date: Wed, 19 Sep 2018 18:40:47 -0400 Subject: Change Management Schedule Optimization Adding CMSO Service Code for Change Management Schedule Optimization Change-Id: Icc150691d39d5d10d09f5da2400fd07efe6b28d3 Issue-ID: OPTFRA-353 Signed-off-by: RamaPrasad Amaranarayana (ra5425) --- .../org/onap/optf/cmso/dispatcher/CMSOClient.java | 224 ++++++++++++ .../java/org/onap/optf/cmso/dispatcher/CmJob.java | 156 +++++++++ .../org/onap/optf/cmso/dispatcher/DispatchJob.java | 251 ++++++++++++++ .../optf/cmso/dispatcher/rs/DispacherService.java | 96 ++++++ .../cmso/dispatcher/rs/DispatcherServiceImpl.java | 137 ++++++++ .../org/onap/optf/cmso/eventq/CMSQueueJob.java | 141 ++++++++ .../org/onap/optf/cmso/eventq/CmQuartzJob.java | 105 ++++++ .../onap/optf/cmso/eventq/CmQuartzJobStartup.java | 79 +++++ .../onap/optf/cmso/eventq/DispatchedEventList.java | 62 ++++ .../optf/cmso/optimizer/CMSOptimizerClient.java | 377 +++++++++++++++++++++ .../cmso/optimizer/DispatchedOptimizerList.java | 62 ++++ .../optf/cmso/optimizer/OptimizerQuartzJob.java | 176 ++++++++++ .../cmso/optimizer/bean/CMOptimizerRequest.java | 74 ++++ .../cmso/optimizer/bean/CMOptimizerResponse.java | 124 +++++++ .../optf/cmso/optimizer/bean/CMRequestInfo.java | 83 +++++ .../onap/optf/cmso/optimizer/bean/CMSchedule.java | 88 +++++ .../optf/cmso/optimizer/bean/CMSchedulingInfo.java | 110 ++++++ .../optf/cmso/optimizer/bean/CMVnfDetails.java | 60 ++++ 18 files changed, 2405 insertions(+) create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CMSOClient.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CmJob.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/DispatchJob.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispacherService.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispatcherServiceImpl.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/eventq/CMSQueueJob.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJob.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJobStartup.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/eventq/DispatchedEventList.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CMSOptimizerClient.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/DispatchedOptimizerList.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/OptimizerQuartzJob.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerRequest.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerResponse.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMRequestInfo.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedule.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedulingInfo.java create mode 100644 cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMVnfDetails.java (limited to 'cmso-service/src/main') diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CMSOClient.java b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CMSOClient.java new file mode 100644 index 0000000..19927ad --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CMSOClient.java @@ -0,0 +1,224 @@ +/* + * Copyright © 2017-2018 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.dispatcher; + +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.optf.cmso.common.BasicAuthenticatorFilter; +import org.onap.optf.cmso.common.CMSStatusEnum; +import org.onap.optf.cmso.common.CmHelpers; +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.ChangeManagementSchedule; +import org.onap.optf.cmso.model.Schedule; +import org.onap.optf.cmso.model.dao.ChangeManagementGroupDAO; +import org.onap.optf.cmso.model.dao.ChangeManagementScheduleDAO; +import org.onap.optf.cmso.model.dao.ScheduleDAO; +import org.onap.optf.cmso.service.rs.models.CmDomainDataEnum; +import org.onap.optf.cmso.ticketmgt.TmClient; +import org.onap.optf.cmso.wf.bean.WfChangeManagementResponse; +import org.onap.optf.cmso.wf.bean.WfVidCmResponse; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class CMSOClient { + private static EELFLogger log = EELFManager.getInstance().getLogger(CMSOClient.class); + private static EELFLogger metrics = EELFManager.getInstance().getMetricsLogger(); + private static EELFLogger errors = EELFManager.getInstance().getErrorLogger(); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + ChangeManagementScheduleDAO cmScheduleDAO; + + @Autowired + ChangeManagementGroupDAO cmGroupDAO; + + @Autowired + ScheduleDAO scheduleDAO; + + @Autowired + Environment env; + + @Autowired + PropertiesManagement pm; + + @Autowired + TmClient tmClient; + + public void dispatch(ChangeManagementSchedule cmSchedule, Schedule schedule) { + try { + + String url = env.getProperty("so.url"); + if (!url.endsWith("/")) + url += "/"; + url = url + "schedule/" + cmSchedule.getVnfName(); + String callbackData = CmHelpers.getDomainData(schedule, CmDomainDataEnum.CallbackData); + String user = env.getProperty("so.user", ""); + String pass = pm.getProperty("so.pass", ""); + Client client = ClientBuilder.newClient(); + if (!user.equals("")) + client.register(new BasicAuthenticatorFilter(user, pass)); + client.register(new CMSOClientFilters()); + WebTarget target = client.target(url); + ObjectMapper om = new ObjectMapper(); + JsonNode jsonEntity = om.readTree(callbackData); + Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON); + try { + Response response = invocationBuilder.post(Entity.json(jsonEntity)); + switch (response.getStatus()) { + case 201: { + debug.debug("Response status=" + response.getStatus()); + // Push the state up to the schedule. + processScheduleResponse(cmSchedule, schedule, response); + break; + } + case 200: { + debug.debug("Response status=" + response.getStatus()); + // Push the state up to the schedule. + processScheduleResponse200(cmSchedule, schedule, response); + break; + } + case 400: // Bad request + case 500: + default: { + errors.error(LogMessages.UNEXPECTED_RESPONSE.toString(), "VID", response.getStatus(), + response.toString()); + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(response.toString()); + updateScheduleStatus(cmSchedule, schedule); + return; + } + } + } + // No sense in retrying. These are time sensitive actions + catch (ResponseProcessingException e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(e.toString()); + updateScheduleStatus(cmSchedule, schedule); + + } catch (ProcessingException e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(e.toString()); + updateScheduleStatus(cmSchedule, schedule); + } + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(e.toString()); + updateScheduleStatus(cmSchedule, schedule); + } + } + + private void processScheduleResponse(ChangeManagementSchedule cmSchedule, Schedule schedule, Response response) + throws SchedulerException { + WfChangeManagementResponse resp = response.readEntity(WfChangeManagementResponse.class); + for (WfVidCmResponse cmResponse : resp.getCmResponses()) { + if (cmResponse.getVnfName().equals(cmSchedule.getVnfName())) { + cmSchedule.setStatus(CMSStatusEnum.Triggered.toString()); + cmSchedule.setDispatchTimeMillis(System.currentTimeMillis()); + cmSchedule.setMsoRequestId(cmResponse.getOrchestratorRequestId()); + // Push the state up to the schedule. + updateTicket(cmSchedule, schedule); + updateScheduleStatus(cmSchedule, schedule); + return; + } + } + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage("Response did not contain vnfName=" + cmSchedule.getVnfName()); + updateScheduleStatus(cmSchedule, schedule); + } + + private void processScheduleResponse200(ChangeManagementSchedule cmSchedule, Schedule schedule, Response response) + throws SchedulerException { + + JsonNode node = response.readEntity(JsonNode.class); + log.info("Message returned from VID callback: " + node.toString()); + JsonNode status = node.get("status"); + Integer msoStatus = status.asInt(); + JsonNode entity = node.get("entity"); + if (msoStatus == 202) { + JsonNode rr = entity.get("requestReferences"); + if (rr != null) { + JsonNode requestId = rr.get("requestId"); + if (requestId != null) { + cmSchedule.setStatus(CMSStatusEnum.Triggered.toString()); + cmSchedule.setDispatchTimeMillis(System.currentTimeMillis()); + cmSchedule.setMsoRequestId(requestId.asText()); + // Push the state up to the schedule. + updateTicket(cmSchedule, schedule); + updateScheduleStatus(cmSchedule, schedule); + return; + } + } + } + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(node.toString()); + updateScheduleStatus(cmSchedule, schedule); + } + + private void updateTicket(ChangeManagementSchedule cmSchedule, Schedule schedule) { + try { + String changeId = cmSchedule.getTmChangeId(); + if (changeId != null && !changeId.equals("")) + tmClient.updateTicket(schedule, cmSchedule, changeId); + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + } + + @Transactional + public void updateScheduleStatus(ChangeManagementSchedule cmSchedule, Schedule schedule) { + cmScheduleDAO.save(cmSchedule); + if (schedule != null) + scheduleDAO.save(schedule); + + } +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CmJob.java b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CmJob.java new file mode 100644 index 0000000..de78385 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/CmJob.java @@ -0,0 +1,156 @@ +/* + * Copyright © 2017-2018 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.dispatcher; + +import java.util.Map; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.onap.optf.cmso.common.BasicAuthenticatorFilter; +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.common.Mdc; +import org.onap.optf.cmso.common.PropertiesManagement; +import org.onap.optf.cmso.eventq.DispatchedEventList; +import org.onap.optf.cmso.model.dao.ChangeManagementGroupDAO; +import org.onap.optf.cmso.model.dao.ChangeManagementScheduleDAO; +import org.onap.optf.cmso.model.dao.ScheduleDAO; +import org.onap.optf.cmso.ticketmgt.TmClient; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * This is the Quartz Job that is run to send the workflow to VID for execution + * + * + */ +@Component +@DisallowConcurrentExecution +public class CmJob implements Job { + private static EELFLogger log = EELFManager.getInstance().getLogger(CmJob.class); + private static EELFLogger metrics = EELFManager.getInstance().getMetricsLogger(); + private static EELFLogger errors = EELFManager.getInstance().getErrorLogger(); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + CMSOClient vidClient; + + @Autowired + ChangeManagementScheduleDAO cmScheduleDAO; + + @Autowired + ChangeManagementGroupDAO cmGroupDAO; + + @Autowired + ScheduleDAO scheduleDAO; + + @Autowired + TmClient tmClient; + + @Autowired + PropertiesManagement pm; + + @Autowired + Environment env; + + @Autowired + DispatchedEventList dispatchedEventList; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + Mdc.quartzJobBegin(context); + debug.debug(LogMessages.CM_JOB, "Entered"); + Integer id = context.getJobDetail().getJobDataMap().getInt("key"); + try { + // Hand this off to a transactional service + loopback(id); + } catch (Exception e) { + log.warn("Unexpected exception", e); + } finally { + dispatchedEventList.remove(id); + } + debug.debug(LogMessages.CM_JOB, "Exited"); + } + + public void loopback(Integer id) { + Map mdcSave = Mdc.save(); + try { + String url = env.getProperty("cmso.dispatch.url", "http://localhost:8089"); + String path = env.getProperty("cmso.dispatch.schedule.path", "/cmso/dispatch/schedule/"); + url = url + path + id; + String user = env.getProperty("mechid.user", ""); + String pass = pm.getProperty("mechid.pass", ""); + Client client = ClientBuilder.newClient(); + client.register(new BasicAuthenticatorFilter(user, pass)); + WebTarget target = client.target(url); + Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON); + Response response = null; + try { + Mdc.metricStart(id.toString(), url); + response = invocationBuilder.get(); + Mdc.metricEnd(response); + metrics.info(LogMessages.CM_JOB, id.toString()); + switch (response.getStatus()) { + case 200: + log.info("Returned from dispatch call"); + break; + case 400: // Bad request + default: { + + throw new SchedulerException( + "Invalid return from dispach service: " + url + " : " + response.toString()); + } + } + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } finally { + Mdc.restore(mdcSave); + } + + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/DispatchJob.java b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/DispatchJob.java new file mode 100644 index 0000000..cb8597f --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/DispatchJob.java @@ -0,0 +1,251 @@ +/* + * Copyright © 2017-2018 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.dispatcher; + +import java.net.InetAddress; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import org.onap.optf.cmso.common.CMSStatusEnum; +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.model.ChangeManagementGroup; +import org.onap.optf.cmso.model.ChangeManagementSchedule; +import org.onap.optf.cmso.model.Schedule; +import org.onap.optf.cmso.model.dao.ChangeManagementGroupDAO; +import org.onap.optf.cmso.model.dao.ChangeManagementScheduleDAO; +import org.onap.optf.cmso.model.dao.ScheduleDAO; +import org.onap.optf.cmso.ticketmgt.TmClient; +import org.onap.optf.cmso.ticketmgt.bean.TmApprovalStatusEnum; +import org.onap.optf.cmso.ticketmgt.bean.TmChangeInfo; +import org.onap.optf.cmso.ticketmgt.bean.TmStatusEnum; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.eelf.i18n.EELFResourceManager; + +/** + * This is the service used to dispatch a job COuld not get QuartzJobBean to + * be @Transactional + * + */ +@Component +public class DispatchJob { + private static EELFLogger log = EELFManager.getInstance().getLogger(DispatchJob.class); + private static EELFLogger metrics = EELFManager.getInstance().getMetricsLogger(); + private static EELFLogger errors = EELFManager.getInstance().getErrorLogger(); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + CMSOClient vidClient; + + @Autowired + ChangeManagementScheduleDAO cmScheduleDAO; + + @Autowired + ChangeManagementGroupDAO cmGroupDAO; + + @Autowired + ScheduleDAO scheduleDAO; + + @Autowired + TmClient tmClient; + + @Autowired + Environment env; + + public void execute(Integer id) throws JobExecutionException { + debug.debug(LogMessages.CM_JOB, "Entered"); + try { + // No other instance can read this cmso until we are done. + ChangeManagementSchedule cmSchedule = cmScheduleDAO.lockOne(id); + cmSchedule.setDispatcherInstance(InetAddress.getLocalHost().getHostAddress()); + ChangeManagementGroup group = cmGroupDAO.findById(cmSchedule.getChangeManagementGroupsId()).orElse(null); + if (group != null) { + Schedule schedule = scheduleDAO.findById(group.getSchedulesId()).orElse(null); + if (schedule != null) { + schedule.setStatus(CMSStatusEnum.NotificationsInitiated.toString()); + if (safeToDispatch(cmSchedule, schedule)) + vidClient.dispatch(cmSchedule, schedule); + } + } + + } catch (Exception e) { + log.warn("Unexpected exception", e); + } + debug.debug(LogMessages.CM_JOB, "Exited"); + + } + + private boolean safeToDispatch(ChangeManagementSchedule cmSchedule, Schedule schedule) { + + Integer leadTime = env.getProperty("cmso.cm.dispatch.lead.time.ms", Integer.class, 1000); + Boolean scheduleImmediateEnabled = env.getProperty("cmso.cm.dispatch.immediate.enabled", Boolean.class, false); + + // ******************************************************************* + // SHould we read with a lock to avoid race condition? + // Not sure there is any real value to that at the moment. + // + + // ******************************************************************* + // Validate that the state is accurate. + // Another instance may have dispatched + Long startTime = cmSchedule.getStartTimeMillis(); + if (!cmSchedule.getStatus().equals(CMSStatusEnum.Scheduled.toString()) + && !cmSchedule.getStatus().equals(CMSStatusEnum.ScheduledImmediate.toString())) { + log.info("Attempt to dispatch an event that is in the incorrect state scheduleId={0}, vnf={1}, status={2}", + schedule.getScheduleId(), cmSchedule.getVnfName(), cmSchedule.getStatus()); + return false; + } + + // ******************************************************************* + // + // Validate ticket is still active with tm + // + // TODO + if (cmSchedule.getTmChangeId() != null && !cmSchedule.getTmChangeId().equals("")) { + if (!isChangeApproved(schedule, cmSchedule, scheduleImmediateEnabled)) { + return false; + } + } + + // ******************************************************************* + // + // If this is schedule immediate. Dispatch it! + // + if (cmSchedule.getFinishTimeMillis() == null) { + if (scheduleImmediateEnabled) { + debug.info("Dispatching an immediate request" + cmSchedule.getVnfName()); + return true; + } else { + // THis should not happen. If schedule immediate is not enables, it will fail + // ticket approval check. + // ... If we see this, it is a bug... + String message = "Attempt to schedule immediate when immmediate scheduling is disabled: " + + cmSchedule.getVnfName(); + log.info(message); + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(message); + updateScheduleStatus(cmSchedule, schedule); + return false; + } + } + + // ******************************************************************* + // + // Validate that event is not past due. Time sensitive. Do not dispatch + // Do not account for lead time. This should be inconsequential, maybe???? + // + long now = System.currentTimeMillis(); + long startMillis = startTime; + if (now > startMillis) { + String message = EELFResourceManager.format(LogMessages.SCHEDULE_PAST_DUE, schedule.getScheduleId(), + cmSchedule.getVnfName(), new Date(now).toString(), new Date(startMillis).toString()); + log.info(message); + + cmSchedule.setStatus(CMSStatusEnum.PastDue.toString()); + cmSchedule.setStatusMessage(message); + updateScheduleStatus(cmSchedule, schedule); + return false; + } + + // ******************************************************************* + // (Sleep until actual dispatch time...) + // leadTime allows for preparing call to VID to the start of workflow. + long sleep = (startMillis - leadTime) - System.currentTimeMillis(); + if (sleep > 0l) { + try { + Thread.sleep(sleep); + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + } + return true; + } + + private boolean isChangeApproved(Schedule schedule, ChangeManagementSchedule cmSchedule, + Boolean scheduleImmediateEnabled) { + String message = ""; + // ChangeManagementGroup group = + // cmGroupDAO.findById(cmSchedule.getChangeManagementGroupsId()).orElse(null); + // Long startDate = group.getStartTimeMillis(); + Set vnfNames = new HashSet(); + vnfNames.add(cmSchedule.getVnfName()); + TmChangeInfo info = tmClient.getChangeTicket(cmSchedule.getTmChangeId()); + String otherStatus = env.getProperty("vtm.status", ""); + String otherApprovalStatus = env.getProperty("vtm.approvalStatus", ""); + String statusConfig = env.getProperty("vtm.approvalStatus", + TmApprovalStatusEnum.Approved.toString() + "|" + TmStatusEnum.Scheduled.toString()); + String[] statusList = statusConfig.split(","); + if (info != null) { + String approvalStatus = info.getApprovalStatus(); + String status = info.getStatus(); + debug.debug("Retrieved changeid=" + info.getChangeId() + " approvlStatus=" + approvalStatus + " status=" + + status); + String actualStatus = approvalStatus + "|" + status; + for (String okStatus : statusList) { + if (actualStatus.equals(okStatus)) { + return true; + } + } + // Look for proper state for immediate VNFs + debug.debug("Retrieved changeid=" + info.getChangeId() + " otherApprovlStatus=" + otherApprovalStatus + + " status=" + otherStatus); + if (cmSchedule.getStartTime() == null && scheduleImmediateEnabled) { + debug.debug("Ignoring status on immediate schedule: " + cmSchedule.getTmChangeId()); + return true; + } + message = EELFResourceManager.format(LogMessages.CM_TICKET_NOT_APPROVED, schedule.getScheduleId(), + cmSchedule.getVnfName(), cmSchedule.getTmChangeId(), status, approvalStatus); + log.warn(message); + } else { + message = EELFResourceManager.format(LogMessages.UNABLE_TO_LOCATE_CHANGE_RECORD, schedule.getScheduleId(), + cmSchedule.getVnfName(), cmSchedule.getTmChangeId()); + errors.error(message); + } + cmSchedule.setStatus(CMSStatusEnum.SchedulingFailed.toString()); + cmSchedule.setStatusMessage(message); + updateScheduleStatus(cmSchedule, schedule); + return false; + } + + @Transactional + public void updateScheduleStatus(ChangeManagementSchedule cmSchedule, Schedule schedule) { + cmScheduleDAO.save(cmSchedule); + scheduleDAO.save(schedule); + + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispacherService.java b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispacherService.java new file mode 100644 index 0000000..d0ff299 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispacherService.java @@ -0,0 +1,96 @@ +/* + * Copyright © 2017-2018 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.dispatcher.rs; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@Api +@Path("/dispatch") +@Produces({MediaType.APPLICATION_JSON}) +public interface DispacherService { + + // ****************************************************************** + @GET + @Path("/schedule/{id}") + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "", notes = "Does dispsatch of provided cm schedule id.", response = Integer.class) + @ApiResponses( + value = {@ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Request failed")}) + public Response dispatchSchedule(@ApiParam(value = "Identifier", allowMultiple = false) @PathParam("id") Integer id, + @Context UriInfo uri, @Context HttpServletRequest request); + + // ****************************************************************** + @GET + @Path("/optimizer/{id}") + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "", notes = "Does dispsatch of provided cm schedule id.", response = Integer.class) + @ApiResponses( + value = {@ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Request failed")}) + public Response dispatchOptimizer( + @ApiParam(value = "Identifier", allowMultiple = false) @PathParam("id") Integer id, @Context UriInfo uri, + @Context HttpServletRequest request); + + // ****************************************************************** + @GET + @Path("/schedulestatus/{id}") + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "", notes = "Does dispsatch of provided schedule id.", response = Integer.class) + @ApiResponses( + value = {@ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Request failed")}) + public Response dispatchScheduleStatus( + @ApiParam(value = "Identifier", allowMultiple = false) @PathParam("id") Integer id, @Context UriInfo uri, + @Context HttpServletRequest request); + + // ****************************************************************** + @GET + @Path("/sostatus/{id}") + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "", notes = "Does dispsatch of provided cm schedule id.", response = Integer.class) + @ApiResponses( + value = {@ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Request failed")}) + public Response dispatchSoStatus(@ApiParam(value = "Identifier", allowMultiple = true) @PathParam("id") Integer id, + @Context UriInfo uri, @Context HttpServletRequest request); + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispatcherServiceImpl.java b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispatcherServiceImpl.java new file mode 100644 index 0000000..1e8a937 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/dispatcher/rs/DispatcherServiceImpl.java @@ -0,0 +1,137 @@ +/* + * Copyright © 2017-2018 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.dispatcher.rs; + +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.common.Mdc; +import org.onap.optf.cmso.dispatcher.DispatchJob; +import org.onap.optf.cmso.optimizer.CMSOptimizerClient; +import org.onap.optf.cmso.sostatus.MsoStatusClient; +import org.onap.optf.cmso.ticketmgt.TmStatusClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +@Controller +public class DispatcherServiceImpl implements DispacherService { + private static EELFLogger log = EELFManager.getInstance().getLogger(DispatcherServiceImpl.class); + private static EELFLogger audit = EELFManager.getInstance().getAuditLogger(); + private static EELFLogger errors = EELFManager.getInstance().getErrorLogger(); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + DispatchJob dispatchJob; + + @Autowired + CMSOptimizerClient sniroClient; + + @Autowired + TmStatusClient tmStatusClient; + + @Autowired + MsoStatusClient msoStatusClient; + + @Override + @Transactional + public Response dispatchSchedule(Integer id, UriInfo uri, HttpServletRequest request) { + Mdc.begin(request, UUID.randomUUID().toString()); + log.info("dispatchVID entered {}", id); + try { + dispatchJob.execute(id); + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e.getMessage()); + debug.error(e.getMessage(), e); + } + Response response = Response.ok().build(); + Mdc.end(response); + audit.info("dispatchVID"); + return response; + } + + @Override + @Transactional + public Response dispatchOptimizer(Integer id, UriInfo uri, HttpServletRequest request) { + Mdc.begin(request, UUID.randomUUID().toString()); + log.info("Dispatch.exec entered {}", id); + try { + sniroClient.scheduleSniroOptimization(id); + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e.getMessage()); + debug.error(e.getMessage(), e); + } + Response response = Response.ok().build(); + Mdc.end(response); + audit.info("dispatchSNIRO"); + return response; + } + + @Override + @Transactional + public Response dispatchScheduleStatus(Integer id, UriInfo uri, HttpServletRequest request) { + Mdc.begin(request, UUID.randomUUID().toString()); + log.info("Dispatch.exec entered {}", id); + try { + tmStatusClient.checkStatus(id); + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e.getMessage()); + debug.error(e.getMessage(), e); + } + Response response = Response.ok().build(); + Mdc.end(response); + audit.info("dispatchScheduleStatus"); + return response; + } + + @Override + @Transactional + public Response dispatchSoStatus(Integer id, UriInfo uri, HttpServletRequest request) { + Mdc.begin(request, UUID.randomUUID().toString()); + log.info("Dispatch.exec entered {}", id); + try { + msoStatusClient.execute(id); + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e.getMessage()); + debug.error(e.getMessage(), e); + } + Response response = Response.ok().build(); + Mdc.end(response); + audit.info("dispatchMsoStatus"); + return response; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CMSQueueJob.java b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CMSQueueJob.java new file mode 100644 index 0000000..59df59f --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CMSQueueJob.java @@ -0,0 +1,141 @@ +/* + * Copyright © 2017-2018 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.eventq; + +import java.util.Date; +import java.util.List; +import org.onap.optf.cmso.common.CMSStatusEnum; +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.dispatcher.CmJob; +import org.onap.optf.cmso.model.ChangeManagementSchedule; +import org.onap.optf.cmso.model.dao.ChangeManagementScheduleDAO; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * This job will look for ChangeManagementSchedule approved jobs that are due + * within the next n intervals of this job and schedule them in as a Quartz + * CmJob to be dispatched. These ChangeManagementSchedule rows will be + * status=Queued The CmJob will confirm that the job is OK to be dispatched and + * set status=.... The next N intervals should be enough to ensure sluggish + * performance of this process does not miss events but does not exhaust + * memory.... + */ +@Component +public class CMSQueueJob { + private static EELFLogger log = EELFManager.getInstance().getLogger(CMSQueueJob.class); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + ChangeManagementScheduleDAO cmScheduleDAO; + + @Autowired + SchedulerFactoryBean qsScheduler; + + @Autowired + Environment env; + + @Autowired + DispatchedEventList dispatchedEventList; + + public boolean queueImminentJobs() { + Integer interval = env.getProperty("cmso.cm.polling.job.interval.ms", Integer.class, 10000); + Integer lookahead = env.getProperty("cmso.cm.polling.job.lookahead.intervals", Integer.class, 5); + long now = System.currentTimeMillis(); + Long endTime = now + (interval * lookahead); + List schedules = + cmScheduleDAO.findByStatusAndEndTime(CMSStatusEnum.Scheduled.toString(), endTime); + if (schedules.size() == 0) + return false; + for (ChangeManagementSchedule schedule : schedules) { + try { + if (!dispatchedEventList.isAlreadyDispatched(schedule.getId())) { + scheduleCmJob(schedule); + dispatchedEventList.addToDispathcedEventList(schedule.getId()); + } + } catch (org.quartz.SchedulerException e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + // WIll keep trying until it goes Past due + schedule.setStatus(CMSStatusEnum.Scheduled.toString()); + schedule.setDispatcherInstance(""); + updateScheduleStatus(schedule); + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + schedule.setStatus(CMSStatusEnum.Scheduled.toString()); + schedule.setDispatcherInstance(""); + updateScheduleStatus(schedule); + } + } + return false; + } + + public void scheduleCmJob(ChangeManagementSchedule schedule) throws org.quartz.SchedulerException { + // + Integer dispatherLeadTime = env.getProperty("cmso.cm.dispatcher.lead.time.ms", Integer.class, 5000); + long dispatchTime = 0; + Long startTime = schedule.getStartTimeMillis(); + + /// If startTIme is null, it is an immediate start + if (startTime != null) + dispatchTime = startTime - dispatherLeadTime; + + JobDetail jobDetail = JobBuilder.newJob(CmJob.class).build(); + jobDetail.getJobDataMap().put("key", schedule.getId()); + + TriggerBuilder tb = TriggerBuilder.newTrigger().forJob(jobDetail); + + long now = System.currentTimeMillis(); + if (now > dispatchTime) + tb.startNow(); + else + tb.startAt(new Date(dispatchTime)); + Trigger trigger = tb.build(); + qsScheduler.getScheduler().scheduleJob(jobDetail, trigger); + + } + + @Transactional + public void updateScheduleStatus(ChangeManagementSchedule cmSchedule) { + cmScheduleDAO.save(cmSchedule); + + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJob.java b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJob.java new file mode 100644 index 0000000..08017cf --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJob.java @@ -0,0 +1,105 @@ +/* + * Copyright © 2017-2018 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.eventq; + +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.common.Mdc; +import org.onap.optf.cmso.model.dao.ChangeManagementScheduleDAO; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * This quartz job runs periodically to query the ChangeManagementSChedule table + * to create CmJobs to queue in quartx. + * + */ +@Component +@DisallowConcurrentExecution +public class CmQuartzJob extends QuartzJobBean { + private static EELFLogger log = EELFManager.getInstance().getLogger(CmQuartzJob.class); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + CMSQueueJob qJob; + + // This is not called directly. Using @Autowired to ensure that startup + // Runs before the fist invocation of executeInternal + @Autowired + CmQuartzJobStartup startup; + + @Autowired + ChangeManagementScheduleDAO cmScheduleDAO; + + @Override + @Transactional + protected void executeInternal(JobExecutionContext context) throws JobExecutionException { + Mdc.quartzJobBegin(context); + debug.debug(LogMessages.CM_QUARTZ_JOB, "Entered"); + + // This logic does not make sense in k8s since we cannot count on IP address + // as the dispatch. + // Need to understand how to requeue when instances go down while dispatching + // jobs + // between "Queued for Dispatch" and "Triggered" + // startup.startup(); // Runs once + + // Turns out that this is not necessary, Quartz does what makes sense after all + // if (isStale(context)) + // return; + + try { + + boolean moreToSchedule = true; + while (moreToSchedule) { + try { + moreToSchedule = qJob.queueImminentJobs(); + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + moreToSchedule = false; + } + } + + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + debug.debug(LogMessages.CM_QUARTZ_JOB, "Exited"); + + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJobStartup.java b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJobStartup.java new file mode 100644 index 0000000..2624bfe --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/CmQuartzJobStartup.java @@ -0,0 +1,79 @@ +/* + * Copyright © 2017-2018 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.eventq; + +import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicBoolean; +import org.onap.optf.cmso.model.dao.ChangeManagementScheduleDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * This bean uses @AUtowired to ensure that it runs once at startup to reset all + * QueuedForDispatch rows that were in flight last time from this + * "dispatcherInstnace" shut down. + * + * Potentially, in a distributed environment, when a "dispatcherInstance" + * shutdown is detected by another instance, it can run this query to requeue + * these items. We are a long way from there. + * + * Chances are great that re-queued events will end up being Past Due events + * + */ +@Component +public class CmQuartzJobStartup { + private static EELFLogger log = EELFManager.getInstance().getLogger(CmQuartzJobStartup.class); + + @Autowired + ChangeManagementScheduleDAO cmScheduleDAO; + + private AtomicBoolean started = new AtomicBoolean(false); + + public CmQuartzJobStartup() { + + } + + @Transactional + public void startup() { + try { + if (started.getAndSet(true)) + return; + int rows = cmScheduleDAO.requeueQueuedForDispatch(InetAddress.getLocalHost().getHostAddress()); + log.info("{0} QUeued For Dispatch rows have been requeued at startup", rows); + } catch (Exception e) { + log.error("Exception caught in requeueing Queued for DIspatch rows at startup", e); + } + } +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/eventq/DispatchedEventList.java b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/DispatchedEventList.java new file mode 100644 index 0000000..0c346d3 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/eventq/DispatchedEventList.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2017-2018 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.eventq; + +import java.util.HashSet; +import java.util.Set; +import org.springframework.stereotype.Component; + +/** + * This class is used to avoid re-dispatching scheduled events until the status + * changes to either ???? or ???? Note that other instances of CM SCheduler may + * be dispatching this event, but only the first one to grab the lock will + * publish the event. + * + */ +@Component +public class DispatchedEventList { + + private Set list = new HashSet<>(); + + public synchronized void addToDispathcedEventList(Integer id) { + list.add(id); + } + + public synchronized void remove(Integer id) { + list.remove(id); + } + + public synchronized boolean isAlreadyDispatched(Integer id) { + return list.contains(id); + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CMSOptimizerClient.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CMSOptimizerClient.java new file mode 100644 index 0000000..153e4a8 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/CMSOptimizerClient.java @@ -0,0 +1,377 @@ +/* + * Copyright © 2017-2018 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 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.optf.cmso.common.BasicAuthenticatorFilter; +import org.onap.optf.cmso.common.CMSStatusEnum; +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.common.Mdc; +import org.onap.optf.cmso.common.PropertiesManagement; +import org.onap.optf.cmso.filters.CMSOClientFilters; +import org.onap.optf.cmso.model.Schedule; +import org.onap.optf.cmso.model.dao.ScheduleDAO; +import org.onap.optf.cmso.optimizer.bean.CMOptimizerRequest; +import org.onap.optf.cmso.optimizer.bean.CMRequestInfo; +import org.onap.optf.cmso.optimizer.bean.CMSchedulingInfo; +import org.onap.optf.cmso.optimizer.bean.CMVnfDetails; +import org.onap.optf.cmso.service.rs.models.CMSInfo; +import org.onap.optf.cmso.service.rs.models.ChangeWindowMessage; +import org.onap.optf.cmso.service.rs.models.HealthCheckComponent; +import org.onap.optf.cmso.service.rs.models.VnfDetailsMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class CMSOptimizerClient { + private static EELFLogger log = EELFManager.getInstance().getLogger(CMSOptimizerClient.class); + private static EELFLogger metrics = EELFManager.getInstance().getMetricsLogger(); + private static EELFLogger errors = EELFManager.getInstance().getErrorLogger(); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + ScheduleDAO scheduleDAO; + + @Autowired + Environment env; + + @Autowired + PropertiesManagement pm; + + public boolean scheduleSniroOptimization(Integer id) { + Map mdcSave = Mdc.save(); + try { + String snirourl = env.getProperty("cmso.optimizer.url"); + String snirocallbackurl = env.getProperty("cmso.optimizer.callbackurl"); + String username = env.getProperty("mechid.user"); + Integer maxAttempts = env.getProperty("cmso.sniro.maxAttempts", Integer.class, 20); + + // Ensure that only one cmso is requsting this call to SNIRO + Schedule schedule = scheduleDAO.lockOne(id); + if (!schedule.getStatus().equals(CMSStatusEnum.PendingSchedule.toString())) + return false; + + String password = pm.getProperty("mechid.pass", ""); + // + // 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 true; + } + CMOptimizerRequest cmReq = new CMOptimizerRequest(); + try { + CMSInfo info = reconstituteMessage(schedule); + if (info == null) { + return true; + } + buildRequest(cmReq, info, schedule, snirocallbackurl); + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + schedule.setStatus(CMSStatusEnum.OptimizationFailed.toString()); + schedule.setOptimizerMessage("Unexpected exception: " + e.getMessage()); + updateScheduleStatus(schedule); + return true; + } + + // This service will call SNIO for each PendingOptimiztion + // If the request is successfully scheduled in SNIRO, status will be + // updated to OptimizationInProgress. + Client client = ClientBuilder.newClient(); + client.register(new BasicAuthenticatorFilter(username, password)); + client.register(new CMSOClientFilters()); + WebTarget sniroTarget = client.target(snirourl); + Invocation.Builder invocationBuilder = sniroTarget.request(MediaType.APPLICATION_JSON); + try { + // + // First, push OptimizationInProgress to the DB (flush()) assuming a 202 status, + // in case the SNIRO callback is received prior to the + // commit of this transaction. + // SNIRO Callback will throw an error if it receives a response in the incorrect + // state. + // + schedule.setOptimizerTransactionId(cmReq.getRequestInfo().getTransactionId()); + schedule.setOptimizerDateTimeMillis(System.currentTimeMillis()); + schedule.setStatus(CMSStatusEnum.OptimizationInProgress.toString()); + updateScheduleStatus(schedule); + debug.debug("SNIRO url / user: " + snirourl + " / " + username); + debug.debug("SNIRO Request: " + new ObjectMapper().writeValueAsString(cmReq)); + log.info(LogMessages.OPTIMIZER_REQUEST, "Begin", schedule.getScheduleId(), snirourl); + Mdc.metricStart(schedule.getScheduleId(), snirourl); + Response response = invocationBuilder.post(Entity.json(cmReq)); + + Mdc.metricEnd(response); + metrics.info(LogMessages.OPTIMIZER_REQUEST, "End", schedule.getScheduleId(), snirourl); + log.info(LogMessages.OPTIMIZER_REQUEST, "End", schedule.getScheduleId(), snirourl); + switch (response.getStatus()) { + case 202: + debug.debug("Successfully scheduled optimization: " + schedule.getScheduleId()); + // Scheduled with SNIRO + 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 SNIRO + // down. + int tries = schedule.getOptimizerAttemptsToSchedule(); + tries++; + schedule.setOptimizerAttemptsToSchedule(tries); + updateScheduleStatus(schedule); + errors.error(LogMessages.OPTIMIZER_EXCEPTION, message); + return true; + } + + 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. + errors.error(LogMessages.OPTIMIZER_EXCEPTION, message); + // Wait until next cycle and try again. + return false; + } + + } + // + return true; + } catch (ResponseProcessingException e) { + schedule.setOptimizerDateTimeMillis(System.currentTimeMillis()); + schedule.setOptimizerStatus("Failed to parse SNIRO response"); + schedule.setStatus(CMSStatusEnum.ScheduleFailed.toString()); + // Need to understand the cause of this error. May be teh same as SNIRO down. + int tries = schedule.getOptimizerAttemptsToSchedule(); + tries++; + schedule.setOptimizerAttemptsToSchedule(tries); + updateScheduleStatus(schedule); + // Getting invalid response from SNIRO. + // May be data related. + errors.error(LogMessages.OPTIMIZER_EXCEPTION, e, e.getMessage()); + return false; + + } catch (ProcessingException e) { + // Don't track number of retries on IO error (SNIRO is down) + schedule.setOptimizerDateTimeMillis(System.currentTimeMillis()); + schedule.setStatus(CMSStatusEnum.PendingSchedule.toString()); + updateScheduleStatus(schedule); + /// Cannot connect to SNIRO + errors.error(LogMessages.OPTIMIZER_EXCEPTION, e, e.getMessage()); + // Wait until next cycle + return false; + } + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + + } finally { + Mdc.restore(mdcSave); + } + return false; + } + + private void buildRequest(CMOptimizerRequest cmReq, CMSInfo info, Schedule schedule, String snirocallbackurl) { + + // TODO: Need to get SNIRO to accept ChangeManagementSchedulingInfo + // This is to support 1707 SNIRO interface + CMRequestInfo reqInfo = cmReq.getRequestInfo(); + CMSchedulingInfo schInfo = cmReq.getSchedulingInfo(); + + UUID uuid = UUID.randomUUID(); + reqInfo.setCallbackUrl(snirocallbackurl); + reqInfo.setOptimizer(new String[] {"scheduling"}); + reqInfo.setTransactionId(schedule.getOptimizerTransactionId()); + reqInfo.setRequestId("CM-" + uuid.toString()); + reqInfo.setSourceId("cmso"); + + String[] policyArray = new String[1]; + policyArray[0] = info.getPolicyId(); + schInfo.setPolicyId(policyArray); + schInfo.setAdditionalDurationInSecs(info.getAdditionalDurationInSeconds()); + schInfo.setConcurrencyLimit(info.getConcurrencyLimit()); + schInfo.setNormalDurationInSecs(info.getNormalDurationInSeconds()); + schInfo.setScheduleId(schedule.getScheduleId()); + List list = new ArrayList(); + String startTime = ""; + String endTime = ""; + + for (VnfDetailsMessage vnf : info.getVnfDetails()) { + String groupId = vnf.getGroupId(); + for (String node : vnf.getNode()) { + CMVnfDetails d = new CMVnfDetails(vnf.getGroupId()); + d.setNode(node); + list.add(d); + } + if (startTime.equals("")) { + // Only supporting 1 CW for 1710 + ChangeWindowMessage cw = vnf.getChangeWindow().get(0); + startTime = cw.getStartTime(); + endTime = cw.getEndTime(); + } + } + schInfo.setStartTime(startTime); + schInfo.setEndTime(endTime); + schInfo.setVnfDetails(list.toArray(new CMVnfDetails[list.size()])); + + } + + private CMSInfo reconstituteMessage(Schedule schedule) { + String request = schedule.getScheduleInfo(); + ObjectMapper om = new ObjectMapper(); + try { + CMSInfo info = om.readValue(request, CMSInfo.class); + return info; + } 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.... + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, "Unable to parse message. Format changed?"); + schedule.setOptimizerStatus("Failed to parse SNIRO request"); + schedule.setOptimizerDateTimeMillis(System.currentTimeMillis()); + schedule.setStatus(CMSStatusEnum.OptimizationFailed.toString()); + scheduleDAO.save(schedule); + } + return null; + } + + @Transactional + public void updateScheduleStatus(Schedule schedule) { + scheduleDAO.save(schedule); + + } + + public HealthCheckComponent healthCheck() { + Map mdcSave = Mdc.save(); + HealthCheckComponent hcc = new HealthCheckComponent(); + hcc.setName("SNIRO Interface"); + String snirourl = env.getProperty("cmso.optimizer.url"); + String snirocallbackurl = env.getProperty("cmso.optimizer.callbackurl"); + String username = env.getProperty("mechid.user"); + String password = pm.getProperty("mechid.pass", ""); + hcc.setUrl(snirourl); + try { + UUID uuid = UUID.randomUUID(); + // Build a bogus request should fail policy validation + CMRequestInfo requestInfo = new CMRequestInfo(); + CMSchedulingInfo schedulingInfo = new CMSchedulingInfo(); + CMOptimizerRequest cmReq = new CMOptimizerRequest(); + cmReq.setRequestInfo(requestInfo); + cmReq.setSchedulingInfo(schedulingInfo); + requestInfo.setCallbackUrl("http://callbackurl.onap.org:8080/healthcheck"); + requestInfo.setOptimizer(new String[] {"scheduling"}); + requestInfo.setTransactionId(uuid.toString()); + requestInfo.setRequestId("CM-" + uuid.toString()); + requestInfo.setSourceId("cmso"); + schedulingInfo.setAdditionalDurationInSecs(10); + schedulingInfo.setConcurrencyLimit(10); + schedulingInfo.setNormalDurationInSecs(10); + schedulingInfo.setPolicyId(new String[] {"healthcheck"}); + schedulingInfo.setScheduleId(uuid.toString()); + CMVnfDetails details = new CMVnfDetails(); + details.setGroupId(""); + details.setNode("healtcheck"); + schedulingInfo.setVnfDetails(new CMVnfDetails[] {details}); + schedulingInfo.setStartTime("2017-12-11T15:23:24Z"); + schedulingInfo.setEndTime("2017-12-11T22:23:24Z"); + + Client client = ClientBuilder.newClient(); + client.register(new BasicAuthenticatorFilter(username, password)); + WebTarget sniroTarget = client.target(snirourl); + Invocation.Builder invocationBuilder = sniroTarget.request(MediaType.APPLICATION_JSON); + debug.debug("SNIRO url / user: " + snirourl + " / " + username); + log.info(LogMessages.OPTIMIZER_REQUEST, "Begin", "healthcheck", snirourl); + Mdc.metricStart("healthcjeck", snirourl); + Response response = invocationBuilder.post(Entity.json(cmReq)); + Mdc.metricEnd(response); + metrics.info(LogMessages.OPTIMIZER_REQUEST, "End", "healthcheck", snirourl); + log.info(LogMessages.OPTIMIZER_REQUEST, "End", "healthcheck", snirourl); + String message = response.getStatus() + ":" + response.readEntity(String.class); + switch (response.getStatus()) { + case 202: + debug.debug("Successful SNIRO healthcheck"); + hcc.setHealthy(true); + break; + case 400: + // Expecting policy not found. + if (message.contains("Cannot fetch policy")) { + debug.debug("Successful SNIRO healthcheck"); + hcc.setHealthy(true); + hcc.setStatus("OK"); + } else { + hcc.setStatus(message); + } + break; + default: + hcc.setStatus(message); + break; + } + } catch (Exception e) { + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e.toString()); + hcc.setStatus(e.toString()); + } finally { + Mdc.restore(mdcSave); + } + return hcc; + + } +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/DispatchedOptimizerList.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/DispatchedOptimizerList.java new file mode 100644 index 0000000..871e831 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/DispatchedOptimizerList.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2017-2018 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 java.util.HashSet; +import java.util.Set; +import org.springframework.stereotype.Component; + +/** + * This class is used to avoid re-dispatching scheduled events until the status + * changes to either ???? or ???? Note that other instances of CM SCheduler may + * be dispatching this event, but only the first one to grab the lock will + * publish the event. + * + */ +@Component +public class DispatchedOptimizerList { + + private Set list = new HashSet<>(); + + public synchronized void addToDispathcedEventList(Integer id) { + list.add(id); + } + + public synchronized void remove(Integer id) { + list.remove(id); + } + + public synchronized boolean isAlreadyDispatched(Integer id) { + return list.contains(id); + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/OptimizerQuartzJob.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/OptimizerQuartzJob.java new file mode 100644 index 0000000..064566c --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/OptimizerQuartzJob.java @@ -0,0 +1,176 @@ +/* + * Copyright © 2017-2018 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 java.util.List; +import java.util.Map; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.onap.optf.cmso.common.BasicAuthenticatorFilter; +import org.onap.optf.cmso.common.CMSStatusEnum; +import org.onap.optf.cmso.common.DomainsEnum; +import org.onap.optf.cmso.common.LogMessages; +import org.onap.optf.cmso.common.Mdc; +import org.onap.optf.cmso.common.PropertiesManagement; +import org.onap.optf.cmso.model.Schedule; +import org.onap.optf.cmso.model.dao.ScheduleDAO; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.stereotype.Component; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +@Component +@DisallowConcurrentExecution +public class OptimizerQuartzJob extends QuartzJobBean { + private static EELFLogger log = EELFManager.getInstance().getLogger(OptimizerQuartzJob.class); + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + private static EELFLogger errors = EELFManager.getInstance().getErrorLogger(); + private static EELFLogger metrics = EELFManager.getInstance().getMetricsLogger(); + + @Autowired + ScheduleDAO scheduleDAO; + + @Autowired + PropertiesManagement pm; + + @Autowired + Environment env; + + @Override + protected void executeInternal(JobExecutionContext context) throws JobExecutionException { + Mdc.quartzJobBegin(context); + debug.debug(LogMessages.OPTIMIZER_QUARTZ_JOB, "Entered"); + + // Turns out that this is not necessary. Quartz behaves in a way that makes + // sense. + // if (isStale(context)) + // return; + + try { + // This job will look at the schedules waiting to go to SNIRO + // (PendingSchedule), + // schedule the request and update the status to PendingSchedule + // and update the state to OptimizationInProgress + List schedules = scheduleDAO.findByDomainStatus(DomainsEnum.ChangeManagement.toString(), + CMSStatusEnum.PendingSchedule.toString()); + for (Schedule s : schedules) { + scheduleOptimization(s); + } + + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + debug.debug(LogMessages.OPTIMIZER_QUARTZ_JOB, "Exited"); + + } + + public void scheduleOptimization(Schedule s) { + Integer id = s.getId(); + Map mdcSave = Mdc.save(); + try { + String url = env.getProperty("cmso.dispatch.url", "http://localhost:8089"); + String path = env.getProperty("cmso.dispatch.optimizer .path", "/cmso/dispatch/optimizer/"); + url = url + path + id; + String user = env.getProperty("mechid.user", ""); + String pass = pm.getProperty("mechid.pass", ""); + Client client = ClientBuilder.newClient(); + client.register(new BasicAuthenticatorFilter(user, pass)); + WebTarget target = client.target(url); + Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON); + Response response = null; + Mdc.metricStart(id.toString(), url); + response = invocationBuilder.get(); + Mdc.metricEnd(response); + metrics.info(LogMessages.OPTIMIZER_QUARTZ_JOB, id.toString()); + switch (response.getStatus()) { + case 200: + log.info("Returned from dispatch call"); + break; + case 400: // Bad request + default: { + + throw new SchedulerException( + "Invalid return from dispach service: " + url + " : " + response.toString()); + } + } + } catch (Exception e) { + debug.debug(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + errors.error(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } finally { + Mdc.restore(mdcSave); + } + + } + + /** + * According to the documentation I read, Quartz would queue a job without + * waiting for the completion of the job with @DisallowConcurrentExecution to + * complete so that there would be a backlog of triggers to process + * + * This was designed to spin though these stale triggers. When this didn't work, + * I discovered that the behavior is that Quartz will wait for the appropriate + * interval after @DisallowConcurrentExecution jobs complete. + * + * I tested by adding a sleep for an interval > the trigger interval + * + * QUartz appears to do what makes sense. Leaving this here in case issues + * arise... + * + */ + @SuppressWarnings("unused") + private boolean isStale(JobExecutionContext context) { + // DO not process stale requests. + long now = System.currentTimeMillis(); + long next = context.getNextFireTime().getTime(); + long sch = context.getScheduledFireTime().getTime(); + log.info("now=" + now); + log.info("nxt=" + next); + log.info("sch=" + sch); + if (now > sch) { + log.info("Skipping stale SNIRO job"); + // return true; + } + return false; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerRequest.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerRequest.java new file mode 100644 index 0000000..e9e80c4 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerRequest.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2017-2018 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.bean; + +public class CMOptimizerRequest { + + /* + * + * { "schedulingInfo": { "scheduleId": "CM-<__SCHEDULE ID__>", "startTime": + * "2017-02-15T00:00:00+05:00", "endTime": "2017-02-18T23:59:00+05:00", + * "normalDurationInSecs": 60, "additionalDurationInSecs": 0, // for backout + * "concurrencyLimit": 10, "policyId": ["SNIRO.TimeLimitAndVerticalTopology"], + * "vnfDetails": [{ “nodeâ€?: "satmo415vbc", “groupIdâ€?: “group1â€?//optional }, { + * “nodeâ€?: "satmo415vbc", “groupIdâ€?: “group1â€?//optional }] }, "requestInfo": { + * “transactionIdâ€?: â€?__TRANSACTIONID__â€?, //logging "requestId": + * "CM-<__SCHEDULE ID__>", "sourceId": "cm-portal", “optimizerâ€?: [“schedulingâ€?], + * "callbackUrl": "http://callbackurl.onap.org:8080/callback" } } + * + */ + + private CMSchedulingInfo schedulingInfo; + private CMRequestInfo requestInfo; + + public CMOptimizerRequest() { + schedulingInfo = new CMSchedulingInfo(); + requestInfo = new CMRequestInfo(); + } + + public CMSchedulingInfo getSchedulingInfo() { + return schedulingInfo; + } + + public void setSchedulingInfo(CMSchedulingInfo schedulingInfo) { + this.schedulingInfo = schedulingInfo; + } + + public CMRequestInfo getRequestInfo() { + return requestInfo; + } + + public void setRequestInfo(CMRequestInfo requestInfo) { + this.requestInfo = requestInfo; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerResponse.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerResponse.java new file mode 100644 index 0000000..a50025b --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMOptimizerResponse.java @@ -0,0 +1,124 @@ +/* + * Copyright © 2017-2018 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.bean; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "Response from schedule optimizer", + description = "Asynchronous response to schedule oprimizer request.") +public class CMOptimizerResponse { + + /* + * + * { "transactionId": "dummy-transaction-id", + * "scheduleId":"CM-<__SCHEDULE ID__>", "requestState": "complete", "status": + * "Optimal", // diagnostic code "description": "Optimal solution found", // + * diagnostic code "schedule": [ { "groupId": "grp06", "startTime": + * "2016-10-01T00:30:00+05:00", // starting time for this group (In 1707, + * seconds will always be zero but there is no reason to hardcode that decision) + * "finishTime": "2016-10-01T00:40:00+05:00", // endtime for this group + * (including failover) "latestInstanceStartTime": "2016-10-01T00:38:00Z", // + * latest time when an instance of this group can be started "node": [ "up01", + * "up03", "up09" ] // list of instances for this group. } ] } + * + */ + + @ApiModelProperty(value = "Unique id of optimization request.") + private String transactionId; + + @ApiModelProperty(value = "Schedule id for which the optimization request was executed.") + private String scheduleId; + + @ApiModelProperty(value = "State of the request as reported by the optimizer.") + private String requestState; + + @ApiModelProperty(value = "Status of the request.") + private String status; + + @ApiModelProperty(value = "Description of the request status.") + private String description; + + @ApiModelProperty(value = "List of schedules returned, one per group. Only 1 group supported at this time.") + private CMSchedule[] schedule; + + public CMOptimizerResponse() {} + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getScheduleId() { + return scheduleId; + } + + public void setScheduleId(String scheduleId) { + this.scheduleId = scheduleId; + } + + public String getRequestState() { + return requestState; + } + + public void setRequestState(String requestState) { + this.requestState = requestState; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public CMSchedule[] getSchedule() { + return schedule; + } + + public void setSchedule(CMSchedule[] schedule) { + this.schedule = schedule; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMRequestInfo.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMRequestInfo.java new file mode 100644 index 0000000..5d8ee69 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMRequestInfo.java @@ -0,0 +1,83 @@ +/* + * Copyright © 2017-2018 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.bean; + +public class CMRequestInfo { + private String transactionId; + private String requestId; + private String sourceId; + private String[] optimizer; + private String callbackUrl; + + public CMRequestInfo() {} + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getSourceId() { + return sourceId; + } + + public void setSourceId(String sourceId) { + this.sourceId = sourceId; + } + + public String[] getOptimizer() { + return optimizer; + } + + public void setOptimizer(String[] optimizer) { + this.optimizer = optimizer; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedule.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedule.java new file mode 100644 index 0000000..184e782 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedule.java @@ -0,0 +1,88 @@ +/* + * Copyright © 2017-2018 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.bean; + +import java.util.ArrayList; +import java.util.List; + +public class CMSchedule { + private String groupId; + private String startTime; + private String finishTime; + private String latestInstanceStartTime; + private List node; + + public CMSchedule() { + node = new ArrayList(); + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getFinishTime() { + return finishTime; + } + + public void setFinishTime(String finishTime) { + this.finishTime = finishTime; + } + + public String getLatestInstanceStartTime() { + return latestInstanceStartTime; + } + + public void setLatestInstanceStartTime(String latestInstanceStartTime) { + this.latestInstanceStartTime = latestInstanceStartTime; + } + + public List getNode() { + return node; + } + + public void setNode(List node) { + this.node = node; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedulingInfo.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedulingInfo.java new file mode 100644 index 0000000..5e86dd7 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMSchedulingInfo.java @@ -0,0 +1,110 @@ +/* + * Copyright © 2017-2018 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.bean; + +public class CMSchedulingInfo { + private String scheduleId; + private String startTime; + private String endTime; + private int normalDurationInSecs; + private int additionalDurationInSecs; + private int concurrencyLimit; + private String[] policyId; + private CMVnfDetails[] vnfDetails; + + public CMSchedulingInfo() {} + + public String getScheduleId() { + return scheduleId; + } + + public void setScheduleId(String scheduleId) { + this.scheduleId = scheduleId; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public int getNormalDurationInSecs() { + return normalDurationInSecs; + } + + public void setNormalDurationInSecs(int normalDurationInSecs) { + this.normalDurationInSecs = normalDurationInSecs; + } + + public int getAdditionalDurationInSecs() { + return additionalDurationInSecs; + } + + public void setAdditionalDurationInSecs(int additionalDurationInSecs) { + this.additionalDurationInSecs = additionalDurationInSecs; + } + + public int getConcurrencyLimit() { + return concurrencyLimit; + } + + public void setConcurrencyLimit(int concurrencyLimit) { + this.concurrencyLimit = concurrencyLimit; + } + + public String[] getPolicyId() { + return policyId; + } + + public void setPolicyId(String[] policyId) { + this.policyId = policyId; + } + + public CMVnfDetails[] getVnfDetails() { + return vnfDetails; + } + + public void setVnfDetails(CMVnfDetails[] vnfDetails) { + this.vnfDetails = vnfDetails; + } + +} diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMVnfDetails.java b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMVnfDetails.java new file mode 100644 index 0000000..4da1ab1 --- /dev/null +++ b/cmso-service/src/main/java/org/onap/optf/cmso/optimizer/bean/CMVnfDetails.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2017-2018 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.bean; + +public class CMVnfDetails { + private String node; + private String groupId; + + public CMVnfDetails() {} + + public CMVnfDetails(String groupId) { + this.groupId = groupId; + } + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + +} -- cgit 1.2.3-korg