/** * Abiquo community edition * cloud management application for hybrid clouds * Copyright (C) 2008-2010 - Abiquo Holdings S.L. * * This application is free software; you can redistribute it and/or * modify it under the terms of the GNU LESSER GENERAL PUBLIC * LICENSE as published by the Free Software Foundation under * version 3 of the License * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * LESSER GENERAL PUBLIC LICENSE v.3 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package com.abiquo.am.resources; import static com.abiquo.am.services.TemplateConventions.ovfUrl; import java.net.URI; import java.net.URISyntaxException; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; import org.apache.wink.common.annotations.Parent; import org.dmtf.schemas.ovf.envelope._1.EnvelopeType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import com.abiquo.am.exceptions.AMError; import com.abiquo.am.services.ErepoFactory; import com.abiquo.am.services.TemplateService; import com.abiquo.am.services.filesystem.TemplateFileSystem; import com.abiquo.api.resource.AbstractResource; import com.abiquo.appliancemanager.exceptions.AMException; import com.abiquo.appliancemanager.exceptions.DownloadException; import com.abiquo.appliancemanager.transport.TemplateDto; import com.abiquo.appliancemanager.transport.TemplateStateDto; import com.abiquo.appliancemanager.transport.TemplateStatusEnumType; import com.ning.http.client.Response.ResponseBuilder; @Parent(TemplatesResource.class) @Path(TemplateResource.TEMPLATE_PATH) @Controller public class TemplateResource extends AbstractResource { public static final String TEMPLATE = ApplianceManagerPaths.TEMPLATE; /** * The resource parameter matching configuration. * <p> * Must override default regular expression in order to be able to match complete URIs as the * OVFPackageInstance identifier. */ public static final String TEMPLATE_PARAM = "{" + TEMPLATE + ": .*}"; // FIXME take care of .* public static final String TEMPLATE_PATH = TEMPLATE_PARAM; /** The resource path. */ private final static String HEADER_PROGRESS = "progress"; private final static String QUERY_PARAM_GET_FORMAT = "format"; @Autowired TemplateService service; @HEAD public Response getTemplateDeployProgress( @PathParam(EnterpriseRepositoryResource.ENTERPRISE_REPOSITORY) final String idEnterprise, @PathParam(TemplateResource.TEMPLATE) final String ovfIdIn) throws DownloadException { final String ovfId = ovfUrl(ovfIdIn); TemplateStateDto status = service.getTemplateStatusIncludeProgress(ovfId, idEnterprise); switch (status.getStatus()) { case NOT_DOWNLOAD: return Response.status(Status.NOT_FOUND).build(); case DOWNLOAD: return Response.status(Status.CREATED).build(); // TODO location(arg0); case DOWNLOADING: final String progress = String.valueOf(status.getDownloadingProgress()); return Response.status(Status.ACCEPTED).header(HEADER_PROGRESS, progress).build(); case ERROR: return Response.status(Status.INTERNAL_SERVER_ERROR).entity(status.getErrorCause()) .build(); // XXX deleted default: return Response.status(Status.NOT_FOUND).entity( "UNKNOW STATUS:" + status.getStatus().name()).build(); } } @GET public Response getTemplate(@Context final UriInfo uriInfo, @PathParam(EnterpriseRepositoryResource.ENTERPRISE_REPOSITORY) final String idEnterprise, @PathParam(TemplateResource.TEMPLATE) final String ovfIdIn, @QueryParam(QUERY_PARAM_GET_FORMAT) final String format) { // XXX can specify the media type final String ovfId = ovfUrl(ovfIdIn); if (format == null || format.isEmpty() || format.equals("ovfpi")) { return Response.ok(getTemplate(idEnterprise, ovfId)).build(); } else if (format.equals("status")) { return evalStatus(idEnterprise, ovfId); } else if (format.equals("envelope")) { return Response.ok(getOVFEnvelope(idEnterprise, ovfId)).build(); } else if (format.equals("diskFile")) { String diskFilePath = getTemplate(idEnterprise, ovfId).getDiskFilePath(); String baseUrl = uriInfo.getBaseUri().toASCIIString(); String diskFileUrl = baseUrl + "files/" + diskFilePath; try { return Response.seeOther(new URI(diskFileUrl)).build(); } catch (URISyntaxException e) { throw new WebApplicationException(e); } } else { return Response.ok(getOVFEnvelope(idEnterprise, ovfId)).build(); } } /** * Eval the current status. * * * @param idEnterprise Id of Enterprise to which this OVFPackage belongs. * @param idRepository Id of the Repository to which the OVFPackage belongs. * @return DataResult<OVFPackageInstanceStatus>@return Response */ private Response evalStatus(final String idEnterprise, final String ovfId) { TemplateStateDto templateStatus = getTemplateStatus(idEnterprise, ovfId); if (templateStatus == null) { return Response.status(Status.NOT_FOUND).build(); } if (!StringUtils.isBlank(templateStatus.getErrorCause())) { return Response.ok(templateStatus).build(); } if (TemplateStatusEnumType.NOT_DOWNLOAD.equals(templateStatus.getStatus())) { templateStatus.setDownloadingProgress(0d); return Response.ok(templateStatus).build(); } if (TemplateStatusEnumType.ERROR.equals(templateStatus.getStatus())) { templateStatus.setDownloadingProgress(0d); return Response.ok(templateStatus).build(); } if (TemplateStatusEnumType.DOWNLOADING.equals(templateStatus.getStatus())) { return Response.ok(templateStatus).build(); } templateStatus.setDownloadingProgress(100d); return Response.ok(templateStatus).build(); } /** * create bundle methods */ @POST @Consumes(MediaType.TEXT_PLAIN) @Produces(MediaType.TEXT_PLAIN) public Response preBundleTemplate( @PathParam(EnterpriseRepositoryResource.ENTERPRISE_REPOSITORY) final String idEnterprise, final String name) { final String ovfId = ErepoFactory.getRepo(idEnterprise).prepareBundle(name); return Response.status(Status.ACCEPTED).entity(ovfId).type(MediaType.TEXT_PLAIN).build(); } @POST public Response bundleTemplate( @PathParam(EnterpriseRepositoryResource.ENTERPRISE_REPOSITORY) final String idEnterprise, @PathParam(TemplateResource.TEMPLATE) final String snapshot, final TemplateDto diskInfo) { // TODO check diskInfo.getEnvelopeId is equals to idEnterprise String bundleOVFId = null; URI bundleUri; try { bundleOVFId = service.createTemplateBundle(diskInfo, snapshot); bundleUri = new URI(bundleOVFId); } catch (URISyntaxException e) { final String cause = String.format("The Bundle URI is not valid [%s]", bundleOVFId); throw new AMException(AMError.TEMPLATE_BOUNDLE, cause, e); } return Response.created(bundleUri).type(MediaType.TEXT_PLAIN).build(); // XXX location } /** * delete */ @DELETE public void deleteTemplate( @PathParam(EnterpriseRepositoryResource.ENTERPRISE_REPOSITORY) final String idEnterprise, @PathParam(TemplateResource.TEMPLATE) final String ovfIdIn) { final String ovfId = ovfUrl(ovfIdIn); service.delete(idEnterprise, ovfId); } /* * NOT EXPOSED * */ // @Produces({MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON}) private TemplateStateDto getTemplateStatus(final String idEnterprise, final String ovfId) { return service.getTemplateStatusIncludeProgress(ovfId, idEnterprise); } private TemplateDto getTemplate(final String idEnterprise, final String ovfId) { return service.getTemplate(idEnterprise, ovfId); } private EnvelopeType getOVFEnvelope(final String idEnterprise, final String ovfId) { return TemplateFileSystem.getEnvelope(ErepoFactory.getRepo(idEnterprise).path(), ovfId); } }