From e1f7974f0badbd4440d5b7ea5f1b1cb2d4973818 Mon Sep 17 00:00:00 2001 From: Einat Vinouze Date: Tue, 27 Aug 2019 16:01:01 +0300 Subject: Adding feature: Replace vfmodule Issue-ID: VID-603 Change-Id: I59068a0979d6fb733e4243c8f78921f396dc9d17 Signed-off-by: Einat Vinouze Signed-off-by: Amichai Hemli Signed-off-by: Ittay Stern --- .../src/main/java/org/onap/vid/aai/AaiClient.java | 3 +- .../org/onap/vid/job/command/CommandUtils.java | 29 +++- .../org/onap/vid/job/command/ResourceCommand.kt | 9 +- .../org/onap/vid/job/command/VfmoduleCommand.kt | 158 +++++++++++++++++++- .../src/main/java/org/onap/vid/model/Action.java | 2 +- .../main/java/org/onap/vid/model/ServiceInfo.java | 23 ++- .../model/serviceInstantiation/BaseResource.java | 2 +- .../vid/model/serviceInstantiation/VfModule.java | 32 +++- .../vid/scripts/constants/componentConstants.js | 1 + .../scripts/controller/InstantiationController.js | 12 +- .../app/vid/scripts/view-models/instantiate.htm | 4 +- .../test/java/org/onap/vid/aai/AaiClientTest.java | 47 ------ .../impl/AsyncInstantiationIntegrationTest.java | 161 ++++++++++++++++----- .../vid/services/AsyncInstantiationBaseTest.java | 2 +- .../onap/vid/services/MsoRequestBuilderTest.java | 10 +- .../payload_jsons/vfmodule/replace_vfmodule.json | 25 ++-- .../vfmodule/replace_vfmodule_fe_input.json | 3 +- 17 files changed, 387 insertions(+), 136 deletions(-) (limited to 'vid-app-common/src') diff --git a/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java b/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java index 8e47bbae5..c43779df1 100644 --- a/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java +++ b/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java @@ -440,6 +440,8 @@ public class AaiClient implements AaiClientInterface { } protected Stream toModelVerStream(ModelVersions modelVersions) { + if (modelVersions == null) + return null; if (modelVersions == null) return null; @@ -454,7 +456,6 @@ public class AaiClient implements AaiClientInterface { } protected ModelVer maxModelVer(Stream modelVerStream) { - if (modelVerStream == null) return null; 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 index 0fe7255c4..2b6b57ade 100644 --- 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 @@ -21,8 +21,10 @@ package org.onap.vid.job.command; import org.apache.commons.lang3.StringUtils; +import org.onap.vid.aai.model.ModelVer; import org.onap.vid.asdc.AsdcCatalogException; import org.onap.vid.model.ServiceModel; +import org.onap.vid.services.AaiService; import org.onap.vid.services.VidService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -31,18 +33,16 @@ import org.springframework.stereotype.Component; public class CommandUtils { private final VidService vidService; + private final AaiService aaiService; @Autowired - public CommandUtils(VidService vidService) { + public CommandUtils(VidService vidService, AaiService aaiService) { this.vidService = vidService; + this.aaiService = aaiService; } 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"); - } + ServiceModel serviceModel = getServiceModel(serviceModelUuid); if (serviceModel.getVfModules() == null) { throw createAsdcCatalogVfModuleModelUUIDNotFoundException(serviceModelUuid, vfModuleModelUUID); @@ -58,6 +58,23 @@ public class CommandUtils { .getBaseModule(); } + public ServiceModel getServiceModel(String serviceModelUuid) throws AsdcCatalogException{ + ServiceModel serviceModel = vidService.getService(serviceModelUuid); + + if (serviceModel==null) { + throw new AsdcCatalogException("Failed to retrieve model with uuid "+serviceModelUuid +" from SDC"); + } + + return serviceModel; + } + + public String getNewestModelUuid(String serviceModelInvariantId) + { + ModelVer serviceModelLatestVersion = aaiService.getNewestModelVersionByInvariantId(serviceModelInvariantId); + + return serviceModelLatestVersion.getModelVersionId(); + } + 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/ResourceCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt index 0e9ab7b7a..2c50e03cd 100644 --- 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 @@ -222,11 +222,16 @@ abstract class ResourceCommand( else -> InternalState.IN_PROGRESS } + InternalState.REPLACE_MYSELF -> when (jobStatus) { + JobStatus.IN_PROGRESS -> InternalState.REPLACE_MYSELF + else -> InternalState.IN_PROGRESS + } + InternalState.IN_PROGRESS -> { when { jobStatus != JobStatus.COMPLETED -> InternalState.IN_PROGRESS isDescendantHasAction(Action.Create) -> InternalState.CREATING_CHILDREN - isDescendantHasAction(Action.Replace) -> InternalState.CREATING_CHILDREN + isDescendantHasAction(Action.Upgrade) -> InternalState.CREATING_CHILDREN else -> InternalState.TERMINAL } } @@ -284,7 +289,7 @@ abstract class ResourceCommand( isNeedToResumeMySelf() -> InternalState.RESUME_MYSELF isNeedToReplaceMySelf() -> InternalState.REPLACE_MYSELF isDescendantHasAction(phase) -> InternalState.CREATING_CHILDREN - isDescendantHasAction(Action.Replace) -> InternalState.CREATING_CHILDREN + isDescendantHasAction(Action.Upgrade) -> InternalState.CREATING_CHILDREN else -> InternalState.TERMINAL } else -> throw IllegalStateException("state $internalState is not supported yet") diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt index af52fa049..276b00e6f 100644 --- a/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt +++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt @@ -5,9 +5,10 @@ import org.onap.vid.job.Job import org.onap.vid.job.JobAdapter import org.onap.vid.job.JobCommand import org.onap.vid.job.JobsBrokerService -import org.onap.vid.model.Action +import org.onap.vid.model.* import org.onap.vid.model.serviceInstantiation.VfModule import org.onap.vid.mso.RestMsoImplementation +import org.onap.vid.mso.model.ModelInfo import org.onap.vid.services.AsyncInstantiationBusinessLogic import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.config.ConfigurableBeanFactory @@ -16,6 +17,8 @@ import org.springframework.http.HttpMethod import org.springframework.stereotype.Component import java.util.* +typealias ToscaVfm = org.onap.vid.model.VfModule + @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) class VfmoduleCommand @Autowired constructor( @@ -45,7 +48,7 @@ class VfmoduleCommand @Autowired constructor( val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID) val vgInstaceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VG_INSTANCE_ID) - val instantiatePath = asyncInstantiationBL.getVfmoduleInstantiationPath(serviceInstanceId, vnfInstanceId) + val instantiatePath = asyncInstantiationBL.getVfmoduleInstantiationPath(serviceInstanceId, vnfInstanceId) val requestDetailsWrapper = msoRequestBuilder.generateVfModuleInstantiationRequest( request as VfModule, @@ -75,14 +78,16 @@ class VfmoduleCommand @Autowired constructor( return false } - private fun planReplaceMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan { + private fun planReplaceMyselfRestCall3(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan { val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID) val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO) val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO) val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID) val replacePath = asyncInstantiationBL.getVfModuleReplacePath(serviceInstanceId, vnfInstanceId, getRequest().instanceId) - val requestDetailsWrapper = msoRequestBuilder.generateVfModuleInstantiationRequest( + amendModelInfoWithNewestModel(serviceModelInfo, vnfModelInfo, (request as VfModule).modelInfo) + + val requestDetailsWrapper = msoRequestBuilder.generateVfModuleInstantiationRequest( request as VfModule, serviceModelInfo, serviceInstanceId,vnfModelInfo, vnfInstanceId,null,userId, testApi) val actionDescription = "replace vfmodule ${request.instanceId}" @@ -90,9 +95,142 @@ class VfmoduleCommand @Autowired constructor( return MsoRestCallPlan(HttpMethod.POST, replacePath, Optional.of(requestDetailsWrapper), Optional.of(userId), actionDescription) } + private fun planReplaceMyselfRestCall(commandParentData: CommandParentData): MsoRestCallPlan { + + val newestModel = fetchNewestServiceModel() + + val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID) + val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID) + + val (serviceModelInfo, vnfModelInfo, vfmModelInfo) = newestSelector(newestModel, commandParentData); + + val originalRequestWithNewestVfmModelInfo = getRequest().cloneWith(vfmModelInfo) + + val requestDetailsWrapper = msoRequestBuilder.generateVfModuleInstantiationRequest( + originalRequestWithNewestVfmModelInfo, serviceModelInfo, serviceInstanceId, + vnfModelInfo, vnfInstanceId, null, sharedData.userId, sharedData.testApi) + + + val replacePath = asyncInstantiationBL.getVfModuleReplacePath(serviceInstanceId, vnfInstanceId, getRequest().instanceId) + + return MsoRestCallPlan(HttpMethod.POST, replacePath, Optional.of(requestDetailsWrapper), Optional.of(sharedData.userId), + "replace vfmodule ${getRequest().instanceId}") + } + + data class ModelsInfoTriplet(val serviceModelInfo: ModelInfo, val vnfModelInfo: ModelInfo, val vfmModelInfo: ModelInfo) + + private fun newestSelector(newestModel: ServiceModel, commandParentData: CommandParentData): ModelsInfoTriplet { + val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO) + val vfmModelInfo = getRequest().modelInfo + val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO) + + val newestServiceModelInfo = newestServiceModelInfo(newestModel) + val newestVfmModelInfo = newestVfmModelInfo(newestModel) + val newestVnfModelInfo = newestVnfModelInfo(newestModel, commandParentData) + + return if (newestServiceModelInfo == null || newestVfmModelInfo == null || newestVnfModelInfo == null) { + ModelsInfoTriplet(serviceModelInfo, vnfModelInfo, vfmModelInfo) + } else { + ModelsInfoTriplet(newestServiceModelInfo, newestVnfModelInfo, newestVfmModelInfo) + } + } + + private fun newestServiceModelInfo(newestModel: ServiceModel) = toModelInfo(newestModel.service) + + private fun newestVfmModelInfo(newestModel: ServiceModel): ModelInfo? { + val vfmModelInfo = getRequest().modelInfo + val newestVfm = selectVfm(newestModel, vfmModelInfo) + return toModelInfo(newestVfm) + } + + private fun newestVnfModelInfo(newestModel: ServiceModel, commandParentData: CommandParentData): ModelInfo? { + val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO) + val newestVnf = selectVnf(newestModel, vnfModelInfo) + return toModelInfo(newestVnf) + } + + private fun selectVfm(newestModel: ServiceModel, modelInfo: ModelInfo) = newestModel.vfModules[modelInfo.modelCustomizationId] + + private fun selectVnf(newestModel: ServiceModel, modelInfo: ModelInfo) = newestModel.vnfs[modelInfo.modelCustomizationId] + + private fun toModelInfo(toBeConverted: VNF?): ModelInfo? = toBeConverted?.let { toModelInfo(it, "vnf") } + + private fun toModelInfo(toBeConverted: ToscaVfm?): ModelInfo? = toBeConverted?.let { toModelInfo(it, "vfModule") } + + private fun toModelInfo(toBeConverted: MinimalNode, modelType: String): ModelInfo { + val targetModelInfo = ModelInfo() + + targetModelInfo.modelType = modelType + targetModelInfo.modelName = toBeConverted.name + targetModelInfo.modelNameVersionId = null + targetModelInfo.modelVersion = toBeConverted.version + targetModelInfo.modelVersionId = toBeConverted.uuid + targetModelInfo.modelInvariantId = toBeConverted.invariantUuid + + targetModelInfo.modelCustomizationId = when (toBeConverted) { + is VNF -> toBeConverted.customizationUuid + is ToscaVfm -> toBeConverted.customizationUuid + else -> throw IllegalArgumentException() + } + + targetModelInfo.modelCustomizationName = when (toBeConverted) { + is VNF -> toBeConverted.modelCustomizationName + is ToscaVfm -> toBeConverted.modelCustomizationName + else -> throw IllegalArgumentException() + } + + return targetModelInfo + } + + private fun toModelInfo(toBeConverted: Service?): ModelInfo? { + + if (toBeConverted == null) + return null + + val targetModelInfo = ModelInfo() + + targetModelInfo.modelVersionId = toBeConverted.uuid + targetModelInfo.modelInvariantId = toBeConverted.invariantUuid + targetModelInfo.modelVersion = toBeConverted.version + //targetModelInfo.modelCustomizationId = toBeConverted.customizationUuid + //targetModelInfo.modelCustomizationName = toBeConverted.modelCustomizationName + targetModelInfo.modelType = "service" + targetModelInfo.modelName = toBeConverted.name + + return targetModelInfo + } + + private fun amendModelInfoWithNewestModel(serviceModelInfo: ModelInfo, vnfModelInfo: ModelInfo, vfmModelInfo: ModelInfo) { + val newestModel = fetchNewestServiceModel() + val newestService = newestModel.service + + val newestVfm = newestModel.vfModules[vfmModelInfo.modelCustomizationId] + val newestVnf = newestModel.vnfs[vnfModelInfo.modelCustomizationId] + + if (!(newestService == null || newestVnf == null || newestVfm == null)) { + + serviceModelInfo.modelName = newestService.name + serviceModelInfo.modelVersionId = newestService.uuid + serviceModelInfo.modelVersion = newestService.version + + vnfModelInfo.modelName = newestVnf.name + vnfModelInfo.modelVersionId = newestVnf.uuid + vnfModelInfo.modelVersion = newestVnf.version + vnfModelInfo.modelCustomizationId = newestVnf.customizationUuid + vnfModelInfo.modelCustomizationName = newestVnf.modelCustomizationName + + vfmModelInfo.modelName = newestVfm.name + vfmModelInfo.modelVersionId = newestVfm.uuid + vfmModelInfo.modelVersion = newestVfm.version + vfmModelInfo.modelCustomizationId = newestVfm.customizationUuid + vfmModelInfo.modelCustomizationName = newestVfm.modelCustomizationName + } + } + + override fun replaceMyself(): Job.JobStatus { try { - val replaceMyselfCommand = planReplaceMyselfRestCall(commandParentData, sharedData.request, sharedData.userId, sharedData.testApi ) + val replaceMyselfCommand = planReplaceMyselfRestCall(commandParentData) return executeAndHandleMsoInstanceRequest(replaceMyselfCommand) } catch (exception: Exception) { LOGGER.error("Failed to replace instanceId ${getRequest().instanceId} ", exception) @@ -101,6 +239,14 @@ class VfmoduleCommand @Autowired constructor( } override fun isNeedToReplaceMySelf(): Boolean { - return getActionType() == Action.Replace + return getActionType() == Action.Upgrade + } + + private fun fetchNewestServiceModel(): ServiceModel { + val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO) + var modelNewestUuid = commandUtils.getNewestModelUuid(serviceModelInfo.modelInvariantId); + var serviceNewestModel = commandUtils.getServiceModel(modelNewestUuid); + + return serviceNewestModel; } } diff --git a/vid-app-common/src/main/java/org/onap/vid/model/Action.java b/vid-app-common/src/main/java/org/onap/vid/model/Action.java index c0d4fae6a..930f97073 100644 --- a/vid-app-common/src/main/java/org/onap/vid/model/Action.java +++ b/vid-app-common/src/main/java/org/onap/vid/model/Action.java @@ -25,7 +25,7 @@ public enum Action { Delete(ServiceInfo.ServiceAction.DELETE), None(ServiceInfo.ServiceAction.UPDATE), Resume(ServiceInfo.ServiceAction.RESUME), - Replace(ServiceInfo.ServiceAction.REPLACE); + Upgrade(ServiceInfo.ServiceAction.UPGRADE); private final ServiceInfo.ServiceAction serviceAction; Action(ServiceInfo.ServiceAction serviceAction){ diff --git a/vid-app-common/src/main/java/org/onap/vid/model/ServiceInfo.java b/vid-app-common/src/main/java/org/onap/vid/model/ServiceInfo.java index 1e1e6c2a7..85c83eb98 100644 --- a/vid-app-common/src/main/java/org/onap/vid/model/ServiceInfo.java +++ b/vid-app-common/src/main/java/org/onap/vid/model/ServiceInfo.java @@ -22,18 +22,25 @@ package org.onap.vid.model; import com.fasterxml.jackson.annotation.JsonProperty; -import org.hibernate.annotations.DynamicUpdate; -import org.hibernate.annotations.SelectBeforeUpdate; -import org.hibernate.annotations.Type; -import org.onap.portalsdk.core.domain.support.DomainVo; -import org.onap.vid.job.Job; - -import javax.persistence.*; import java.io.Serializable; import java.util.Date; import java.util.Objects; import java.util.Set; import java.util.UUID; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.SelectBeforeUpdate; +import org.hibernate.annotations.Type; +import org.onap.portalsdk.core.domain.support.DomainVo; +import org.onap.vid.job.Job; /* The following 2 annotations let hibernate to update only fields that actually have been changed. @@ -51,7 +58,7 @@ public class ServiceInfo extends DomainVo { DELETE, UPDATE, RESUME, - REPLACE + UPGRADE } private UUID jobId; diff --git a/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/BaseResource.java b/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/BaseResource.java index 926dc3cdc..75658f2b1 100644 --- a/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/BaseResource.java +++ b/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/BaseResource.java @@ -65,7 +65,7 @@ public abstract class BaseResource implements JobAdapter.AsyncJobRequest { .put("Update_Delete", Action.Delete) .put("None_Delete", Action.Delete) .put("Resume", Action.Resume) - .put("Replace", Action.Replace) + .put("Upgrade", Action.Upgrade) .build(); diff --git a/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/VfModule.java b/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/VfModule.java index 97b23af20..233850d58 100644 --- a/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/VfModule.java +++ b/vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/VfModule.java @@ -20,18 +20,17 @@ package org.onap.vid.model.serviceInstantiation; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import org.onap.vid.job.JobAdapter; -import org.onap.vid.job.JobType; -import org.onap.vid.mso.model.ModelInfo; - import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import org.onap.vid.job.JobAdapter; +import org.onap.vid.job.JobType; +import org.onap.vid.mso.model.ModelInfo; /** * The Class VfModule. @@ -91,4 +90,25 @@ public class VfModule extends BaseResource implements JobAdapter.AsyncJobRequest public JobType getJobType() { return JobType.VfmoduleInstantiation; } + + public VfModule cloneWith(ModelInfo modelInfo) { + return new VfModule( + modelInfo, + this.getInstanceName(), + this.getVolumeGroupInstanceName(), + this.getAction().toString(), + this.getLcpCloudRegionId(), + this.getLcpCloudRegionId(), + this.getTenantId(), + this.getInstanceParams(), + this.getSupplementaryParams(), + this.isRollbackOnFailure(), + this.isUsePreload(), + this.getInstanceId(), + this.getTrackById(), + this.getIsFailed(), + this.getStatusMessage() + ); + + } } \ No newline at end of file diff --git a/vid-app-common/src/main/webapp/app/vid/scripts/constants/componentConstants.js b/vid-app-common/src/main/webapp/app/vid/scripts/constants/componentConstants.js index 01b8e8acf..67a89ee74 100755 --- a/vid-app-common/src/main/webapp/app/vid/scripts/constants/componentConstants.js +++ b/vid-app-common/src/main/webapp/app/vid/scripts/constants/componentConstants.js @@ -262,6 +262,7 @@ appDS2 FLAG_VF_MODULE_RESUME_STATUS_CREATE: "FLAG_VF_MODULE_RESUME_STATUS_CREATE", FLAG_1908_RELEASE_TENANT_ISOLATION: "FLAG_1908_RELEASE_TENANT_ISOLATION", FLAG_FLASH_REPLACE_VF_MODULE: "FLAG_FLASH_REPLACE_VF_MODULE", + FLAG_FLASH_VIEW_IN_NEW_VIEWEDIT_SCREEN: "FLAG_FLASH_VIEW_IN_NEW_VIEWEDIT_SCREEN", } }; diff --git a/vid-app-common/src/main/webapp/app/vid/scripts/controller/InstantiationController.js b/vid-app-common/src/main/webapp/app/vid/scripts/controller/InstantiationController.js index 7fa312ed9..a21776e5d 100755 --- a/vid-app-common/src/main/webapp/app/vid/scripts/controller/InstantiationController.js +++ b/vid-app-common/src/main/webapp/app/vid/scripts/controller/InstantiationController.js @@ -225,12 +225,20 @@ }; $scope.allowTransferToNewScreenAndShowButton = function (){ - if(featureFlags.isOn(COMPONENT.FEATURE_FLAGS.FLAG_FLASH_REPLACE_VF_MODULE)) { - return $scope.isPermitted && !($scope.isMacro()); + if(featureFlags.isOn(COMPONENT.FEATURE_FLAGS.FLAG_FLASH_VIEW_IN_NEW_VIEWEDIT_SCREEN)) { + return $scope.isPermitted; } return false; }; + $scope.navigateToNewEditViewScreen = function(){ + window.location.href = 'serviceModels.htm#/servicePlanning/EDIT?' + + 'serviceModelId=' + _.get($scope, 'service.model.service.uuid') + + '&subscriberId=' + $location.search().subscriberId + + '&serviceType=' + $location.search().serviceType + + '&serviceInstanceId=' + $location.search().serviceInstanceId; + }; + $scope.deleteService = function (serviceObject, serviceOrchestrationStatus) { var serviceInstance = serviceObject.object; diff --git a/vid-app-common/src/main/webapp/app/vid/scripts/view-models/instantiate.htm b/vid-app-common/src/main/webapp/app/vid/scripts/view-models/instantiate.htm index f80f924b3..6399065f8 100755 --- a/vid-app-common/src/main/webapp/app/vid/scripts/view-models/instantiate.htm +++ b/vid-app-common/src/main/webapp/app/vid/scripts/view-models/instantiate.htm @@ -41,7 +41,9 @@

{{isPermitted ? "View/Edit" : "View"}} Service Instance

- + More actions
diff --git a/vid-app-common/src/test/java/org/onap/vid/aai/AaiClientTest.java b/vid-app-common/src/test/java/org/onap/vid/aai/AaiClientTest.java index 5c37bb1ee..777729c03 100644 --- a/vid-app-common/src/test/java/org/onap/vid/aai/AaiClientTest.java +++ b/vid-app-common/src/test/java/org/onap/vid/aai/AaiClientTest.java @@ -56,7 +56,6 @@ import java.net.URI; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Map; -import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.stream.Stream; @@ -756,51 +755,6 @@ public class AaiClientTest { }; } - @Test - public void testGetLatestVersionByInvariantId() throws IOException { - - ModelVersions modelVersions = JACKSON_OBJECT_MAPPER.readValue("" + - "{\n" + - " \"results\": [\n" + - " {\n" + - " \"model\": {\n" + - " \"model-invariant-id\": \"f6342be5-d66b-4d03-a1aa-c82c3094c4ea\",\n" + - " \"model-type\": \"service\",\n" + - " \"resource-version\": \"1534274421300\"\n" + - " }\n" + - " },\n" + - " {\n" + - " \"model-ver\": {\n" + - " \"model-version-id\": \"a92f899d-a3ec-465b-baed-1663b0a5aee1\",\n" + - " \"model-name\": \"NCM_VLAN_SVC_ym161f\",\n" + - " \"model-version\": \"bbb\",\n" + - " \"distribution-status\": \"DISTRIBUTION_COMPLETE_OK\",\n" + - " \"model-description\": \"Network Collection service for vLAN tagging\",\n" + - " \"resource-version\": \"1534788756086\"\n" + - " }\n" + - " },\n" + - " {\n" + - " \"model-ver\": {\n" + - " \"model-version-id\": \"d2fda667-e92e-4cfa-9620-5da5de01a319\",\n" + - " \"model-name\": \"NCM_VLAN_SVC_ym161f\",\n" + - " \"model-version\": \"aaa\",\n" + - " \"distribution-status\": \"DISTRIBUTION_COMPLETE_OK\",\n" + - " \"model-description\": \"Network Collection service for vLAN tagging\",\n" + - " \"resource-version\": \"1534444087221\"\n" + - " }\n" + - " }]}", ModelVersions.class); - - - final AaiClient aaiClient = new AaiClient(null, null, null); - - assertThat(aaiClient.toModelVerStream(modelVersions).collect(toList()), - containsInAnyOrder( - hasProperty("modelVersionId", is("a92f899d-a3ec-465b-baed-1663b0a5aee1")), - hasProperty("modelVersionId", is("d2fda667-e92e-4cfa-9620-5da5de01a319")) - )); - - } - @DataProvider public static Object[][] versionsDataProvider() { return new Object[][] { @@ -984,5 +938,4 @@ public class AaiClientTest { )); } - } diff --git a/vid-app-common/src/test/java/org/onap/vid/job/impl/AsyncInstantiationIntegrationTest.java b/vid-app-common/src/test/java/org/onap/vid/job/impl/AsyncInstantiationIntegrationTest.java index 498708d06..fdc416a3b 100644 --- a/vid-app-common/src/test/java/org/onap/vid/job/impl/AsyncInstantiationIntegrationTest.java +++ b/vid-app-common/src/test/java/org/onap/vid/job/impl/AsyncInstantiationIntegrationTest.java @@ -20,9 +20,66 @@ package org.onap.vid.job.impl; +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.joining; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonPartEquals; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonPartMatches; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.core.Every.everyItem; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.endsWith; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.onap.vid.job.Job.JobStatus.COMPLETED; +import static org.onap.vid.job.Job.JobStatus.COMPLETED_WITH_ERRORS; +import static org.onap.vid.job.Job.JobStatus.COMPLETED_WITH_NO_ACTION; +import static org.onap.vid.job.Job.JobStatus.FAILED; +import static org.onap.vid.job.Job.JobStatus.IN_PROGRESS; +import static org.onap.vid.job.Job.JobStatus.PAUSE; +import static org.onap.vid.job.Job.JobStatus.PENDING; +import static org.onap.vid.job.Job.JobStatus.PENDING_RESOURCE; +import static org.onap.vid.job.Job.JobStatus.RESOURCE_IN_PROGRESS; +import static org.onap.vid.job.Job.JobStatus.STOPPED; +import static org.onap.vid.job.impl.JobSchedulerInitializer.WORKERS_TOPICS; +import static org.onap.vid.model.JobAuditStatus.SourceStatus.VID; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Stack; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import javax.inject.Inject; +import javax.ws.rs.ProcessingException; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.mutable.MutableInt; import org.jetbrains.annotations.NotNull; @@ -33,13 +90,24 @@ import org.onap.portalsdk.core.service.DataAccessService; import org.onap.portalsdk.core.util.SystemProperties; import org.onap.vid.asdc.AsdcCatalogException; import org.onap.vid.changeManagement.RequestDetailsWrapper; +import org.onap.vid.config.DataSourceConfig; +import org.onap.vid.config.JobCommandsConfigWithMockedMso; +import org.onap.vid.config.MockedAaiClientAndFeatureManagerConfig; import org.onap.vid.job.Job; import org.onap.vid.job.Job.JobStatus; import org.onap.vid.job.JobType; import org.onap.vid.job.JobsBrokerService; import org.onap.vid.job.command.CommandUtils; import org.onap.vid.job.command.InternalState; -import org.onap.vid.model.*; +import org.onap.vid.model.Action; +import org.onap.vid.model.JobAuditStatus; +import org.onap.vid.model.NameCounter; +import org.onap.vid.model.RequestReferencesContainer; +import org.onap.vid.model.Service; +import org.onap.vid.model.ServiceInfo; +import org.onap.vid.model.ServiceModel; +import org.onap.vid.model.VNF; +import org.onap.vid.model.VfModule; import org.onap.vid.model.serviceInstantiation.BaseResource; import org.onap.vid.model.serviceInstantiation.InstanceGroup; import org.onap.vid.model.serviceInstantiation.ServiceInstantiation; @@ -49,15 +117,12 @@ import org.onap.vid.mso.model.RequestReferences; import org.onap.vid.mso.rest.AsyncRequestStatus; import org.onap.vid.mso.rest.AsyncRequestStatusList; import org.onap.vid.properties.Features; +import org.onap.vid.services.AsyncInstantiationBaseTest; import org.onap.vid.services.AsyncInstantiationBusinessLogic; import org.onap.vid.services.AuditService; import org.onap.vid.services.VersionService; -import org.onap.vid.utils.DaoUtils; -import org.onap.vid.config.DataSourceConfig; -import org.onap.vid.config.JobCommandsConfigWithMockedMso; -import org.onap.vid.config.MockedAaiClientAndFeatureManagerConfig; -import org.onap.vid.services.AsyncInstantiationBaseTest; import org.onap.vid.testUtils.TestUtils; +import org.onap.vid.utils.DaoUtils; import org.springframework.http.HttpMethod; import org.springframework.test.context.ContextConfiguration; import org.testng.annotations.BeforeClass; @@ -66,34 +131,6 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.togglz.core.manager.FeatureManager; -import javax.inject.Inject; -import javax.ws.rs.ProcessingException; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.*; -import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; -import static net.javacrumbs.jsonunit.JsonMatchers.*; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.core.Every.everyItem; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.endsWith; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.onap.vid.job.Job.JobStatus.*; -import static org.onap.vid.job.impl.JobSchedulerInitializer.WORKERS_TOPICS; -import static org.onap.vid.model.JobAuditStatus.SourceStatus.VID; -import static org.testng.AssertJUnit.*; - //it's more like integration test than UT //But it's very hard to test in API test so I use UT @ContextConfiguration(classes = {DataSourceConfig.class, SystemProperties.class, MockedAaiClientAndFeatureManagerConfig.class, JobCommandsConfigWithMockedMso.class}) @@ -1203,12 +1240,18 @@ public class AsyncInstantiationIntegrationTest extends AsyncInstantiationBaseTes } @Test - public void whenUpgradingAvfModule_thanExpectedReplaceRequestSent() throws IOException { - String instanceId = "5d49c3b1-fc90-4762-8c98-e800170baa55"; //from feRequestResumeMacroService.json + public void whenUpgradingAvfModule_thanExpectedReplaceRequestSent() throws IOException, AsdcCatalogException { + String instanceId = "5d49c3b1-fc90-4762-8c98-e800170baa55"; //from replace_vfmodule_fe_input.json String replaceRequestId = randomUuid(); String userId = "az2016"; + //prepare mocks for newest model + String newestModelUuid = "newest-model-uuid"; + when(commandUtils.getNewestModelUuid(eq("b16a9398-ffa3-4041-b78c-2956b8ad9c7b"))).thenReturn(newestModelUuid); + + when(commandUtils.getServiceModel(eq(newestModelUuid))).thenReturn(generateMockLatestModelForUpgrade()); + //prepare mocks resume request when(restMso.restCall(eq(HttpMethod.POST), eq(RequestReferencesContainer.class), any(), eq("/serviceInstantiation/v7/serviceInstances/e9993045-cc96-4f3f-bf9a-71b2a400a956/vnfs/5c9c2896-1fe6-4055-b7ec-d0a01e5f9bf5/vfModules/5d49c3b1-fc90-4762-8c98-e800170baa55/replace"), eq(Optional.of(userId)))) .thenReturn(createResponse(202, instanceId, replaceRequestId)); @@ -1235,7 +1278,53 @@ public class AsyncInstantiationIntegrationTest extends AsyncInstantiationBaseTes requestCaptor.getAllValues().forEach(x->assertJsonEquals(expectedJson, x)); } + private ServiceModel generateMockLatestModelForUpgrade() { + ServiceModel expectedNewestModel = new ServiceModel(); + + + VfModule vfm = new VfModule(); + vfm.setModelCustomizationName("newest-model-customization-name-vfm"); + vfm.setCustomizationUuid("newest-model-customization-uuid-vfm"); + vfm.setVersion("newest-model-version-vfm"); + vfm.setUuid("newest-model-uuid-vfm"); + vfm.setName("newest-model-name-vfm"); + vfm.setInvariantUuid("f7a867f2-596b-4f4a-a128-421e825a6190"); + + + Map vfms = new HashMap<>(); + vfms.put("074c64d0-7e13-4bcc-8bdb-ea922331102d", vfm); + + + VNF vnf = new VNF(); + vnf.setModelCustomizationName("newest-model-customization-name-vnf"); + vnf.setCustomizationUuid("newest-model-customization-uuid-vnf"); + vnf.setVersion("newest-model-version-vnf"); + vnf.setUuid("newest-model-uuid-vnf"); + vnf.setName("newest-model-name-vnf"); + vnf.setInvariantUuid("23122c9b-dd7f-483f-bf0a-e069303db2f7"); + vnf.setVfModules(vfms); + expectedNewestModel.setVfModules(vfms); + + Map vnfs = new HashMap<>(); + vnfs.put("96c23a4a-6887-4b2c-9cce-1e4ea35eaade", vnf); + + Service svc = new Service(); + svc.setInvariantUuid("b16a9398-ffa3-4041-b78c-2956b8ad9c7b"); + svc.setUuid("newest-model-uuid-service"); + svc.setVersion("newest-model-version-service"); + svc.setName("newest-model-name-service"); + + expectedNewestModel.setService(svc); + + expectedNewestModel.setVnfs(vnfs); + + return expectedNewestModel; + + + } + private ServiceInstantiation generateReplaceVfModulePayload() throws IOException { return TestUtils.readJsonResourceFileAsObject("/payload_jsons/vfmodule/replace_vfmodule_fe_input.json", ServiceInstantiation.class); } + } diff --git a/vid-app-common/src/test/java/org/onap/vid/services/AsyncInstantiationBaseTest.java b/vid-app-common/src/test/java/org/onap/vid/services/AsyncInstantiationBaseTest.java index 69458aa86..9cc97116b 100644 --- a/vid-app-common/src/test/java/org/onap/vid/services/AsyncInstantiationBaseTest.java +++ b/vid-app-common/src/test/java/org/onap/vid/services/AsyncInstantiationBaseTest.java @@ -183,7 +183,7 @@ public class AsyncInstantiationBaseTest extends AbstractTestNGSpringContextTests } protected VfModule createVfModuleForReplace(ModelInfo vfModuleModelInfo, String instanceName, String lcpCloudRegionId, String tenantId) { - return new VfModule( vfModuleModelInfo, instanceName, null, Action.Replace.name(), lcpCloudRegionId, null, tenantId, + return new VfModule( vfModuleModelInfo, instanceName, null, Action.Upgrade.name(), lcpCloudRegionId, null, tenantId, null, null, true, null, null, UUID.randomUUID().toString(), null, null); } diff --git a/vid-app-common/src/test/java/org/onap/vid/services/MsoRequestBuilderTest.java b/vid-app-common/src/test/java/org/onap/vid/services/MsoRequestBuilderTest.java index 311eb04cc..bd761f275 100644 --- a/vid-app-common/src/test/java/org/onap/vid/services/MsoRequestBuilderTest.java +++ b/vid-app-common/src/test/java/org/onap/vid/services/MsoRequestBuilderTest.java @@ -603,18 +603,18 @@ public class MsoRequestBuilderTest extends AsyncInstantiationBaseTest { when(featureManager.isActive(Features.FLAG_1810_CR_ADD_CLOUD_OWNER_TO_MSO_REQUEST)).thenReturn(true); when(aaiClient.getCloudOwnerByCloudRegionId("regionOne")).thenReturn("irma-aic"); - ModelInfo vfModuleModelInfo = createVfModuleModelInfo("VfZrdm5bpxmc02092017Vf..CORNELIUS_base..module-0", "1", "eb5de6fb-9ecf-4009-b922-fae3a9ae7d46", - "f7a867f2-596b-4f4a-a128-421e825a6190", "074c64d0-7e13-4bcc-8bdb-ea922331102d",null ); + ModelInfo vfModuleModelInfo = createVfModuleModelInfo("newest-model-name-vfm", "newest-model-version-vfm", "newest-model-uuid-vfm", + "f7a867f2-596b-4f4a-a128-421e825a6190", "newest-model-customization-uuid-vfm","newest-model-customization-name-vfm" ); VfModule vfModuleDetails = createVfModuleForReplace(vfModuleModelInfo, "replace_module", "regionOne", "0422ffb57ba042c0800a29dc85ca70f8"); - ModelInfo serviceModelInfo = createServiceModelInfo("Vf zolson5bpxmc02092017-Service", "1", "bad955c3-29b2-4a27-932e-28e942cc6480", "b16a9398-ffa3-4041-b78c-2956b8ad9c7b", null, null ); + ModelInfo serviceModelInfo = createServiceModelInfo("newest-model-name-service", "newest-model-version-service", "newest-model-uuid-service", "b16a9398-ffa3-4041-b78c-2956b8ad9c7b", null, null ); - ModelInfo vnfModelInfo = createVnfModelInfo("Vf zolson5bpxmc02092017-VF", "1", "d326f424-2312-4dd6-b7fe-364fadbd1ef5", "23122c9b-dd7f-483f-bf0a-e069303db2f7", "96c23a4a-6887-4b2c-9cce-1e4ea35eaade", "Vf zolson5bpxmc02092017-VF 0" ); + ModelInfo vnfModelInfo = createVnfModelInfo("newest-model-name-vnf", "newest-model-version-vnf", "newest-model-uuid-vnf", "23122c9b-dd7f-483f-bf0a-e069303db2f7", "newest-model-customization-uuid-vnf", "newest-model-customization-name-vnf" ); RequestDetailsWrapper result = msoRequestBuilder.generateVfModuleInstantiationRequest(vfModuleDetails, serviceModelInfo, "e9993045-cc96-4f3f-bf9a-71b2a400a956", vnfModelInfo, "5c9c2896-1fe6-4055-b7ec-d0a01e5f9bf5", null,"az2016", "GR_API"); - MsoOperationalEnvironmentTest.assertThatExpectationIsLikeObject(expected, result); + assertThat(result, jsonEquals(expected).when(IGNORING_ARRAY_ORDER)); } } \ No newline at end of file diff --git a/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule.json b/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule.json index c3ab694aa..103985c96 100644 --- a/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule.json +++ b/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule.json @@ -10,9 +10,9 @@ "relatedInstance": { "instanceId": "e9993045-cc96-4f3f-bf9a-71b2a400a956", "modelInfo": { - "modelVersionId": "bad955c3-29b2-4a27-932e-28e942cc6480", - "modelVersion": "1", - "modelName": "Vf zolson5bpxmc02092017-Service", + "modelVersionId": "newest-model-uuid-service", + "modelVersion": "newest-model-version-service", + "modelName": "newest-model-name-service", "modelInvariantId": "b16a9398-ffa3-4041-b78c-2956b8ad9c7b", "modelType": "service" } @@ -21,13 +21,13 @@ "relatedInstance": { "instanceId": "5c9c2896-1fe6-4055-b7ec-d0a01e5f9bf5", "modelInfo": { - "modelName": "Vf zolson5bpxmc02092017-VF", - "modelVersion": "1", + "modelName": "newest-model-name-vnf", + "modelVersion": "newest-model-version-vnf", "modelInvariantId": "23122c9b-dd7f-483f-bf0a-e069303db2f7", "modelType": "vnf", - "modelCustomizationName": "Vf zolson5bpxmc02092017-VF 0", - "modelVersionId": "d326f424-2312-4dd6-b7fe-364fadbd1ef5", - "modelCustomizationId": "96c23a4a-6887-4b2c-9cce-1e4ea35eaade" + "modelCustomizationName": "newest-model-customization-name-vnf", + "modelVersionId": "newest-model-uuid-vnf", + "modelCustomizationId": "newest-model-customization-uuid-vnf" } } }], @@ -36,12 +36,13 @@ "testApi": "GR_API" }, "modelInfo": { - "modelName": "VfZrdm5bpxmc02092017Vf..CORNELIUS_base..module-0", - "modelVersion": "1", + "modelName": "newest-model-name-vfm", + "modelVersion": "newest-model-version-vfm", "modelInvariantId": "f7a867f2-596b-4f4a-a128-421e825a6190", "modelType": "vfModule", - "modelVersionId": "eb5de6fb-9ecf-4009-b922-fae3a9ae7d46", - "modelCustomizationId": "074c64d0-7e13-4bcc-8bdb-ea922331102d" + "modelVersionId": "newest-model-uuid-vfm", + "modelCustomizationId": "newest-model-customization-uuid-vfm", + "modelCustomizationName":"newest-model-customization-name-vfm" }, "cloudConfiguration": { "cloudOwner": "irma-aic", diff --git a/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule_fe_input.json b/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule_fe_input.json index 92ccfe541..8d30fd873 100644 --- a/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule_fe_input.json +++ b/vid-app-common/src/test/resources/payload_jsons/vfmodule/replace_vfmodule_fe_input.json @@ -8,7 +8,7 @@ "VfZrdm5bpxmc02092017Vf..CORNELIUS_base..module-0-?": { "instanceName": "replace_module", "instanceId": "5d49c3b1-fc90-4762-8c98-e800170baa55", - "action": "Replace", + "action": "Upgrade", "orchStatus": "Create", "provStatus": "Prov Status", "inMaint": false, @@ -21,6 +21,7 @@ "modelName": "VfZrdm5bpxmc02092017Vf..CORNELIUS_base..module-0", "modelVersion": "1", "modelCustomizationId": "074c64d0-7e13-4bcc-8bdb-ea922331102d", + "modelCustomizationName" : "VfZrdm5bpxmc02092017Vf..CORNELIUS_base..module-0", "uuid": "eb5de6fb-9ecf-4009-b922-fae3a9ae7d46" }, "uuid": "eb5de6fb-9ecf-4009-b922-fae3a9ae7d46" -- cgit 1.2.3-korg