Pause Upon VF Module Failure 87/110387/12
authorPATTANAYAK, SAUMYA SWARUP (sp931a) <sp931a@att.com>
Thu, 13 Aug 2020 16:35:01 +0000 (12:35 -0400)
committerPATTANAYAK, SAUMYA SWARUP (sp931a) <sp931a@att.com>
Mon, 31 Aug 2020 19:06:10 +0000 (15:06 -0400)
Issue-ID: VID-862

Currently in VID, once a failure is received from SO on the
instantiation of a VF Module, it is assumed that other VF Modules may
continue with the execution without stopping. However, in most of the
cases, it is a good idea to stop further requests to SO if one of the VF
Module instantiation returns an error. This user story, makes sure this
functionality is achieved.

Change-Id: I07c51b81111f805b61c8b3714a65171d7cbaa254
Signed-off-by: PATTANAYAK, SAUMYA SWARUP (sp931a) <sp931a@att.com>
20 files changed:
vid-app-common/src/main/java/org/onap/vid/job/Job.java
vid-app-common/src/main/java/org/onap/vid/job/command/WatchChildrenJobsBL.kt
vid-app-common/src/main/java/org/onap/vid/job/impl/JobsBrokerServiceInDatabaseImpl.java
vid-app-common/src/main/java/org/onap/vid/properties/Features.java
vid-app-common/src/main/java/org/onap/vid/services/AsyncInstantiationBusinessLogicImpl.java
vid-app-common/src/main/webapp/WEB-INF/conf/dev.features.properties
vid-app-common/src/test/java/org/onap/vid/config/JobCommandsConfigWithMockedMso.java
vid-app-common/src/test/java/org/onap/vid/job/command/WatchChildrenJobsBLTest.java
vid-app-common/src/test/java/org/onap/vid/services/JobsBrokerServiceTest.java
vid-automation/src/main/java/org/onap/vid/api/AsyncInstantiationBase.java
vid-automation/src/main/java/org/onap/vid/api/CreateServiceWithFailedVnf.java
vid-automation/src/main/java/vid/automation/test/infra/Features.java
vid-automation/src/main/java/vid/automation/test/model/JobStatus.java
vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest.java
vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest3.java
vid-automation/src/test/resources/features.properties
vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts
vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts
vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts
vid-webpack-master/src/app/shared/models/serviceInstanceActions.ts

index 9861d07..230e70f 100644 (file)
@@ -68,6 +68,7 @@ public interface Job {
         CREATING(false),
         PENDING_RESOURCE(false),
         COMPLETED_AND_PAUSED(true, false),
+        FAILED_AND_PAUSED(true, true),
         ;
 
         private final Boolean finalStatus;
index 502d834..09357e5 100644 (file)
@@ -25,9 +25,11 @@ 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.properties.Features
 import org.onap.vid.utils.DaoUtils
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
+import org.togglz.core.manager.FeatureManager
 import java.util.*
 import java.util.stream.Collectors
 import java.util.stream.Stream
@@ -35,7 +37,7 @@ import java.util.stream.Stream
 
 @Service
 class WatchChildrenJobsBL @Autowired
-constructor(private val dataAccessService: DataAccessService) {
+constructor(private val dataAccessService: DataAccessService, private val featureManager: FeatureManager) {
 
     fun retrieveChildrenJobsStatus(childrenJobsIds: List<String>): Job.JobStatus {
         val jobs = getAllChildrenJobs(childrenJobsIds)
@@ -47,14 +49,16 @@ constructor(private val dataAccessService: DataAccessService) {
                     else -> it.status
                 }}
 
-        return cumulateJobStatus(jobsStatuses)
+        return if(featureManager.isActive(Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE))
+            cumulateJobStatusWithPauseOnFailure(jobsStatuses) else cumulateJobStatus(jobsStatuses)
 
     }
 
     fun cumulateJobStatus(childrenComulatedStatus: Job.JobStatus, fatherJobStatus: Job.JobStatus): Job.JobStatus {
-        return cumulateJobStatus(Stream.of(childrenComulatedStatus, fatherJobStatus))
+        return if(featureManager.isActive(Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE))
+            cumulateJobStatusWithPauseOnFailure(Stream.of(childrenComulatedStatus, fatherJobStatus))
+                else cumulateJobStatus(Stream.of(childrenComulatedStatus, fatherJobStatus))
     }
-
     private fun cumulateJobStatus(jobsStatuses: Stream<Job.JobStatus>): Job.JobStatus {
 
         return jobsStatuses.reduce{ a, b ->
@@ -70,7 +74,21 @@ constructor(private val dataAccessService: DataAccessService) {
             }
         } .orElse(COMPLETED_WITH_NO_ACTION)
   }
+    private fun cumulateJobStatusWithPauseOnFailure(jobsStatuses: Stream<Job.JobStatus>): Job.JobStatus {
 
+        return jobsStatuses.reduce{ a, b ->
+            when {
+                a == FAILED_AND_PAUSED || b == FAILED_AND_PAUSED-> FAILED_AND_PAUSED
+                a == COMPLETED && b.isFailure -> FAILED_AND_PAUSED
+                b == COMPLETED && a.isFailure -> FAILED_AND_PAUSED
+                !a.isFinal || !b.isFinal -> IN_PROGRESS
+                a == COMPLETED_AND_PAUSED || b == COMPLETED_AND_PAUSED -> COMPLETED_AND_PAUSED
+                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 }))
index 5180389..7391f41 100644 (file)
@@ -45,12 +45,14 @@ 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.Features;
 import org.onap.vid.properties.VidProperties;
 import org.onap.vid.services.VersionService;
 import org.onap.vid.utils.DaoUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.togglz.core.manager.FeatureManager;
 
 @Service
 public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
@@ -64,19 +66,21 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
     private int pollingIntervalSeconds;
 
     private final VersionService versionService;
-
+    private final FeatureManager featureManager;
     @Autowired
     public JobsBrokerServiceInDatabaseImpl(DataAccessService dataAccessService,
                                            SessionFactory sessionFactory,
                                            @Value("0") int maxOpenedInstantiationRequestsToMso,
                                            @Value("10") int pollingIntervalSeconds,
-                                           VersionService versionService) {
+                                           VersionService versionService,
+                                           FeatureManager featureManager) {
         // tha @Value will inject conservative defaults; overridden in @PostConstruct from configuration
         this.dataAccessService = dataAccessService;
         this.sessionFactory = sessionFactory;
         this.maxOpenedInstantiationRequestsToMso = maxOpenedInstantiationRequestsToMso;
         this.pollingIntervalSeconds = pollingIntervalSeconds;
         this.versionService = versionService;
+        this.featureManager = featureManager;
     }
 
     @PostConstruct
@@ -199,7 +203,7 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
                 "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
+                "   (JOB_STATUS IN('FAILED','FAILED_AND_PAUSED') and DELETED_AT is null)" + // failed but not deleted
                 "   or JOB_STATUS='IN_PROGRESS'" +
                 "   or TAKEN_BY IS NOT NULL))" + " \n " +
                 // prefer older jobs, but the earlier in each bulk
@@ -232,13 +236,24 @@ public class JobsBrokerServiceInDatabaseImpl implements JobsBrokerService {
                 "    and in_progress_count is NULL \n" +
                 //and that have valid templateId
                 "    and JOB.template_id is not NULL \n"+
-                ")\n" +
+
+                filterFailedStatusForPendingResource()
+
+                + ")" +
                 //INDEX_IN_BULK is for order them inside same templateId,
                 //template_id - for order between different templateId (just to be deterministic)
                 "order by INDEX_IN_BULK,JOB.template_id \n" +
                 "limit 1;";
     }
-
+    private String filterFailedStatusForPendingResource() {
+        String sql = "and JOB.template_id not in \n" +
+                "(select TEMPLATE_Id from vid_job where" +
+                "   TEMPLATE_Id IS NOT NULL and (JOB_STATUS IN('FAILED','FAILED_AND_PAUSED') "
+                + " AND JOB_TYPE NOT IN('NetworkInstantiation','InstanceGroup','InstanceGroupMember') and DELETED_AT is null)" + // failed but not deleted
+                "   or TAKEN_BY IS NOT NULL)";
+        return featureManager.isActive(Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE) ?
+                sql : "";
+    }
 
     @Override
     public void pushBack(Job job) {
index f863b30..9d3faa0 100644 (file)
@@ -102,6 +102,7 @@ public enum Features implements Feature {
     FLAG_2008_CREATE_VFMODULE_INSTANTIATION_ORDER_NUMBER,
     FLAG_2008_PAUSE_INSTANTIATION_ON_VFMODULE_POPUP,
     FLAG_2008_REMOVE_PAUSE_INSTANTIATION,
+    FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE,
     ;
 
     public boolean isActive() {
index 9180197..bf0344c 100644 (file)
@@ -436,7 +436,7 @@ public class AsyncInstantiationBusinessLogicImpl implements
 
     private boolean isRetryEnabledForStatus(JobStatus jobStatus) {
         return jobStatus==JobStatus.COMPLETED_AND_PAUSED || (featureManager.isActive(Features.FLAG_1902_RETRY_JOB) &&
-                (jobStatus==JobStatus.COMPLETED_WITH_ERRORS || jobStatus==JobStatus.FAILED));
+                (jobStatus==JobStatus.COMPLETED_WITH_ERRORS || jobStatus==JobStatus.FAILED || jobStatus==JobStatus.FAILED_AND_PAUSED));
     }
 
     private void setServiceInfoStatus(ServiceInfo serviceInfo, JobStatus jobStatus) {
index 92be1c7..2c73281 100644 (file)
@@ -34,3 +34,4 @@ FLAG_SHOW_ORCHESTRATION_TYPE = false
 FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE = false
 FLAG_2002_ANY_ALACARTE_BESIDES_EXCLUDED_NEW_INSTANTIATION_UI = false
 FLAG_GUILIN_CHANGEMG_SUBMIT_TO_SO = true
+FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE = false
\ No newline at end of file
index 468fb41..ecec705 100644 (file)
@@ -79,7 +79,7 @@ public class JobCommandsConfigWithMockedMso {
 
     @Bean
     public JobsBrokerService jobsBrokerService(DataAccessService dataAccessService, SessionFactory sessionFactory, VersionService versionService) {
-        return new JobsBrokerServiceInDatabaseImpl(dataAccessService, sessionFactory, 200, 0,versionService);
+        return new JobsBrokerServiceInDatabaseImpl(dataAccessService, sessionFactory, 200, 0,versionService,featureManager());
     }
 
     @Bean
@@ -314,7 +314,7 @@ public class JobCommandsConfigWithMockedMso {
 
     @Bean
     public WatchChildrenJobsBL watchChildrenJobsService(DataAccessService dataAccessService) {
-        return new WatchChildrenJobsBL(dataAccessService);
+        return new WatchChildrenJobsBL(dataAccessService,featureManager());
     }
 
 }
index fad32bb..a8613f7 100644 (file)
@@ -37,10 +37,12 @@ import org.mockito.MockitoAnnotations;
 import org.onap.portalsdk.core.service.DataAccessService;
 import org.onap.vid.job.Job.JobStatus;
 import org.onap.vid.job.impl.JobDaoImpl;
+import org.onap.vid.properties.Features;
 import org.onap.vid.utils.DaoUtils;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
+import org.togglz.core.manager.FeatureManager;
 
 public class WatchChildrenJobsBLTest {
     @Mock
@@ -49,6 +51,9 @@ public class WatchChildrenJobsBLTest {
     @InjectMocks
     private WatchChildrenJobsBL watchChildrenJobsBL;
 
+    @Mock
+    private static FeatureManager featureManager;
+
     @BeforeClass
     public void initMocks() {
         MockitoAnnotations.initMocks(this);
@@ -80,16 +85,16 @@ public class WatchChildrenJobsBLTest {
                 {Arrays.asList(JobStatus.COMPLETED, JobStatus.COMPLETED), JobStatus.COMPLETED},
                 {Arrays.asList(JobStatus.COMPLETED, JobStatus.COMPLETED_WITH_NO_ACTION), JobStatus.COMPLETED},
                 {Arrays.asList(JobStatus.FAILED, JobStatus.COMPLETED_WITH_NO_ACTION), JobStatus.FAILED},
-                {Arrays.asList(JobStatus.FAILED, JobStatus.COMPLETED), JobStatus.COMPLETED_WITH_ERRORS},
+                {Arrays.asList(JobStatus.FAILED, JobStatus.COMPLETED), getErrorStatus()},
                 {Arrays.asList(JobStatus.RESOURCE_IN_PROGRESS, JobStatus.FAILED), JobStatus.IN_PROGRESS},
                 {Arrays.asList(JobStatus.PAUSE, JobStatus.FAILED), JobStatus.IN_PROGRESS},
                 {Arrays.asList(JobStatus.PENDING, JobStatus.FAILED), JobStatus.IN_PROGRESS},
                 {Arrays.asList(JobStatus.IN_PROGRESS, JobStatus.COMPLETED), JobStatus.IN_PROGRESS},
                 {Arrays.asList(JobStatus.IN_PROGRESS, JobStatus.IN_PROGRESS),  JobStatus.IN_PROGRESS},
-                {Arrays.asList(JobStatus.COMPLETED, JobStatus.COMPLETED_WITH_ERRORS), JobStatus.COMPLETED_WITH_ERRORS},
-                {Arrays.asList(JobStatus.COMPLETED_WITH_ERRORS, JobStatus.FAILED), JobStatus.COMPLETED_WITH_ERRORS},
-                {Arrays.asList(JobStatus.COMPLETED_WITH_ERRORS, JobStatus.COMPLETED_WITH_ERRORS), JobStatus.COMPLETED_WITH_ERRORS},
-                {Arrays.asList(JobStatus.COMPLETED_WITH_ERRORS, JobStatus.COMPLETED_WITH_NO_ACTION), JobStatus.COMPLETED_WITH_ERRORS},
+                {Arrays.asList(JobStatus.COMPLETED, getErrorStatus()), getErrorStatus()},
+                {Arrays.asList(getErrorStatus(), JobStatus.FAILED), getErrorStatus()},
+                {Arrays.asList(getErrorStatus(), getErrorStatus()), getErrorStatus()},
+                {Arrays.asList(getErrorStatus(), JobStatus.COMPLETED_WITH_NO_ACTION), getErrorStatus()},
                 {Arrays.asList(JobStatus.COMPLETED_WITH_NO_ACTION, JobStatus.COMPLETED_WITH_NO_ACTION), JobStatus.COMPLETED_WITH_NO_ACTION},
                 {Arrays.asList(JobStatus.COMPLETED_AND_PAUSED, JobStatus.RESOURCE_IN_PROGRESS), JobStatus.IN_PROGRESS},
                 {Arrays.asList(JobStatus.COMPLETED_AND_PAUSED, JobStatus.COMPLETED), JobStatus.COMPLETED_AND_PAUSED},
@@ -117,4 +122,8 @@ public class WatchChildrenJobsBLTest {
     public void whenCumulate2JobStatus_thenResultAsExpected(List<JobStatus> jobs, JobStatus expectedChildrenJobsStatus) {
         assertEquals(expectedChildrenJobsStatus, watchChildrenJobsBL.cumulateJobStatus(jobs.get(0), jobs.get(1)));
     }
+    private static JobStatus getErrorStatus() {
+        return featureManager.isActive(Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE) ?
+            JobStatus.FAILED_AND_PAUSED : JobStatus.COMPLETED_WITH_ERRORS;
+    }
 }
index 00b2b95..df8f503 100644 (file)
@@ -103,6 +103,7 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
+import org.togglz.core.manager.FeatureManager;
 
 @ContextConfiguration(classes = {DataSourceConfig.class, SystemProperties.class, JobAdapterConfig.class})
 public class JobsBrokerServiceTest extends AbstractTestNGSpringContextTests {
@@ -124,6 +125,9 @@ public class JobsBrokerServiceTest extends AbstractTestNGSpringContextTests {
     private static final String DELETE_SERVICE_NOT_EXIST_EXCEPTION_MESSAGE = "Service does not exist";
     private JobsBrokerService broker;
 
+    @Mock
+    private FeatureManager featureManager;
+
     @Inject
     JobAdapter jobAdapter;
     @Inject
@@ -144,7 +148,7 @@ public class JobsBrokerServiceTest extends AbstractTestNGSpringContextTests {
     public void initializeBroker() {
         MockitoAnnotations.initMocks(this);
         when(versionService.retrieveBuildNumber()).thenReturn("aBuildNumber");
-        broker = new JobsBrokerServiceInDatabaseImpl(dataAccessService, sessionFactory, 200, 0, versionService);
+        broker = new JobsBrokerServiceInDatabaseImpl(dataAccessService, sessionFactory, 200, 0, versionService, featureManager);
         ((JobsBrokerServiceInDatabaseImpl) broker).deleteAll();
     }
 
@@ -607,7 +611,7 @@ public class JobsBrokerServiceTest extends AbstractTestNGSpringContextTests {
 
     @Test(dataProvider = "jobs")
     public void givenSomeJobs_pullNextJob_returnNextOrNothingAsExpected(List<Jobber> jobbers, int msoLimit, int expectedIndexSelected, Job.JobStatus topic, String assertionReason) {
-        JobsBrokerServiceInDatabaseImpl aBroker = new JobsBrokerServiceInDatabaseImpl(dataAccessService, sessionFactory, msoLimit, 20, versionService);
+        JobsBrokerServiceInDatabaseImpl aBroker = new JobsBrokerServiceInDatabaseImpl(dataAccessService, sessionFactory, msoLimit, 20, versionService, featureManager);
         final List<JobDaoImpl> jobs = addJobsWithModifiedDate(jobbers, aBroker);
         Optional<Job> nextJob = aBroker.pull(topic, UUID.randomUUID().toString());
         boolean shouldAnyBeSelected = expectedIndexSelected >= 0;
index f4dd678..e5da62a 100644 (file)
@@ -135,7 +135,8 @@ public class AsyncInstantiationBase extends BaseMsoApiTest {
     }
 
     protected boolean getExpectedRetryEnabled(JobStatus jobStatus) {
-        return Features.FLAG_1902_RETRY_JOB.isActive() && (jobStatus==JobStatus.FAILED || jobStatus==JobStatus.COMPLETED_WITH_ERRORS);
+        return Features.FLAG_1902_RETRY_JOB.isActive() && (jobStatus==JobStatus.FAILED || jobStatus==JobStatus.COMPLETED_WITH_ERRORS
+                || jobStatus==JobStatus.FAILED_AND_PAUSED);
     }
 
     public List<BasePreset> getPresets(List<PresetMSOBaseDelete> presetOnDeleteList, List<PresetMSOBaseCreateInstancePost> presetOnCreateList, List<PresetMSOOrchestrationRequestGet> presetInProgressList) {
@@ -203,7 +204,7 @@ public class AsyncInstantiationBase extends BaseMsoApiTest {
         return ImmutableList.of(
                 vidAuditStatus(jobId, "PENDING", false),
                 vidAuditStatus(jobId, "IN_PROGRESS", false),
-                vidAuditStatus(jobId, "COMPLETED_WITH_ERRORS", true)
+                vidAuditStatus(jobId, "COMPLETED_WITH_ERROR", true)
         );
     }
 
@@ -214,7 +215,13 @@ public class AsyncInstantiationBase extends BaseMsoApiTest {
                 vidAuditStatus(jobId, "FAILED", true)
         );
     }
-
+    protected ImmutableList<JobAuditStatus> vidAuditStatusesFailedAndPaused(String jobId) {
+        return ImmutableList.of(
+                vidAuditStatus(jobId, "PENDING", false),
+                vidAuditStatus(jobId, "IN_PROGRESS", false),
+                vidAuditStatus(jobId, "FAILED_AND_PAUSED", true)
+        );
+    }
     protected JobAuditStatus vidAuditStatus(String jobId, String jobStatus, boolean isFinal) {
         return new JobAuditStatus(UUID.fromString(jobId), jobStatus, JobAuditStatus.SourceStatus.VID, null, null, isFinal);
     }
@@ -578,4 +585,8 @@ public class AsyncInstantiationBase extends BaseMsoApiTest {
             org.junit.Assert.assertEquals("MSO instanceType  #" + i + " is not as expected", expectedStatus.getInstanceType(), actualStatus.getInstanceType());
         });
     }
+    protected static JobStatus getErrorStatus() {
+            return Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() ?
+                            JobStatus.FAILED_AND_PAUSED : JobStatus.COMPLETED_WITH_ERRORS;
+   }
 }
index 30076a9..a8bcc9f 100644 (file)
@@ -13,6 +13,7 @@ import org.onap.simulator.presetGenerator.presets.sdc.PresetSDCGetServiceToscaMo
 import org.onap.vid.model.asyncInstantiation.ServiceInfo;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import vid.automation.test.infra.Features;
 import vid.automation.test.infra.ModelInfo;
 import vid.automation.test.model.JobStatus;
 import vid.automation.test.model.ServiceAction;
@@ -105,9 +106,13 @@ Legit Preset  ||  deploy 1 Service, 1 VNF which will fail
     public void firstTimeAssertion() {
         assertThat(uuids, hasSize(1));
         originalJobId = uuids.get(0);
+        boolean isPauseOnFailureFlagOn = Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive();
 
-        asyncInstantiationBase.assertServiceInfoSpecific1(originalJobId, JobStatus.COMPLETED_WITH_ERRORS, names.get(SERVICE_NAME), "us16807000", firstIds.serviceId, ServiceAction.INSTANTIATE);
-        asyncInstantiationBase.assertAuditStatuses(originalJobId, asyncInstantiationBase.vidAuditStatusesCompletedWithErrors(originalJobId),null);
+        asyncInstantiationBase.assertServiceInfoSpecific1(originalJobId, isPauseOnFailureFlagOn ?
+                JobStatus.FAILED_AND_PAUSED : JobStatus.COMPLETED_WITH_ERRORS, names.get(SERVICE_NAME), "us16807000", firstIds.serviceId, ServiceAction.INSTANTIATE);
+        asyncInstantiationBase.assertAuditStatuses(originalJobId, isPauseOnFailureFlagOn ?
+                asyncInstantiationBase.vidAuditStatusesFailedAndPaused(originalJobId) :
+                asyncInstantiationBase.vidAuditStatusesCompletedWithErrors(originalJobId),null);
         assertThat(SimulatorApi.retrieveRecordedRequestsPathCounter(), allOf(
                 hasOrLacksOfEntry(createPresets.get(0).getReqPath(), 1L),
                 hasOrLacksOfEntry(createPresets.get(1).getReqPath(), 1L),
index 3e499de..ba7ebdf 100644 (file)
@@ -71,6 +71,7 @@ public enum Features implements Feature {
     FLAG_2008_CREATE_VFMODULE_INSTANTIATION_ORDER_NUMBER,
     FLAG_2008_PAUSE_INSTANTIATION_ON_VFMODULE_POPUP,
     FLAG_2008_REMOVE_PAUSE_INSTANTIATION,
+    FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE,
     ;
     public boolean isActive() {
         return FeatureContext.getFeatureManager().isActive(this);
index bbe1e3e..cfe32bc 100644 (file)
@@ -9,5 +9,6 @@ public enum JobStatus {
     PENDING,
     STOPPED,
     COMPLETED_AND_PAUSED,
-    COMPLETED_WITH_ERRORS;
+    COMPLETED_WITH_ERRORS,
+    FAILED_AND_PAUSED;
 }
index 20fce40..c032d5f 100644 (file)
@@ -208,7 +208,7 @@ public class AsyncInstantiationALaCarteApiTest extends AsyncInstantiationBase {
 
         assertThat(uuids, hasSize(1));
         final String jobId = uuids.get(0);
-        assertServiceInfoSpecificDeletion(jobId, JobStatus.COMPLETED_WITH_ERRORS, "SERVICE_INSTANCE_NAME", "service-instance-type");
+        assertServiceInfoSpecificDeletion(jobId, getErrorStatus(), "SERVICE_INSTANCE_NAME", "service-instance-type");
         assertThat(SimulatorApi.retrieveRecordedRequestsPathCounter(), allOf(
                 TestUtils.hasOrLacksOfEntry(deletePresets.get(0).getReqPath(), 1L),
                 TestUtils.hasOrLacksOfEntry(deletePresets.get(1).getReqPath(), 1L),
@@ -324,29 +324,42 @@ public class AsyncInstantiationALaCarteApiTest extends AsyncInstantiationBase {
         String parentServiceInstanceId = "service-instance-id";
         String vnfGroupToDeleteInstanceId = "VNF_GROUP1_INSTANCE_ID";
 
+        SimulatorApi.clearExpectations();
+
         //failed to create vnf group, failed to remove 1 member (and then also vnf group isn't deleted)
         viewEditVnfGroup_registerPresets(parentServiceInstanceId, vnfGroupToDeleteInstanceId, MSO_FAILED_STATUS);
 
         final List<String> uuids = createBulkOfInstances(false, 1, ImmutableMap.of(), VIEW_EDIT_VNF_GROUPS_REQUEST);
 
+        try {
+            Thread.sleep(20000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
         assertThat(uuids, hasSize(1));
         final String jobId = uuids.get(0);
 
-        assertServiceInfoSpecificUpdate(jobId, JobStatus.COMPLETED_WITH_ERRORS, "SERVICE_INSTANCE_NAME");
-        assertExpectedStatus(JobStatus.COMPLETED_WITH_ERRORS, jobId);
+        assertServiceInfoSpecificUpdate(jobId, getErrorStatus(), "SERVICE_INSTANCE_NAME");
+        assertExpectedStatus(getErrorStatus(), jobId);
         Map<String, Long> recordedRequest = SimulatorApi.retrieveRecordedRequestsPathCounter();
         assertThat(recordedRequest, allOf(
                 TestUtils.hasOrLacksOfEntry("/mso/serviceInstantiation/v./instanceGroups/" + vnfGroupToDeleteInstanceId, 0L), //delete vnf group
                 TestUtils.hasOrLacksOfEntry("/mso/serviceInstantiation/v./instanceGroups", 1L), //create vnf group
                 TestUtils.hasOrLacksOfEntry("/mso/serviceInstantiation/v./instanceGroups/" + vnfGroupToDeleteInstanceId + "/removeMembers", 3L) //remove vnf group members
         ));
-
+        SimulatorApi.clearExpectations();
         //retry - vnf group create, 1 member remove, vnf group delete
         viewEditVnfGroup_registerPresets(parentServiceInstanceId, vnfGroupToDeleteInstanceId, MSO_COMPLETE_STATUS);
         final List<String> retryUuids = retryJob(jobId);
         assertThat(retryUuids, hasSize(1));
         final String retryJobId = retryUuids.get(0);
 
+        try {
+            Thread.sleep(20000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
         assertServiceInfoSpecificUpdate(retryJobId, JobStatus.COMPLETED, "SERVICE_INSTANCE_NAME");
         assertExpectedStatus(JobStatus.COMPLETED, retryJobId);
         assertThat(SimulatorApi.retrieveRecordedRequestsPathCounter(), allOf(
@@ -406,26 +419,67 @@ public class AsyncInstantiationALaCarteApiTest extends AsyncInstantiationBase {
 
     @DataProvider
     Object[][] data_deploy1ServiceFromCypress__verifyStatusAndMsoCalls() {
-        return Features.FLAG_ASYNC_ALACARTE_VFMODULE.isActive() ? new Object[][]{
-                {"none", emptyMap(), emptyMap(), true},
-                {"none", emptyMap(), emptyMap(), false},
-                {"instance",  ImmutableMap.of("vnfs", 0L, "networks", 0L, "vfModules", 0L, "volumeGroups", 0L),
-                        ImmutableMap.of("serviceInstances", 1L, "vnfs", 1L, "networks", 1L, "vfModules", 3L, "volumeGroups", 1L),true},
-                {"network", emptyMap(),
-                        ImmutableMap.of("networks", 1L), true},
-                {"vnf0", ImmutableMap.of("vfModules", 0L, "volumeGroups", 0L),
-                        ImmutableMap.of("vnfs", 1L, "vfModules", 3L, "volumeGroups", 1L), true},
-                {"vfModule0", ImmutableMap.of("vfModules", 1L, "volumeGroups", 0L),
-                        ImmutableMap.of("vfModules", 3L, "volumeGroups", 1L), true},
-                {"volumeGroup", ImmutableMap.of("vfModules", 2L),
-                        ImmutableMap.of("vfModules", 1L, "volumeGroups", 1L), true},
-                {"vfModule1", emptyMap(),
-                        ImmutableMap.of("vfModules", 1L, "volumeGroups", 1L), true},
-                {"vfModule2", emptyMap(),
-                        ImmutableMap.of("vfModules", 1L), true}
-        } : new Object[][]{
-                {"none", ImmutableMap.of("vfModules", 0L, "volumeGroups", 0L), emptyMap(), true}
-        };
+        boolean isAsyncAlacarteVfModuleWithPauseOnFailure = Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() &&
+                Features.FLAG_ASYNC_ALACARTE_VFMODULE.isActive() ;
+
+        if(isAsyncAlacarteVfModuleWithPauseOnFailure) {
+            return new Object[][] {
+                    {"none", ImmutableMap.of("vfModules", 3L), emptyMap() , true},
+                    {"none", ImmutableMap.of("vfModules", 3L), emptyMap() , false},
+                    {"instance",
+                            ImmutableMap.of("vnfs", 0L, "networks", 0L, "vfModules", 0L, "volumeGroups", 0L),
+                            ImmutableMap.of("serviceInstances", 1L, "vnfs", 1L, "networks", 1L, "vfModules", 3L, "volumeGroups", 1L),
+                            true},
+                    {"network",
+                            ImmutableMap.of("vnfs", 1L, "networks", 1L, "vfModules", 3L, "volumeGroups", 1L, "serviceInstances", 1L),
+                            ImmutableMap.of("networks", 1L),
+                            true},
+                    {"vnf0",
+                            ImmutableMap.of("vfModules", 0L, "volumeGroups", 0L),
+                            ImmutableMap.of("vnfs", 1L, "vfModules", 3L, "volumeGroups", 1L),
+                            true},
+                    {"vfModule0", ImmutableMap.of("vfModules", 1L, "volumeGroups", 0L),
+                            ImmutableMap.of("vfModules", 3L, "volumeGroups", 1L),
+                            true},
+//                    {"volumeGroup",
+//                            ImmutableMap.of("vnfs", 1L, "networks", 1L, "vfModules", 1L, "volumeGroups", 1L, "serviceInstances", 1L),
+//                            ImmutableMap.of("vfModules", 1L, "volumeGroups", 1L),
+//                            true},
+                    {"vfModule1",
+                            ImmutableMap.of("vfModules", 2L, "volumeGroups", 1L) ,
+                            ImmutableMap.of("vfModules", 2L, "volumeGroups", 1L) ,
+                            true},
+                    {"vfModule2",
+                            ImmutableMap.of("vfModules", 3L, "volumeGroups", 1L),
+                            ImmutableMap.of("vfModules", 1L, "volumeGroups", 0L),
+                            true }
+            };
+        } else if (Features.FLAG_ASYNC_ALACARTE_VFMODULE.isActive()) {
+            return new Object[][]{
+                    {"none", emptyMap(), emptyMap(), true},
+                    {"none", emptyMap(), emptyMap(), false},
+                    {"instance", ImmutableMap.of("vnfs", 0L, "networks", 0L, "vfModules", 0L, "volumeGroups", 0L),
+                            ImmutableMap.of("serviceInstances", 1L, "vnfs", 1L, "networks", 1L, "vfModules", 3L, "volumeGroups",
+                                    1L), true},
+                    {"network", emptyMap(),
+                            ImmutableMap.of("networks", 1L), true},
+                    {"vnf0", ImmutableMap.of("vfModules", 0L, "volumeGroups", 0L),
+                            ImmutableMap.of("vnfs", 1L, "vfModules", 3L, "volumeGroups", 1L), true},
+                    {"vfModule0", ImmutableMap.of("vfModules", 1L, "volumeGroups", 0L),
+                            ImmutableMap.of("vfModules", 3L, "volumeGroups", 1L), true},
+                    {"volumeGroup", ImmutableMap.of("vfModules", 2L),
+                            ImmutableMap.of("vfModules", 1L, "volumeGroups", 1L), true},
+                    {"vfModule1", emptyMap(),
+                            ImmutableMap.of("vfModules", 1L, "volumeGroups", 1L), true},
+                    {"vfModule2", emptyMap(),
+                            ImmutableMap.of("vfModules", 1L), true}
+            };
+        } else {
+            return new Object[][]{
+                    {"none", ImmutableMap.of("vfModules", 0L, "volumeGroups", 0L), emptyMap(), true}
+            };
+        }
+
     }
 
     @Test(dataProvider = "data_deploy1ServiceFromCypress__verifyStatusAndMsoCalls")
@@ -443,7 +497,7 @@ public class AsyncInstantiationALaCarteApiTest extends AsyncInstantiationBase {
         switch (whatToFail) {
             case "none": finalJobStatus = JobStatus.COMPLETED; break;
             case "instance": finalJobStatus = JobStatus.FAILED; break;
-            default: finalJobStatus = JobStatus.COMPLETED_WITH_ERRORS; break;
+            default: finalJobStatus = getErrorStatus(); break;
         }
         assertServiceInfoSpecific2(jobId, finalJobStatus, names.get(SERVICE_NAME));
         assertRecordedRequests(pathCounterOverride, 1L, vnfRequestId);
@@ -486,7 +540,8 @@ public class AsyncInstantiationALaCarteApiTest extends AsyncInstantiationBase {
 
         final String msoURL = "/mso";
 
-        deploy1ServiceFromCypress__verifyStatusAndMsoCalls_andRetry("none", emptyMap(), emptyMap(), true);
+        deploy1ServiceFromCypress__verifyStatusAndMsoCalls_andRetry("none",
+                Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() ? ImmutableMap.of("vfModules", 3L):emptyMap(), emptyMap(), true);
         List<String> logLines =  LoggerFormatTest.getLogLinesAsList(LogName.metrics2019, 200, 1, restTemplate, uri);
         List<RecordedRequests> underTestRequests = retrieveRecordedRequests();
 
@@ -603,7 +658,8 @@ public class AsyncInstantiationALaCarteApiTest extends AsyncInstantiationBase {
                         pathCounterOverride.getOrDefault("volumeGroups", defaultValue)),
 
                 TestUtils.hasOrLacksOfEntry("/mso/serviceInstantiation/v./serviceInstances/" + DEFAULT_INSTANCE_ID + "/vnfs/" + vnfRequestId + "/vfModules",
-                        pathCounterOverride.getOrDefault("vfModules", vfModulesDefaultValue))
+                        pathCounterOverride.getOrDefault("vfModules",
+                                Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() ? defaultValue : vfModulesDefaultValue))
         ));
     }
 
index 07b81a4..2e21653 100644 (file)
@@ -135,7 +135,9 @@ public class AsyncInstantiationALaCarteApiTest3 extends AsyncInstantiationBase {
         } else if (expectedStatus.equals("SERVICE_FAILED")){
             vidAuditStatuses = vidAuditStatusesFailed(jobId);
         } else {
-            vidAuditStatuses = vidAuditStatusesCompletedWithErrors(jobId);
+            vidAuditStatuses = Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() ?
+                                vidAuditStatusesFailedAndPaused(jobId) :
+                                vidAuditStatusesCompletedWithErrors(jobId);
         }
 
         assertServiceInfoSpecific3(jobId, expectedJobStatus , names.get(SERVICE_NAME));
@@ -145,7 +147,12 @@ public class AsyncInstantiationALaCarteApiTest3 extends AsyncInstantiationBase {
 
     @DataProvider
     Object[][] multipleVnfDataProvider() {
-        return new Object[][]{{MSO_FAILED_STATUS, JobStatus.COMPLETED_WITH_ERRORS},{MSO_COMPLETE_STATUS, JobStatus.COMPLETED}, {"SERVICE_FAILED", JobStatus.FAILED}};
+        return new Object[][]{
+                {
+                    MSO_FAILED_STATUS, Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() ? JobStatus.FAILED_AND_PAUSED :
+                                JobStatus.COMPLETED_WITH_ERRORS },
+                {   MSO_COMPLETE_STATUS, JobStatus.COMPLETED },
+                {   "SERVICE_FAILED", JobStatus.FAILED } };
     }
 
     @Test
@@ -197,7 +204,9 @@ public class AsyncInstantiationALaCarteApiTest3 extends AsyncInstantiationBase {
         return new Object[][]{
                 {MSO_COMPLETE_STATUS, MSO_COMPLETE_STATUS, JobStatus.COMPLETED},
                 {MSO_FAILED_STATUS, MSO_FAILED_STATUS, JobStatus.FAILED},
-                {MSO_COMPLETE_STATUS, MSO_FAILED_STATUS, JobStatus.COMPLETED_WITH_ERRORS}
+                {MSO_FAILED_STATUS, MSO_COMPLETE_STATUS,
+                        Features.FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE.isActive() ?
+                                JobStatus.FAILED_AND_PAUSED : JobStatus.COMPLETED_WITH_ERRORS }
         };
     }
 
@@ -535,6 +544,8 @@ public class AsyncInstantiationALaCarteApiTest3 extends AsyncInstantiationBase {
                 return vidAuditStatusesFailed(jobId);
             case IN_PROGRESS:
                 return vidAuditStatusesInProgress(jobId);
+            case FAILED_AND_PAUSED:
+                return vidAuditStatusesFailedAndPaused(jobId);
         }
 
         return null;
index a1a6cf7..35a044f 100644 (file)
@@ -33,4 +33,4 @@ FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE = false
 FLAG_SHOW_ORCHESTRATION_TYPE = false
 FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE = false
 FLAG_A_LA_CARTE_PLATFORM_MULTI_SELECT = false
-
+FLAG_2008_PAUSE_VFMODULE_INSTANTIATION_FAILURE = false
index 5d7d898..5652923 100644 (file)
@@ -1,6 +1,7 @@
 import {getTestBed, TestBed} from '@angular/core/testing';
 import {
   COMPLETED_WITH_ERRORS,
+  FAILED_AND_PAUSED,
   INPROGRESS,
   InstantiationStatusComponentService,
   PAUSE,
@@ -150,6 +151,7 @@ describe('Instantiation Status Service', () => {
     'COMPLETED_WITH_ERRORS': 'Completed with errors: some of the planned actions where successfully committed while other have not.\n Open the service to check it out.',
     'UNEXPECTED_RANDOM_STATUS': 'Unexpected status: "UNEXPECTED_RANDOM_STATUS"',
     'COMPLETED_AND_PAUSED': 'Pause upon completion. you may resume the instantiation.\n Open the service to check it out.',
+    'FAILED_AND_PAUSED': 'Failed and Paused: you may re-deploy the instantiation.\n Open the service to check it out.',
   })) {
 
     test(`getStatusTooltip should return status popover: status=${status}`, () => {
@@ -213,6 +215,9 @@ describe('Instantiation Status Service', () => {
     result = service.getStatus('COMPLETED_AND_PAUSED');
     expect(result.iconClassName).toEqual(PAUSE_UPON_COMPLETION);
 
+    result = service.getStatus('FAILED_AND_PAUSED');
+    expect(result.iconClassName).toEqual(FAILED_AND_PAUSED);
+
     result = service.getStatus(undefined);
     expect(result.iconClassName).toEqual(UNKNOWN);
   });
index cdbe890..709cb89 100644 (file)
@@ -23,6 +23,7 @@ export let SUCCESS_CIRCLE : string = "success-circle-o";
 export let STOPPED : string = "stop";
 export let COMPLETED_WITH_ERRORS : string = "success_with_warning";
 export let PAUSE_UPON_COMPLETION : string = "stopped-upon-success";
+export let FAILED_AND_PAUSED : string = "success_with_warning";
 export let UNKNOWN : string = "question-mark-circle-o";
 
 
@@ -172,6 +173,8 @@ export class InstantiationStatusComponentService {
         return new ServiceStatus(COMPLETED_WITH_ERRORS, 'success', 'Completed with errors: some of the planned actions where successfully committed while other have not.\n Open the service to check it out.');
       case  'COMPLETED_AND_PAUSED' :
         return new ServiceStatus(PAUSE_UPON_COMPLETION, 'default','Pause upon completion. you may resume the instantiation.\n Open the service to check it out.' );
+      case 'FAILED_AND_PAUSED' :
+        return new ServiceStatus(FAILED_AND_PAUSED, 'success','Failed and Paused: you may re-deploy the instantiation.\n Open the service to check it out.' );
       default:
         return new ServiceStatus(UNKNOWN, 'primary', `Unexpected status: "${status}"`);
     }
index 5e0c2a8..676c3a4 100644 (file)
@@ -196,17 +196,17 @@ export class InstantiationStatusComponent implements OnInit {
   isOpenEnabled(item: ServiceInfoModel):boolean {
     switch(item.action) {
       case ServiceAction.DELETE:
-      return _.includes([ JobStatus.PENDING, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.FAILED], item.jobStatus);
+        return _.includes([ JobStatus.PENDING, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.FAILED, JobStatus.FAILED_AND_PAUSED], item.jobStatus);
       case ServiceAction.UPDATE:
-        return _.includes([JobStatus.PENDING, JobStatus.PAUSE, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.COMPLETED, JobStatus.FAILED], item.jobStatus);
+        return _.includes([JobStatus.PENDING, JobStatus.PAUSE, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.FAILED_AND_PAUSED], item.jobStatus);
       default:
-        return _.includes([JobStatus.COMPLETED, JobStatus.PAUSE, JobStatus.COMPLETED_WITH_ERRORS], item.jobStatus);
+        return _.includes([JobStatus.COMPLETED, JobStatus.PAUSE, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.FAILED_AND_PAUSED], item.jobStatus);
     }
   }
 
   isAuditInfoEnabled(item: ServiceInfoModel): boolean {
     if(item.action === ServiceAction.DELETE || item.action=== ServiceAction.UPDATE) {
-      return _.includes([JobStatus.FAILED, JobStatus.IN_PROGRESS, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.PAUSE, JobStatus.COMPLETED], item.jobStatus);
+      return _.includes([JobStatus.FAILED, JobStatus.IN_PROGRESS, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.FAILED_AND_PAUSED, JobStatus.PAUSE, JobStatus.COMPLETED], item.jobStatus);
     }
     return true;// ServiceAction.INSTANTIATE
   }
@@ -219,7 +219,7 @@ export class InstantiationStatusComponent implements OnInit {
   }
 
   isHideEnabled(item: ServiceInfoModel):boolean {
-    return _.includes([JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.STOPPED, JobStatus.COMPLETED_WITH_ERRORS], item.jobStatus);
+    return _.includes([JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.STOPPED, JobStatus.COMPLETED_WITH_ERRORS, JobStatus.FAILED_AND_PAUSED], item.jobStatus);
   }
 
   public onContextMenu($event: MouseEvent, item: any): void {
index e7eb55d..900b19e 100644 (file)
@@ -26,7 +26,8 @@ export enum JobStatus {
   COMPLETED_WITH_ERRORS = 'COMPLETED_WITH_ERRORS',
   CREATING = 'CREATING',
   PAUSE_UPON_COMPLETION = 'PAUSE_UPON_COMPLETION',
-  COMPLETED_AND_PAUSED = 'COMPLETED_AND_PAUSED'
+  COMPLETED_AND_PAUSED = 'COMPLETED_AND_PAUSED',
+  FAILED_AND_PAUSED = 'FAILED_AND_PAUSED'
 }
 export enum PauseStatus {
   AFTER_COMPLETION = 'afterCompletion',