From 5223788222fd78c9e50680471eb0529361645230 Mon Sep 17 00:00:00 2001 From: Elena Kuleshov Date: Mon, 15 Apr 2019 22:59:18 -0400 Subject: [PATCH] Use distribution json for workflow install Use distribution json for workflow install Change-Id: I2eec3700d0ba92794b6ca11bd43683d91fb480ee Issue-ID: SO-1726 Signed-off-by: Kuleshov, Elena --- .../org/onap/so/asdc/client/ASDCConfiguration.java | 2 +- .../org/onap/so/asdc/client/ASDCController.java | 28 +-- .../so/asdc/installer/PnfResourceStructure.java | 6 + .../onap/so/asdc/installer/ResourceStructure.java | 13 ++ .../so/asdc/installer/VfResourceStructure.java | 6 + .../onap/so/asdc/installer/WorkflowArtifact.java | 65 +++++++ .../onap/so/asdc/installer/bpmn/BpmnInstaller.java | 12 +- .../so/asdc/installer/bpmn/WorkflowResource.java | 215 +++++++++++++++++++++ .../installer/heat/ToscaResourceInstaller.java | 5 + .../client/test/rest/ASDCRestInterfaceTest.java | 63 +++++- .../so/asdc/installer/bpmn/BpmnInstallerTest.java | 4 +- .../asdc/installer/bpmn/WorkflowResourceTest.java | 109 +++++++++++ .../src/test/resources/application-test.yaml | 1 + .../WorkflowBpmn/TestBpmnFromSDC.bpmn | 44 +++++ .../WorkflowBpmn/TestWF2-1_0.bpmn | 16 ++ .../testvf0/artifacts/TestWF-1_0.bpmn | 16 ++ .../testvf0/artifacts/TestWF-2_0.bpmn | 20 ++ .../testvf0/artifacts/TestWF2-1_0.bpmn | 16 ++ .../service-Testparentservice-csar.csar | Bin 0 -> 48128 bytes .../WorkflowBpmn/workflow-distribution.json | 76 ++++++++ 20 files changed, 694 insertions(+), 23 deletions(-) create mode 100644 asdc-controller/src/main/java/org/onap/so/asdc/installer/WorkflowArtifact.java create mode 100644 asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/WorkflowResource.java create mode 100644 asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/WorkflowResourceTest.java create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestBpmnFromSDC.bpmn create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestWF2-1_0.bpmn create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-1_0.bpmn create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-2_0.bpmn create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF2-1_0.bpmn create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/service-Testparentservice-csar.csar create mode 100644 asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/workflow-distribution.json diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCConfiguration.java b/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCConfiguration.java index e2c358aa53..2eace7587f 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCConfiguration.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCConfiguration.java @@ -55,7 +55,7 @@ public class ASDCConfiguration implements IConfiguration { public static final String HEAT_VOL = "HEAT_VOL"; public static final String OTHER = "OTHER"; public static final String TOSCA_CSAR = "TOSCA_CSAR"; - public static final String WORKFLOWS = "Workflows"; + public static final String WORKFLOW = "WORKFLOW"; public static final String VF_MODULES_METADATA = "VF_MODULES_METADATA"; private static final String[] SUPPORTED_ARTIFACT_TYPES = diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCController.java b/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCController.java index f2e875fc0c..9b838c4d98 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCController.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/client/ASDCController.java @@ -47,6 +47,7 @@ import org.onap.sdc.api.results.IDistributionClientResult; import org.onap.sdc.impl.DistributionClientFactory; import org.onap.sdc.utils.DistributionActionResultEnum; import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.so.asdc.activity.DeployActivitySpecs; import org.onap.so.asdc.client.exceptions.ASDCControllerException; import org.onap.so.asdc.client.exceptions.ASDCDownloadException; import org.onap.so.asdc.client.exceptions.ASDCParametersException; @@ -57,7 +58,6 @@ import org.onap.so.asdc.installer.ResourceStructure; import org.onap.so.asdc.installer.ResourceType; import org.onap.so.asdc.installer.ToscaResourceStructure; import org.onap.so.asdc.installer.VfResourceStructure; -import org.onap.so.asdc.installer.bpmn.BpmnInstaller; import org.onap.so.asdc.installer.heat.ToscaResourceInstaller; import org.onap.so.asdc.tenantIsolation.DistributionStatus; import org.onap.so.asdc.tenantIsolation.WatchdogDistribution; @@ -88,9 +88,6 @@ public class ASDCController { @Autowired private ToscaResourceInstaller toscaInstaller; - @Autowired - private BpmnInstaller bpmnInstaller; - @Autowired private WatchdogDistributionStatusRepository wdsRepo; @@ -110,6 +107,9 @@ public class ASDCController { @Autowired private WatchdogDistribution wd; + @Autowired + DeployActivitySpecs deployActivitySpecs; + public int getNbOfNotificationsOngoing() { return nbOfNotificationsOngoing; } @@ -668,9 +668,6 @@ public class ASDCController { msoConfigPath + "/ASDC/" + iArtifact.getArtifactVersion() + "/" + iArtifact.getArtifactName(); File csarFile = new File(filePath); String csarFilePath = csarFile.getAbsolutePath(); - if (bpmnInstaller.containsWorkflows(csarFilePath)) { - bpmnInstaller.installBpmn(csarFilePath); - } for (IResourceInstance resource : iNotif.getResources()) { @@ -679,7 +676,7 @@ public class ASDCController { logger.info("Processing Resource Type: {}, Model UUID: {}", resourceType, resource.getResourceUUID()); - if ("VF".equals(resourceType) && !"Allotted Resource".equalsIgnoreCase(category)) { + if ("VF".equals(resourceType)) { resourceStructure = new VfResourceStructure(iNotif, resource); } else if ("PNF".equals(resourceType)) { resourceStructure = new PnfResourceStructure(iNotif, resource); @@ -697,7 +694,7 @@ public class ASDCController { logger.debug("Processing Resource Type: " + resourceType + " and Model UUID: " + resourceStructure.getResourceInstance().getResourceUUID()); - if ("VF".equals(resourceType) && !"Allotted Resource".equalsIgnoreCase(category)) { + if ("VF".equals(resourceType)) { hasVFResource = true; for (IArtifactInfo artifact : resource.getArtifacts()) { IDistributionClientDownloadResult resultArtifact = @@ -711,8 +708,15 @@ public class ASDCController { .dumpVfModuleMetaDataList(((VfResourceStructure) resourceStructure) .decodeVfModuleArtifact(resultArtifact.getArtifactPayload()))); } - resourceStructure.addArtifactToStructure(distributionClient, artifact, - resultArtifact); + if (!ASDCConfiguration.WORKFLOW.equals(artifact.getArtifactType())) { + resourceStructure.addArtifactToStructure(distributionClient, artifact, + resultArtifact); + } else { + writeArtifactToFile(artifact, resultArtifact); + logger.debug( + "Adding workflow artifact to structure: " + artifact.getArtifactName()); + resourceStructure.addWorkflowArtifactToStructure(artifact, resultArtifact); + } } } @@ -801,7 +805,7 @@ public class ASDCController { "processCsarServiceArtifacts", ErrorCode.BusinessProcesssError.getValue(), "Exception in processCsarServiceArtifacts", e); } - } else if (artifact.getArtifactType().equals(ASDCConfiguration.WORKFLOWS)) { + } else if (artifact.getArtifactType().equals(ASDCConfiguration.WORKFLOW)) { try { diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/PnfResourceStructure.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/PnfResourceStructure.java index 8aa9684426..2a6e77ed40 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/installer/PnfResourceStructure.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/PnfResourceStructure.java @@ -38,6 +38,12 @@ public class PnfResourceStructure extends ResourceStructure { } + @Override + public void addWorkflowArtifactToStructure(IArtifactInfo artifactinfo, + IDistributionClientDownloadResult clientResult) throws UnsupportedEncodingException { + + } + @Override public void prepareInstall() throws ArtifactInstallerException { diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/ResourceStructure.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/ResourceStructure.java index 9965a05294..8be3d6ba06 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/installer/ResourceStructure.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/ResourceStructure.java @@ -68,10 +68,16 @@ public abstract class ResourceStructure { */ protected final Map artifactsMapByUUID; + /** + * The list of workflow artifacts existing in this resource + */ + protected final Map workflowArtifactsMapByUUID; + public ResourceStructure(INotificationData notificationData, IResourceInstance resourceInstance) { this.notificationData = notificationData; this.resourceInstance = resourceInstance; artifactsMapByUUID = new HashMap<>(); + workflowArtifactsMapByUUID = new HashMap<>(); } /** @@ -85,6 +91,9 @@ public abstract class ResourceStructure { public abstract void addArtifactToStructure(IDistributionClient distributionClient, IArtifactInfo artifactinfo, IDistributionClientDownloadResult clientResult) throws UnsupportedEncodingException; + public abstract void addWorkflowArtifactToStructure(IArtifactInfo artifactinfo, + IDistributionClientDownloadResult clientResult) throws UnsupportedEncodingException; + /** * Prepare the resource for installation. * @@ -144,4 +153,8 @@ public abstract class ResourceStructure { return artifactsMapByUUID; } + public Map getWorkflowArtifactsMapByUUID() { + return workflowArtifactsMapByUUID; + } + } diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/VfResourceStructure.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/VfResourceStructure.java index 62408be922..16e9fda7c4 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/installer/VfResourceStructure.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/VfResourceStructure.java @@ -98,6 +98,12 @@ public class VfResourceStructure extends ResourceStructure { } } + public void addWorkflowArtifactToStructure(IArtifactInfo artifactinfo, + IDistributionClientDownloadResult clientResult) throws UnsupportedEncodingException { + WorkflowArtifact workflowArtifact = new WorkflowArtifact(artifactinfo, clientResult); + workflowArtifactsMapByUUID.put(artifactinfo.getArtifactUUID(), workflowArtifact); + } + protected void addArtifactByType(IArtifactInfo artifactinfo, IDistributionClientDownloadResult clientResult, VfModuleArtifact vfModuleArtifact) throws UnsupportedEncodingException { diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/WorkflowArtifact.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/WorkflowArtifact.java new file mode 100644 index 0000000000..83b5614104 --- /dev/null +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/WorkflowArtifact.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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.so.asdc.installer; + + +import java.io.UnsupportedEncodingException; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; + +/** + * The structure that contains the artifactInfo and its associated DownloadedResult. + * + */ +public final class WorkflowArtifact { + private final IArtifactInfo artifactInfo; + private int deployedInDb = 0; + private final String result; + + public WorkflowArtifact(IArtifactInfo artifactinfo, IDistributionClientDownloadResult clientResult) + throws UnsupportedEncodingException { + result = new String(clientResult.getArtifactPayload(), "UTF-8"); + artifactInfo = artifactinfo; + + } + + public IArtifactInfo getArtifactInfo() { + return artifactInfo; + } + + public String getResult() { + return result; + } + + public int getDeployedInDb() { + return deployedInDb; + } + + public void incrementDeployedInDB() { + ++deployedInDb; + } + + + +} diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/BpmnInstaller.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/BpmnInstaller.java index c98fb9b619..7945ad0174 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/BpmnInstaller.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/BpmnInstaller.java @@ -58,7 +58,7 @@ public class BpmnInstaller { protected static final Logger logger = LoggerFactory.getLogger(BpmnInstaller.class); private static final String BPMN_SUFFIX = ".bpmn"; private static final String CAMUNDA_URL = "mso.camundaURL"; - private static final String CREATE_DEPLOYMENT_PATH = "/sobpmnengine/deployment/create"; + private static final String CREATE_DEPLOYMENT_PATH = "sobpmnengine/deployment/create"; @Autowired private Environment env; @@ -78,7 +78,7 @@ public class BpmnInstaller { Path p = Paths.get(name); String fileName = p.getFileName().toString(); extractBpmnFileFromCsar(csarFile, fileName); - HttpResponse response = sendDeploymentRequest(fileName); + HttpResponse response = sendDeploymentRequest(fileName, ""); logger.debug("Response status line: {}", response.getStatusLine()); logger.debug("Response entity: {}", response.getEntity().toString()); if (response.getStatusLine().getStatusCode() != 200) { @@ -125,21 +125,21 @@ public class BpmnInstaller { return workflowsInCsar; } - protected HttpResponse sendDeploymentRequest(String bpmnFileName) throws Exception { + protected HttpResponse sendDeploymentRequest(String bpmnFileName, String version) throws Exception { HttpClient client = HttpClientBuilder.create().build(); URI deploymentUri = new URI(this.env.getProperty(CAMUNDA_URL) + CREATE_DEPLOYMENT_PATH); HttpPost post = new HttpPost(deploymentUri); RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(1000000).setConnectTimeout(1000) .setConnectionRequestTimeout(1000).build(); post.setConfig(requestConfig); - HttpEntity requestEntity = buildMimeMultipart(bpmnFileName); + HttpEntity requestEntity = buildMimeMultipart(bpmnFileName, version); post.setEntity(requestEntity); return client.execute(post); } - protected HttpEntity buildMimeMultipart(String bpmnFileName) throws Exception { + protected HttpEntity buildMimeMultipart(String bpmnFileName, String version) throws Exception { FileInputStream bpmnFileStream = new FileInputStream( - Paths.get(System.getProperty("mso.config.path"), "ASDC", bpmnFileName).normalize().toString()); + Paths.get(System.getProperty("mso.config.path"), "ASDC", version, bpmnFileName).normalize().toString()); byte[] bytesToSend = IOUtils.toByteArray(bpmnFileStream); HttpEntity requestEntity = diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/WorkflowResource.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/WorkflowResource.java new file mode 100644 index 0000000000..daeda2f976 --- /dev/null +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/bpmn/WorkflowResource.java @@ -0,0 +1,215 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright (c) 2019 Samsung + * ================================================================================ + * 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.so.asdc.installer.bpmn; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.http.HttpResponse; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.so.asdc.installer.VfResourceStructure; +import org.onap.so.asdc.installer.WorkflowArtifact; +import org.onap.so.db.catalog.beans.ActivitySpec; +import org.onap.so.db.catalog.beans.VnfResourceWorkflow; +import org.onap.so.db.catalog.beans.Workflow; +import org.onap.so.db.catalog.beans.WorkflowActivitySpecSequence; +import org.onap.so.db.catalog.data.repository.ActivitySpecRepository; +import org.onap.so.db.catalog.data.repository.WorkflowRepository; +import org.onap.so.logger.ErrorCode; +import org.onap.so.logger.MessageEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class WorkflowResource { + protected static final Logger logger = LoggerFactory.getLogger(WorkflowResource.class); + + private static final String pattern = ".*\\\"activity:(.*)\\\" .*"; + private static final String TARGET_RESOURCE_VNF = "vnf"; + private static final String SOURCE_SDC = "sdc"; + private static final String BPMN_SUFFIX = ".bpmn"; + + @Autowired + protected WorkflowRepository workflowRepo; + + @Autowired + protected ActivitySpecRepository activityRepo; + + @Autowired + private BpmnInstaller bpmnInstaller; + + public void processWorkflows(VfResourceStructure vfResourceStructure) throws Exception { + Map artifactsMapByUUID = vfResourceStructure.getWorkflowArtifactsMapByUUID(); + String vfResourceModelUuid = vfResourceStructure.getResourceInstance().getResourceUUID(); + for (String uuid : artifactsMapByUUID.keySet()) { + WorkflowArtifact artifactToInstall = artifactsMapByUUID.get(uuid); + if (isLatestVersionAvailable(artifactsMapByUUID, artifactToInstall)) { + logger.debug("Installing the BPMN: " + artifactToInstall.getArtifactInfo().getArtifactName()); + deployWorkflowResourceToCamunda(artifactToInstall); + installWorkflowResource(artifactToInstall, vfResourceModelUuid); + } else { + logger.debug("Skipping installing - not the latest version: " + + artifactToInstall.getArtifactInfo().getArtifactName()); + } + } + } + + protected void deployWorkflowResourceToCamunda(WorkflowArtifact artifact) throws Exception { + String bpmnName = artifact.getArtifactInfo().getArtifactName(); + String version = artifact.getArtifactInfo().getArtifactVersion(); + logger.debug("BPMN Name: " + bpmnName); + try { + HttpResponse response = bpmnInstaller.sendDeploymentRequest(bpmnName, version); + logger.debug("Response status line: {}", response.getStatusLine()); + logger.debug("Response entity: {}", response.getEntity().toString()); + if (response.getStatusLine().getStatusCode() != 200) { + logger.debug("Failed deploying BPMN {}", bpmnName); + logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_NOT_DEPLOYED_DETAIL.toString(), bpmnName, + bpmnName, Integer.toString(response.getStatusLine().getStatusCode()), + ErrorCode.DataError.getValue(), "ASDC BPMN deploy failed"); + throw (new Exception("Error from Camunda on deploying the BPMN: " + bpmnName)); + } else { + logger.debug("Successfully deployed to Camunda: {}", bpmnName); + } + } catch (Exception e) { + logger.debug("Exception :", e); + logger.error("{} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_NOT_DEPLOYED_DETAIL.toString(), bpmnName, + e.getMessage(), ErrorCode.DataError.getValue(), "ASDC BPMN deploy failed"); + throw e; + } + } + + protected void installWorkflowResource(WorkflowArtifact artifact, String vfResourceModelUuid) throws Exception { + IArtifactInfo artifactInfo = artifact.getArtifactInfo(); + + Workflow workflow = new Workflow(); + + workflow.setArtifactChecksum(artifactInfo.getArtifactChecksum()); + workflow.setArtifactName(artifactInfo.getArtifactName()); + workflow.setArtifactUUID(artifactInfo.getArtifactUUID()); + workflow.setBody(artifact.getResult()); + workflow.setDescription(artifactInfo.getArtifactDescription()); + workflow.setName(getWorkflowNameFromArtifactName(artifactInfo.getArtifactName())); + workflow.setResourceTarget(TARGET_RESOURCE_VNF); + workflow.setSource(SOURCE_SDC); + workflow.setTimeoutMinutes(artifactInfo.getArtifactTimeout()); + workflow.setOperationName(getWorkflowNameFromArtifactName(artifactInfo.getArtifactName())); + workflow.setVersion(getWorkflowVersionFromArtifactName(artifactInfo.getArtifactName())); + + VnfResourceWorkflow vnfResourceWorkflow = new VnfResourceWorkflow(); + vnfResourceWorkflow.setVnfResourceModelUUID(vfResourceModelUuid); + List vnfResourceWorkflows = new ArrayList(); + vnfResourceWorkflows.add(vnfResourceWorkflow); + + workflow.setVnfResourceWorkflow(vnfResourceWorkflows); + + List activityNames = getActivityNameList(artifact.getResult()); + List wfss = getWorkflowActivitySpecSequence(activityNames); + workflow.setWorkflowActivitySpecSequence(wfss); + + workflowRepo.save(workflow); + + } + + protected boolean isLatestVersionAvailable(Map artifactsMapByUUID, + WorkflowArtifact artifact) { + String workflowName = getWorkflowNameFromArtifactName(artifact.getArtifactInfo().getArtifactName()); + Double workflowVersion = getWorkflowVersionFromArtifactName(artifact.getArtifactInfo().getArtifactName()); + if (workflowVersion == null) { + workflowVersion = 0.0; + } + for (WorkflowArtifact artifactInMap : artifactsMapByUUID.values()) { + Double versionInMap = getWorkflowVersionFromArtifactName(artifactInMap.getArtifactInfo().getArtifactName()); + if (versionInMap == null) { + versionInMap = 0.0; + } + if (workflowName.equals(getWorkflowNameFromArtifactName(artifactInMap.getArtifactInfo().getArtifactName())) + && Double.compare(workflowVersion, versionInMap) < 0) { + return false; + } + } + return true; + } + + protected List getActivityNameList(String bpmnContent) { + List activityNameList = new ArrayList(); + + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(bpmnContent); + while (m.find()) { + activityNameList.add(m.group(1)); + } + return activityNameList; + } + + protected List getWorkflowActivitySpecSequence(List activityNames) + throws Exception { + if (activityNames == null || activityNames.size() == 0) { + return null; + } + List workflowActivitySpecs = new ArrayList(); + for (String activityName : activityNames) { + ActivitySpec activitySpec = activityRepo.findByName(activityName); + if (activitySpec != null) { + WorkflowActivitySpecSequence workflowActivitySpec = new WorkflowActivitySpecSequence(); + workflowActivitySpec.setActivitySpec(activitySpec); + workflowActivitySpecs.add(workflowActivitySpec); + } + } + return workflowActivitySpecs; + } + + public String getWorkflowNameFromArtifactName(String artifactName) { + if (artifactName == null) { + return null; + } else { + if (artifactName.contains(BPMN_SUFFIX)) { + return artifactName.substring(0, artifactName.lastIndexOf(BPMN_SUFFIX)).split("-")[0]; + } else { + return artifactName.split("-")[0]; + } + } + } + + public Double getWorkflowVersionFromArtifactName(String artifactName) { + if (artifactName == null) { + return null; + } else { + String[] workflowNameParts = null; + if (artifactName.contains(BPMN_SUFFIX)) { + workflowNameParts = artifactName.substring(0, artifactName.lastIndexOf(BPMN_SUFFIX)).split("-"); + } else { + workflowNameParts = artifactName.split("-"); + } + if (workflowNameParts.length < 2) { + return null; + } else { + return Double.valueOf(workflowNameParts[1].replaceAll("_", ".")); + } + } + } +} diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java index d3eab9a3fd..23c31f3298 100644 --- a/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java +++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java @@ -70,6 +70,7 @@ import org.onap.so.asdc.installer.ToscaResourceStructure; import org.onap.so.asdc.installer.VfModuleArtifact; import org.onap.so.asdc.installer.VfModuleStructure; import org.onap.so.asdc.installer.VfResourceStructure; +import org.onap.so.asdc.installer.bpmn.WorkflowResource; import org.onap.so.asdc.util.YamlEditor; import org.onap.so.db.catalog.beans.AllottedResource; import org.onap.so.db.catalog.beans.AllottedResourceCustomization; @@ -246,6 +247,9 @@ public class ToscaResourceInstaller { @Autowired protected PnfCustomizationRepository pnfCustomizationRepository; + @Autowired + protected WorkflowResource workflowResource; + protected static final Logger logger = LoggerFactory.getLogger(ToscaResourceInstaller.class); public boolean isResourceAlreadyDeployed(ResourceStructure vfResourceStruct, boolean serviceDeployed) @@ -400,6 +404,7 @@ public class ToscaResourceInstaller { vfCustomizationCategory); } + workflowResource.processWorkflows(vfResourceStructure); processResourceSequence(toscaResourceStruct, service); List allottedResourceList = toscaResourceStruct.getSdcCsarHelper().getAllottedResources(); processAllottedResources(toscaResourceStruct, service, allottedResourceList); diff --git a/asdc-controller/src/test/java/org/onap/so/asdc/client/test/rest/ASDCRestInterfaceTest.java b/asdc-controller/src/test/java/org/onap/so/asdc/client/test/rest/ASDCRestInterfaceTest.java index 2e5ad13c21..ac107f6449 100644 --- a/asdc-controller/src/test/java/org/onap/so/asdc/client/test/rest/ASDCRestInterfaceTest.java +++ b/asdc-controller/src/test/java/org/onap/so/asdc/client/test/rest/ASDCRestInterfaceTest.java @@ -22,12 +22,15 @@ package org.onap.so.asdc.client.test.rest; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; import static com.shazam.shazamcrest.MatcherAssert.assertThat; import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.HashSet; import java.util.Set; import javax.transaction.Transactional; @@ -43,9 +46,11 @@ import org.onap.so.asdc.client.test.emulators.NotificationDataImpl; import org.onap.so.db.catalog.beans.AllottedResource; import org.onap.so.db.catalog.beans.AllottedResourceCustomization; import org.onap.so.db.catalog.beans.Service; +import org.onap.so.db.catalog.beans.Workflow; import org.onap.so.db.catalog.data.repository.AllottedResourceRepository; import org.onap.so.db.catalog.data.repository.NetworkResourceRepository; import org.onap.so.db.catalog.data.repository.ServiceRepository; +import org.onap.so.db.catalog.data.repository.WorkflowRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; @@ -66,6 +71,9 @@ public class ASDCRestInterfaceTest extends BaseTest { @Autowired private NetworkResourceRepository networkRepo; + @Autowired + private WorkflowRepository workflowRepo; + @Autowired private ASDCRestInterface asdcRestInterface; @@ -97,6 +105,10 @@ public class ASDCRestInterfaceTest extends BaseTest { wireMockServer.stubFor(post(urlPathMatching("/aai/.*")) .willReturn(aResponse().withStatus(200).withHeader("Content-Type", "application/json"))); + wireMockServer.stubFor(post(urlPathMatching("/v1.0/activity-spec")) + .willReturn(aResponse().withHeader("Content-Type", "application/json") + .withStatus(org.springframework.http.HttpStatus.ACCEPTED.value()))); + ObjectMapper mapper = new ObjectMapper(); NotificationDataImpl request = mapper.readValue(new File("src/test/resources/resource-examples/allottedresource/notif-portm.json"), @@ -146,6 +158,10 @@ public class ASDCRestInterfaceTest extends BaseTest { wireMockServer.stubFor(post(urlPathMatching("/aai/.*")) .willReturn(aResponse().withStatus(200).withHeader("Content-Type", "application/json"))); + wireMockServer.stubFor(post(urlPathMatching("/v1.0/activity-spec")) + .willReturn(aResponse().withHeader("Content-Type", "application/json") + .withStatus(org.springframework.http.HttpStatus.ACCEPTED.value()))); + ObjectMapper mapper = new ObjectMapper(); NotificationDataImpl request = mapper.readValue( new File("src/test/resources/resource-examples/vFW/notification.json"), NotificationDataImpl.class); @@ -175,16 +191,59 @@ public class ASDCRestInterfaceTest extends BaseTest { assertEquals(expectedService.getModelName(), actualService.getModelName()); } + @Test + @Transactional + public void testWorkflowDistribution() throws Exception { + + wireMockServer.stubFor(post(urlPathMatching("/aai/.*")) + .willReturn(aResponse().withStatus(200).withHeader("Content-Type", "application/json"))); + + wireMockServer.stubFor(post(urlPathMatching("/v1.0/activity-spec")) + .willReturn(aResponse().withHeader("Content-Type", "application/json") + .withStatus(org.springframework.http.HttpStatus.ACCEPTED.value()))); + + wireMockServer.stubFor( + post(urlPathEqualTo("/sobpmnengine/deployment/create")).willReturn(aResponse().withStatus(200))); + + ObjectMapper mapper = new ObjectMapper(); + NotificationDataImpl request = mapper.readValue( + new File("src/test/resources/resource-examples/WorkflowBpmn/workflow-distribution.json"), + NotificationDataImpl.class); + headers.add("resource-location", "src/test/resources/resource-examples/WorkflowBpmn/"); + HttpEntity entity = new HttpEntity(request, headers); + + ResponseEntity response = restTemplate.exchange(createURLWithPort("test/treatNotification/v1"), + HttpMethod.POST, entity, String.class); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + + Workflow actualResponse = workflowRepo.findByArtifactUUID("a90f8eaa-7c20-422f-8c81-aacbca6fb9e7"); + + if (actualResponse == null) + throw new Exception("No Workflow Written to database"); + + String expectedBody = new String( + Files.readAllBytes(Paths.get("src/test/resources/resource-examples/WorkflowBpmn/TestWF2-1_0.bpmn"))); + assertEquals(actualResponse.getArtifactChecksum(), "ZjUzNjg1NDMyMTc4MWJmZjFlNDcyOGQ0Zjc1YWQwYzQ\u003d"); + assertEquals(actualResponse.getArtifactName(), "TestWF2-1_0.bpmn"); + assertEquals(actualResponse.getDescription(), "Workflow Artifact Description"); + assertEquals(actualResponse.getBody(), expectedBody); + + Workflow shouldNotBeFound = workflowRepo.findByArtifactUUID("f27066a1-c3a7-4672-b02e-1251b74b7b71"); + assertNull(shouldNotBeFound); + } + @Test public void invokeASDCStatusDataNullTest() { String request = ""; + wireMockServer.stubFor(post(urlPathMatching("/v1.0/activity-spec")) + .willReturn(aResponse().withHeader("Content-Type", "application/json") + .withStatus(org.springframework.http.HttpStatus.ACCEPTED.value()))); Response response = asdcRestInterface.invokeASDCStatusData(request); assertNull(response); } - - protected String createURLWithPort(String uri) { return "http://localhost:" + port + uri; } diff --git a/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/BpmnInstallerTest.java b/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/BpmnInstallerTest.java index 6efb04fc35..7071a68a23 100644 --- a/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/BpmnInstallerTest.java +++ b/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/BpmnInstallerTest.java @@ -81,7 +81,7 @@ public class BpmnInstallerTest { public void buildMimeMultiPart_Test() throws Exception { Path tempFilePath = Paths.get(tempDirectoryPath.toAbsolutePath().toString(), "TestBB.bpmn"); Files.createFile(tempFilePath); - HttpEntity entity = bpmnInstaller.buildMimeMultipart("TestBB.bpmn"); + HttpEntity entity = bpmnInstaller.buildMimeMultipart("TestBB.bpmn", ""); String mimeMultipartBodyFilePath = "src/test/resources" + "/mime-multipart-body.txt"; File mimeMultipartBody = new File(mimeMultipartBodyFilePath); @@ -99,7 +99,7 @@ public class BpmnInstallerTest { HttpClient httpClient = mock(HttpClient.class); doReturn(response).when(httpClient).execute(any(HttpPost.class)); bpmnInstallerSpy.installBpmn(TEST_CSAR); - verify(bpmnInstallerSpy, times(1)).sendDeploymentRequest(anyString()); + verify(bpmnInstallerSpy, times(1)).sendDeploymentRequest(anyString(), anyString()); } @Test diff --git a/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/WorkflowResourceTest.java b/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/WorkflowResourceTest.java new file mode 100644 index 0000000000..e655245c31 --- /dev/null +++ b/asdc-controller/src/test/java/org/onap/so/asdc/installer/bpmn/WorkflowResourceTest.java @@ -0,0 +1,109 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright (c) 2019 Samsung + * ================================================================================ + * 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.so.asdc.installer.bpmn; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import javax.transaction.Transactional; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicHttpResponse; +import org.apache.http.message.BasicStatusLine; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.onap.sdc.api.notification.IArtifactInfo; + +@Transactional +public class WorkflowResourceTest { + + private WorkflowResource workflowResource = new WorkflowResource(); + + private static final String TEST_CSAR = "src/test/resources/resource-examples/WorkflowBpmn/service-CxSvc-csar.csar"; + private Path tempDirectoryPath; + + @Test + public void getActivityNameList_Test() throws Exception { + String bpmnContent = new String(Files + .readAllBytes(Paths.get("src/test/resources/resource-examples/WorkflowBpmn/TestBpmnFromSDC.bpmn"))); + List activityNames = workflowResource.getActivityNameList(bpmnContent); + assertEquals("VNFSetInMaintFlagActivity", activityNames.get(0)); + } + + @Test + public void getWorkflowNameStandard_Test() { + String workflowName = workflowResource.getWorkflowNameFromArtifactName("TestWF2-1_0.bpmn"); + assertEquals("TestWF2", workflowName); + } + + @Test + public void getWorkflowNameNoVersion_Test() { + String workflowName = workflowResource.getWorkflowNameFromArtifactName("TestWF2.bpmn"); + assertEquals("TestWF2", workflowName); + } + + @Test + public void getWorkflowNameNoSuffix_Test() { + String workflowName = workflowResource.getWorkflowNameFromArtifactName("TestWF2-1_0"); + assertEquals("TestWF2", workflowName); + } + + @Test + public void getWorkflowVersionStandard_Test() { + Double workflowVersion = workflowResource.getWorkflowVersionFromArtifactName("TestWF2-1_0.bpmn"); + assertTrue(workflowVersion == 1.0); + } + + @Test + public void getWorkflowVersionNoVersion_Test() { + Double workflowVersion = workflowResource.getWorkflowVersionFromArtifactName("TestWF2.bpmn"); + assertNull(workflowVersion); + } + + @Test + public void getWorkflowVersionNoSuffix_Test() { + Double workflowVersion = workflowResource.getWorkflowVersionFromArtifactName("TestWF2-1_0"); + assertTrue(workflowVersion == 1.0); + } + +} diff --git a/asdc-controller/src/test/resources/application-test.yaml b/asdc-controller/src/test/resources/application-test.yaml index ec536491a1..9fa20550db 100644 --- a/asdc-controller/src/test/resources/application-test.yaml +++ b/asdc-controller/src/test/resources/application-test.yaml @@ -66,6 +66,7 @@ mso: db: spring: endpoint: "http://localhost:" + camundaURL: http://localhost:${wiremock.server.port}/ db: auth: Basic YnBlbDptc28tZGItMTUwNyE= site-name: siteName diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestBpmnFromSDC.bpmn b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestBpmnFromSDC.bpmn new file mode 100644 index 0000000000..f3a5c7cc68 --- /dev/null +++ b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestBpmnFromSDC.bpmn @@ -0,0 +1,44 @@ + + + + + + + + SequenceFlow_1v7ptqz + + + + + + SequenceFlow_1v7ptqz + SequenceFlow_16i7mid + + + SequenceFlow_16i7mid + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestWF2-1_0.bpmn b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestWF2-1_0.bpmn new file mode 100644 index 0000000000..11378cfbb6 --- /dev/null +++ b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/TestWF2-1_0.bpmn @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-1_0.bpmn b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-1_0.bpmn new file mode 100644 index 0000000000..4e21a47a27 --- /dev/null +++ b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-1_0.bpmn @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-2_0.bpmn b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-2_0.bpmn new file mode 100644 index 0000000000..e54d79aee4 --- /dev/null +++ b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-2_0.bpmn @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF2-1_0.bpmn b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF2-1_0.bpmn new file mode 100644 index 0000000000..11378cfbb6 --- /dev/null +++ b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF2-1_0.bpmn @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/service-Testparentservice-csar.csar b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/service-Testparentservice-csar.csar new file mode 100644 index 0000000000000000000000000000000000000000..fe99318fe3f8ccf11feb8bdf90649d7d680f1c66 GIT binary patch literal 48128 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 E1DLhtB>(^b literal 0 HcmV?d00001 diff --git a/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/workflow-distribution.json b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/workflow-distribution.json new file mode 100644 index 0000000000..9f49be5bbb --- /dev/null +++ b/asdc-controller/src/test/resources/resource-examples/WorkflowBpmn/workflow-distribution.json @@ -0,0 +1,76 @@ +{ + "distributionID": "48cc0f04-1d42-4fb4-a5ab-9fa62f8d64c1", + "serviceName": "TestParentService", + "serviceVersion": "1.0", + "serviceUUID": "2f55da47-c58a-453e-909f-172c94765fba", + "serviceDescription": "TestParentService", + "serviceInvariantUUID": "13b817ae-6388-40cf-9261-1619b607f1de", + "resources": [ + { + "resourceInstanceName": "TestVF 0", + "resourceName": "TestVF", + "resourceVersion": "1.0", + "resoucreType": "VF", + "resourceUUID": "5185253e-4bef-4eb4-bbf9-8c328c787ebd", + "resourceInvariantUUID": "ea8264db-3e24-4324-87cc-12c6903ed43d", + "resourceCustomizationUUID": "a959a3cb-4988-435c-9cb7-5a40ef2ef2ac", + "category": "Allotted Resource", + "subcategory": "Contrail Route", + "artifacts": [ + { + "artifactName": "TestWF2-1_0.bpmn", + "artifactType": "WORKFLOW", + "artifactURL": "/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF2-1_0.bpmn", + "artifactChecksum": "ZjUzNjg1NDMyMTc4MWJmZjFlNDcyOGQ0Zjc1YWQwYzQ\u003d", + "artifactDescription": "Workflow Artifact Description", + "artifactTimeout": 120, + "artifactUUID": "a90f8eaa-7c20-422f-8c81-aacbca6fb9e7", + "artifactVersion": "1" + }, + { + "artifactName": "TestWF-1_0.bpmn", + "artifactType": "WORKFLOW", + "artifactURL": "/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-1_0.bpmn", + "artifactChecksum": "YzA4NDY3M2E3Njk3Y2FjMmViZjRlODIzNTY1NDY3MDY\u003d", + "artifactDescription": "Workflow Artifact Description", + "artifactTimeout": 120, + "artifactUUID": "f27066a1-c3a7-4672-b02e-1251b74b7b71", + "artifactVersion": "1" + }, + { + "artifactName": "TestWF-2_0.bpmn", + "artifactType": "WORKFLOW", + "artifactURL": "/sdc/v1/catalog/services/Testparentservice/1.0/resourceInstances/testvf0/artifacts/TestWF-2_0.bpmn", + "artifactChecksum": "MTE0MDA2ZGNjZmY3YWEyNzNlNjUwZDQ2OGU4YTM5ZjU\u003d", + "artifactDescription": "Workflow Artifact Description", + "artifactTimeout": 120, + "artifactUUID": "f51d2203-d1f5-43f1-9492-e59d12facb8f", + "artifactVersion": "1" + } + ] + } + ], + "serviceArtifacts": [ + { + "artifactName": "service-Testparentservice-template.yml", + "artifactType": "TOSCA_TEMPLATE", + "artifactURL": "/sdc/v1/catalog/services/Testparentservice/1.0/artifacts/service-Testparentservice-template.yml", + "artifactChecksum": "YWZlYWMwMjNkODBlYTI2MzZlNjg3YzEzODZiNzNkNTg\u003d", + "artifactDescription": "TOSCA representation of the asset", + "artifactTimeout": 0, + "artifactUUID": "8ec96c3f-d527-48bd-8dc5-1e7682bda676", + "artifactVersion": "1" + }, + { + "artifactName": "service-Testparentservice-csar.csar", + "artifactType": "TOSCA_CSAR", + "artifactURL": "service-Testparentservice-csar.csar", + "artifactChecksum": "MTc4OWU0MGRhOTE4OGZiM2JiMjM3YmI3NzI2YWZjNjI\u003d", + "artifactDescription": "TOSCA definition package of the asset", + "artifactTimeout": 0, + "artifactUUID": "8dac522d-8e00-4794-819e-88e559ebc170", + "artifactVersion": "1" + } + ], + "workloadContext": "Production" +} \ No newline at end of file -- 2.16.6