aboutsummaryrefslogtreecommitdiffstats
path: root/vid-app-common/src/main/java/org/onap/vid/job
diff options
context:
space:
mode:
Diffstat (limited to 'vid-app-common/src/main/java/org/onap/vid/job')
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/Job.java28
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/JobAdapter.java11
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/JobCommand.java9
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/JobException.java16
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/JobType.java24
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/JobsBrokerService.java2
-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
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobAdapterImpl.java55
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobDaoImpl.java40
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobData.java54
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobSchedulerInitializer.java4
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobSharedData.java84
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobWorker.java35
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/impl/JobsBrokerServiceInDatabaseImpl.java75
47 files changed, 2378 insertions, 339 deletions
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/Job.java b/vid-app-common/src/main/java/org/onap/vid/job/Job.java
index 77f348dc6..144c96ca4 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/Job.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/Job.java
@@ -1,6 +1,7 @@
package org.onap.vid.job;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.onap.vid.job.impl.JobSharedData;
import java.util.Map;
import java.util.UUID;
@@ -18,30 +19,49 @@ public interface Job {
@JsonIgnore
Map<String, Object> getData();
+ JobSharedData getSharedData();
+
void setTypeAndData(JobType jobType, Map<String, Object> data);
UUID getTemplateId();
void setTemplateId(UUID templateId);
+ Integer getIndexInBulk();
+
void setIndexInBulk(Integer indexInBulk);
JobType getType();
enum JobStatus {
- COMPLETED(true),
- FAILED(true),
+ COMPLETED(true, false),
+ FAILED(true, true),
IN_PROGRESS(false),
+ RESOURCE_IN_PROGRESS(false),
PAUSE(false),
PENDING(false),
- STOPPED(true);
+ STOPPED(true, true),
+ COMPLETED_WITH_ERRORS(true, true),
+ COMPLETED_WITH_NO_ACTION(true, false),
+ CREATING(false);
private final Boolean finalStatus;
public Boolean isFinal(){return finalStatus;}
+ private final Boolean failure;
+ public Boolean isFailure() {
+ return failure;
+ }
+
JobStatus(Boolean finalStatus)
{
- this.finalStatus = finalStatus ;
+ this(finalStatus, false);
}
+
+ JobStatus(Boolean finalStatus, boolean failure) {
+ this.finalStatus = finalStatus;
+ this.failure = failure;
+ }
+
}
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/JobAdapter.java b/vid-app-common/src/main/java/org/onap/vid/job/JobAdapter.java
index 1701092b3..f281f98a0 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/JobAdapter.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/JobAdapter.java
@@ -1,9 +1,8 @@
package org.onap.vid.job;
-import org.onap.vid.model.JobBulk;
+import org.onap.vid.job.impl.JobSharedData;
import org.onap.vid.model.JobModel;
-import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -13,14 +12,12 @@ import java.util.UUID;
public interface JobAdapter {
JobModel toModel(Job job);
- JobBulk toModelBulk(List<Job> jobList);
+ Job createServiceInstantiationJob(JobType jobType, AsyncJobRequest request, UUID templateId, String userId, String optimisticUniqueServiceInstanceName, Integer indexInBulk);
- List<Job> createBulkOfJobs(Map<String, Object> bulkRequest);
-
- Job createJob(JobType jobType, AsyncJobRequest request, UUID templateId, String userId, Integer indexInBulk);
+ Job createChildJob(JobType jobType, Job.JobStatus jobStatus, AsyncJobRequest request, JobSharedData parentSharedData, Map<String, Object> jobData);
// Marks types that are an AsyncJob payload
- public interface AsyncJobRequest {
+ interface AsyncJobRequest {
}
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/JobCommand.java b/vid-app-common/src/main/java/org/onap/vid/job/JobCommand.java
index c32645cad..7f62bcac6 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/JobCommand.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/JobCommand.java
@@ -1,7 +1,8 @@
package org.onap.vid.job;
+import org.onap.vid.job.impl.JobSharedData;
+
import java.util.Map;
-import java.util.UUID;
/**
@@ -13,11 +14,11 @@ public interface JobCommand {
/**
* Initialize the command state
- * @param jobUuid Parent job's uuid
- * @param data An input to be set into the command. Each implementation may expect different keys in the map.
+ * @param sharedData shared data cross all job commands
+ * @param commandData An input to be set into the command. Each implementation may expect different keys in the map.
* @return Returns itself
*/
- default JobCommand init(UUID jobUuid, Map<String, Object> data) {
+ default JobCommand init(JobSharedData sharedData, Map<String, Object> commandData) {
return this;
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/JobException.java b/vid-app-common/src/main/java/org/onap/vid/job/JobException.java
new file mode 100644
index 000000000..ca389b039
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/JobException.java
@@ -0,0 +1,16 @@
+package org.onap.vid.job;
+
+import java.util.UUID;
+
+public class JobException extends RuntimeException {
+ private final UUID jobUuid;
+
+ public JobException(String message, UUID jobUuid, Throwable cause) {
+ super(message, cause);
+ this.jobUuid = jobUuid;
+ }
+
+ public UUID getJobUuid() {
+ return jobUuid;
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/JobType.java b/vid-app-common/src/main/java/org/onap/vid/job/JobType.java
index 9846d2775..e856ba0d4 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/JobType.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/JobType.java
@@ -6,15 +6,33 @@ import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static org.onap.vid.utils.Streams.not;
+
public enum JobType {
HttpCall(HttpCallCommand.class),
AggregateState(AggregateStateCommand.class),
- ServiceInstantiation(ServiceInstantiationCommand.class),
- InProgressStatus(InProgressStatusCommand.class),
+ ServiceInstantiation(MacroServiceInstantiationCommand.class),
+ MacroServiceInstantiation(MacroServiceInstantiationCommand.class),
+ ALaCarteServiceInstantiation(ALaCarteServiceInstantiationCommand.class),
+ ALaCarteService(ALaCarteServiceCommand.class),
+ VnfInstantiation(VnfInstantiationCommand.class),
+ VfmoduleInstantiation(VfmoduleInstantiationCommand.class),
+ VolumeGroupInstantiation(VolumeGroupInstantiationCommand.class),
+ VolumeGroupInProgressStatus(VolumeGroupInProgressStatusCommand.class),
+ NetworkInstantiation(NetworkInstantiationCommand.class),
+ InstanceGroupInstantiation(InstanceGroupInstantiationCommand.class),
+ InstanceGroup(InstanceGroupCommand.class),
+ InProgressStatus(ServiceInProgressStatusCommand.class),
+ ResourceInProgressStatus(ResourceInProgressStatusCommand.class),
+ VnfInProgressStatus(VnfInProgressStatusCommand.class),
+ Watching(WatchingCommand.class),
+ WatchingBaseModule(WatchingCommandBaseModule.class),
NoOp(NoOpCommand.class);
- private static final Map<Class, JobType> REVERSE_MAP = Stream.of(values()).collect(Collectors.toMap(t -> t.getCommandClass(), t -> t));
+ private static final Map<Class, JobType> REVERSE_MAP = Stream.of(values())
+ .filter(not(jobType -> jobType.equals(ServiceInstantiation)))
+ .collect(Collectors.toMap(t -> t.getCommandClass(), t -> t));
private final Class commandClass;
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/JobsBrokerService.java b/vid-app-common/src/main/java/org/onap/vid/job/JobsBrokerService.java
index 856f50b2e..98925d072 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/JobsBrokerService.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/JobsBrokerService.java
@@ -18,4 +18,6 @@ public interface JobsBrokerService {
void delete(UUID jobId);
+ boolean mute(UUID jobId);
+
}
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();
+ }
+
+
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobAdapterImpl.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobAdapterImpl.java
index 59f12f4c5..1050ab933 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobAdapterImpl.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobAdapterImpl.java
@@ -4,16 +4,11 @@ import com.google.common.collect.ImmutableMap;
import org.onap.vid.job.Job;
import org.onap.vid.job.JobAdapter;
import org.onap.vid.job.JobType;
-import org.onap.vid.model.JobBulk;
import org.onap.vid.model.JobModel;
import org.springframework.stereotype.Component;
-import javax.ws.rs.BadRequestException;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.stream.Collectors;
@Component
public class JobAdapterImpl implements JobAdapter {
@@ -28,44 +23,32 @@ public class JobAdapterImpl implements JobAdapter {
}
@Override
- public JobBulk toModelBulk(List<Job> jobList) {
- return new JobBulk(jobList.stream().map(this::toModel).collect(Collectors.toList()));
- }
-
- @Override
- public Job createJob(JobType jobType, AsyncJobRequest request, UUID templateId, String userId, Integer indexInBulk) {
- JobDaoImpl job = createJob(jobType, templateId, indexInBulk, ImmutableMap.of(
- "request", request,
- "userId", userId));
- job.setUserId(userId);
+ public Job createServiceInstantiationJob(JobType jobType, AsyncJobRequest request, UUID templateId, String userId, String optimisticUniqueServiceInstanceName, Integer indexInBulk){
+ JobDaoImpl job = createJob(jobType, Job.JobStatus.PENDING , userId);
+ job.setSharedData(new JobSharedData(job.getUuid(), userId, request));
+ job.setTypeAndData(jobType, ImmutableMap.of(
+ "optimisticUniqueServiceInstanceName", optimisticUniqueServiceInstanceName
+ ));
+ job.setTemplateId(templateId);
+ job.setIndexInBulk(indexInBulk);
return job;
}
@Override
- public List<Job> createBulkOfJobs(Map<String, Object> bulkRequest) {
- int count;
- JobType jobType;
-
- try {
- count = (Integer) bulkRequest.get("count");
- jobType = JobType.valueOf((String) bulkRequest.get("type"));
- } catch (Exception exception) {
- throw new BadRequestException(exception);
- }
- List<Job> jobList = new ArrayList<>(count + 1);
- UUID templateId = UUID.randomUUID();
- for (int i = 0; i < count; i++) {
- jobList.add(createJob(jobType, templateId, i, bulkRequest));
- }
- return jobList;
+ public Job createChildJob(JobType jobType, Job.JobStatus jobStatus, AsyncJobRequest request, JobSharedData parentSharedData, Map<String, Object> jobData) {
+ JobDaoImpl job = createJob(jobType, jobStatus , parentSharedData.getUserId());
+ job.setSharedData(new JobSharedData(job.getUuid(), request, parentSharedData));
+ job.setTypeAndData(jobType, jobData);
+ return job;
}
- private JobDaoImpl createJob(JobType jobType, UUID templateId, Integer indexInBulk, Map<String, Object> data) {
+ protected JobDaoImpl createJob(JobType jobType, Job.JobStatus jobStatus, String userId) {
JobDaoImpl job = new JobDaoImpl();
- job.setStatus(Job.JobStatus.PENDING);
- job.setTypeAndData(jobType, data);
- job.setTemplateId(templateId);
- job.setIndexInBulk(indexInBulk);
+ job.setTypeAndData(jobType, null);
+ job.setStatus(jobStatus);
+ job.setUuid(UUID.randomUUID());
+ job.setUserId(userId);
return job;
}
+
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobDaoImpl.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobDaoImpl.java
index 1ff1296c7..b301a2fbc 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobDaoImpl.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobDaoImpl.java
@@ -3,19 +3,31 @@ package org.onap.vid.job.impl;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.MoreObjects;
+import org.hibernate.annotations.DynamicUpdate;
+import org.hibernate.annotations.SelectBeforeUpdate;
import org.hibernate.annotations.Type;
import org.onap.vid.exceptions.GenericUncheckedException;
import org.onap.vid.job.Job;
+import org.onap.vid.job.JobException;
import org.onap.vid.job.JobType;
import org.onap.vid.model.VidBaseEntity;
import javax.persistence.*;
import java.io.IOException;
-import java.util.*;
-
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+
+/*
+ The following 2 annotations let hibernate to update only fields that actually have been changed.
+ DynamicUpdate tell hibernate to update only dirty fields.
+ SelectBeforeUpdate is needed since during update the entity is detached (get and update are in different sessions)
+*/
+@DynamicUpdate()
+@SelectBeforeUpdate()
@Entity
@Table(name = "vid_job")
public class JobDaoImpl extends VidBaseEntity implements Job {
@@ -23,7 +35,7 @@ public class JobDaoImpl extends VidBaseEntity implements Job {
private static ObjectMapper objectMapper = new ObjectMapper();
private Job.JobStatus status;
private JobType type;
- private Map<JobType, Map<String, Object>> data = new TreeMap<>();
+ private JobData data = new JobData();
private UUID templateId;
private UUID uuid;
private String takenBy;
@@ -83,16 +95,25 @@ public class JobDaoImpl extends VidBaseEntity implements Job {
public void setDataRaw(String data) {
try {
- this.data = objectMapper.readValue(data, new TypeReference<Map<JobType, Map<String, Object>>>() {
- });
+ this.data = objectMapper.readValue(data, JobData.class);
} catch (IOException e) {
- throw new GenericUncheckedException(e);
+ throw new JobException("Error parsing job's data", uuid, e);
}
}
@Transient
public Map<String, Object> getData() {
- return data.get(getType());
+ return data.getCommandData().get(getType());
+ }
+
+ public void setSharedData(JobSharedData sharedData) {
+ this.data.setSharedData(sharedData);
+ }
+
+ @Override
+ @Transient
+ public JobSharedData getSharedData() {
+ return this.data.getSharedData();
}
@Override
@@ -100,7 +121,7 @@ public class JobDaoImpl extends VidBaseEntity implements Job {
// *add* the data to map,
// then change state to given type
this.type = jobType;
- this.data.put(jobType, data);
+ this.data.getCommandData().put(jobType, data);
}
@Column(name = "TAKEN_BY")
@@ -123,6 +144,7 @@ public class JobDaoImpl extends VidBaseEntity implements Job {
this.templateId = templateId;
}
+ @Override
@Column(name="INDEX_IN_BULK")
public Integer getIndexInBulk() {
return indexInBulk;
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobData.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobData.java
new file mode 100644
index 000000000..0b7a6b7cf
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobData.java
@@ -0,0 +1,54 @@
+package org.onap.vid.job.impl;
+
+import org.onap.vid.job.JobType;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+
+public class JobData {
+
+ private TreeMap<JobType, Map<String, Object>> commandData;
+ private JobSharedData sharedData;
+
+ public JobData() {
+ commandData = new TreeMap<>();
+ sharedData = new JobSharedData();
+ }
+
+ public JobData(TreeMap<JobType, Map<String, Object>> commandData, JobSharedData sharedData) {
+ this.commandData = commandData;
+ this.sharedData = sharedData;
+ }
+
+ public TreeMap<JobType, Map<String, Object>> getCommandData() {
+ return commandData;
+ }
+
+ public void setCommandData(TreeMap<JobType, Map<String, Object>> commandData) {
+ this.commandData = commandData;
+ }
+
+ public JobSharedData getSharedData() {
+ return sharedData;
+ }
+
+ public void setSharedData(JobSharedData sharedData) {
+ this.sharedData = sharedData;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof JobData)) return false;
+ JobData jobData = (JobData) o;
+ return Objects.equals(getCommandData(), jobData.getCommandData()) &&
+ Objects.equals(getSharedData(), jobData.getSharedData());
+ }
+
+ @Override
+ public int hashCode() {
+
+ return Objects.hash(getCommandData(), getSharedData());
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSchedulerInitializer.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSchedulerInitializer.java
index a5070fbdf..59b2f250c 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSchedulerInitializer.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSchedulerInitializer.java
@@ -1,12 +1,12 @@
package org.onap.vid.job.impl;
import com.google.common.collect.ImmutableMap;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
import org.onap.vid.exceptions.GenericUncheckedException;
import org.onap.vid.job.Job;
import org.onap.vid.job.JobsBrokerService;
import org.onap.vid.job.command.JobCommandFactory;
import org.onap.vid.properties.Features;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@@ -46,7 +46,9 @@ public class JobSchedulerInitializer {
return;
}
scheduleJobWorker(Job.JobStatus.PENDING, 1);
+ scheduleJobWorker(Job.JobStatus.CREATING, 1);
scheduleJobWorker(Job.JobStatus.IN_PROGRESS, 1);
+ scheduleJobWorker(Job.JobStatus.RESOURCE_IN_PROGRESS, 1);
}
private void scheduleJobWorker(Job.JobStatus topic, int intervalInSeconds) {
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSharedData.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSharedData.java
new file mode 100644
index 000000000..8f1e45736
--- /dev/null
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobSharedData.java
@@ -0,0 +1,84 @@
+package org.onap.vid.job.impl;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.onap.vid.job.JobAdapter;
+
+import java.util.Objects;
+import java.util.UUID;
+
+public class JobSharedData {
+
+ protected UUID jobUuid;
+ protected String userId;
+ protected Class requestType;
+ protected UUID rootJobId;
+
+ @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, property="class")
+ protected JobAdapter.AsyncJobRequest request;
+
+ public JobSharedData() {
+ }
+
+ public JobSharedData(UUID jobUuid, String userId, JobAdapter.AsyncJobRequest request) {
+ this.jobUuid = jobUuid;
+ this.userId = userId;
+ this.requestType = request.getClass();
+ this.request = request;
+ this.rootJobId = jobUuid;
+ }
+
+ public JobSharedData(UUID jobUuid, JobAdapter.AsyncJobRequest request, JobSharedData parentData) {
+ this(jobUuid, parentData.getUserId(), request);
+ rootJobId = parentData.getRootJobId() != null ? parentData.getRootJobId() : parentData.getJobUuid();
+ }
+
+
+ public UUID getJobUuid() {
+ return jobUuid;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public Class getRequestType() {
+ return requestType;
+ }
+
+ public void setRequestType(Class requestType) {
+ this.requestType = requestType;
+ }
+
+ public JobAdapter.AsyncJobRequest getRequest() {
+ return request;
+ }
+
+ public void setRequest(JobAdapter.AsyncJobRequest request) {
+ this.request = request;
+ }
+
+ public UUID getRootJobId() {
+ return rootJobId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof JobSharedData)) return false;
+ JobSharedData that = (JobSharedData) o;
+ return Objects.equals(getJobUuid(), that.getJobUuid()) &&
+ Objects.equals(getUserId(), that.getUserId()) &&
+ Objects.equals(getRequestType(), that.getRequestType()) &&
+ Objects.equals(getRootJobId(), that.getRootJobId()) &&
+ Objects.equals(getRequest(), that.getRequest());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getJobUuid(), getUserId(), getRequestType(), getRootJobId(), getRequest());
+ }
+}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobWorker.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobWorker.java
index aa94a2aa0..36ec4314e 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobWorker.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobWorker.java
@@ -1,13 +1,11 @@
package org.onap.vid.job.impl;
import org.apache.commons.lang3.StringUtils;
-import org.onap.vid.job.Job;
-import org.onap.vid.job.JobCommand;
-import org.onap.vid.job.JobsBrokerService;
-import org.onap.vid.job.NextCommand;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.vid.job.*;
import org.onap.vid.job.command.JobCommandFactory;
import org.onap.vid.properties.Features;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
@@ -52,6 +50,8 @@ public class JobWorker extends QuartzJobBean {
return jobsBrokerService.pull(topic, UUID.randomUUID().toString());
} catch (Exception e) {
LOGGER.error(EELFLoggerDelegate.errorLogger, "failed to pull job from queue, breaking: {}", e, e);
+ tryMutingJobFromException(e);
+
return Optional.empty();
}
}
@@ -72,9 +72,7 @@ public class JobWorker extends QuartzJobBean {
NextCommand nextCommand = executeCommandAndGetNext(job);
- Job nextJob = setNextCommandInJob(nextCommand, job);
-
- return nextJob;
+ return setNextCommandInJob(nextCommand, job);
}
private NextCommand executeCommandAndGetNext(Job job) {
@@ -83,7 +81,7 @@ public class JobWorker extends QuartzJobBean {
final JobCommand jobCommand = jobCommandFactory.toCommand(job);
nextCommand = jobCommand.call();
} catch (Exception e) {
- LOGGER.error(EELFLoggerDelegate.errorLogger, "error while executing job from queue: {}", e, e);
+ LOGGER.error("error while executing job from queue: {}", e);
nextCommand = new NextCommand(FAILED);
}
@@ -114,6 +112,25 @@ public class JobWorker extends QuartzJobBean {
return featureManager.isActive(Features.FLAG_ASYNC_INSTANTIATION);
}
+ private void tryMutingJobFromException(Exception e) {
+ // If there's JobException in the stack, read job uuid from
+ // the exception, and mute it in DB.
+ final int indexOfJobException =
+ ExceptionUtils.indexOfThrowable(e, JobException.class);
+
+ if (indexOfJobException >= 0) {
+ try {
+ final JobException jobException = (JobException) ExceptionUtils.getThrowableList(e).get(indexOfJobException);
+ LOGGER.info(EELFLoggerDelegate.debugLogger, "muting job: {} ({})", jobException.getJobUuid(), jobException.toString());
+ final boolean success = jobsBrokerService.mute(jobException.getJobUuid());
+ if (!success) {
+ LOGGER.error(EELFLoggerDelegate.errorLogger, "failed to mute job {}", jobException.getJobUuid());
+ }
+ } catch (Exception e1) {
+ LOGGER.error(EELFLoggerDelegate.errorLogger, "failed to mute job: {}", e1, e1);
+ }
+ }
+ }
//used by quartz to inject JobsBrokerService into the job
//see JobSchedulerInitializer
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobsBrokerServiceInDatabaseImpl.java b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobsBrokerServiceInDatabaseImpl.java
index e286cc4aa..e87478794 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/impl/JobsBrokerServiceInDatabaseImpl.java
+++ b/vid-app-common/src/main/java/org/onap/vid/job/impl/JobsBrokerServiceInDatabaseImpl.java
@@ -2,15 +2,15 @@ package org.onap.vid.job.impl;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.SessionFactory;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.service.DataAccessService;
+import org.onap.portalsdk.core.util.SystemProperties;
import org.onap.vid.exceptions.GenericUncheckedException;
import org.onap.vid.exceptions.OperationNotAllowedException;
import org.onap.vid.job.Job;
import org.onap.vid.job.JobsBrokerService;
import org.onap.vid.properties.VidProperties;
import org.onap.vid.utils.DaoUtils;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.onap.portalsdk.core.service.DataAccessService;
-import org.onap.portalsdk.core.util.SystemProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -21,6 +21,8 @@ import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
+import static org.onap.vid.job.Job.JobStatus.CREATING;
+
@Service
public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
@@ -56,7 +58,6 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
@Override
public UUID add(Job job) {
final JobDaoImpl jobDao = castToJobDaoImpl(job);
- jobDao.setUuid(UUID.randomUUID());
dataAccessService.saveDomainObject(jobDao, DaoUtils.getPropsMap());
return job.getUuid();
}
@@ -102,23 +103,30 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
return Timestamp.valueOf(LocalDateTime.now().minusSeconds(pollingIntervalSeconds));
}
+ private String selectQueryByJobStatus(Job.JobStatus topic){
+
+ String intervalCondition = (topic==CREATING) ? "" : (" and MODIFIED_DATE <= '" + nowMinusInterval()+"'");
+ return "" +
+ "select * from VID_JOB" +
+ " where" +
+ // select only non-deleted in-progress jobs
+ " JOB_STATUS = '" + topic + "'" +
+ " and TAKEN_BY is null" +
+ " and DELETED_AT is null" +
+ // give some breath, don't select jos that were recently reached
+ intervalCondition +
+ // take the oldest handled one
+ " order by MODIFIED_DATE ASC" +
+ // select only one result
+ " limit 1";
+ }
+
private String sqlQueryForTopic(Job.JobStatus topic) {
switch (topic) {
case IN_PROGRESS:
- return "" +
- "select * from VID_JOB" +
- " where" +
- // select only non-deleted in-progress jobs
- " JOB_STATUS = 'IN_PROGRESS'" +
- " and TAKEN_BY is null" +
- " and DELETED_AT is null" +
- // give some breath, don't select jos that were recently reached
- " and MODIFIED_DATE <= '" + nowMinusInterval() +
- // take the oldest handled one
- "' order by MODIFIED_DATE ASC" +
- // select only one result
- " limit 1";
-
+ case RESOURCE_IN_PROGRESS:
+ case CREATING:
+ return selectQueryByJobStatus(topic);
case PENDING:
return "" +
// select only pending jobs
@@ -137,9 +145,10 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
// don't take jobs from templates that already in-progress/failed
"and TEMPLATE_Id not in \n" +
"(select TEMPLATE_Id from vid_job where" +
+ " TEMPLATE_Id IS NOT NULL and("+
" (JOB_STATUS='FAILED' and DELETED_AT is null)" + // failed but not deleted
" or JOB_STATUS='IN_PROGRESS'" +
- " or TAKEN_BY IS NOT NULL)" + " \n " +
+ " or TAKEN_BY IS NOT NULL))" + " \n " +
// prefer older jobs, but the earlier in each bulk
"order by has_any_in_progress_job, CREATED_DATE, INDEX_IN_BULK " +
// select only one result
@@ -233,4 +242,32 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
throw new OperationNotAllowedException("Service deletion failed");
}
}
+
+ @Override
+ public boolean mute(UUID jobId) {
+ if (jobId == null) {
+ return false;
+ }
+
+ final String prefix = "DUMP";
+ int updatedEntities;
+
+ // Changing the topic (i.e. `job.status`) makes the job non-fetchable.
+ String hqlUpdate = "" +
+ "update JobDaoImpl job set" +
+ " job.status = concat('" + prefix + "_', job.status)," +
+ // empty `takenBy`, because some logics treat taken as in-progress
+ " takenBy = null" +
+ " where " +
+ " job.id = :id" +
+ // if prefix already on the topic -- no need to do it twice.
+ " and job.status NOT LIKE '" + prefix + "\\_%'";
+
+ updatedEntities = DaoUtils.tryWithSessionAndTransaction(sessionFactory, session ->
+ session.createQuery(hqlUpdate)
+ .setText("id", jobId.toString())
+ .executeUpdate());
+
+ return updatedEntities != 0;
+ }
}