From e7fe6ef90bc5a29560e5495fd2eb70912f844540 Mon Sep 17 00:00:00 2001 From: dfilppi Date: Wed, 14 Mar 2018 21:40:13 +0000 Subject: Added Aria VDU adapter Change-Id: I232b2bd6ac9e40bcc9415f484b6adb96db81261e Issue-ID: SO-441 Signed-off-by: DeWayne Filppi --- adapters/mso-vnf-adapter/pom.xml | 5 + .../openecomp/mso/adapters/vnf/AriaVduPlugin.java | 305 +++++++++++++++++++++ .../java/org/openecomp/mso/adapters/vnf/CSAR.java | 185 +++++++++++++ 3 files changed, 495 insertions(+) create mode 100644 adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/AriaVduPlugin.java create mode 100644 adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/CSAR.java diff --git a/adapters/mso-vnf-adapter/pom.xml b/adapters/mso-vnf-adapter/pom.xml index 9a290f4f00..643f42f2ba 100644 --- a/adapters/mso-vnf-adapter/pom.xml +++ b/adapters/mso-vnf-adapter/pom.xml @@ -144,6 +144,11 @@ status-control ${project.version} + + org.onap.so + aria-client + 1.2.0 + org.jmockit jmockit diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/AriaVduPlugin.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/AriaVduPlugin.java new file mode 100644 index 0000000000..5258b978cc --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/AriaVduPlugin.java @@ -0,0 +1,305 @@ +/*- + * ============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.openecomp.mso.adapters.vnf; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.gigaspaces.aria.rest.client.AriaClient; +import com.gigaspaces.aria.rest.client.AriaClientFactory; +import com.gigaspaces.aria.rest.client.ExecutionDetails; +import com.gigaspaces.aria.rest.client.Input; +import com.gigaspaces.aria.rest.client.InputImpl; +import com.gigaspaces.aria.rest.client.Output; +import com.gigaspaces.aria.rest.client.Service; +import com.gigaspaces.aria.rest.client.ServiceTemplate; +import com.gigaspaces.aria.rest.client.ServiceTemplateImpl; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.exceptions.MsoAdapterException; +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.vdu.utils.VduBlueprint; +import org.openecomp.mso.vdu.utils.VduInfo; +import org.openecomp.mso.vdu.utils.VduPlugin; +import org.openecomp.mso.vdu.utils.VduStatus; + +/** + * ARIA VDU Plugin. Pluggable interface for the ARIA REST API to support TOSCA + * orchestration. + * + * @author DeWayne + * + */ +public class AriaVduPlugin implements VduPlugin { + private static final String API_VERSION = "0.1"; + private static final MsoLogger logger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA); + private AriaClient client=null; + private Map templateIds = new HashMap<>(); + private Map serviceIds = new HashMap<>(); + private Map> inputsCache = new HashMap<>(); + + public AriaVduPlugin() { + super(); + } + + public AriaVduPlugin( String host, int port) { + try { + client = new AriaClientFactory().createRestClient("http", host, port, API_VERSION); + }catch(Exception e) { + logger.error (MessageEnum.RA_CREATE_VNF_ERR, "", "", "", "", "aria", MsoLogger.ErrorCode.AvailabilityError, "Connection to ARIA REST API failed", e); + throw e; + } + } + + /** + * Instantiate VDU in ARIA. vduInstanceName is used for both service template + * name and service name.< + */ + @SuppressWarnings("unchecked") + @Override + public VduInfo instantiateVdu(String cloudSiteId, String tenantId, String vduInstanceName, + VduBlueprint vduBlueprint, Map inputs, String environmentFile, int timeoutMinutes, + boolean suppressBackout) throws MsoException { + + VduInfo vinfo = new VduInfo(vduInstanceName); + byte[] csar = new CSAR(vduBlueprint).create(); + ServiceTemplate template = new ServiceTemplateImpl( vduInstanceName, csar); + try { + client.install_service_template(template); + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceName, MsoLogger.ErrorCode.BusinessProcesssError, + "instantiate vdu via csar failed", e); + throw new MsoAdapterException(e.getMessage()); + } + + /** + * Create a service + */ + + try { + int templateId=-1; + for(ServiceTemplate stemplate:(List)client.list_service_templates()) { + if(stemplate.getName().equals(vduInstanceName)) { + templateId = stemplate.getId(); + } + } + List sinputs = new ArrayList(); + for(Map.Entry entry: inputs.entrySet()) { + Input inp = new InputImpl(entry.getKey(),entry.getValue().toString(),""); + sinputs.add(inp); + } + client.create_service(templateId, vduInstanceName, sinputs); + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceName, MsoLogger.ErrorCode.BusinessProcesssError, + "aria service creation failed", e); + throw new MsoAdapterException(e.getMessage()); + } + + // Get the service ID and cache it + int sid = getServiceId(vduInstanceName); + serviceIds.put(vduInstanceName, sid); + + /** + * Run install + */ + + try { + client.start_execution( sid, "install", new ExecutionDetails()); + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceName, MsoLogger.ErrorCode.BusinessProcesssError, + "aria install workflow failed", e); + throw new MsoAdapterException(e.getMessage()); + } + + /** + * Get the outputs and return + */ + + try { + Map voutputs = getOutputs(sid); + + VduInfo vi = new VduInfo(vduInstanceName); + vi.setInputs((Map)inputs); + inputsCache.put(vduInstanceName,vi.getInputs()); + vi.setOutputs(voutputs); + vi.setStatus(VduStatus.INSTANTIATED); + return vi; + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceName, MsoLogger.ErrorCode.BusinessProcesssError, + "aria service output fetch failed", e); + throw new MsoAdapterException(e.getMessage()); + } + + } + + /** + * Queries ARIA for VDU status. vduInstanceId used as template and service name in ARIA (by convention). + */ + @Override + public VduInfo queryVdu(String cloudSiteId, String tenantId, String vduInstanceId) throws MsoException { + if(client == null) { + throw new MsoAdapterException("Internal error: no ARIA connection found"); + } + + VduInfo vif = new VduInfo(vduInstanceId); + Integer sid = serviceIds.get(vduInstanceId); + if(sid == null) { + // service doesn't exist + vif.setStatus(VduStatus.NOTFOUND); + return vif; + } + Service service = client.get_service(sid); + if(service == null) { + throw new MsoAdapterException(String.format("Internal error: cached service id %s not found in ARIA",sid)); + } + Map voutputs = getOutputs(sid); + vif.setOutputs(voutputs); + vif.setInputs(inputsCache.get(vduInstanceId)); + vif.setStatus(VduStatus.INSTANTIATED); + return vif; + } + + @Override + public VduInfo deleteVdu(String cloudSiteId, String tenantId, String vduInstanceId, int timeoutMinutes, + boolean keepBlueprintLoaded) throws MsoException { + + if(client == null) { + throw new MsoAdapterException("Internal error: no ARIA connection found"); + } + Integer sid = serviceIds.get(vduInstanceId); + VduInfo vif = new VduInfo(vduInstanceId); + if(sid == null) { + // service doesn't exist + vif.setStatus(VduStatus.NOTFOUND); + return vif; + } + + /** + * Run uninstall + */ + try { + client.start_execution( sid, "uninstall", new ExecutionDetails()); + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceId, MsoLogger.ErrorCode.BusinessProcesssError, + "aria uninstall workflow failed", e); + throw new MsoAdapterException(e.getMessage()); + } + + /** + * Delete the service + */ + try { + client.delete_service(sid); + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceId, MsoLogger.ErrorCode.BusinessProcesssError, + String.format("aria service delete failed. Service id: %d",sid), e); + throw new MsoAdapterException(e.getMessage()); + } + + /** + * Delete the blueprint + */ + try { + client.delete_service_template(templateIds.get(vduInstanceId)); + } + catch(Exception e) { + logger.error(MessageEnum.RA_CREATE_VNF_ERR, "","","","", vduInstanceId, MsoLogger.ErrorCode.BusinessProcesssError, + "aria template delete failed", e); + throw new MsoAdapterException(e.getMessage()); + } + + vif.setStatus(VduStatus.DELETED); + return vif; + } + + /** + * Deployment update not possible with ARIA + */ + @Override + public VduInfo updateVdu(String cloudSiteId, String tenantId, String vduInstanceId, VduBlueprint vduBlueprint, + Map inputs, String environmentFile, int timeoutMinutes) throws MsoException { + throw new MsoAdapterException("NOT IMPLEMENTED"); + } + + /** + * Nonsensical in the context of ARIA: blueprint lifespan = vdulifespan + */ + @Override + public boolean isBlueprintLoaded(String cloudSiteId, String vduModelId) throws MsoException { + throw new MsoAdapterException("NOT IMPLEMENTED"); + } + + /** + * Nonsensical in the context of ARIA: blueprint lifespan = vdulifespan + */ + @Override + public void uploadBlueprint(String cloudSiteId, VduBlueprint vduBlueprint, boolean failIfExists) + throws MsoException { + throw new MsoAdapterException("NOT IMPLEMENTED"); + } + + @Override + public boolean blueprintUploadSupported() { + return false; + } + + /** + * Private + */ + + /**p + * Gets and repacks service outputs for internal use + * @param sid the service id (ARIA service id) + * @return + */ + private Map getOutputs(int sid) { + @SuppressWarnings("unchecked") + List outputs=(List)client.list_service_outputs(sid); + Map voutputs = new HashMap<>(); + for(Output output: outputs) { + voutputs.put(output.getName(), output.getValue()); + } + return voutputs; + } + + @SuppressWarnings("unchecked") + private int getServiceId(String service_name) throws MsoAdapterException{ + int sid = -1; + List services = (List)client.list_services(); + for(Service service:services) { + if(service.getName().equals(service_name)) { + sid = service.getId(); + } + } + if(sid == -1) { + throw new MsoAdapterException(String.format("Internal error: just created service not found: %s",service_name)); + } + return sid; + } + +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/CSAR.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/CSAR.java new file mode 100644 index 0000000000..8bea228629 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/CSAR.java @@ -0,0 +1,185 @@ +/* + * ============LICENSE_START=================================================== + * Copyright (c) 2017 Cloudify.co. 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.openecomp.mso.adapters.vnf; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.openecomp.mso.vdu.utils.VduBlueprint; + +import com.google.common.io.Files; + +/** + * The purpose of this class is to create a CSAR byte array from Vdu inputs for the purpose + * of forwarding to a TOSCA orchestrator. + * + * @author DeWayne + * + */ +public class CSAR { + private static final String MANIFEST_FILENAME = "MANIFEST.MF"; + + private VduBlueprint blueprint; + + + public CSAR(VduBlueprint blueprint) { + this.blueprint = blueprint; + } + + /** + * Creates a byte array representation of a CSAR corresponding to the VduBlueprint arg in the + * constructor. + * + * @return + */ + public byte[] create() { + File dir = Files.createTempDir(); + + /** + * Create subdir + */ + File metadir = new File(dir.getAbsolutePath() + "/" + "TOSCA-Metadata"); + if (!metadir.mkdir()) { + throw new RuntimeException("CSAR TOSCA-Metadata directory create failed"); + } + + /** + * Write template files + */ + OutputStream ofs = null; + try { + ofs = new FileOutputStream(new File(dir, blueprint.getMainTemplateName())); + ofs.write(blueprint.getTemplateFiles().get(blueprint.getMainTemplateName())); + ofs.close(); + + /** + * Write other files + */ + if (blueprint.getTemplateFiles() != null) { + for (Map.Entry entry : blueprint.getTemplateFiles().entrySet()) { + if (!entry.getKey().equals(blueprint.getMainTemplateName())) { + ofs = new FileOutputStream(new File(dir, entry.getKey())); + ofs.write(entry.getValue()); + ofs.close(); + } + } + } + + /** + * Write attached files + */ + if (blueprint.getAttachedFiles() != null) { + for (Map.Entry entry : blueprint.getAttachedFiles().entrySet()) { + ofs = new FileOutputStream(new File(dir, entry.getKey())); + ofs.write(entry.getValue()); + ofs.close(); + } + } + + /** + * Create manifest + */ + PrintStream mfstream = new PrintStream(new File(metadir.getAbsolutePath() + "/" + MANIFEST_FILENAME)); + mfstream.println("TOSCA-Meta-File-Version: 1.0"); + mfstream.println("CSAR-Version: 1.1"); + mfstream.println("Created-by: ONAP"); + mfstream.println("Entry-Definitions: " + blueprint.getMainTemplateName()); + mfstream.close(); + + /** + * ZIP it up + */ + ByteArrayOutputStream zipbytes = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(zipbytes); + compressTree(zos, "", dir, dir); + zos.close(); + return zipbytes.toByteArray(); + + } catch (Exception e) { + throw new RuntimeException("Failed to create CSAR: " + e.getMessage()); + } finally { + + /** + * Clean up tmpdir + */ + deleteDirectory(dir); + } + } + + /** + * Private methods + */ + + /** + * Compresses (ZIPs) a directory tree + * + * @param dir + * @throws IOException + */ + private void compressTree(ZipOutputStream zos, String path, File basedir, File dir) throws IOException { + if (!dir.isDirectory()) + return; + + for (File f : dir.listFiles()) { + if (f.isDirectory()) { + String newpath = path + f.getName() + "/"; + ZipEntry entry = new ZipEntry(newpath); + zos.putNextEntry(entry); + zos.closeEntry(); + compressTree(zos, newpath, basedir, f); + } else { + ZipEntry ze = new ZipEntry( + f.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1).replaceAll("\\\\", "/")); + zos.putNextEntry(ze); + // read the file and write to ZipOutputStream + FileInputStream fis = new FileInputStream(f); + byte[] buffer = new byte[1024]; + int len; + while ((len = fis.read(buffer)) > 0) { + zos.write(buffer, 0, len); + } + zos.closeEntry(); + fis.close(); + } + } + } + + private boolean deleteDirectory(File directory) { + if (directory.exists()) { + File[] files = directory.listFiles(); + if (null != files) { + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + deleteDirectory(files[i]); + } else { + files[i].delete(); + } + } + } + } + return (directory.delete()); + } +} -- cgit 1.2.3-korg