aboutsummaryrefslogtreecommitdiffstats
path: root/vid-app-common/src/main/java/org/onap/vid/job/command
diff options
context:
space:
mode:
Diffstat (limited to 'vid-app-common/src/main/java/org/onap/vid/job/command')
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceCommand.kt122
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceInstantiationCommand.java21
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/BaseInProgressStatusCommand.java95
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/BaseInstantiationCommand.java18
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/BaseRootCommand.java41
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/BaseWatchingCommand.java70
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/CommandBase.java27
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/CommandParentData.java80
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/CommandUtils.java46
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ExpiryChecker.java8
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/HttpCallCommand.java8
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusCommand.java137
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusService.java87
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt59
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupInstantiationCommand.java47
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/JobCommandFactory.java2
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/MacroServiceInstantiationCommand.java26
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/MsoResult.kt9
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/MsoResultHandlerService.kt66
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/NetworkInstantiationCommand.java41
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt324
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInProgressStatusCommand.java32
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInstantiationCommand.java87
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ResourceWithChildrenInProgressCommand.java65
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInProgressStatusCommand.java100
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInstantiationCommand.java146
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleInstantiationCommand.java44
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VnfInProgressStatusCommand.java87
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VnfInstantiationCommand.java50
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInProgressStatusCommand.java65
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInstantiationCommand.java83
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/WatchChildrenJobsBL.kt61
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommand.java33
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommandBaseModule.java93
34 files changed, 2033 insertions, 247 deletions
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceCommand.kt
new file mode 100644
index 000000000..f88e9d65e
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceCommand.kt
@@ -0,0 +1,122 @@
+package org.onap.vid.job.command
+
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate
+import org.onap.vid.changeManagement.RequestDetailsWrapper
+import org.onap.vid.job.*
+import org.onap.vid.model.Action
+import org.onap.vid.model.serviceInstantiation.ServiceInstantiation
+import org.onap.vid.mso.RestMsoImplementation
+import org.onap.vid.mso.model.ServiceDeletionRequestDetails
+import org.onap.vid.properties.VidProperties
+import org.onap.vid.services.AsyncInstantiationBusinessLogic
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.config.ConfigurableBeanFactory
+import org.springframework.context.annotation.Scope
+import org.springframework.http.HttpMethod
+import org.springframework.stereotype.Component
+import java.time.ZonedDateTime
+import java.time.temporal.ChronoUnit
+import java.util.*
+
+class ServiceExpiryChecker : ExpiryChecker {
+
+ override fun isExpired(jobStartTime: ZonedDateTime?): Boolean {
+ val now = ZonedDateTime.now()
+ val maxHoursInProgress = VidProperties.getLongProperty(VidProperties.VID_JOB_MAX_HOURS_IN_PROGRESS)
+ val hoursBetween = ChronoUnit.HOURS.between(jobStartTime, now)
+ return maxHoursInProgress in 1..hoursBetween
+ }
+}
+
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+class ALaCarteServiceCommand @Autowired constructor(
+ inProgressStatusService: InProgressStatusService,
+ watchChildrenJobsBL: WatchChildrenJobsBL,
+ private val asyncInstantiationBL: AsyncInstantiationBusinessLogic,
+ private val jobsBrokerService: JobsBrokerService,
+ msoResultHandlerService: MsoResultHandlerService,
+ private val jobAdapter: JobAdapter,
+ restMso: RestMsoImplementation
+) : ResourceCommand(restMso, inProgressStatusService, msoResultHandlerService, watchChildrenJobsBL), JobCommand {
+
+ override fun getExpiryChecker(): ExpiryChecker {
+ return ServiceExpiryChecker();
+ }
+
+ companion object {
+ private val LOGGER = EELFLoggerDelegate.getLogger(ALaCarteServiceCommand::class.java)
+ }
+
+ override fun getRequest(): ServiceInstantiation {
+ return msoResultHandlerService.getRequest(sharedData)
+ }
+
+ override fun createChildren(): Job.JobStatus {
+ val dataForChild = buildDataForChild(getRequest())//.plus(ACTION_PHASE to actionPhase)
+
+ val childJobType = when (actionPhase) {
+ Action.Create -> JobType.InstanceGroupInstantiation
+ Action.Delete -> JobType.InstanceGroup
+ else -> return Job.JobStatus.COMPLETED
+ }
+
+ childJobs = getRequest().vnfGroups
+ .map { jobAdapter.createChildJob(childJobType, Job.JobStatus.CREATING, it.value, sharedData, dataForChild) }
+ .map { jobsBrokerService.add(it) }
+ .map { it.toString() }
+
+ return Job.JobStatus.COMPLETED_WITH_NO_ACTION
+ }
+
+ private fun buildDataForChild(request: ServiceInstantiation): Map<String, Any> {
+ val commandParentData = CommandParentData()
+ commandParentData.addInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID, request.instanceId)
+ commandParentData.addModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO, request.modelInfo)
+ return commandParentData.parentData
+ }
+
+ override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
+ TODO("not implemented")
+ }
+
+ override fun planDeleteMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
+ val requestDetailsWrapper = generateServiceDeletionRequest()
+ val path = asyncInstantiationBL.getServiceDeletionPath(getRequest().instanceId)
+ return MsoRestCallPlan(HttpMethod.DELETE, path, Optional.of(requestDetailsWrapper), Optional.empty(),
+ "delete instance with id ${getRequest().instanceId}")
+
+ }
+
+ override fun handleInProgressStatus(jobStatus: Job.JobStatus): Job.JobStatus {
+ if (jobStatus==Job.JobStatus.FAILED) {
+ asyncInstantiationBL.handleFailedInstantiation(sharedData.jobUuid)
+ return jobStatus
+ }
+
+ asyncInstantiationBL.updateServiceInfoAndAuditStatus(sharedData.jobUuid, jobStatus)
+ return if (jobStatus == Job.JobStatus.PAUSE) Job.JobStatus.IN_PROGRESS else jobStatus
+ }
+
+
+ private fun generateServiceDeletionRequest(): RequestDetailsWrapper<ServiceDeletionRequestDetails> {
+ return asyncInstantiationBL.generateALaCarteServiceDeletionRequest(
+ sharedData.jobUuid, getRequest(), sharedData.userId
+ )
+ }
+
+ override fun getExternalInProgressStatus() = Job.JobStatus.IN_PROGRESS
+
+ override fun isServiceCommand(): Boolean = true
+
+ override fun onFinal(jobStatus: Job.JobStatus) {
+ asyncInstantiationBL.updateServiceInfoAndAuditStatus(sharedData.jobUuid, jobStatus)
+ }
+
+ override fun onInitial(phase: Action) {
+ if (phase== Action.Delete) {
+ asyncInstantiationBL.updateServiceInfoAndAuditStatus(sharedData.jobUuid, Job.JobStatus.IN_PROGRESS)
+ }
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceInstantiationCommand.java
new file mode 100644
index 000000000..8a1346d2e
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ALaCarteServiceInstantiationCommand.java
@@ -0,0 +1,21 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.JobCommand;
+import org.onap.vid.mso.model.ServiceInstantiationRequestDetails;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ALaCarteServiceInstantiationCommand extends ServiceInstantiationCommand implements JobCommand {
+
+ @Override
+ protected RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateServiceInstantiationRequest() {
+ return asyncInstantiationBL.generateALaCarteServiceInstantiationRequest(
+ getSharedData().getJobUuid(), getRequest(), optimisticUniqueServiceInstanceName, getSharedData().getUserId()
+ );
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/BaseInProgressStatusCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseInProgressStatusCommand.java
new file mode 100644
index 000000000..a035708f2
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseInProgressStatusCommand.java
@@ -0,0 +1,95 @@
+package org.onap.vid.job.command;
+
+import com.google.common.collect.ImmutableMap;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.job.*;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.mso.RestMsoImplementation;
+import org.onap.vid.mso.RestObject;
+import org.onap.vid.mso.rest.AsyncRequestStatus;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.togglz.core.manager.FeatureManager;
+
+import javax.inject.Inject;
+import java.util.Map;
+
+public abstract class BaseInProgressStatusCommand extends BaseInstantiationCommand implements JobCommand {
+ private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(BaseInProgressStatusCommand.class);
+
+ @Inject
+ protected AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Inject
+ protected JobsBrokerService jobsBrokerService;
+
+ @Inject
+ protected JobAdapter jobAdapter;
+
+ @Inject
+ protected RestMsoImplementation restMso;
+
+ @Inject
+ protected FeatureManager featureManager;
+
+ @Inject
+ protected InProgressStatusService inProgressStatusService;
+
+
+ protected String requestId;
+
+ protected String instanceId;
+
+
+ @Override
+ public NextCommand call() {
+
+ try {
+ Job.JobStatus jobStatus = inProgressStatusService.call(getExpiryChecker(), getSharedData(), requestId);
+ return processJobStatus(jobStatus);
+ } catch (javax.ws.rs.ProcessingException e) {
+ // Retry when we can't connect MSO during getStatus
+ LOGGER.error(EELFLoggerDelegate.errorLogger, "Cannot get orchestration status for {}, will retry: {}", requestId, e, e);
+ return new NextCommand(Job.JobStatus.IN_PROGRESS, this);
+ } catch (InProgressStatusService.BadResponseFromMso e) {
+ return handleFailedMsoResponse(e.getMsoResponse());
+ }
+ catch (RuntimeException e) {
+ LOGGER.error(EELFLoggerDelegate.errorLogger, "Cannot get orchestration status for {}, stopping: {}", requestId, e, e);
+ return new NextCommand(Job.JobStatus.STOPPED, this);
+ }
+ }
+
+ protected abstract ExpiryChecker getExpiryChecker();
+
+ abstract NextCommand processJobStatus(Job.JobStatus jobStatus);
+
+ private NextCommand handleFailedMsoResponse(RestObject<AsyncRequestStatus> msoResponse) {
+ inProgressStatusService.handleFailedMsoResponse(getSharedData().getJobUuid(), requestId, msoResponse);
+ return new NextCommand(Job.JobStatus.IN_PROGRESS, this);
+ }
+
+ @Override
+ public BaseInProgressStatusCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
+ return init(sharedData, (String) commandData.get("requestId"), (String) commandData.get("instanceId"));
+ }
+
+
+ protected BaseInProgressStatusCommand init(JobSharedData sharedData,
+ String requestId,
+ String instanceId) {
+ init(sharedData);
+ this.requestId = requestId;
+ this.instanceId = instanceId;
+ return this;
+ }
+
+ @Override
+ public Map<String, Object> getData() {
+ return ImmutableMap.of(
+ "requestId", requestId,
+ "instanceId", instanceId
+ );
+ }
+
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/BaseInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseInstantiationCommand.java
new file mode 100644
index 000000000..6f78eafab
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseInstantiationCommand.java
@@ -0,0 +1,18 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.impl.JobSharedData;
+
+import java.util.Map;
+
+
+public abstract class BaseInstantiationCommand extends CommandBase{
+
+
+ protected CommandParentData commandParentData = new CommandParentData();
+
+ protected BaseInstantiationCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
+ super.init(sharedData);
+ commandParentData.initParentData(commandData);
+ return this;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/BaseRootCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseRootCommand.java
new file mode 100644
index 000000000..4930c94c3
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseRootCommand.java
@@ -0,0 +1,41 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.RequestReferencesContainer;
+import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
+import org.onap.vid.mso.RestObject;
+
+import javax.inject.Inject;
+
+
+public abstract class BaseRootCommand extends CommandBase{
+
+ @Inject
+ private MsoResultHandlerService msoResultHandlerService;
+
+ @Override
+ protected CommandBase init(JobSharedData sharedData) {
+ super.init(sharedData);
+ return this;
+ }
+
+ protected ServiceInstantiation getRequest() {
+ return msoResultHandlerService.getRequest(getSharedData());
+ }
+
+ protected NextCommand handleRootResponse(RestObject<RequestReferencesContainer> msoResponse){
+ MsoResult msoResult = msoResultHandlerService.handleRootResponse(getSharedData().getJobUuid(), msoResponse);
+ return new NextCommand(msoResult.getJobStatus(),
+ (msoResult.getMsoResourceIds()!=null) ?
+ new ServiceInProgressStatusCommand(getSharedData(), msoResult.getMsoResourceIds()) :
+ null
+ );
+
+ }
+
+ protected NextCommand handleCommandFailed() {
+ return new NextCommand(msoResultHandlerService.handleRootCommandFailed(getSharedData().getJobUuid()).getJobStatus());
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/BaseWatchingCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseWatchingCommand.java
new file mode 100644
index 000000000..b619eddfd
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/BaseWatchingCommand.java
@@ -0,0 +1,70 @@
+package org.onap.vid.job.command;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.job.Job;
+import org.onap.vid.job.JobCommand;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class BaseWatchingCommand extends BaseInstantiationCommand implements JobCommand {
+
+ private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(BaseWatchingCommand.class);
+
+ @Inject
+ protected AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Inject
+ private WatchChildrenJobsBL watchChildrenJobsBL;
+
+ private List<String> childrenJobsIds;
+
+ protected boolean isService;
+
+ public BaseWatchingCommand() {}
+
+ public BaseWatchingCommand(JobSharedData sharedData, List<String> childrenJobsIds, boolean isService) {
+ init(sharedData, childrenJobsIds, isService);
+ }
+
+ @Override
+ public NextCommand call() {
+ Job.JobStatus cumulativeJobsStatus = watchChildrenJobsBL.cumulateJobStatus(
+ watchChildrenJobsBL.retrieveChildrenJobsStatus(childrenJobsIds),
+ Job.JobStatus.COMPLETED);
+ return getNextCommand(cumulativeJobsStatus);
+ }
+
+ protected abstract NextCommand getNextCommand(Job.JobStatus cumulativeJobsStatus);
+
+ @Override
+ public BaseWatchingCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
+ return init(
+ sharedData,
+ (List<String>) commandData.get("childrenJobs"),
+ (boolean) commandData.get("isService")
+ );
+ }
+
+ protected BaseWatchingCommand init(JobSharedData sharedData, List<String> childrenJobsIds, boolean isService) {
+ super.init(sharedData);
+ this.childrenJobsIds = ObjectUtils.defaultIfNull(childrenJobsIds, new ArrayList<>());
+ this.isService = isService;
+ return this;
+ }
+
+ @Override
+ public Map<String, Object> getData() {
+ Map<String, Object> data = new HashMap<>();
+ data.put("childrenJobs", childrenJobsIds);
+ data.put("isService", isService);
+ return data;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/CommandBase.java b/vid-app-common/src/main/java/org/onap/vid/job/command/CommandBase.java
new file mode 100644
index 000000000..163106c09
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/CommandBase.java
@@ -0,0 +1,27 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.impl.JobSharedData;
+
+import javax.inject.Inject;
+
+
+public abstract class CommandBase {
+
+ @Inject
+ protected CommandUtils commandUtils;
+
+ private JobSharedData sharedData;
+
+ protected CommandBase init(JobSharedData sharedData) {
+ this.setSharedData(sharedData);
+ return this;
+ }
+
+ public JobSharedData getSharedData() {
+ return sharedData;
+ }
+
+ private void setSharedData(JobSharedData sharedData) {
+ this.sharedData = sharedData;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/CommandParentData.java b/vid-app-common/src/main/java/org/onap/vid/job/command/CommandParentData.java
new file mode 100644
index 000000000..25c197278
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/CommandParentData.java
@@ -0,0 +1,80 @@
+package org.onap.vid.job.command;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onap.vid.mso.model.ModelInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CommandParentData {
+
+
+ public enum CommandDataKey{
+ SERVICE_MODEL_INFO,
+ SERVICE_INSTANCE_ID,
+ VNF_INSTANCE_ID,
+ VNF_MODEL_INFO,
+ VG_INSTANCE_ID,
+ ;
+ }
+
+ private static final String RESOURCE_INSTANCE_IDS = "resourceInstancesIds";
+ private static final String RESOURCE_MODEL_INFOS = "resourceModelInfos";
+
+ private final TypeReference<Map<CommandDataKey, String>> mapCommandKeyToString =
+ new TypeReference<Map<CommandDataKey, String>> () {};
+
+ private final TypeReference<Map<CommandDataKey, ModelInfo>> mapCommandKeyToModelInfo =
+ new TypeReference<Map<CommandDataKey, ModelInfo>> () {};
+
+
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ private Map<CommandDataKey,ModelInfo> getModelInfosByCommandData(Map<String, Object> commandData) {
+ Object object = commandData.get(RESOURCE_MODEL_INFOS);
+ if (object != null) {
+ return objectMapper.convertValue(object, mapCommandKeyToModelInfo);
+ }
+ return null;
+ }
+
+ private Map<CommandDataKey,String> getInstanceIdsByCommandData(Map<String, Object> commandData) {
+ Object object = commandData.get(RESOURCE_INSTANCE_IDS);
+ if (object != null) {
+ return objectMapper.convertValue(object, mapCommandKeyToString);
+ }
+ return null;
+ }
+
+ public Map<String, Object> getParentData() {
+ Map<String, Object> data = new HashMap<>();
+ data.put(RESOURCE_INSTANCE_IDS, resourceInstancesIds);
+ data.put(RESOURCE_MODEL_INFOS, resourceModelInfos);
+ return data;
+ }
+ private Map<CommandDataKey, String> resourceInstancesIds = new HashMap<>();
+ private Map<CommandDataKey, ModelInfo> resourceModelInfos = new HashMap<>();
+
+ public void addModelInfo(CommandDataKey modelInfoKey, ModelInfo modelInfo) {
+ resourceModelInfos.put(modelInfoKey, modelInfo);
+ }
+
+ public void addInstanceId(CommandDataKey instanceIdKey, String instanceId) {
+ resourceInstancesIds.put(instanceIdKey, instanceId);
+ }
+ public ModelInfo getModelInfo(CommandDataKey modelInfoKey) {
+ return resourceModelInfos.get(modelInfoKey);
+ }
+
+ public String getInstanceId(CommandDataKey instanceIdKey) {
+ return resourceInstancesIds.get(instanceIdKey);
+ }
+
+ public CommandParentData initParentData(Map<String, Object> commandData) {
+ resourceModelInfos = getModelInfosByCommandData(commandData);
+ resourceInstancesIds = getInstanceIdsByCommandData(commandData);
+ return this;
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/CommandUtils.java b/vid-app-common/src/main/java/org/onap/vid/job/command/CommandUtils.java
new file mode 100644
index 000000000..497eafda9
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/CommandUtils.java
@@ -0,0 +1,46 @@
+package org.onap.vid.job.command;
+
+import org.apache.commons.lang3.StringUtils;
+import org.onap.vid.asdc.AsdcCatalogException;
+import org.onap.vid.model.ServiceModel;
+import org.onap.vid.services.VidService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CommandUtils {
+
+ private final VidService vidService;
+
+ @Autowired
+ public CommandUtils(VidService vidService) {
+ this.vidService = vidService;
+ }
+
+ public boolean isVfModuleBaseModule(String serviceModelUuid, String vfModuleModelUUID) throws AsdcCatalogException{
+ ServiceModel serviceModel = vidService.getService(serviceModelUuid);
+
+ if (serviceModel==null) {
+ throw new AsdcCatalogException("Failed to retrieve model with uuid "+serviceModelUuid +" from SDC");
+ }
+
+ if (serviceModel.getVfModules() == null) {
+ throw createAsdcCatalogVfModuleModelUUIDNotFoundException(serviceModelUuid, vfModuleModelUUID);
+ }
+
+ return serviceModel.getVfModules()
+ .values()
+ .stream()
+ .filter(vfModule -> StringUtils.equals(vfModule.getUuid(), vfModuleModelUUID))
+ .findFirst()
+ .orElseThrow(() -> createAsdcCatalogVfModuleModelUUIDNotFoundException(serviceModelUuid, vfModuleModelUUID))
+ .getProperties()
+ .getBaseModule();
+ }
+
+ private AsdcCatalogException createAsdcCatalogVfModuleModelUUIDNotFoundException(String serviceModelUuid, String vfModuleModelUUID) {
+ return new AsdcCatalogException("Failed to find vfModuleModelUUID: " + vfModuleModelUUID +
+ "in model with uuid: " + serviceModelUuid);
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ExpiryChecker.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ExpiryChecker.java
new file mode 100644
index 000000000..1ae5d2185
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ExpiryChecker.java
@@ -0,0 +1,8 @@
+package org.onap.vid.job.command;
+
+import java.time.ZonedDateTime;
+
+public interface ExpiryChecker {
+
+ boolean isExpired(ZonedDateTime jobStartTime);
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/HttpCallCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/HttpCallCommand.java
index 5951d7c83..7ee48a8e1 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/HttpCallCommand.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/HttpCallCommand.java
@@ -4,13 +4,13 @@ import com.google.common.collect.ImmutableMap;
import org.onap.vid.job.Job;
import org.onap.vid.job.JobCommand;
import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Response;
import java.util.Map;
import java.util.UUID;
@@ -30,13 +30,13 @@ public class HttpCallCommand implements JobCommand {
@Override
public NextCommand call() {
- final Response response = ClientBuilder.newClient().target(url).request().post(Entity.text(uuid.toString()));
+ ClientBuilder.newClient().target(url).request().post(Entity.text(uuid.toString()));
return new NextCommand(Job.JobStatus.COMPLETED);
}
@Override
- public HttpCallCommand init(UUID jobUuid, Map<String, Object> data) {
- return init((String) data.get("url"), jobUuid);
+ public HttpCallCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
+ return init((String) commandData.get("url"), sharedData.getJobUuid());
}
private HttpCallCommand init(String url, UUID jobUuid) {
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusCommand.java
deleted file mode 100644
index 6685a63d6..000000000
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusCommand.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * VID
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2018 Nokia. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-package org.onap.vid.job.command;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.ImmutableMap;
-import io.joshworks.restclient.http.HttpResponse;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.onap.vid.job.Job.JobStatus;
-import org.onap.vid.job.JobCommand;
-import org.onap.vid.job.NextCommand;
-import org.onap.vid.mso.MsoInterface;
-import org.onap.vid.mso.rest.AsyncRequestStatus;
-import org.onap.vid.services.AsyncInstantiationBusinessLogic;
-import org.onap.vid.services.AuditService;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-import org.springframework.stereotype.Component;
-
-import javax.inject.Inject;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-
-
-@Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class InProgressStatusCommand implements JobCommand {
-
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
-
- private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(InProgressStatusCommand.class);
-
- @Inject
- private AsyncInstantiationBusinessLogic asyncInstantiationBL;
-
- @Inject
- private MsoInterface restMso;
-
- @Inject
- private AuditService auditService;
-
- private String requestId;
-
- private UUID jobUuid;
-
- public InProgressStatusCommand() {
- }
-
- InProgressStatusCommand(UUID jobUuid, String requestId) {
- init(jobUuid, requestId);
- }
-
- InProgressStatusCommand(AsyncInstantiationBusinessLogic asyncInstantiationBusinessLogic, MsoInterface msoInterface, AuditService auditService, UUID jobUuid, String requestId) {
- this(jobUuid, requestId);
- this.asyncInstantiationBL = asyncInstantiationBusinessLogic;
- this.restMso = msoInterface;
- this.auditService = auditService;
- }
-
- @Override
- public NextCommand call() {
-
- try {
- String path = asyncInstantiationBL.getOrchestrationRequestsPath() + "/" + requestId;
- HttpResponse<AsyncRequestStatus> msoResponse = restMso.get(path, AsyncRequestStatus.class);
-
-
- JobStatus jobStatus;
- if (msoResponse.getStatus() >= 400 || msoResponse.getBody() == null) {
- auditService.setFailedAuditStatusFromMso(jobUuid, requestId, msoResponse.getStatus(), Objects.toString(msoResponse.getBody()));
- LOGGER.error(EELFLoggerDelegate.errorLogger,
- "Failed to get orchestration status for {}. Status code: {}, Body: {}",
- requestId, msoResponse.getStatus(), Objects.toString(msoResponse.getRawBody()));
- return new NextCommand(JobStatus.IN_PROGRESS, this);
- } else {
- jobStatus = asyncInstantiationBL.calcStatus(msoResponse.getBody());
- }
-
- asyncInstantiationBL.auditMsoStatus(jobUuid, msoResponse.getBody().request);
-
-
- if (jobStatus == JobStatus.FAILED) {
- asyncInstantiationBL.handleFailedInstantiation(jobUuid);
- } else {
- asyncInstantiationBL.updateServiceInfoAndAuditStatus(jobUuid, jobStatus);
- }
- //in case of JobStatus.PAUSE we leave the job itself as IN_PROGRESS, for keep tracking job progress
- if (jobStatus == JobStatus.PAUSE) {
- return new NextCommand(JobStatus.IN_PROGRESS, this);
- }
- return new NextCommand(jobStatus, this);
- } catch (javax.ws.rs.ProcessingException e) {
- // Retry when we can't connect MSO during getStatus
- LOGGER.error(EELFLoggerDelegate.errorLogger, "Cannot get orchestration status for {}, will retry: {}", requestId, e, e);
- return new NextCommand(JobStatus.IN_PROGRESS, this);
- } catch (RuntimeException e) {
- LOGGER.error(EELFLoggerDelegate.errorLogger, "Cannot get orchestration status for {}, stopping: {}", requestId, e, e);
- return new NextCommand(JobStatus.STOPPED, this);
- }
- }
-
- @Override
- public InProgressStatusCommand init(UUID jobUuid, Map<String, Object> data) {
- return init(jobUuid, (String) data.get("requestId"));
- }
-
- private InProgressStatusCommand init(UUID jobUuid, String requestId) {
- this.requestId = requestId;
- this.jobUuid = jobUuid;
- return this;
- }
-
- @Override
- public Map<String, Object> getData() {
- return ImmutableMap.of("requestId", requestId);
- }
-
-}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusService.java b/vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusService.java
new file mode 100644
index 000000000..4799f0087
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/InProgressStatusService.java
@@ -0,0 +1,87 @@
+package org.onap.vid.job.command;
+
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.job.Job;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.mso.RestMsoImplementation;
+import org.onap.vid.mso.RestObject;
+import org.onap.vid.mso.rest.AsyncRequestStatus;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.onap.vid.services.AuditService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeParseException;
+import java.util.UUID;
+
+import static org.onap.vid.utils.TimeUtils.parseZonedDateTime;
+
+@Service
+public class InProgressStatusService {
+
+ private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(InProgressStatusService.class);
+
+ private final AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ private final RestMsoImplementation restMso;
+
+ private final AuditService auditService;
+
+ @Autowired
+ public InProgressStatusService(AsyncInstantiationBusinessLogic asyncInstantiationBL, RestMsoImplementation restMso, AuditService auditService) {
+ this.asyncInstantiationBL = asyncInstantiationBL;
+ this.restMso = restMso;
+ this.auditService = auditService;
+ }
+
+
+ public Job.JobStatus call(ExpiryChecker expiryChecker, JobSharedData sharedData, String requestId) {
+
+ RestObject<AsyncRequestStatus> asyncRequestStatus = getAsyncRequestStatus(requestId);
+ asyncInstantiationBL.auditMsoStatus(sharedData.getRootJobId(), asyncRequestStatus.get().request);
+ Job.JobStatus jobStatus = asyncInstantiationBL.calcStatus(asyncRequestStatus.get());
+ ZonedDateTime jobStartTime = getZonedDateTime(asyncRequestStatus, requestId);
+ jobStatus = expiryChecker.isExpired(jobStartTime) ? Job.JobStatus.FAILED : jobStatus;
+ return jobStatus;
+ }
+
+ private RestObject<AsyncRequestStatus> getAsyncRequestStatus(String requestId) {
+ String path = asyncInstantiationBL.getOrchestrationRequestsPath()+"/"+requestId;
+ RestObject<AsyncRequestStatus> msoResponse = restMso.GetForObject(path, AsyncRequestStatus.class);
+ if (msoResponse.getStatusCode() >= 400 || msoResponse.get() == null) {
+ throw new BadResponseFromMso(msoResponse);
+ }
+ return msoResponse;
+ }
+
+ public void handleFailedMsoResponse(UUID jobUUID, String requestId, RestObject<AsyncRequestStatus> msoResponse) {
+ auditService.setFailedAuditStatusFromMso(jobUUID, requestId, msoResponse.getStatusCode(), msoResponse.getRaw());
+ LOGGER.error(EELFLoggerDelegate.errorLogger,
+ "Failed to get orchestration status for {}. Status code: {}, Body: {}",
+ requestId, msoResponse.getStatusCode(), msoResponse.getRaw());
+ }
+
+ public static class BadResponseFromMso extends RuntimeException {
+ private final RestObject<AsyncRequestStatus> msoResponse;
+
+ public BadResponseFromMso(RestObject<AsyncRequestStatus> msoResponse) {
+ this.msoResponse = msoResponse;
+ }
+
+ public RestObject<AsyncRequestStatus> getMsoResponse() {
+ return msoResponse;
+ }
+ }
+
+ private ZonedDateTime getZonedDateTime(RestObject<AsyncRequestStatus> asyncRequestStatusResponse, String requestId) {
+ ZonedDateTime jobStartTime;
+ try {
+ jobStartTime = parseZonedDateTime(asyncRequestStatusResponse.get().request.startTime);
+ } catch (DateTimeParseException | NullPointerException e) {
+ LOGGER.error(EELFLoggerDelegate.errorLogger, "Failed to parse start time for {}, body: {}. Current time will be used", requestId, asyncRequestStatusResponse.getRaw(), e);
+ jobStartTime = ZonedDateTime.now();
+ }
+ return jobStartTime;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt
new file mode 100644
index 000000000..36da5084b
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt
@@ -0,0 +1,59 @@
+package org.onap.vid.job.command
+
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate
+import org.onap.vid.job.Job
+import org.onap.vid.job.JobAdapter
+import org.onap.vid.job.JobCommand
+import org.onap.vid.model.serviceInstantiation.InstanceGroup
+import org.onap.vid.mso.RestMsoImplementation
+import org.onap.vid.services.AsyncInstantiationBusinessLogic
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.config.ConfigurableBeanFactory
+import org.springframework.context.annotation.Scope
+import org.springframework.http.HttpMethod
+import org.springframework.stereotype.Component
+import java.util.*
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+class InstanceGroupCommand @Autowired constructor(
+ private val asyncInstantiationBL: AsyncInstantiationBusinessLogic,
+ restMso: RestMsoImplementation,
+ msoResultHandlerService: MsoResultHandlerService,
+ inProgressStatusService:InProgressStatusService,
+ watchChildrenJobsBL: WatchChildrenJobsBL
+) : ResourceCommand(restMso, inProgressStatusService, msoResultHandlerService, watchChildrenJobsBL), JobCommand {
+
+ companion object {
+ private val LOGGER = EELFLoggerDelegate.getLogger(InstanceGroupCommand::class.java)
+ }
+
+ override fun createChildren(): Job.JobStatus {
+ return Job.JobStatus.COMPLETED_WITH_NO_ACTION
+ }
+
+ override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
+ val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
+ val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
+
+ val instantiatePath = asyncInstantiationBL.getInstanceGroupInstantiationPath()
+
+ val requestDetailsWrapper = asyncInstantiationBL.generateInstanceGroupInstantiationRequest(
+ request as InstanceGroup,
+ serviceModelInfo, serviceInstanceId,
+ userId
+ )
+
+ val actionDescription = "create instance group in $serviceInstanceId"
+
+ return MsoRestCallPlan(HttpMethod.POST, instantiatePath, Optional.of(requestDetailsWrapper), Optional.empty(), actionDescription)
+ }
+
+ override fun planDeleteMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
+ val path = asyncInstantiationBL.getInstanceGroupDeletePath(getRequest().instanceId)
+ return MsoRestCallPlan(HttpMethod.DELETE, path, Optional.empty(), Optional.of(userId),
+ "delete instance group with id ${getRequest().instanceId}")
+
+ }
+
+} \ No newline at end of file
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupInstantiationCommand.java
new file mode 100644
index 000000000..17b3f3552
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupInstantiationCommand.java
@@ -0,0 +1,47 @@
+package org.onap.vid.job.command;//package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.JobAdapter;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.model.Action;
+import org.onap.vid.model.serviceInstantiation.InstanceGroup;
+import org.onap.vid.mso.model.InstanceGroupInstantiationRequestDetails;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class InstanceGroupInstantiationCommand extends ResourceInstantiationCommand {
+
+ @Inject
+ private AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Override
+ protected String getRequestPath() {
+ return asyncInstantiationBL.getInstanceGroupInstantiationPath();
+ }
+
+ @Override
+ protected RequestDetailsWrapper<InstanceGroupInstantiationRequestDetails> generateMSORequest(JobAdapter.AsyncJobRequest request, String userId) {
+ return asyncInstantiationBL.generateInstanceGroupInstantiationRequest(
+ (InstanceGroup) getSharedData().getRequest(),
+ commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),
+ getSharedData().getUserId()
+ );
+ }
+
+ @Override
+ protected String getJobAuditMSOStatus() {
+ return "INSTANCE_GROUP_REQUESTED";
+ }
+
+ @Override
+ protected boolean shouldInstantiateMyself() {
+ return Action.Create == ((InstanceGroup) getSharedData().getRequest()).getAction();
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/JobCommandFactory.java b/vid-app-common/src/main/java/org/onap/vid/job/command/JobCommandFactory.java
index 1e613c58b..5661663b2 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/JobCommandFactory.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/JobCommandFactory.java
@@ -34,7 +34,7 @@ public class JobCommandFactory {
public JobCommand toCommand(Job job) {
final JobCommand command = jobFactory.apply(job.getType().getCommandClass());
- command.init(job.getUuid(), job.getData());
+ command.init(job.getSharedData(), job.getData());
return command;
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/MacroServiceInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/MacroServiceInstantiationCommand.java
new file mode 100644
index 000000000..e03f9b8d7
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/MacroServiceInstantiationCommand.java
@@ -0,0 +1,26 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.JobCommand;
+import org.onap.vid.mso.model.ServiceInstantiationRequestDetails;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class MacroServiceInstantiationCommand extends ServiceInstantiationCommand implements JobCommand {
+
+ public MacroServiceInstantiationCommand() {
+ // empty constructor
+ }
+
+ @Override
+ protected RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateServiceInstantiationRequest() {
+ return asyncInstantiationBL.generateMacroServiceInstantiationRequest(
+ getSharedData().getJobUuid(), getRequest(), optimisticUniqueServiceInstanceName, getSharedData().getUserId()
+ );
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/MsoResult.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/MsoResult.kt
new file mode 100644
index 000000000..95f520f80
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/MsoResult.kt
@@ -0,0 +1,9 @@
+package org.onap.vid.job.command
+
+import org.onap.vid.job.Job
+
+data class MsoResourceIds (val requestId:String, val instanceId:String)
+
+val EMPTY_MSO_RESOURCE_ID = MsoResourceIds("","")
+
+data class MsoResult @JvmOverloads constructor(val jobStatus: Job.JobStatus, val msoResourceIds: MsoResourceIds = EMPTY_MSO_RESOURCE_ID)
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/MsoResultHandlerService.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/MsoResultHandlerService.kt
new file mode 100644
index 000000000..9760f667f
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/MsoResultHandlerService.kt
@@ -0,0 +1,66 @@
+package org.onap.vid.job.command
+
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate
+import org.onap.vid.job.Job
+import org.onap.vid.job.impl.JobSharedData
+import org.onap.vid.model.RequestReferencesContainer
+import org.onap.vid.model.serviceInstantiation.ServiceInstantiation
+import org.onap.vid.mso.RestObject
+import org.onap.vid.services.AsyncInstantiationBusinessLogic
+import org.onap.vid.services.AuditService
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+import java.util.*
+
+@Service
+class MsoResultHandlerService
+@Autowired constructor(private val asyncInstantiationBL: AsyncInstantiationBusinessLogic, private val auditService: AuditService) {
+
+ companion object {
+ private val LOGGER = EELFLoggerDelegate.getLogger(MsoResultHandlerService::class.java)
+ }
+
+ fun getRequest(jobSharedData: JobSharedData): ServiceInstantiation {
+ return jobSharedData.request as ServiceInstantiation
+ }
+
+ fun handleRootResponse(jobUUID: UUID, msoResponse: RestObject<RequestReferencesContainer>): MsoResult {
+ return if (msoResponse.statusCode in 200..399) {
+ val jobStatus = Job.JobStatus.IN_PROGRESS
+ val msoResourceIds = MsoResourceIds(msoResponse.get().requestReferences.requestId, msoResponse.get().requestReferences.instanceId)
+ asyncInstantiationBL.auditVidStatus(jobUUID, jobStatus)
+ setInitialRequestAuditStatusFromMso(jobUUID, msoResourceIds.requestId)
+ asyncInstantiationBL.updateServiceInfo(jobUUID) { x ->
+ x.jobStatus = jobStatus
+ x.serviceInstanceId = msoResourceIds.instanceId
+ x.msoRequestId = UUID.fromString(msoResourceIds.requestId)
+ }
+ MsoResult(jobStatus, msoResourceIds)
+ } else {
+ auditService.setFailedAuditStatusFromMso(jobUUID, null, msoResponse.statusCode, msoResponse.raw)
+ handleRootCommandFailed(jobUUID)
+ }
+ }
+
+ fun handleResponse(msoResponse: RestObject<RequestReferencesContainer>, actionDescription: String): MsoResult {
+ return if (msoResponse.statusCode in 200..399) {
+ val msoResourceIds = MsoResourceIds(msoResponse.get().requestReferences.requestId, msoResponse.get().requestReferences.instanceId)
+ LOGGER.debug("Successfully sent $actionDescription. Request id: ${msoResourceIds.requestId}")
+ MsoResult(Job.JobStatus.COMPLETED_WITH_NO_ACTION, msoResourceIds)
+ } else {
+ LOGGER.debug("Failed to $actionDescription. Details: ${msoResponse.raw}")
+ MsoResult(Job.JobStatus.FAILED)
+ }
+ }
+
+
+ fun handleRootCommandFailed(jobUUID: UUID): MsoResult {
+ asyncInstantiationBL.handleFailedInstantiation(jobUUID)
+ return MsoResult(Job.JobStatus.FAILED)
+ }
+
+ private fun setInitialRequestAuditStatusFromMso(jobUUID: UUID, requestId: String) {
+ val initialMsoRequestStatus = "REQUESTED"
+ asyncInstantiationBL.auditMsoStatus(jobUUID, initialMsoRequestStatus, requestId, null)
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkInstantiationCommand.java
new file mode 100644
index 000000000..401bab723
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkInstantiationCommand.java
@@ -0,0 +1,41 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.JobAdapter;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.model.serviceInstantiation.Network;
+import org.onap.vid.mso.model.NetworkInstantiationRequestDetails;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class NetworkInstantiationCommand extends ResourceInstantiationCommand {
+
+ @Inject
+ private AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Override
+ protected String getRequestPath() {
+ return asyncInstantiationBL.getNetworkInstantiationPath(commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID));
+ }
+
+ @Override
+ protected RequestDetailsWrapper<NetworkInstantiationRequestDetails> generateMSORequest(JobAdapter.AsyncJobRequest request, String userId) {
+ return asyncInstantiationBL.generateNetworkInstantiationRequest(
+ (Network) getSharedData().getRequest(),
+ commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),
+ getSharedData().getUserId()
+ );
+ }
+
+ @Override
+ protected String getJobAuditMSOStatus() {
+ return "NETWORK_REQUESTED";
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt
new file mode 100644
index 000000000..6dfcbdf3a
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt
@@ -0,0 +1,324 @@
+package org.onap.vid.job.command
+
+import com.fasterxml.jackson.module.kotlin.convertValue
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate
+import org.onap.vid.changeManagement.RequestDetailsWrapper
+import org.onap.vid.job.Job
+import org.onap.vid.job.Job.JobStatus
+import org.onap.vid.job.JobAdapter
+import org.onap.vid.job.JobCommand
+import org.onap.vid.job.NextCommand
+import org.onap.vid.job.impl.JobSharedData
+import org.onap.vid.model.Action
+import org.onap.vid.model.RequestReferencesContainer
+import org.onap.vid.model.serviceInstantiation.BaseResource
+import org.onap.vid.mso.RestMsoImplementation
+import org.onap.vid.utils.JACKSON_OBJECT_MAPPER
+import org.onap.vid.utils.getEnumFromMapOfStrings
+import org.springframework.http.HttpMethod
+import java.util.*
+
+const val INTERNAL_STATE = "internalState"
+const val ACTION_PHASE = "actionPhase"
+const val CHILD_JOBS = "childJobs"
+const val MSO_RESOURCE_ID = "msoResourceIds"
+const val CUMULATIVE_STATUS = "cumulativeStatus"
+
+enum class InternalState constructor(val immediate:Boolean=false) {
+ INITIAL,
+ CREATING_CHILDREN(true),
+ WATCHING,
+ DELETE_MYSELF,
+ CREATE_MYSELF,
+ IN_PROGRESS,
+ TERMINAL
+}
+
+data class NextInternalState(val nextActionPhase: Action, val nextInternalState: InternalState)
+
+
+data class MsoRestCallPlan(
+ val httpMethod: HttpMethod,
+ val path: String,
+ val payload: Optional<RequestDetailsWrapper<out Any>>,
+ val userId: Optional<String>,
+ val actionDescription: String
+)
+
+abstract class ResourceCommand(
+ protected val restMso: RestMsoImplementation,
+ protected val inProgressStatusService: InProgressStatusService,
+ protected val msoResultHandlerService: MsoResultHandlerService,
+ protected val watchChildrenJobsBL: WatchChildrenJobsBL
+) : CommandBase(), JobCommand {
+
+ companion object {
+ private val Logger = EELFLoggerDelegate.getLogger(ResourceCommand::class.java)
+ }
+
+ abstract fun createChildren():JobStatus
+
+ abstract fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan
+
+ abstract fun planDeleteMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan
+
+ private val commandByInternalState: Map<InternalState, () -> JobStatus> = hashMapOf(
+ Pair(InternalState.CREATING_CHILDREN, ::createChildren),
+ Pair(InternalState.WATCHING, ::watchChildren),
+ Pair(InternalState.CREATE_MYSELF, ::createMyself),
+ Pair(InternalState.DELETE_MYSELF, ::deleteMyself),
+ Pair(InternalState.IN_PROGRESS, ::inProgress)
+ )
+
+ private lateinit var internalState:InternalState
+ protected lateinit var actionPhase: Action
+ private var commandParentData: CommandParentData = CommandParentData()
+ private var msoResourceIds: MsoResourceIds = EMPTY_MSO_RESOURCE_ID
+ protected var childJobs:List<String> = emptyList()
+ private lateinit var cumulativeStatus:JobStatus
+
+
+ override fun call(): NextCommand {
+ var jobStatus:JobStatus = invokeCommand()
+ jobStatus = comulateStatusAndUpdatePropertyIfFinal(jobStatus)
+
+ Logger.debug("command for job ${sharedData.jobUuid} invoked and finished with jobStatus $jobStatus")
+ if (shallStopJob(jobStatus)) {
+ onFinal(jobStatus)
+ return NextCommand(jobStatus)
+ }
+
+ val (nextActionPhase, nextInternalState) = calcNextInternalState(jobStatus, internalState, actionPhase)
+ Logger.debug("next state for job ${sharedData.jobUuid} is $nextInternalState")
+ actionPhase = nextActionPhase
+ internalState = nextInternalState
+
+ if (internalState==InternalState.TERMINAL) {
+ onFinal(jobStatus)
+ return NextCommand(jobStatus)
+ }
+
+ jobStatus = getExternalInProgressStatus()
+ Logger.debug("next status for job ${sharedData.jobUuid} is $jobStatus")
+// if (internalState.immediate) return call() //shortcut instead of execute another command
+ return NextCommand(jobStatus, this)
+ }
+
+ //we want to stop in faliures, except for service witn no action, since service with no action trigger 2 phases (delete and create)
+ protected fun shallStopJob(jobStatus: JobStatus) =
+ jobStatus.isFailure && !(isServiceCommand() && getActionType()==Action.None)
+
+ //this method is used to expose the job status after successful completion of current state
+ //should be override by subclass (like ServiceCommand) that need to return other default job status
+ protected open fun getExternalInProgressStatus() = JobStatus.RESOURCE_IN_PROGRESS
+
+ private fun invokeCommand(): JobStatus {
+ return commandByInternalState.getOrDefault (internalState, ::throwIllegalState).invoke()
+ }
+
+ private fun throwIllegalState():JobStatus {
+ throw IllegalStateException("can't find action for pashe $actionPhase and state $internalState")
+ }
+
+ private fun calcNextInternalState(jobStatus: JobStatus, internalState: InternalState, actionPhase: Action): NextInternalState {
+
+ val nextInternalState = when (actionPhase) {
+ Action.Delete -> calcNextStateDeletePhase(jobStatus, internalState)
+ Action.Create -> calcNextStateCreatePhase(jobStatus, internalState)
+ else -> InternalState.TERMINAL
+ }
+
+ if (nextInternalState == InternalState.TERMINAL
+ && actionPhase == Action.Delete
+ && isServiceCommand()) {
+ // Loop over to "Create" phase
+ return NextInternalState(Action.Create, InternalState.INITIAL)
+ }
+
+ return NextInternalState(actionPhase, nextInternalState)
+
+ }
+
+ //no need to refer to failed (final) states here
+ //This method is called only for non final states or COMPLETED
+ protected fun calcNextStateDeletePhase(jobStatus: JobStatus, internalState: InternalState): InternalState {
+ return when (internalState) {
+
+ InternalState.CREATING_CHILDREN -> InternalState.WATCHING
+
+ InternalState.WATCHING -> {
+ when {
+ !jobStatus.isFinal -> InternalState.WATCHING
+ isNeedToDeleteMyself() -> InternalState.DELETE_MYSELF
+ else -> InternalState.TERMINAL
+ }
+ }
+
+ InternalState.DELETE_MYSELF -> InternalState.IN_PROGRESS
+
+ InternalState.IN_PROGRESS -> {
+ if (jobStatus == Job.JobStatus.COMPLETED) InternalState.TERMINAL else InternalState.IN_PROGRESS
+ }
+
+ else -> InternalState.TERMINAL
+ }
+ }
+
+ protected fun calcNextStateCreatePhase(jobStatus: JobStatus, internalState: InternalState): InternalState {
+ return when (internalState) {
+
+ InternalState.CREATE_MYSELF -> InternalState.IN_PROGRESS
+
+ InternalState.IN_PROGRESS -> {
+ if (jobStatus == Job.JobStatus.COMPLETED) InternalState.CREATING_CHILDREN else InternalState.IN_PROGRESS
+ }
+
+ InternalState.CREATING_CHILDREN -> InternalState.WATCHING
+
+ InternalState.WATCHING -> {
+ when {
+ !jobStatus.isFinal -> InternalState.WATCHING
+ else -> InternalState.TERMINAL
+ }
+ }
+
+
+ else -> InternalState.TERMINAL
+ }
+ }
+
+ override fun getData(): Map<String, Any?> {
+ return mapOf(
+ ACTION_PHASE to actionPhase,
+ INTERNAL_STATE to internalState,
+ MSO_RESOURCE_ID to msoResourceIds,
+ CHILD_JOBS to childJobs,
+ CUMULATIVE_STATUS to cumulativeStatus
+ )
+ }
+
+ override fun init(sharedData: JobSharedData, commandData: Map<String, Any>): ResourceCommand {
+ init(sharedData)
+ val resourceIdsRaw:Any? = commandData[MSO_RESOURCE_ID]
+ commandParentData.initParentData(commandData)
+ msoResourceIds =
+ if (resourceIdsRaw != null) JACKSON_OBJECT_MAPPER.convertValue(resourceIdsRaw)
+ else EMPTY_MSO_RESOURCE_ID
+
+ childJobs = JACKSON_OBJECT_MAPPER.convertValue(commandData.getOrDefault(CHILD_JOBS, emptyList<String>()))
+ cumulativeStatus = getEnumFromMapOfStrings(commandData, CUMULATIVE_STATUS, JobStatus.COMPLETED_WITH_NO_ACTION)
+ actionPhase = getEnumFromMapOfStrings(commandData, ACTION_PHASE, Action.Delete)
+ internalState = calcInitialState(commandData, actionPhase)
+ return this
+ }
+
+ private fun calcInitialState(commandData: Map<String, Any>, phase: Action):InternalState {
+ val status:InternalState = getEnumFromMapOfStrings(commandData, INTERNAL_STATE, InternalState.INITIAL)
+ if (status == InternalState.INITIAL) {
+ onInitial(phase)
+ return when (phase) {
+ Action.Delete -> InternalState.CREATING_CHILDREN
+ Action.Create -> if (isNeedToCreateMyself()) InternalState.CREATE_MYSELF else InternalState.CREATING_CHILDREN
+ else -> throw IllegalStateException("state $internalState is not supported yet")
+ }
+ }
+ return status
+ }
+
+ //command may override it in order to do something while init state
+ protected open fun onInitial(phase: Action) {
+ //do nothing
+ }
+
+ //command may override it in order to do something while final status
+ protected open fun onFinal(jobStatus: JobStatus) {
+ //do nothing
+ }
+
+ protected open fun getRequest(): BaseResource {
+ return sharedData.request as BaseResource
+ }
+
+ protected open fun getActionType(): Action {
+ return getRequest().action
+ }
+
+ protected open fun isServiceCommand(): Boolean = false
+
+ protected open fun isNeedToDeleteMyself(): Boolean = getActionType() == Action.Delete
+
+ protected open fun isNeedToCreateMyself(): Boolean = getActionType() == Action.Create
+
+ protected open fun inProgress(): Job.JobStatus {
+ val requestId:String = msoResourceIds.requestId;
+ return try {
+ val jobStatus = inProgressStatusService.call(getExpiryChecker(), sharedData, requestId)
+ handleInProgressStatus(jobStatus)
+ } catch (e: javax.ws.rs.ProcessingException) {
+ // Retry when we can't connect MSO during getStatus
+ Logger.error(EELFLoggerDelegate.errorLogger, "Cannot get orchestration status for {}, will retry: {}", requestId, e, e)
+ Job.JobStatus.IN_PROGRESS;
+ } catch (e: InProgressStatusService.BadResponseFromMso) {
+ inProgressStatusService.handleFailedMsoResponse(sharedData.jobUuid, requestId, e.msoResponse)
+ Job.JobStatus.IN_PROGRESS
+ } catch (e: RuntimeException) {
+ Logger.error(EELFLoggerDelegate.errorLogger, "Cannot get orchestration status for {}, stopping: {}", requestId, e, e)
+ Job.JobStatus.STOPPED
+ }
+ }
+
+ fun createMyself(): Job.JobStatus {
+ val createMyselfCommand = planCreateMyselfRestCall(commandParentData, sharedData.request, sharedData.userId)
+
+ return executeAndHandleMsoInstanceRequest(createMyselfCommand)
+ }
+
+ fun deleteMyself(): Job.JobStatus {
+ val deleteMyselfCommand = planDeleteMyselfRestCall(commandParentData, sharedData.request, sharedData.userId)
+
+ return executeAndHandleMsoInstanceRequest(deleteMyselfCommand)
+ }
+
+ private fun executeAndHandleMsoInstanceRequest(restCallPlan: MsoRestCallPlan): JobStatus {
+ val msoResponse = restMso.restCall(
+ restCallPlan.httpMethod,
+ RequestReferencesContainer::class.java,
+ restCallPlan.payload.orElse(null),
+ restCallPlan.path,
+ restCallPlan.userId
+ )
+
+ val msoResult = if (isServiceCommand()) {
+ msoResultHandlerService.handleRootResponse(sharedData.jobUuid, msoResponse)
+ } else {
+ msoResultHandlerService.handleResponse(msoResponse, restCallPlan.actionDescription)
+ }
+
+ this.msoResourceIds = msoResult.msoResourceIds
+ return msoResult.jobStatus
+ }
+
+ protected open fun getExpiryChecker(): ExpiryChecker = ExpiryChecker {false}
+
+ protected open fun handleInProgressStatus(jobStatus: JobStatus): JobStatus {
+ return if (jobStatus == Job.JobStatus.PAUSE) Job.JobStatus.IN_PROGRESS else jobStatus
+ }
+
+ protected open fun watchChildren():JobStatus {
+ return watchChildrenJobsBL.retrieveChildrenJobsStatus(childJobs)
+ }
+
+ private fun comulateStatusAndUpdatePropertyIfFinal(internalStateStatus: JobStatus): JobStatus {
+ val status = watchChildrenJobsBL.cumulateJobStatus(internalStateStatus, cumulativeStatus)
+
+ //we want to update cumulativeStatus only for final status
+ if (status.isFinal) {
+ cumulativeStatus = status;
+ }
+
+ return status
+ }
+}
+
+
+
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInProgressStatusCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInProgressStatusCommand.java
new file mode 100644
index 000000000..9ab600aae
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInProgressStatusCommand.java
@@ -0,0 +1,32 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.Job;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ResourceInProgressStatusCommand extends BaseInProgressStatusCommand {
+
+ public ResourceInProgressStatusCommand() {
+ }
+
+ ResourceInProgressStatusCommand(JobSharedData sharedData, String requestId, String instanceId) {
+ init(sharedData, requestId, instanceId);
+ }
+
+ @Override
+ protected ExpiryChecker getExpiryChecker() {
+ return x->false;
+ }
+
+ @Override
+ protected NextCommand processJobStatus(Job.JobStatus jobStatus) {
+ return new NextCommand(jobStatus, this);
+ }
+
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInstantiationCommand.java
new file mode 100644
index 000000000..c86c6f1be
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceInstantiationCommand.java
@@ -0,0 +1,87 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.Job;
+import org.onap.vid.job.JobAdapter;
+import org.onap.vid.job.JobCommand;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.RequestReferencesContainer;
+import org.onap.vid.mso.RestMsoImplementation;
+import org.onap.vid.mso.RestObject;
+import org.onap.vid.mso.model.BaseResourceInstantiationRequestDetails;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.onap.vid.services.AuditService;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import java.util.Map;
+
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public abstract class ResourceInstantiationCommand extends BaseInstantiationCommand implements JobCommand {
+
+
+ @Inject
+ protected RestMsoImplementation restMso;
+
+ @Inject
+ private AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Inject
+ private AuditService auditService;
+
+ @Override
+ public ResourceInstantiationCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
+ super.init(sharedData, commandData);
+ return this;
+ }
+
+ @Override
+ public Map<String, Object> getData() {
+ return commandParentData.getParentData();
+ }
+
+ @Override
+ public NextCommand call() {
+ if (!shouldInstantiateMyself()) {
+ return new NextCommand(Job.JobStatus.COMPLETED_WITH_NO_ACTION);
+ }
+
+ RequestDetailsWrapper<? extends BaseResourceInstantiationRequestDetails> requestDetailsWrapper = generateMSORequest(
+ getSharedData().getRequest(),
+ getSharedData().getUserId()
+ );
+ String instantiatePath = getRequestPath();
+
+ RestObject<RequestReferencesContainer> msoResponse = restMso.PostForObject(requestDetailsWrapper,
+ instantiatePath, RequestReferencesContainer.class);
+
+ if (msoResponse.getStatusCode() >= 200 && msoResponse.getStatusCode() < 400) {
+ String requestId = msoResponse.get().getRequestReferences().getRequestId();
+ String instanceId = msoResponse.get().getRequestReferences().getInstanceId();
+ asyncInstantiationBL.auditMsoStatus(getSharedData().getRootJobId(), getJobAuditMSOStatus(), requestId, null);
+ return getNextCommand(requestId, instanceId);
+ }
+ else {
+ auditService.setFailedAuditStatusFromMso(getSharedData().getRootJobId(), null, msoResponse.getStatusCode(), msoResponse.getRaw());
+ return new NextCommand(Job.JobStatus.FAILED);
+ }
+ }
+ protected NextCommand getNextCommand(String requestId, String instanceId){
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, new ResourceInProgressStatusCommand(getSharedData(), requestId, instanceId));
+ }
+
+ protected boolean shouldInstantiateMyself() {
+ return true;
+ }
+
+ protected abstract String getRequestPath();
+ protected abstract RequestDetailsWrapper<? extends BaseResourceInstantiationRequestDetails> generateMSORequest(JobAdapter.AsyncJobRequest request, String userId);
+ protected abstract String getJobAuditMSOStatus();
+}
+
+
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceWithChildrenInProgressCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceWithChildrenInProgressCommand.java
new file mode 100644
index 000000000..53164f433
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceWithChildrenInProgressCommand.java
@@ -0,0 +1,65 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.Job;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class ResourceWithChildrenInProgressCommand extends BaseInProgressStatusCommand {
+
+ public ResourceWithChildrenInProgressCommand() {
+ }
+
+ public ResourceWithChildrenInProgressCommand(JobSharedData sharedData,
+ String requestId,
+ String instanceId,
+ CommandParentData commandParentData) {
+ init(sharedData, requestId, instanceId, commandParentData);
+ }
+
+ protected BaseInProgressStatusCommand init(JobSharedData sharedData,
+ String requestId,
+ String instanceId,
+ CommandParentData commandParentData) {
+ init(sharedData, requestId, instanceId);
+ this.commandParentData= commandParentData;
+ return this;
+ }
+
+
+ @Override
+ public Map<String, Object> getData() {
+ Map<String, Object> data = new HashMap<>(super.getData());
+ data.putAll(buildDataForChild());
+ return data;
+ }
+
+ @Override
+ public BaseInProgressStatusCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
+ return init(
+ sharedData,
+ (String) commandData.get("requestId"),
+ (String) commandData.get("instanceId"),
+ commandParentData.initParentData(commandData));
+ }
+
+ protected Map<String, Object> buildDataForChild() {
+ return commandParentData.getParentData();
+ }
+
+
+
+ @Override
+ protected NextCommand processJobStatus(Job.JobStatus jobStatus) {
+ return new NextCommand(jobStatus, this);
+ }
+
+ @Override
+ protected ExpiryChecker getExpiryChecker() {
+ return x->false;
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInProgressStatusCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInProgressStatusCommand.java
new file mode 100644
index 000000000..ac8b5546f
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInProgressStatusCommand.java
@@ -0,0 +1,100 @@
+package org.onap.vid.job.command;
+
+import org.apache.commons.collections.MapUtils;
+import org.onap.vid.job.Job;
+import org.onap.vid.job.Job.JobStatus;
+import org.onap.vid.job.JobCommand;
+import org.onap.vid.job.JobType;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
+import org.onap.vid.properties.Features;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ServiceInProgressStatusCommand extends BaseInProgressStatusCommand {
+
+ public ServiceInProgressStatusCommand() {
+ }
+
+ ServiceInProgressStatusCommand(JobSharedData sharedData, MsoResourceIds msoResourceIds) {
+ init(sharedData, msoResourceIds.getRequestId(), msoResourceIds.getInstanceId());
+ }
+
+ @Override
+ protected ExpiryChecker getExpiryChecker() {
+ return new ServiceExpiryChecker();
+ }
+
+ protected NextCommand processJobStatus(Job.JobStatus jobStatus) {
+ JobCommand jobCommand = this;
+ Job.JobStatus nextJobStatus = jobStatus;
+ switch (jobStatus) {
+ case FAILED:
+ asyncInstantiationBL.handleFailedInstantiation(getSharedData().getJobUuid());
+ return new NextCommand(nextJobStatus, jobCommand);
+ case PAUSE:
+ nextJobStatus = Job.JobStatus.IN_PROGRESS;
+ break;
+ case COMPLETED:
+ ServiceInstantiation request = (ServiceInstantiation) getSharedData().getRequest();
+ if (isNeedToCreateChildJobs(request)) {
+ List<String> childrenJobs = getChildJobs(request);
+ nextJobStatus = Job.JobStatus.IN_PROGRESS;
+ jobCommand = new WatchingCommand(getSharedData(), childrenJobs, true);
+ return new NextCommand(nextJobStatus, jobCommand);
+ }
+ break;
+ default: // for sonar
+ }
+ asyncInstantiationBL.updateServiceInfoAndAuditStatus(getSharedData().getJobUuid(), jobStatus);
+ return new NextCommand(nextJobStatus, jobCommand);
+ }
+
+ private List<String> getChildJobs(ServiceInstantiation request) {
+ Map<String, Object> dataForChild = buildDataForChild(request);
+
+ Stream<String> vnfJobs = request.getVnfs().values().stream().map(
+ vnf -> jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.VnfInstantiation, JobStatus.CREATING , vnf, getSharedData(), dataForChild)).toString()
+ );
+
+ Stream<String> networkJobs = request.getNetworks().values().stream().map(
+ network -> jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.NetworkInstantiation, JobStatus.CREATING , network, getSharedData(), dataForChild)).toString()
+ );
+
+ Stream<String> instanceGroupJobs = request.getVnfGroups().values().stream().map(
+ instanceGroup -> jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.InstanceGroupInstantiation, JobStatus.CREATING , instanceGroup, getSharedData(), dataForChild)).toString()
+ );
+
+ return Stream.of(vnfJobs, networkJobs, instanceGroupJobs)
+ .reduce(Stream::concat)
+ .orElseGet(Stream::empty)
+ .collect(Collectors.toList());
+ }
+
+ public boolean isNeedToCreateChildJobs(ServiceInstantiation request) {
+ return featureManager.isActive(Features.FLAG_ASYNC_ALACARTE_VNF) && request.isALaCarte() &&
+ (
+ MapUtils.isNotEmpty(request.getVnfs()) || MapUtils.isNotEmpty(request.getNetworks()) ||
+ (featureManager.isActive(Features.FLAG_1902_VNF_GROUPING) && MapUtils.isNotEmpty(request.getVnfGroups()))
+ );
+ }
+
+ protected Map<String, Object> buildDataForChild(ServiceInstantiation request) {
+ commandParentData.addInstanceId(CommandDataKey.SERVICE_INSTANCE_ID, this.instanceId);
+ commandParentData.addModelInfo(CommandDataKey.SERVICE_MODEL_INFO, request.getModelInfo());
+ return commandParentData.getParentData();
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInstantiationCommand.java
index 958fc115e..b40b7015c 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInstantiationCommand.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ServiceInstantiationCommand.java
@@ -1,170 +1,106 @@
-/*-
- * ============LICENSE_START=======================================================
- * VID
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2018 Nokia. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
package org.onap.vid.job.command;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
-import io.joshworks.restclient.http.HttpResponse;
-import org.onap.vid.aai.exceptions.InvalidAAIResponseException;
+import org.apache.commons.lang3.ObjectUtils;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.aai.ExceptionWithRequestInfo;
import org.onap.vid.changeManagement.RequestDetailsWrapper;
import org.onap.vid.exceptions.MaxRetriesException;
import org.onap.vid.job.Job;
import org.onap.vid.job.JobCommand;
import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
import org.onap.vid.model.RequestReferencesContainer;
import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
-import org.onap.vid.mso.MsoInterface;
+import org.onap.vid.mso.RestMsoImplementation;
+import org.onap.vid.mso.RestObject;
import org.onap.vid.mso.model.ServiceInstantiationRequestDetails;
import org.onap.vid.services.AsyncInstantiationBusinessLogic;
-import org.onap.vid.services.AuditService;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-@Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceInstantiationCommand implements JobCommand {
-
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+public abstract class ServiceInstantiationCommand extends BaseRootCommand implements JobCommand {
private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(ServiceInstantiationCommand.class);
@Inject
- private AsyncInstantiationBusinessLogic asyncInstantiationBL;
-
- @Inject
- private AuditService auditService;
+ protected AsyncInstantiationBusinessLogic asyncInstantiationBL;
@Inject
- private MsoInterface restMso;
+ private RestMsoImplementation restMso;
- private UUID uuid;
- private ServiceInstantiation serviceInstantiationRequest;
- private String userId;
+ protected String optimisticUniqueServiceInstanceName;
public ServiceInstantiationCommand() {
}
- public ServiceInstantiationCommand(UUID uuid, ServiceInstantiation serviceInstantiationRequest, String userId) {
- init(uuid, serviceInstantiationRequest, userId);
- }
-
- ServiceInstantiationCommand(AsyncInstantiationBusinessLogic asyncInstantiationBL, AuditService auditService, MsoInterface msoInterface,
- UUID uuid, ServiceInstantiation serviceInstantiation, String userId) {
- this(uuid, serviceInstantiation, userId);
- this.asyncInstantiationBL = asyncInstantiationBL;
- this.auditService = auditService;
- this.restMso = msoInterface;
- }
-
@Override
public NextCommand call() {
RequestDetailsWrapper<ServiceInstantiationRequestDetails> requestDetailsWrapper ;
try {
- requestDetailsWrapper = asyncInstantiationBL.generateServiceInstantiationRequest(
- uuid, serviceInstantiationRequest, userId
- );
+ requestDetailsWrapper = generateServiceInstantiationRequest();
}
+
//Aai return bad response while checking names uniqueness
- catch (InvalidAAIResponseException exception) {
- LOGGER.error("Failed to check name uniqueness in AAI. VID will try again later", exception);
- //put the job in_progress so we will keep trying to check name uniqueness in AAI
- //And then send the request to MSO
- return new NextCommand(Job.JobStatus.IN_PROGRESS, this);
+ catch (ExceptionWithRequestInfo exception) {
+ return handleAaiNameUniquenessBadResponse(exception);
}
//Vid reached to max retries while trying to find unique name in AAI
catch (MaxRetriesException exception) {
- LOGGER.error("Failed to find unused name in AAI. Set the job to FAILED ", exception);
- return handleCommandFailed();
+ return handleMaxRetryInNameUniqueness(exception);
}
- String path = asyncInstantiationBL.getServiceInstantiationPath(serviceInstantiationRequest);
+ String path = asyncInstantiationBL.getServiceInstantiationPath(getRequest());
- HttpResponse<RequestReferencesContainer> msoResponse = restMso.post(path,
- requestDetailsWrapper, RequestReferencesContainer.class);
+ RestObject<RequestReferencesContainer> msoResponse = restMso.PostForObject(requestDetailsWrapper,
+ path, RequestReferencesContainer.class);
+ return handleRootResponse(msoResponse);
- if (msoResponse.getStatus() >= 200 && msoResponse.getStatus() < 400) {
- final Job.JobStatus jobStatus = Job.JobStatus.IN_PROGRESS;
- final String requestId = msoResponse.getBody().getRequestReferences().getRequestId();
- final String instanceId = msoResponse.getBody().getRequestReferences().getInstanceId();
- asyncInstantiationBL.auditVidStatus(uuid, jobStatus);
- setInitialRequestAuditStatusFromMso(requestId);
- asyncInstantiationBL.updateServiceInfo(uuid, x-> {
- x.setJobStatus(jobStatus);
- x.setServiceInstanceId(instanceId);
- });
-
- return new NextCommand(jobStatus, new InProgressStatusCommand(uuid, requestId));
- } else {
- auditService.setFailedAuditStatusFromMso(uuid,null, msoResponse.getStatus(),
- Objects.toString(msoResponse.getBody()));
- return handleCommandFailed();
- }
+ }
+ @Override
+ protected ServiceInstantiation getRequest() {
+ return (ServiceInstantiation) getSharedData().getRequest();
}
- private void setInitialRequestAuditStatusFromMso(String requestId){
- final String initialMsoRequestStatus = "REQUESTED";
- asyncInstantiationBL.auditMsoStatus(uuid,initialMsoRequestStatus,requestId,null);
+ protected abstract RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateServiceInstantiationRequest();
+
+ private NextCommand handleMaxRetryInNameUniqueness(MaxRetriesException exception) {
+ LOGGER.error("Failed to find unused name in AAI. Set the job to FAILED ", exception);
+ return handleCommandFailed();
}
- protected NextCommand handleCommandFailed() {
- asyncInstantiationBL.handleFailedInstantiation(uuid);
- return new NextCommand(Job.JobStatus.FAILED);
+ private NextCommand handleAaiNameUniquenessBadResponse(ExceptionWithRequestInfo exception) {
+ LOGGER.error("Failed to check name uniqueness in AAI. VID will try again later", exception);
+ //put the job in_progress so we will keep trying to check name uniqueness in AAI
+ //And then send the request to MSO
+ return new NextCommand(Job.JobStatus.IN_PROGRESS, this);
}
@Override
- public ServiceInstantiationCommand init(UUID jobUuid, Map<String, Object> data) {
- final Object request = data.get("request");
+ public ServiceInstantiationCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
return init(
- jobUuid,
- OBJECT_MAPPER.convertValue(request, ServiceInstantiation.class),
- (String) data.get("userId")
+ sharedData,
+ (String) commandData.get("optimisticUniqueServiceInstanceName")
);
}
- private ServiceInstantiationCommand init(UUID jobUuid, ServiceInstantiation serviceInstantiationRequest, String userId) {
- this.uuid = jobUuid;
- this.serviceInstantiationRequest = serviceInstantiationRequest;
- this.userId = userId;
-
+ protected ServiceInstantiationCommand init(JobSharedData sharedData, String optimisticUniqueServiceInstanceName) {
+ init(sharedData);
+ this.optimisticUniqueServiceInstanceName = ObjectUtils.defaultIfNull(optimisticUniqueServiceInstanceName,
+ (getRequest()).getInstanceName());
return this;
}
@Override
public Map<String, Object> getData() {
return ImmutableMap.of(
- "uuid", uuid,
- "request", serviceInstantiationRequest,
- "userId", userId
+ "optimisticUniqueServiceInstanceName", optimisticUniqueServiceInstanceName
);
}
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleInstantiationCommand.java
new file mode 100644
index 000000000..a3f827e2f
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleInstantiationCommand.java
@@ -0,0 +1,44 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.JobAdapter;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.model.serviceInstantiation.VfModule;
+import org.onap.vid.mso.model.VfModuleInstantiationRequestDetails;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class VfmoduleInstantiationCommand extends ResourceInstantiationCommand {
+ @Inject
+ private AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Override
+ protected String getRequestPath() {
+ return asyncInstantiationBL.getVfmoduleInstantiationPath(commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),commandParentData.getInstanceId(CommandDataKey.VNF_INSTANCE_ID));
+ }
+
+ @Override
+ protected RequestDetailsWrapper<VfModuleInstantiationRequestDetails> generateMSORequest(JobAdapter.AsyncJobRequest request, String userId) {
+ return asyncInstantiationBL.generateVfModuleInstantiationRequest(
+ (VfModule) getSharedData().getRequest(),
+ commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),
+ commandParentData.getModelInfo(CommandDataKey.VNF_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.VNF_INSTANCE_ID),
+ commandParentData.getInstanceId(CommandDataKey.VG_INSTANCE_ID),
+ getSharedData().getUserId()
+ );
+ }
+
+ @Override
+ protected String getJobAuditMSOStatus() {
+ return "VF_MODULE_REQUESTED";
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VnfInProgressStatusCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/VnfInProgressStatusCommand.java
new file mode 100644
index 000000000..a6a41b1ae
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VnfInProgressStatusCommand.java
@@ -0,0 +1,87 @@
+package org.onap.vid.job.command;
+
+import org.apache.commons.collections.MapUtils;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.asdc.AsdcCatalogException;
+import org.onap.vid.job.Job;
+import org.onap.vid.job.JobType;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.serviceInstantiation.BaseResource;
+import org.onap.vid.model.serviceInstantiation.VfModule;
+import org.onap.vid.model.serviceInstantiation.Vnf;
+import org.onap.vid.properties.Features;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class VnfInProgressStatusCommand extends ResourceWithChildrenInProgressCommand {
+ private static final EELFLoggerDelegate LOG = EELFLoggerDelegate.getLogger(VnfInProgressStatusCommand.class);
+
+ public VnfInProgressStatusCommand(JobSharedData sharedData,
+ String requestId,
+ String instanceId,
+ CommandParentData commandParentData) {
+ super(sharedData, requestId, instanceId, commandParentData);
+ }
+
+ public VnfInProgressStatusCommand() {
+ }
+
+ @Override
+ protected NextCommand processJobStatus(Job.JobStatus jobStatus) {
+ if (jobStatus == Job.JobStatus.FAILED) {
+ return new NextCommand(jobStatus);
+ }
+
+ Vnf request = (Vnf) getSharedData().getRequest();
+
+ if (isNeedToCreateChildJobs(jobStatus, request)) {
+ commandParentData.addInstanceId(CommandDataKey.VNF_INSTANCE_ID, instanceId);
+ commandParentData.addModelInfo(CommandDataKey.VNF_MODEL_INFO, request.getModelInfo());
+ //create volume group of base module job
+ Map<String, Object> dataForChild = buildDataForChild();
+ List<VfModule> vfModules = request.getVfModules().values().stream().flatMap(vfKey -> vfKey.values().stream()).collect(Collectors.toList());
+ List<String> vgBaseJobs = new ArrayList<>();
+ for( VfModule vfModule : vfModules){
+ try {
+ if(commandUtils.isVfModuleBaseModule(commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO).getModelVersionId(), vfModule.getModelInfo().getModelVersionId())) {
+ vgBaseJobs.add(jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.VolumeGroupInstantiation, Job.JobStatus.CREATING, vfModule, getSharedData(), dataForChild)).toString());
+ }
+ } catch (AsdcCatalogException e) {
+ LOG.error("Failed to retrieve service definitions from SDC, for VfModule is BaseModule. Error: "+e.getMessage() , e);
+ return new NextCommand(Job.JobStatus.COMPLETED_WITH_ERRORS);
+ }
+ }
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, new WatchingCommandBaseModule(getSharedData(), vgBaseJobs, false, commandParentData));
+ }
+
+ //in case of JobStatus.PAUSE we leave the job itself as IN_PROGRESS, for keep tracking job progress
+ if (jobStatus == Job.JobStatus.PAUSE) {
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, this);
+ }
+ return new NextCommand(jobStatus, this);
+ }
+
+
+ protected boolean isNeedToCreateChildJobs(Job.JobStatus jobStatus, BaseResource request) {
+ return featureManager.isActive(Features.FLAG_ASYNC_ALACARTE_VFMODULE) &&
+ jobStatus == Job.JobStatus.COMPLETED &&
+ MapUtils.isNotEmpty(((Vnf)request).getVfModules());
+ }
+
+
+ @Override
+ protected ExpiryChecker getExpiryChecker() {
+ return x->false;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VnfInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/VnfInstantiationCommand.java
new file mode 100644
index 000000000..8853cdc14
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VnfInstantiationCommand.java
@@ -0,0 +1,50 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.Job;
+import org.onap.vid.job.JobAdapter;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.model.serviceInstantiation.Vnf;
+import org.onap.vid.mso.model.VnfInstantiationRequestDetails;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class VnfInstantiationCommand extends ResourceInstantiationCommand {
+
+ @Inject
+ private AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Override
+ protected String getRequestPath() {
+ return asyncInstantiationBL.getVnfInstantiationPath( commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID));
+ }
+
+ @Override
+ protected RequestDetailsWrapper<VnfInstantiationRequestDetails> generateMSORequest(JobAdapter.AsyncJobRequest request, String userId) {
+ return asyncInstantiationBL.generateVnfInstantiationRequest(
+ (Vnf) getSharedData().getRequest(),
+ commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),
+ getSharedData().getUserId()
+ );
+ }
+
+ @Override
+ protected String getJobAuditMSOStatus() {
+ return "VNF_REQUESTED";
+ }
+
+ @Override
+ protected NextCommand getNextCommand(String requestId, String instanceId) {
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS,
+ new VnfInProgressStatusCommand(getSharedData(), requestId, instanceId, commandParentData));
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInProgressStatusCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInProgressStatusCommand.java
new file mode 100644
index 000000000..663696b32
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInProgressStatusCommand.java
@@ -0,0 +1,65 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.Job;
+import org.onap.vid.job.JobType;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.serviceInstantiation.VfModule;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class VolumeGroupInProgressStatusCommand extends ResourceWithChildrenInProgressCommand {
+
+ public VolumeGroupInProgressStatusCommand(
+ JobSharedData sharedData,
+ String requestId,
+ String instanceId,
+ CommandParentData parentData) {
+ super(sharedData, requestId, instanceId, parentData);
+ }
+
+ public VolumeGroupInProgressStatusCommand() {
+ }
+
+ @Override
+ protected NextCommand processJobStatus(Job.JobStatus jobStatus) {
+ if (jobStatus == Job.JobStatus.FAILED) {
+ return new NextCommand(Job.JobStatus.FAILED);
+ }
+ VfModule request = (VfModule) getSharedData().getRequest();
+
+ if (jobStatus == Job.JobStatus.COMPLETED) {
+ //vf module creation
+ Map<String, Object> dataForChild = buildDataForChild();
+ List<String> vfModuleJob = Arrays.asList(jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.VfmoduleInstantiation, Job.JobStatus.CREATING , request, getSharedData(), dataForChild)).toString());
+
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, new WatchingCommand(getSharedData(), vfModuleJob, false));
+ }
+
+ //in case of JobStatus.PAUSE we leave the job itself as IN_PROGRESS, for keep tracking job progress
+ if (jobStatus == Job.JobStatus.PAUSE) {
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, this);
+ }
+ return new NextCommand(jobStatus, this);
+ }
+
+ @Override
+ protected Map<String, Object> buildDataForChild() {
+ commandParentData.addInstanceId(CommandDataKey.VG_INSTANCE_ID, this.instanceId);
+ return super.buildDataForChild();
+ }
+
+ @Override
+ protected ExpiryChecker getExpiryChecker() {
+ return x->false;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInstantiationCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInstantiationCommand.java
new file mode 100644
index 000000000..b2a3da472
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupInstantiationCommand.java
@@ -0,0 +1,83 @@
+package org.onap.vid.job.command;
+
+
+import org.apache.commons.lang3.StringUtils;
+import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.job.*;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.model.serviceInstantiation.VfModule;
+import org.onap.vid.mso.model.VolumeGroupRequestDetails;
+import org.onap.vid.services.AsyncInstantiationBusinessLogic;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class VolumeGroupInstantiationCommand extends ResourceInstantiationCommand {
+ @Inject
+ private AsyncInstantiationBusinessLogic asyncInstantiationBL;
+
+ @Inject
+ protected JobsBrokerService jobsBrokerService;
+
+ @Inject
+ protected JobAdapter jobAdapter;
+
+ @Override
+ protected String getRequestPath() {
+ return asyncInstantiationBL.getVolumeGroupInstantiationPath(commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),commandParentData.getInstanceId(CommandDataKey.VNF_INSTANCE_ID));
+ }
+
+ @Override
+ protected RequestDetailsWrapper<VolumeGroupRequestDetails> generateMSORequest(JobAdapter.AsyncJobRequest request, String userId) {
+ return asyncInstantiationBL.generateVolumeGroupInstantiationRequest(
+ (VfModule) getSharedData().getRequest(),
+ commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.SERVICE_INSTANCE_ID),
+ commandParentData.getModelInfo(CommandDataKey.VNF_MODEL_INFO),
+ commandParentData.getInstanceId(CommandDataKey.VNF_INSTANCE_ID),
+ getSharedData().getUserId()
+ );
+ }
+
+ @Override
+ protected NextCommand getNextCommand(String requestId, String instanceId){
+ return new NextCommand(
+ Job.JobStatus.RESOURCE_IN_PROGRESS,
+ new VolumeGroupInProgressStatusCommand(getSharedData(), requestId, instanceId, commandParentData)
+ );
+ }
+
+ @Override
+ protected String getJobAuditMSOStatus() {
+ return "VOLUME_GROUP_REQUESTED";
+ }
+
+ @Override
+ public NextCommand call() {
+ String vgName = ((VfModule)getSharedData().getRequest()).getVolumeGroupInstanceName();
+ if(StringUtils.isNotEmpty(vgName)){
+ return super.call();//create volume group
+ }else {
+ //go to vf module creation
+ VfModule request = (VfModule) getSharedData().getRequest();
+ Map<String, Object> dataForChild = buildDataForChild();
+ List<String> vfModuleJob = Collections.singletonList(jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.VfmoduleInstantiation, Job.JobStatus.CREATING, request, getSharedData(), dataForChild)).toString());
+
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, new WatchingCommand(getSharedData(), vfModuleJob, false));
+ }
+
+ }
+
+ private Map<String, Object> buildDataForChild() {
+ return commandParentData.getParentData();
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/WatchChildrenJobsBL.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/WatchChildrenJobsBL.kt
new file mode 100644
index 000000000..b31e7f92e
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/WatchChildrenJobsBL.kt
@@ -0,0 +1,61 @@
+package org.onap.vid.job.command
+
+import org.apache.commons.lang3.StringUtils
+import org.onap.portalsdk.core.service.DataAccessService
+import org.onap.vid.job.Job
+import org.onap.vid.job.Job.JobStatus.*
+import org.onap.vid.job.impl.JobDaoImpl
+import org.onap.vid.utils.DaoUtils
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+import java.util.*
+import java.util.stream.Collectors
+import java.util.stream.Stream
+
+
+@Service
+class WatchChildrenJobsBL @Autowired
+constructor(private val dataAccessService: DataAccessService) {
+
+ fun retrieveChildrenJobsStatus(childrenJobsIds: List<String>): Job.JobStatus {
+ val jobs = getAllChildrenJobs(childrenJobsIds)
+
+ val jobsStatuses = childrenJobsIds.stream()
+ .map<JobDaoImpl> { jobId -> jobs[UUID.fromString(jobId)] }
+ .map {when {
+ (it == null || it.status == null) -> Job.JobStatus.FAILED
+ else -> it.status
+ }}
+
+ return cumulateJobStatus(jobsStatuses)
+
+ }
+
+ fun cumulateJobStatus(childrenComulatedStatus: Job.JobStatus, fatherJobStatus: Job.JobStatus): Job.JobStatus {
+ return cumulateJobStatus(Stream.of(childrenComulatedStatus, fatherJobStatus))
+ }
+
+ private fun cumulateJobStatus(jobsStatuses: Stream<Job.JobStatus>): Job.JobStatus {
+
+ return jobsStatuses.reduce{ a, b ->
+ when {
+ !a.isFinal || !b.isFinal -> IN_PROGRESS
+ a == COMPLETED_WITH_ERRORS || b == COMPLETED_WITH_ERRORS-> COMPLETED_WITH_ERRORS
+ a == COMPLETED && b.isFailure -> COMPLETED_WITH_ERRORS
+ b == COMPLETED && a.isFailure -> COMPLETED_WITH_ERRORS
+ a == COMPLETED || b == COMPLETED -> COMPLETED
+ a.isFailure || b.isFailure -> FAILED
+ else -> COMPLETED_WITH_NO_ACTION
+ }
+ } .orElse(COMPLETED_WITH_NO_ACTION)
+ }
+
+ private fun getAllChildrenJobs(childrenJobsIds: List<String>): Map<UUID, JobDaoImpl> {
+ val jobs:MutableList<JobDaoImpl> = dataAccessService.getList(JobDaoImpl::class.java, filterByJobIds(childrenJobsIds), null, DaoUtils.getPropsMap()) as MutableList<JobDaoImpl>
+ return jobs.stream().collect(Collectors.toMap( { it.uuid }, { it }))
+ }
+
+ private fun filterByJobIds(childrenJobsIds: List<String>): String {
+ return " WHERE JOB_ID IN('" + StringUtils.join(childrenJobsIds, "', '") + "')"
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommand.java
new file mode 100644
index 000000000..8659cfe1a
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommand.java
@@ -0,0 +1,33 @@
+package org.onap.vid.job.command;
+
+import org.onap.vid.job.Job;
+import org.onap.vid.job.NextCommand;
+import org.onap.vid.job.impl.JobSharedData;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class WatchingCommand extends BaseWatchingCommand {
+
+ public WatchingCommand() {}
+
+ public WatchingCommand(JobSharedData sharedData, List<String> childrenJobsIds, boolean isService) {
+ super(sharedData, childrenJobsIds, isService);
+ }
+
+ protected NextCommand getNextCommand(Job.JobStatus cumulativeJobsStatus) {
+ if (cumulativeJobsStatus==Job.JobStatus.IN_PROGRESS) {
+ return (isService) ? new NextCommand(Job.JobStatus.IN_PROGRESS, this)
+ : new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, this);
+ }
+ if (isService) {
+ asyncInstantiationBL.updateServiceInfoAndAuditStatus(getSharedData().getJobUuid(), cumulativeJobsStatus);
+ }
+ return new NextCommand(cumulativeJobsStatus);
+ }
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommandBaseModule.java b/vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommandBaseModule.java
new file mode 100644
index 000000000..8012aa9f3
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/WatchingCommandBaseModule.java
@@ -0,0 +1,93 @@
+package org.onap.vid.job.command;
+
+import com.google.common.collect.ImmutableMap;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.asdc.AsdcCatalogException;
+import org.onap.vid.job.*;
+import org.onap.vid.job.command.CommandParentData.CommandDataKey;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.serviceInstantiation.VfModule;
+import org.onap.vid.model.serviceInstantiation.Vnf;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class WatchingCommandBaseModule extends BaseWatchingCommand {
+ @Inject
+ protected JobsBrokerService jobsBrokerService;
+
+ @Inject
+ protected JobAdapter jobAdapter;
+ private static final EELFLoggerDelegate LOG = EELFLoggerDelegate.getLogger(WatchingCommandBaseModule.class);
+
+ public WatchingCommandBaseModule(
+ JobSharedData sharedData,
+ List<String> childrenJobsIds,
+ boolean isService,
+ CommandParentData commandParentData) {
+ super(sharedData, childrenJobsIds, isService);
+ this.commandParentData = commandParentData;
+ }
+
+ public WatchingCommandBaseModule() {
+
+ }
+
+ @Override
+ protected NextCommand getNextCommand(Job.JobStatus cumulativeJobsStatus) {
+
+ if (cumulativeJobsStatus== Job.JobStatus.IN_PROGRESS) {
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, this);
+ }
+
+ if(cumulativeJobsStatus==Job.JobStatus.FAILED || cumulativeJobsStatus==Job.JobStatus.COMPLETED_WITH_ERRORS){
+ return new NextCommand(Job.JobStatus.COMPLETED_WITH_ERRORS);
+ }
+ Vnf request = (Vnf) getSharedData().getRequest();
+ Map<String, Object> dataForChild = buildDataForChild();
+ //Create non-base Volume groups job
+ List<VfModule> vfModules = request.getVfModules().values().stream().flatMap(vfKey -> vfKey.values().stream()).collect(Collectors.toList());
+ List<String> vgNonBaseJobs = new ArrayList<>();
+ for( VfModule vfModule : vfModules){
+ try {
+ if(!commandUtils.isVfModuleBaseModule(commandParentData.getModelInfo(CommandDataKey.SERVICE_MODEL_INFO).getModelVersionId(), vfModule.getModelInfo().getModelVersionId())) {
+ vgNonBaseJobs.add(jobsBrokerService.add(
+ jobAdapter.createChildJob(JobType.VolumeGroupInstantiation, Job.JobStatus.CREATING, vfModule, getSharedData(), dataForChild)).toString());
+ }
+ } catch (AsdcCatalogException e) {
+ LOG.error("Failed to retrieve service definitions from SDC, for VfModule is BaseModule. Error: "+e.getMessage() , e);
+ return new NextCommand(Job.JobStatus.COMPLETED_WITH_ERRORS);
+ }
+ }
+ return new NextCommand(Job.JobStatus.RESOURCE_IN_PROGRESS, new WatchingCommand(getSharedData(), vgNonBaseJobs, false));
+ }
+
+ @Override
+ public WatchingCommandBaseModule init(JobSharedData sharedData, Map<String, Object> commandData) {
+ super.init(sharedData, commandData);
+ commandParentData.initParentData(commandData);
+ return this;
+ }
+
+ protected Map<String, Object> buildDataForChild() {
+ return commandParentData.getParentData();
+ }
+
+ @Override
+ public Map<String, Object> getData() {
+ return ImmutableMap.<String, Object>builder()
+ .putAll(super.getData())
+ .putAll(commandParentData.getParentData())
+ .build();
+ }
+
+
+}