package com.telefonica.claudia.slm.paas.vmiHandler; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.log4j.Logger; import org.dmtf.schemas.ovf.envelope._1.AnnotationSectionType; import org.dmtf.schemas.ovf.envelope._1.EnvelopeType; import org.dmtf.schemas.ovf.envelope._1.MsgType; import org.dmtf.schemas.ovf.envelope._1.ProductSectionType; import org.dmtf.schemas.ovf.envelope._1.ReferencesType; import org.dmtf.schemas.ovf.envelope._1.VirtualSystemType; import org.dmtf.schemas.wbem.wscim._1.common.CimString; import org.restlet.Client; import org.restlet.data.MediaType; import org.restlet.data.Protocol; import org.restlet.data.Reference; import org.restlet.data.Response; import org.restlet.resource.DomRepresentation; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.abiquo.ovf.OVFEnvelopeUtils; import com.abiquo.ovf.exceptions.InvalidSectionException; import com.abiquo.ovf.exceptions.SectionAlreadyPresentException; import com.abiquo.ovf.exceptions.XMLException; import com.abiquo.ovf.xml.OVFSerializer; import com.telefonica.claudia.slm.common.SMConfiguration; import com.telefonica.claudia.slm.deployment.VEE; import com.telefonica.claudia.slm.deployment.paas.Product; import com.telefonica.claudia.slm.deployment.paas.Property; import com.telefonica.claudia.slm.paas.OVFContextualization; import com.telefonica.claudia.slm.paas.PaasUtils; import com.telefonica.claudia.slm.paas.URICreationPaaS; import com.telefonica.claudia.slm.vmiHandler.TCloudClient; import com.telefonica.claudia.slm.vmiHandler.VEEReplicaAllocationResult; import com.telefonica.claudia.slm.vmiHandler.exceptions.AccessDeniedException; import com.telefonica.claudia.slm.vmiHandler.exceptions.CommunicationErrorException; import com.telefonica.claudia.smi.TCloudConstants; import com.telefonica.claudia.smi.URICreation; public class RECManagerClient implements VMIHandler { private static final long POLLING_INTERVAL = 15000; private Client client; private String serverURL; MediaType APPLICATION_OVF_XML = MediaType.register("application/ovf+xml", "XML OVF document"); private static Logger logger = Logger.getLogger(RECManagerClient.class); public RECManagerClient (String url) { logger.info("SDC Url " + url); if (url.charAt(url.length()-1) == '/') serverURL = url.substring(0, url.length()-1); else serverURL = url; client = new Client(Protocol.HTTP); } public void installApplication(Product product) throws AccessDeniedException, CommunicationErrorException { } public void installProductsInVm (VEE vee, String ip, String login, String password) throws CommunicationErrorException, AccessDeniedException, Exception { Reference urlReplica = new Reference(serverURL + URICreationPaaS.getURIService((vee.getFQN().toString())) + "/vms"); System.out.println ("URL " +urlReplica); DomRepresentation data = null; try { Document doc = getInstallProductInVirtualMachine(vee, ip, login, password); System.out.println ("VEE Product " + PaasUtils.tooString(doc)); data = new DomRepresentation(APPLICATION_OVF_XML, doc); } catch (ParserConfigurationException e) { logger.error("Error creating parser: " + e.getMessage()); return; } catch (XMLException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (SectionAlreadyPresentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidSectionException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Call the server with the URI and the data logger.debug("Posting product information: " ); Response response = client.post(urlReplica,data); // Depending on the response code, return with an error, or wait for a response switch (response.getStatus().getCode()) { case 401: // Unauthorized case 403: // Forbidden // Throw an Access Denied Exception logger.error("Not enough privileges to access the VM information."); throw new AccessDeniedException(response.getStatus().getDescription(), null, null); case 400: // Bad Request case 404: // Not found logger.error("The resource was not found on the server; the tcloud server may be misconfigured, or the URL may be wrong."); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 501: case 500: logger.error("Internal error in the VEEM tcloud server: " + response.getStatus().getDescription()); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 202: case 201: case 200: logger.info("Operation suceesfully done."); try { String job = response.getEntity().getText(); while (true) { String status = getTaskStatus(serverURL +"/jobs/"+job); System.out.println ("Status " + serverURL +"/jobs/"+job + " " + status); if (status.equals("FINISHED")) return; else if (status.equals("PENDING")) { } else if (status.equals("FAILED")) { // String error = getTaskMessageError (); logger.error("Error to create the VM " ); throw new Exception("Error to install the product in the VM: Aborting operation", null); } try { Thread.sleep(5000); } catch (InterruptedException e) {} } } catch (IOException e1) { // TODO Auto-generated catch block logger.info("Error to obtain the job."); } break; } } public void installProductsInService (VEE vee) throws CommunicationErrorException, AccessDeniedException { Reference urlReplica = new Reference(serverURL + "/applications"); // URICreationPaaS.getURIService(vee.getFQN().toString())); System.out.println ("URL " +urlReplica); DomRepresentation data = null; try { Document doc = getEnvelope(vee.getServiceApplication().getSerAppName()); System.out.println ("VEE Product " + PaasUtils.tooString(doc)); data = new DomRepresentation(APPLICATION_OVF_XML, doc); System.out.println(data.getMediaType()); } catch (ParserConfigurationException e) { logger.error("Error creating parser: " + e.getMessage()); return; } catch (XMLException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (SectionAlreadyPresentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidSectionException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Call the server with the URI and the data logger.debug("Posting product information: " ); Response response = client.post(urlReplica,data); // Depending on the response code, return with an error, or wait for a response switch (response.getStatus().getCode()) { case 401: // Unauthorized case 403: // Forbidden // Throw an Access Denied Exception logger.error("Not enough privileges to access the VM information."); throw new AccessDeniedException(response.getStatus().getDescription(), null, null); case 400: // Bad Request case 404: // Not found logger.error("The resource was not found on the server; the tcloud server may be misconfigured, or the URL may be wrong."); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 501: case 500: logger.error("Internal error in the VEEM tcloud server: " + response.getStatus().getDescription()); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 412: case 415: logger.error("Internal error in communication " + response.getStatus().getDescription()); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 202: case 201: case 200: logger.info("Operation suceesfully done."); try { String job = response.getEntity().getText(); while (true) { String status = getTaskStatus(serverURL +"/jobs/"+job); System.out.println ("Status " + serverURL +"/jobs/"+job + " " + status); if (status.equals("FINISHED")) { return; } else if (status.toLowerCase().equals("error")) { } try { Thread.sleep(5000); } catch (InterruptedException e) {} } } catch (IOException e1) { // TODO Auto-generated catch block logger.info("Error to obtain the job."); } break; } } public void installProduct(Product product, String ip) throws AccessDeniedException, CommunicationErrorException { Reference urlReplica = new Reference(serverURL + URICreationPaaS.getURIVEE((product.getFQN().toString()))+"/pics"); System.out.println ("URL " +urlReplica); // Call the server with the URI and the data DomRepresentation data; try { Document doc = getInstallProductParams(product,ip); System.out.println ("Product " + PaasUtils.tooString(doc)); data = new DomRepresentation(APPLICATION_OVF_XML, doc); } catch (ParserConfigurationException e) { logger.error("Error creating parser: " + e.getMessage()); return; } catch (XMLException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("Error creating parser: " + e.getMessage()); return; } // Call the server with the URI and the data logger.debug("Posting product information: " ); Response response = client.post(urlReplica,data); // Depending on the response code, return with an error, or wait for a response switch (response.getStatus().getCode()) { case 401: // Unauthorized case 403: // Forbidden // Throw an Access Denied Exception logger.error("Not enough privileges to access the VM information."); throw new AccessDeniedException(response.getStatus().getDescription(), null, null); case 400: // Bad Request case 404: // Not found logger.error("The resource was not found on the server; the tcloud server may be misconfigured, or the URL may be wrong."); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 501: case 500: logger.error("Internal error in the VEEM tcloud server: " + response.getStatus().getDescription()); throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 202: case 201: case 200: logger.info("Operation suceesfully done."); try { String job = response.getEntity().getText(); while (true) { String status = getTaskStatus(serverURL +"/jobs/"+job); if (status.equals("FINISHED")) { return; } else if (status.equals("PENDING")) { } else if (status.equals("FAILED")) { // String error = getTaskMessageError (); logger.error("Error to create the VM " ); throw new AccessDeniedException("Error to install the product in the VM: Aborting operation", null, null); } try { Thread.sleep(5000); } catch (InterruptedException e) {} } } catch (IOException e1) { // TODO Auto-generated catch block logger.info("Error to obtain the job."); } /* try { responseXml = response.getEntity().getText() System.out.println (PaasUtils.tooString(responseXml)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } break;*/ } } public Document getInstallProductParams(Product product,String ip) throws ParserConfigurationException, XMLException, SAXException, IOException { String productxml = product.getProductXML(ip); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); InputStream is = new ByteArrayInputStream(productxml.getBytes("UTF-8")); Document doc = docBuilder.parse (is); return doc; } public Document getInstallProductInVirtualMachine(VEE vee, String ip, String login, String password) throws ParserConfigurationException, XMLException, SAXException, IOException, SectionAlreadyPresentException, InvalidSectionException { VirtualSystemType vs = new VirtualSystemType(); vs.setId(vee.getVEEName()+"-"+ip.replace(".", "-")); vee.setVEEName (vee.getVEEName()+"-"+ip.replace(".", "-")); // vs.setId(vee.getVEEName()+"-"+ip.replace(".", "-")); ProductSectionType productsection = new ProductSectionType(); MsgType category = new MsgType (); category.setMsgid("org.fourcaast.instancecomponent"); category.setValue("Instance Component Metadata"); productsection.getCategoryOrProperty().add(category); ProductSectionType.Property property = new ProductSectionType.Property (); property.setKey("org.fourcaast.instancecomponent.type"); property.setValue("REC"); productsection.getCategoryOrProperty().add(property); if (vee.getRecipes()!= null && vee.getRecipes().size() >0) { for (String recipe: vee.getRecipes()) { property = new ProductSectionType.Property (); property.setKey("org.fourcaast.instancecomponent.recipe"); property.setValue(recipe); productsection.getCategoryOrProperty().add(property); } } category = new MsgType (); category.setMsgid("org.fourcaast.rec"); category.setValue("REC Attributes"); productsection.getCategoryOrProperty().add(category); property = new ProductSectionType.Property (); property.setKey("org.fourcaast.rec.address"); property.setValue(ip); productsection.getCategoryOrProperty().add(property); property = new ProductSectionType.Property (); property.setKey("org.fourcaast.rec.username"); if (vee.getUserName().indexOf("@")!=-1) property.setValue(login); else property.setValue(vee.getUserName()); productsection.getCategoryOrProperty().add(property); property = new ProductSectionType.Property (); property.setKey("org.fourcaast.rec.password"); if (vee.getPassword().indexOf("@")!=-1) property.setValue(password); else property.setValue(vee.getPassword()); productsection.getCategoryOrProperty().add(property); OVFEnvelopeUtils.addSection(vs, productsection); OVFSerializer ovfSerializer = OVFSerializer.getInstance(); String vsstring = ovfSerializer.writeXML(vs); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); InputStream is = new ByteArrayInputStream(vsstring.getBytes("UTF-8")); Document doc = docBuilder.parse (is); return doc; } public Document getEnvelope(String servicename) throws ParserConfigurationException, XMLException, SAXException, IOException, SectionAlreadyPresentException, InvalidSectionException { EnvelopeType env = new EnvelopeType(); AnnotationSectionType annot = new AnnotationSectionType(); MsgType info = new MsgType (); info.setMsgid("org.fourcaast.application.id"); info.setValue(servicename); annot.setInfo(info); annot.setAnnotation(null); ReferencesType ref = new ReferencesType(); /* <ovfenvelope:Envelope xmlns:cimresallocdata="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:ovfenvelope="http://schemas.dmtf.org/ovf/envelope/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ovfenvelope:References/> <ovfenvelope:AnnotationSection ovfenvelope:required="true"> <ovfenvelope:Info ovfenvelope:msgid="org.fourcaast.application.id">app-00001</ovfenvelope:Info> <ovfenvelope:Annotation></ovfenvelope:Annotation> </ovfenvelope:AnnotationSection> </ovfenvelope:Envelope>*/ OVFSerializer ovfSerializer = OVFSerializer.getInstance(); OVFEnvelopeUtils.addSection(env,annot); String vsstring = ovfSerializer.writeXML(env); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); InputStream is = new ByteArrayInputStream(vsstring.getBytes("UTF-8")); Document doc = docBuilder.parse (is); return doc; } private Document getTask(String url) throws AccessDeniedException, CommunicationErrorException { // Check the state of the task Reference urlTask = new Reference(url); System.out.println ("URL " + url); Response response = client.get(urlTask); switch (response.getStatus().getCode()) { case 401: // Unauthorized case 403: // Forbidden throw new AccessDeniedException(response.getStatus().getDescription(), null, null); case 400: // Bad Request case 404: // Not found throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 501: case 500: throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); case 202: // The VEE has been accepted to be deployed, but the response will be asynchronous. // Wait for the response actively. case 201: case 200: // The VirtualMachine has been started without errors. Parse the response and // get the task id. try { Document responseXml = response.getEntityAsDom().getDocument(); return responseXml; } catch (IOException e) { throw new CommunicationErrorException(response.getStatus().getDescription(), new Exception(response.getStatus().getName())); } catch (Throwable e) { throw new CommunicationErrorException("Internal error while decoding the answer", e); } } return null; } private String getTaskStatus(String url) throws AccessDeniedException, CommunicationErrorException { Document responseXml = getTask (url); if (responseXml == null) return "unknown"; NodeList tasks = responseXml.getElementsByTagName("status"); if (tasks.getLength() != 0 ) { // If the task is Success or Error, store the result. return ((Element)tasks.item(0)).getFirstChild().getNodeValue(); } return "unknown"; } private String getTaskMessageError(Document message) throws AccessDeniedException, CommunicationErrorException { NodeList tasks = message.getElementsByTagName("message"); if (tasks.getLength() != 0 ) { // If the task is Success or Error, store the result. return ((Element)tasks.item(0)).getFirstChild().getNodeValue(); } return null; } }