/*
* Copyright (C) 2011 Citrix Systems, Inc. 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.
*/
package com.cloud.bridge.service;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.databinding.ADBBean;
import org.apache.axis2.databinding.ADBException;
import org.apache.axis2.databinding.utils.writer.MTOMAwareXMLSerializer;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import com.amazon.ec2.AllocateAddressResponse;
import com.amazon.ec2.AssociateAddressResponse;
import com.amazon.ec2.AttachVolumeResponse;
import com.amazon.ec2.AuthorizeSecurityGroupIngressResponse;
import com.amazon.ec2.CreateImageResponse;
import com.amazon.ec2.CreateKeyPairResponse;
import com.amazon.ec2.CreateSecurityGroupResponse;
import com.amazon.ec2.CreateSnapshotResponse;
import com.amazon.ec2.CreateVolumeResponse;
import com.amazon.ec2.DeleteKeyPairResponse;
import com.amazon.ec2.DeleteSecurityGroupResponse;
import com.amazon.ec2.DeleteSnapshotResponse;
import com.amazon.ec2.DeleteVolumeResponse;
import com.amazon.ec2.DeregisterImageResponse;
import com.amazon.ec2.DescribeAvailabilityZonesResponse;
import com.amazon.ec2.DescribeImageAttributeResponse;
import com.amazon.ec2.DescribeImagesResponse;
import com.amazon.ec2.DescribeInstanceAttributeResponse;
import com.amazon.ec2.DescribeInstancesResponse;
import com.amazon.ec2.DescribeKeyPairsResponse;
import com.amazon.ec2.DescribeSecurityGroupsResponse;
import com.amazon.ec2.DescribeSnapshotsResponse;
import com.amazon.ec2.DescribeVolumesResponse;
import com.amazon.ec2.DetachVolumeResponse;
import com.amazon.ec2.DisassociateAddressResponse;
import com.amazon.ec2.GetPasswordDataResponse;
import com.amazon.ec2.ImportKeyPairResponse;
import com.amazon.ec2.ModifyImageAttributeResponse;
import com.amazon.ec2.RebootInstancesResponse;
import com.amazon.ec2.RegisterImageResponse;
import com.amazon.ec2.ReleaseAddressResponse;
import com.amazon.ec2.ResetImageAttributeResponse;
import com.amazon.ec2.RevokeSecurityGroupIngressResponse;
import com.amazon.ec2.RunInstancesResponse;
import com.amazon.ec2.StartInstancesResponse;
import com.amazon.ec2.StopInstancesResponse;
import com.amazon.ec2.TerminateInstancesResponse;
import com.amazon.ec2.ModifyInstanceAttributeResponse;
import com.cloud.bridge.model.UserCredentials;
import com.cloud.bridge.persist.dao.OfferingDao;
import com.cloud.bridge.persist.dao.UserCredentialsDao;
import com.cloud.bridge.service.core.ec2.EC2AssociateAddress;
import com.cloud.bridge.service.core.ec2.EC2AuthorizeRevokeSecurityGroup;
import com.cloud.bridge.service.core.ec2.EC2CreateImage;
import com.cloud.bridge.service.core.ec2.EC2CreateKeyPair;
import com.cloud.bridge.service.core.ec2.EC2CreateVolume;
import com.cloud.bridge.service.core.ec2.EC2DeleteKeyPair;
import com.cloud.bridge.service.core.ec2.EC2DescribeAddresses;
import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZones;
import com.cloud.bridge.service.core.ec2.EC2DescribeImageAttributes;
import com.cloud.bridge.service.core.ec2.EC2DescribeImages;
import com.cloud.bridge.service.core.ec2.EC2DescribeInstances;
import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairs;
import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroups;
import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshots;
import com.cloud.bridge.service.core.ec2.EC2DescribeVolumes;
import com.cloud.bridge.service.core.ec2.EC2DisassociateAddress;
import com.cloud.bridge.service.core.ec2.EC2Engine;
import com.cloud.bridge.service.core.ec2.EC2Filter;
import com.cloud.bridge.service.core.ec2.EC2GroupFilterSet;
import com.cloud.bridge.service.core.ec2.EC2Image;
import com.cloud.bridge.service.core.ec2.EC2ImportKeyPair;
import com.cloud.bridge.service.core.ec2.EC2InstanceFilterSet;
import com.cloud.bridge.service.core.ec2.EC2IpPermission;
import com.cloud.bridge.service.core.ec2.EC2KeyPairFilterSet;
import com.cloud.bridge.service.core.ec2.EC2ModifyImageAttribute;
import com.cloud.bridge.service.core.ec2.EC2ModifyInstanceAttribute;
import com.cloud.bridge.service.core.ec2.EC2RebootInstances;
import com.cloud.bridge.service.core.ec2.EC2RegisterImage;
import com.cloud.bridge.service.core.ec2.EC2ReleaseAddress;
import com.cloud.bridge.service.core.ec2.EC2RunInstances;
import com.cloud.bridge.service.core.ec2.EC2SecurityGroup;
import com.cloud.bridge.service.core.ec2.EC2SnapshotFilterSet;
import com.cloud.bridge.service.core.ec2.EC2StartInstances;
import com.cloud.bridge.service.core.ec2.EC2StopInstances;
import com.cloud.bridge.service.core.ec2.EC2Volume;
import com.cloud.bridge.service.core.ec2.EC2VolumeFilterSet;
import com.cloud.bridge.service.exception.EC2ServiceException;
import com.cloud.bridge.service.exception.NoSuchObjectException;
import com.cloud.bridge.service.exception.PermissionDeniedException;
import com.cloud.bridge.service.exception.EC2ServiceException.ClientError;
import com.cloud.bridge.util.AuthenticationUtils;
import com.cloud.bridge.util.ConfigurationHelper;
import com.cloud.bridge.util.EC2RestAuth;
import com.cloud.stack.models.CloudStackAccount;
public class EC2RestServlet extends HttpServlet {
private static final long serialVersionUID = -6168996266762804888L;
public static final Logger logger = Logger.getLogger(EC2RestServlet.class);
private OMFactory factory = OMAbstractFactory.getOMFactory();
private XMLOutputFactory xmlOutFactory = XMLOutputFactory.newInstance();
private String pathToKeystore = null;
private String keystorePassword = null;
private String wsdlVersion = null;
private String version = null;
boolean debug=true;
/**
* We build the path to where the keystore holding the WS-Security X509 certificates
* are stored.
*/
@Override
public void init( ServletConfig config ) throws ServletException {
File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
Properties EC2Prop = null;
if (null != propertiesFile) {
logger.info("Use EC2 properties file: " + propertiesFile.getAbsolutePath());
EC2Prop = new Properties();
try {
EC2Prop.load( new FileInputStream( propertiesFile ));
} catch (FileNotFoundException e) {
logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
} catch (IOException e) {
logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
}
String keystore = EC2Prop.getProperty( "keystore" );
keystorePassword = EC2Prop.getProperty( "keystorePass" );
wsdlVersion = EC2Prop.getProperty( "WSDLVersion", "2010-11-15" );
version = EC2Prop.getProperty( "cloudbridgeVersion", "UNKNOWN VERSION" );
String installedPath = System.getenv("CATALINA_HOME");
if (installedPath == null) installedPath = System.getenv("CATALINA_BASE");
if (installedPath == null) installedPath = System.getProperty("catalina.home");
String webappPath = config.getServletContext().getRealPath("/");
//pathToKeystore = new String( installedPath + File.separator + "webapps" + File.separator + webappName + File.separator + "WEB-INF" + File.separator + "classes" + File.separator + keystore );
pathToKeystore = new String( webappPath + "WEB-INF" + File.separator + "classes" + File.separator + keystore );
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
doGetOrPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
doGetOrPost(req, resp);
}
protected void doGetOrPost(HttpServletRequest request, HttpServletResponse response) {
if(debug){
System.out.println("EC2RestServlet.doGetOrPost: javax.servlet.forward.request_uri: "+request.getAttribute("javax.servlet.forward.request_uri"));
System.out.println("EC2RestServlet.doGetOrPost: javax.servlet.forward.context_path: "+request.getAttribute("javax.servlet.forward.context_path"));
System.out.println("EC2RestServlet.doGetOrPost: javax.servlet.forward.servlet_path: "+request.getAttribute("javax.servlet.forward.servlet_path"));
System.out.println("EC2RestServlet.doGetOrPost: javax.servlet.forward.path_info: "+request.getAttribute("javax.servlet.forward.path_info"));
System.out.println("EC2RestServlet.doGetOrPost: javax.servlet.forward.query_string: "+request.getAttribute("javax.servlet.forward.query_string"));
}
String action = request.getParameter( "Action" );
logRequest(request);
// -> unauthenticated calls, should still be done over HTTPS
if (action.equalsIgnoreCase( "SetUserKeys" )) {
setUserKeys(request, response);
return;
}
if (action.equalsIgnoreCase( "CloudEC2Version" )) {
cloudEC2Version(request, response);
return;
}
// -> authenticated calls
try {
if (!authenticateRequest( request, response )) return;
if (action.equalsIgnoreCase( "AllocateAddress" )) allocateAddress(request, response);
else if (action.equalsIgnoreCase( "AssociateAddress" )) associateAddress(request, response);
else if (action.equalsIgnoreCase( "AttachVolume" )) attachVolume(request, response );
else if (action.equalsIgnoreCase( "AuthorizeSecurityGroupIngress" )) authorizeSecurityGroupIngress(request, response);
else if (action.equalsIgnoreCase( "CreateImage" )) createImage(request, response);
else if (action.equalsIgnoreCase( "CreateSecurityGroup" )) createSecurityGroup(request, response);
else if (action.equalsIgnoreCase( "CreateSnapshot" )) createSnapshot(request, response);
else if (action.equalsIgnoreCase( "CreateVolume" )) createVolume(request, response);
else if (action.equalsIgnoreCase( "DeleteSecurityGroup" )) deleteSecurityGroup(request, response);
else if (action.equalsIgnoreCase( "DeleteSnapshot" )) deleteSnapshot(request, response);
else if (action.equalsIgnoreCase( "DeleteVolume" )) deleteVolume(request, response);
else if (action.equalsIgnoreCase( "DeregisterImage" )) deregisterImage(request, response);
else if (action.equalsIgnoreCase( "DescribeAddresses" )) describeAddresses(request, response);
else if (action.equalsIgnoreCase( "DescribeAvailabilityZones" )) describeAvailabilityZones(request, response);
else if (action.equalsIgnoreCase( "DescribeImageAttribute" )) describeImageAttribute(request, response);
else if (action.equalsIgnoreCase( "DescribeImages" )) describeImages(request, response);
else if (action.equalsIgnoreCase( "DescribeInstanceAttribute" )) describeInstanceAttribute(request, response);
else if (action.equalsIgnoreCase( "DescribeInstances" )) describeInstances(request, response);
else if (action.equalsIgnoreCase( "DescribeSecurityGroups" )) describeSecurityGroups(request, response);
else if (action.equalsIgnoreCase( "DescribeSnapshots" )) describeSnapshots(request, response);
else if (action.equalsIgnoreCase( "DescribeVolumes" )) describeVolumes(request, response);
else if (action.equalsIgnoreCase( "DetachVolume" )) detachVolume(request, response);
else if (action.equalsIgnoreCase( "DisassociateAddress" )) disassociateAddress(request, response);
else if (action.equalsIgnoreCase( "ModifyImageAttribute" )) modifyImageAttribute(request, response);
else if (action.equalsIgnoreCase( "ModifyInstanceAttribute" )) modifyInstanceAttribute(request, response);
else if (action.equalsIgnoreCase( "RebootInstances" )) rebootInstances(request, response);
else if (action.equalsIgnoreCase( "RegisterImage" )) registerImage(request, response);
else if (action.equalsIgnoreCase( "ReleaseAddress" )) releaseAddress(request, response);
else if (action.equalsIgnoreCase( "ResetImageAttribute" )) resetImageAttribute(request, response);
else if (action.equalsIgnoreCase( "RevokeSecurityGroupIngress")) revokeSecurityGroupIngress(request, response);
else if (action.equalsIgnoreCase( "RunInstances" )) runInstances(request, response);
else if (action.equalsIgnoreCase( "StartInstances" )) startInstances(request, response);
else if (action.equalsIgnoreCase( "StopInstances" )) stopInstances(request, response);
else if (action.equalsIgnoreCase( "TerminateInstances" )) terminateInstances(request, response);
else if (action.equalsIgnoreCase( "SetCertificate" )) setCertificate(request, response);
else if (action.equalsIgnoreCase( "DeleteCertificate" )) deleteCertificate(request, response);
else if (action.equalsIgnoreCase( "SetOfferMapping" )) setOfferMapping(request, response);
else if (action.equalsIgnoreCase( "DeleteOfferMapping" )) deleteOfferMapping(request, response);
else if (action.equalsIgnoreCase( "CreateKeyPair" )) createKeyPair(request, response);
else if (action.equalsIgnoreCase( "ImportKeyPair" )) importKeyPair(request, response);
else if (action.equalsIgnoreCase( "DeleteKeyPair" )) deleteKeyPair(request, response);
else if (action.equalsIgnoreCase( "DescribeKeyPairs" )) describeKeyPairs(request, response);
else if (action.equalsIgnoreCase( "GetPasswordData" )) getPasswordData(request, response);
else {
logger.error("Unsupported action " + action);
throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
}
} catch( EC2ServiceException e ) {
response.setStatus(e.getErrorCode());
if (e.getCause() != null && e.getCause() instanceof AxisFault)
faultResponse(response, ((AxisFault)e.getCause()).getFaultCode().getLocalPart(), e.getMessage());
else {
logger.error("EC2ServiceException: " + e.getMessage(), e);
endResponse(response, e.toString());
}
} catch( PermissionDeniedException e ) {
logger.error("Unexpected exception: " + e.getMessage(), e);
response.setStatus(403);
endResponse(response, "Access denied");
} catch( Exception e ) {
logger.error("Unexpected exception: " + e.getMessage(), e);
response.setStatus(500);
endResponse(response, e.toString());
} finally {
try {
response.flushBuffer();
} catch (IOException e) {
logger.error("Unexpected exception " + e.getMessage(), e);
}
}
}
/**
* Provide an easy way to determine the version of the implementation running.
*
* This is an unauthenticated REST call.
*/
private void cloudEC2Version( HttpServletRequest request, HttpServletResponse response ) {
String version_response = new String( "<?xml version=\"1.0\" encoding=\"utf-8\"?><CloudEC2Version>" + version + "</CloudEC2Version>" );
response.setStatus(200);
endResponse(response, version_response);
}
/**
* This request registers the Cloud.com account holder to the EC2 service. The Cloud.com
* account holder saves his API access and secret keys with the EC2 service so that
* the EC2 service can make Cloud.com API calls on his behalf. The given API access
* and secret key are saved into the "usercredentials" database table.
*
* This is an unauthenticated REST call. The only required parameters are 'accesskey' and
* 'secretkey'.
*
* To verify that the given keys represent an existing account they are used to execute the
* Cloud.com's listAccounts API function. If the keys do not represent a valid account the
* listAccounts function will fail.
*
* A user can call this REST function any number of times, on each call the Cloud.com secret
* key is simply over writes any previously stored value.
*
* As with all REST calls HTTPS should be used to ensure their security.
*/
private void setUserKeys( HttpServletRequest request, HttpServletResponse response ) {
String[] accessKey = null;
String[] secretKey = null;
try {
// -> all these parameters are required
accessKey = request.getParameterValues( "accesskey" );
if ( null == accessKey || 0 == accessKey.length ) {
response.sendError(530, "Missing accesskey parameter" );
return;
}
secretKey = request.getParameterValues( "secretkey" );
if ( null == secretKey || 0 == secretKey.length ) {
response.sendError(530, "Missing secretkey parameter" );
return;
}
} catch( Exception e ) {
logger.error("SetUserKeys exception " + e.getMessage(), e);
response.setStatus(500);
endResponse(response, "SetUserKeys exception " + e.getMessage());
return;
}
// Due to design, we must prime the UserContext here...
@SuppressWarnings("unused")
UserContext context = UserContext.current();
try {
// -> use the keys to see if the account actually exists
ServiceProvider.getInstance().getEC2Engine().validateAccount( accessKey[0], secretKey[0] );
UserCredentialsDao credentialDao = new UserCredentialsDao();
credentialDao.setUserKeys( accessKey[0], secretKey[0] );
} catch( Exception e ) {
logger.error("SetUserKeys " + e.getMessage(), e);
response.setStatus(401);
endResponse(response, e.toString());
return;
}
response.setStatus(200);
endResponse(response, "User keys set successfully");
}
/**
* The SOAP API for EC2 uses WS-Security to sign all client requests. This requires that
* the client have a public/private key pair and the public key defined by a X509 certificate.
* Thus in order for a Cloud.com account holder to use the EC2's SOAP API he must register
* his X509 certificate with the EC2 service. This function allows the Cloud.com account
* holder to "load" his X509 certificate into the service. Note, that the SetUserKeys REST
* function must be called before this call.
*
* This is an authenticated REST call and as such must contain all the required REST parameters
* including: Signature, Timestamp, Expires, etc. The signature is calculated using the
* Cloud.com account holder's API access and secret keys and the Amazon defined EC2 signature
* algorithm.
*
* A user can call this REST function any number of times, on each call the X509 certificate
* simply over writes any previously stored value.
*/
private void setCertificate( HttpServletRequest request, HttpServletResponse response )
throws Exception {
try {
// [A] Pull the cert and cloud AccessKey from the request
String[] certificate = request.getParameterValues( "cert" );
if (null == certificate || 0 == certificate.length) {
response.sendError(530, "Missing cert parameter" );
return;
}
// logger.debug( "SetCertificate cert: [" + certificate[0] + "]" );
String [] accessKey = request.getParameterValues( "AWSAccessKeyId" );
if ( null == accessKey || 0 == accessKey.length ) {
response.sendError(530, "Missing AWSAccessKeyId parameter" );
return;
}
// [B] Open our keystore
FileInputStream fsIn = new FileInputStream( pathToKeystore );
KeyStore certStore = KeyStore.getInstance( "JKS" );
certStore.load( fsIn, keystorePassword.toCharArray());
// -> use the Cloud API key to save the cert in the keystore
// -> write the cert into the keystore on disk
Certificate userCert = null;
CertificateFactory cf = CertificateFactory.getInstance( "X.509" );
ByteArrayInputStream bs = new ByteArrayInputStream( certificate[0].getBytes());
while (bs.available() > 0) userCert = cf.generateCertificate(bs);
certStore.setCertificateEntry( accessKey[0], userCert );
FileOutputStream fsOut = new FileOutputStream( pathToKeystore );
certStore.store( fsOut, keystorePassword.toCharArray());
// [C] Associate the cert's uniqueId with the Cloud API keys
String uniqueId = AuthenticationUtils.X509CertUniqueId( userCert );
logger.debug( "SetCertificate, uniqueId: " + uniqueId );
UserCredentialsDao credentialDao = new UserCredentialsDao();
credentialDao.setCertificateId( accessKey[0], uniqueId );
response.setStatus(200);
endResponse(response, "User certificate set successfully");
} catch( NoSuchObjectException e ) {
logger.error("SetCertificate exception " + e.getMessage(), e);
response.sendError(404, "SetCertificate exception " + e.getMessage());
} catch( Exception e ) {
logger.error("SetCertificate exception " + e.getMessage(), e);
response.sendError(500, "SetCertificate exception " + e.getMessage());
}
}
/**
* The SOAP API for EC2 uses WS-Security to sign all client requests. This requires that
* the client have a public/private key pair and the public key defined by a X509 certificate.
* This REST call allows a Cloud.com account holder to remove a previouly "loaded" X509
* certificate out of the EC2 service.
*
* This is an unauthenticated REST call and as such must contain all the required REST parameters
* including: Signature, Timestamp, Expires, etc. The signature is calculated using the
* Cloud.com account holder's API access and secret keys and the Amazon defined EC2 signature
* algorithm.
*/
private void deleteCertificate( HttpServletRequest request, HttpServletResponse response )
throws Exception {
try {
String [] accessKey = request.getParameterValues( "AWSAccessKeyId" );
if ( null == accessKey || 0 == accessKey.length ) {
response.sendError(530, "Missing AWSAccessKeyId parameter" );
return;
}
// -> delete the specified entry and save back to disk
FileInputStream fsIn = new FileInputStream( pathToKeystore );
KeyStore certStore = KeyStore.getInstance( "JKS" );
certStore.load( fsIn, keystorePassword.toCharArray());
if ( certStore.containsAlias( accessKey[0] )) {
certStore.deleteEntry( accessKey[0] );
FileOutputStream fsOut = new FileOutputStream( pathToKeystore );
certStore.store( fsOut, keystorePassword.toCharArray());
// -> dis-associate the cert's uniqueId with the Cloud API keys
UserCredentialsDao credentialDao = new UserCredentialsDao();
credentialDao.setCertificateId( accessKey[0], null );
response.setStatus(200);
endResponse(response, "User certificate deleted successfully");
}
else response.setStatus(404);
} catch( NoSuchObjectException e ) {
logger.error("SetCertificate exception " + e.getMessage(), e);
response.sendError(404, "SetCertificate exception " + e.getMessage());
} catch( Exception e ) {
logger.error("DeleteCertificate exception " + e.getMessage(), e);
response.sendError(500, "DeleteCertificate exception " + e.getMessage());
}
}
/**
* Allow the caller to define the mapping between the Amazon instance type strings
* (e.g., m1.small, cc1.4xlarge) and the cloudstack service offering ids. Setting
* an existing mapping just over writes the prevous values.
*/
private void setOfferMapping( HttpServletRequest request, HttpServletResponse response ) {
String amazonOffer = null;
String cloudOffer = null;
try {
// -> all these parameters are required
amazonOffer = request.getParameter( "amazonoffer" );
if ( null == amazonOffer ) {
response.sendError(530, "Missing amazonoffer parameter" );
return;
}
cloudOffer = request.getParameter( "cloudoffer" );
if ( null == cloudOffer ) {
response.sendError(530, "Missing cloudoffer parameter" );
return;
}
} catch( Exception e ) {
logger.error("SetOfferMapping exception " + e.getMessage(), e);
response.setStatus(500);
endResponse(response, "SetOfferMapping exception " + e.getMessage());
return;
}
// validate account is admin level
try {
CloudStackAccount currentAccount = ServiceProvider.getInstance().getEC2Engine().getCurrentAccount();
if (currentAccount.getAccountType() != 1) {
logger.debug("SetOfferMapping called by non-admin user!");
response.setStatus(500);
endResponse(response, "Permission denied for non-admin user to setOfferMapping!");
return;
}
} catch (Exception e) {
logger.error("SetOfferMapping " + e.getMessage(), e);
response.setStatus(401);
endResponse(response, e.toString());
return;
}
try {
OfferingDao ofDao = new OfferingDao();
ofDao.setOfferMapping( amazonOffer, cloudOffer );
} catch( Exception e ) {
logger.error("SetOfferMapping " + e.getMessage(), e);
response.setStatus(401);
endResponse(response, e.toString());
return;
}
response.setStatus(200);
endResponse(response, "offering mapping set successfully");
}
private void deleteOfferMapping( HttpServletRequest request, HttpServletResponse response ) {
String amazonOffer = null;
try {
// -> all these parameters are required
amazonOffer = request.getParameter( "amazonoffer" );
if ( null == amazonOffer ) {
response.sendError(530, "Missing amazonoffer parameter" );
return;
}
} catch( Exception e ) {
logger.error("DeleteOfferMapping exception " + e.getMessage(), e);
response.setStatus(500);
endResponse(response, "DeleteOfferMapping exception " + e.getMessage());
return;
}
// validate account is admin level
try {
CloudStackAccount currentAccount = ServiceProvider.getInstance().getEC2Engine().getCurrentAccount();
if (currentAccount.getAccountType() != 1) {
logger.debug("deleteOfferMapping called by non-admin user!");
response.setStatus(500);
endResponse(response, "Permission denied for non-admin user to deleteOfferMapping!");
return;
}
} catch (Exception e) {
logger.error("deleteOfferMapping " + e.getMessage(), e);
response.setStatus(401);
endResponse(response, e.toString());
return;
}
try {
OfferingDao ofDao = new OfferingDao();
ofDao.deleteOfferMapping( amazonOffer );
} catch( Exception e ) {
logger.error("DeleteOfferMapping " + e.getMessage(), e);
response.setStatus(401);
endResponse(response, e.toString());
return;
}
response.setStatus(200);
endResponse(response, "offering mapping deleted successfully");
}
/**
* The approach taken here is to map these REST calls into the same objects used
* to implement the matching SOAP requests (e.g., AttachVolume). This is done by parsing
* out the URL parameters and loading them into the relevant EC2XXX object(s). Once
* the parameters are loaded the appropriate EC2Engine function is called to perform
* the requested action. The result of the EC2Engine function is a standard
* Amazon WSDL defined object (e.g., AttachVolumeResponse Java object). Finally the
* serialize method is called on the returned response object to obtain the extected
* response XML.
*/
private void attachVolume( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Volume EC2request = new EC2Volume();
// -> all these parameters are required
String[] volumeId = request.getParameterValues( "VolumeId" );
if ( null != volumeId && 0 < volumeId.length )
EC2request.setId( volumeId[0] );
else { response.sendError(530, "Missing VolumeId parameter" ); return; }
String[] instanceId = request.getParameterValues( "InstanceId" );
if ( null != instanceId && 0 < instanceId.length )
EC2request.setInstanceId( instanceId[0] );
else { response.sendError(530, "Missing InstanceId parameter" ); return; }
String[] device = request.getParameterValues( "Device" );
if ( null != device && 0 < device.length )
EC2request.setDevice( device[0] );
else { response.sendError(530, "Missing Device parameter" ); return; }
// -> execute the request
AttachVolumeResponse EC2response = EC2SoapServiceImpl.toAttachVolumeResponse( ServiceProvider.getInstance().getEC2Engine().attachVolume( EC2request ));
serializeResponse(response, EC2response);
}
/**
* The SOAP equivalent of this function appears to allow multiple permissions per request, yet
* in the REST API documentation only one permission is allowed.
*/
private void revokeSecurityGroupIngress( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2AuthorizeRevokeSecurityGroup EC2request = new EC2AuthorizeRevokeSecurityGroup();
String[] groupName = request.getParameterValues( "GroupName" );
if ( null != groupName && 0 < groupName.length )
EC2request.setName( groupName[0] );
else { response.sendError(530, "Missing GroupName parameter" ); return; }
EC2IpPermission perm = new EC2IpPermission();
String[] protocol = request.getParameterValues( "IpProtocol" );
if ( null != protocol && 0 < protocol.length )
perm.setProtocol( protocol[0] );
else { response.sendError(530, "Missing IpProtocol parameter" ); return; }
String[] fromPort = request.getParameterValues( "FromPort" );
if ( null != fromPort && 0 < fromPort.length )
perm.setProtocol( fromPort[0] );
else { response.sendError(530, "Missing FromPort parameter" ); return; }
String[] toPort = request.getParameterValues( "ToPort" );
if ( null != toPort && 0 < toPort.length )
perm.setProtocol( toPort[0] );
else { response.sendError(530, "Missing ToPort parameter" ); return; }
String[] ranges = request.getParameterValues( "CidrIp" );
if ( null != ranges && 0 < ranges.length)
perm.addIpRange( ranges[0] );
else { response.sendError(530, "Missing CidrIp parameter" ); return; }
String[] user = request.getParameterValues( "SourceSecurityGroupOwnerId" );
if ( null == user || 0 == user.length) {
response.sendError(530, "Missing SourceSecurityGroupOwnerId parameter" );
return;
}
String[] name = request.getParameterValues( "SourceSecurityGroupName" );
if ( null == name || 0 == name.length) {
response.sendError(530, "Missing SourceSecurityGroupName parameter" );
return;
}
EC2SecurityGroup group = new EC2SecurityGroup();
group.setAccount( user[0] );
group.setName( name[0] );
perm.addUser( group );
EC2request.addIpPermission( perm );
// -> execute the request
RevokeSecurityGroupIngressResponse EC2response = EC2SoapServiceImpl.toRevokeSecurityGroupIngressResponse(
ServiceProvider.getInstance().getEC2Engine().revokeSecurityGroup( EC2request ));
serializeResponse(response, EC2response);
}
private void authorizeSecurityGroupIngress( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
// -> parse the complicated paramters into our standard object
EC2AuthorizeRevokeSecurityGroup EC2request = new EC2AuthorizeRevokeSecurityGroup();
String[] groupName = request.getParameterValues( "GroupName" );
if ( null != groupName && 0 < groupName.length )
EC2request.setName( groupName[0] );
else { response.sendError(530, "Missing GroupName parameter" ); return; }
// -> not clear how many parameters there are until we fail to get IpPermissions.n.IpProtocol
int nCount = 1;
do
{ EC2IpPermission perm = new EC2IpPermission();
String[] protocol = request.getParameterValues( "IpPermissions." + nCount + ".IpProtocol" );
if ( null != protocol && 0 < protocol.length )
perm.setProtocol( protocol[0] );
else break;
String[] fromPort = request.getParameterValues( "IpPermissions." + nCount + ".FromPort" );
if (null != fromPort && 0 < fromPort.length) perm.setProtocol( fromPort[0] );
String[] toPort = request.getParameterValues( "IpPermissions." + nCount + ".ToPort" );
if (null != toPort && 0 < toPort.length) perm.setProtocol( toPort[0] );
// -> list: IpPermissions.n.IpRanges.m.CidrIp
int mCount = 1;
do
{ String[] ranges = request.getParameterValues( "IpPermissions." + nCount + ".IpRanges." + mCount + ".CidrIp" );
if ( null != ranges && 0 < ranges.length)
perm.addIpRange( ranges[0] );
else break;
mCount++;
} while( true );
// -> list: IpPermissions.n.Groups.m.UserId and IpPermissions.n.Groups.m.GroupName
mCount = 1;
do
{ String[] user = request.getParameterValues( "IpPermissions." + nCount + ".Groups." + mCount + ".UserId" );
if ( null == user || 0 == user.length) break;
String[] name = request.getParameterValues( "IpPermissions." + nCount + ".Groups." + mCount + ".GroupName" );
if ( null == name || 0 == name.length) break;
EC2SecurityGroup group = new EC2SecurityGroup();
group.setAccount( user[0] );
group.setName( name[0] );
perm.addUser( group );
mCount++;
} while( true );
// -> multiple IP permissions can be specified per group name
EC2request.addIpPermission( perm );
nCount++;
} while( true );
if (1 == nCount) { response.sendError(530, "At least one IpPermissions required" ); return; }
// -> execute the request
AuthorizeSecurityGroupIngressResponse EC2response = EC2SoapServiceImpl.toAuthorizeSecurityGroupIngressResponse(
ServiceProvider.getInstance().getEC2Engine().authorizeSecurityGroup( EC2request ));
serializeResponse(response, EC2response);
}
private void detachVolume( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Volume EC2request = new EC2Volume();
String[] volumeId = request.getParameterValues( "VolumeId" );
if ( null != volumeId && 0 < volumeId.length )
EC2request.setId(volumeId[0]);
else { response.sendError(530, "Missing VolumeId parameter" ); return; }
String[] instanceId = request.getParameterValues( "InstanceId" );
if ( null != instanceId && 0 < instanceId.length )
EC2request.setInstanceId(instanceId[0]);
String[] device = request.getParameterValues( "Device" );
if ( null != device && 0 < device.length )
EC2request.setDevice( device[0] );
// -> execute the request
DetachVolumeResponse EC2response = EC2SoapServiceImpl.toDetachVolumeResponse( ServiceProvider.getInstance().getEC2Engine().detachVolume( EC2request ));
serializeResponse(response, EC2response);
}
private void deleteVolume( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Volume EC2request = new EC2Volume();
String[] volumeId = request.getParameterValues( "VolumeId" );
if ( null != volumeId && 0 < volumeId.length )
EC2request.setId(volumeId[0]);
else { response.sendError(530, "Missing VolumeId parameter" ); return; }
// -> execute the request
DeleteVolumeResponse EC2response = EC2SoapServiceImpl.toDeleteVolumeResponse( ServiceProvider.getInstance().getEC2Engine().deleteVolume( EC2request ));
serializeResponse(response, EC2response);
}
private void createVolume( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2CreateVolume EC2request = new EC2CreateVolume();
String[] zoneName = request.getParameterValues( "AvailabilityZone" );
if ( null != zoneName && 0 < zoneName.length )
EC2request.setZoneName( zoneName[0] );
else { response.sendError(530, "Missing AvailabilityZone parameter" ); return; }
String[] size = request.getParameterValues( "Size" );
String[] snapshotId = request.getParameterValues("SnapshotId");
boolean useSnapshot = false;
boolean useSize = false;
if (null != size && 0 < size.length)
useSize = true;
if (snapshotId != null && snapshotId.length != 0)
useSnapshot = true;
if (useSize && !useSnapshot) {
EC2request.setSize( size[0] );
} else if (useSnapshot && !useSize) {
EC2request.setSnapshotId(snapshotId[0]);
} else if (useSize && useSnapshot) {
response.sendError(530, "Size and SnapshotId parameters are mutually exclusive" ); return;
} else {
response.sendError(530, "Size or SnapshotId has to be specified" ); return;
}
// -> execute the request
CreateVolumeResponse EC2response = EC2SoapServiceImpl.toCreateVolumeResponse( ServiceProvider.getInstance().getEC2Engine().createVolume( EC2request ));
serializeResponse(response, EC2response);
}
private void createSecurityGroup( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
String groupName, groupDescription = null;
String[] name = request.getParameterValues( "GroupName" );
if ( null != name && 0 < name.length )
groupName = name[0];
else { response.sendError(530, "Missing GroupName parameter" ); return; }
String[] desc = request.getParameterValues( "GroupDescription" );
if ( null != desc && 0 < desc.length )
groupDescription = desc[0];
else { response.sendError(530, "Missing GroupDescription parameter" ); return; }
// -> execute the request
CreateSecurityGroupResponse EC2response = EC2SoapServiceImpl.toCreateSecurityGroupResponse( ServiceProvider.getInstance().getEC2Engine().createSecurityGroup( groupName, groupDescription ));
serializeResponse(response, EC2response);
}
private void deleteSecurityGroup( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
String groupName = null;
String[] name = request.getParameterValues( "GroupName" );
if ( null != name && 0 < name.length )
groupName = name[0];
else { response.sendError(530, "Missing GroupName parameter" ); return; }
// -> execute the request
DeleteSecurityGroupResponse EC2response = EC2SoapServiceImpl.toDeleteSecurityGroupResponse( ServiceProvider.getInstance().getEC2Engine().deleteSecurityGroup( groupName ));
serializeResponse(response, EC2response);
}
private void deleteSnapshot( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
String snapshotId = null;
String[] snapSet = request.getParameterValues( "SnapshotId" );
if ( null != snapSet && 0 < snapSet.length )
snapshotId = snapSet[0];
else { response.sendError(530, "Missing SnapshotId parameter" ); return; }
// -> execute the request
DeleteSnapshotResponse EC2response = EC2SoapServiceImpl.toDeleteSnapshotResponse( ServiceProvider.getInstance().getEC2Engine().deleteSnapshot( snapshotId ));
serializeResponse(response, EC2response);
}
private void createSnapshot( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
String volumeId = null;
String[] volSet = request.getParameterValues( "VolumeId" );
if ( null != volSet && 0 < volSet.length )
volumeId = volSet[0];
else { response.sendError(530, "Missing VolumeId parameter" ); return; }
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
CreateSnapshotResponse EC2response = EC2SoapServiceImpl.toCreateSnapshotResponse( engine.createSnapshot( volumeId ), engine);
serializeResponse(response, EC2response);
}
private void deregisterImage( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Image image = new EC2Image();
String[] imageId = request.getParameterValues( "ImageId" );
if ( null != imageId && 0 < imageId.length )
image.setId( imageId[0] );
else { response.sendError(530, "Missing ImageId parameter" ); return; }
// -> execute the request
DeregisterImageResponse EC2response = EC2SoapServiceImpl.toDeregisterImageResponse( ServiceProvider.getInstance().getEC2Engine().deregisterImage( image ));
serializeResponse(response, EC2response);
}
private void createImage( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2CreateImage EC2request = new EC2CreateImage();
String[] instanceId = request.getParameterValues( "InstanceId" );
if ( null != instanceId && 0 < instanceId.length )
EC2request.setInstanceId( instanceId[0] );
else { response.sendError(530, "Missing InstanceId parameter" ); return; }
String[] name = request.getParameterValues( "Name" );
if ( null != name && 0 < name.length )
EC2request.setName( name[0] );
else { response.sendError(530, "Missing Name parameter" ); return; }
String[] description = request.getParameterValues( "Description" );
if ( null != description && 0 < description.length )
EC2request.setDescription( description[0] );
// -> execute the request
CreateImageResponse EC2response = EC2SoapServiceImpl.toCreateImageResponse( ServiceProvider.getInstance().getEC2Engine().createImage( EC2request ));
serializeResponse(response, EC2response);
}
private void registerImage( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2RegisterImage EC2request = new EC2RegisterImage();
String[] location = request.getParameterValues( "ImageLocation" );
if ( null != location && 0 < location.length )
EC2request.setLocation( location[0] );
else { response.sendError(530, "Missing ImageLocation parameter" ); return; }
String[] cloudRedfined = request.getParameterValues( "Architecture" );
if ( null != cloudRedfined && 0 < cloudRedfined.length )
EC2request.setArchitecture( cloudRedfined[0] );
else { response.sendError(530, "Missing Architecture parameter" ); return; }
String[] name = request.getParameterValues( "Name" );
if ( null != name && 0 < name.length )
EC2request.setName( name[0] );
String[] description = request.getParameterValues( "Description" );
if ( null != description && 0 < description.length )
EC2request.setDescription( description[0] );
// -> execute the request
RegisterImageResponse EC2response = EC2SoapServiceImpl.toRegisterImageResponse( ServiceProvider.getInstance().getEC2Engine().registerImage( EC2request ));
serializeResponse(response, EC2response);
}
private void modifyImageAttribute( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2ModifyImageAttribute EC2request = new EC2ModifyImageAttribute();
String[] imageId = request.getParameterValues( "ImageId" );
if ( null != imageId && 0 < imageId.length )
EC2request.setImageId(imageId[0]);
else {
response.sendError(530, "Missing ImageId parameter" );
return;
}
int nCount = 1;
do {
// LaunchPermission.Add.n.UserId
String[] addedUserId = request.getParameterValues("LaunchPermission.Add." + nCount + ".UserId");
if (addedUserId != null && addedUserId.length > 0) {
EC2request.addAddedUser(addedUserId[0]);
} else
break;
String[] addedGroup = request.getParameterValues("LaunchPermission.Add." + nCount + ".Group");
if (addedGroup != null && addedGroup.length > 0) {
// according to api, all is the only legitimate value
if (addedGroup[0].equalsIgnoreCase("all")) {
EC2request.setIsPublic(true);
}
return;
}
} while (true);
nCount = 1;
do {
String[] removedUserId = request.getParameterValues("LaunchPermission.Remove." + nCount + ".UserId");
if (removedUserId != null && removedUserId.length > 0) {
EC2request.addRemovedUser(removedUserId[0]);
} else
break;
nCount++;
String[] removedGroup = request.getParameterValues("LaunchPermission.Remove." + nCount + ".Group");
if (removedGroup != null && removedGroup.length > 0) {
// according to api, all is the only legitimate value
if (removedGroup[0].equalsIgnoreCase("all")) {
EC2request.setIsPublic(false);
}
}
} while(true);
// unsupported description...
String[] description = request.getParameterValues( "Description" );
if ( null != description && 0 < description.length )
EC2request.setDescription( description[0] );
// -> execute the request
ModifyImageAttributeResponse EC2response = EC2SoapServiceImpl.toModifyImageAttributeResponse(
ServiceProvider.getInstance().getEC2Engine().modifyImageAttribute(EC2request));
serializeResponse(response, EC2response);
}
/**
* @param request
* @param response
* @throws Exception
*/
private void modifyInstanceAttribute(HttpServletRequest request,
HttpServletResponse response) throws Exception {
EC2ModifyInstanceAttribute ec2request = new EC2ModifyInstanceAttribute();
String[] instanceIds = request.getParameterValues("InstanceId");
if (instanceIds != null && instanceIds.length > 0) {
ec2request.setInstanceId(instanceIds[0]);
} else {
response.sendError(530, "Missing InstanceId parameter");
return;
}
boolean supported = false;
String[] instanceTypes = request.getParameterValues("InstanceType.Value");
if (instanceTypes != null && instanceTypes.length > 0) {
ec2request.setInstanceType(instanceTypes[0]);
supported = true;
}
String[] userDatas = request.getParameterValues("UserData.Value");
if (userDatas != null && userDatas.length > 0) {
ec2request.setUserData(userDatas[0]);
supported = true;
}
if (supported != true) {
response.sendError(530, "Unsupported parameter passed to modifyInstanceAttribute!");
return;
}
ModifyInstanceAttributeResponse EC2response = EC2SoapServiceImpl.toModifyInstanceAttributeResponse(ServiceProvider.getInstance().getEC2Engine().modifyInstanceAttribute(ec2request));
serializeResponse(response, EC2response);
}
private void resetImageAttribute( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2ModifyImageAttribute EC2request = new EC2ModifyImageAttribute();
String[] imageId = request.getParameterValues( "ImageId" );
if ( null != imageId && 0 < imageId.length )
EC2request.setImageId(imageId[0]);
else {
response.sendError(530, "Missing ImageId parameter" );
return;
}
EC2request.setReset(true);
ResetImageAttributeResponse EC2response = EC2SoapServiceImpl.toResetImageAttributeResponse(
ServiceProvider.getInstance().getEC2Engine().modifyImageAttribute(EC2request));
serializeResponse(response, EC2response);
}
private void runInstances( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2RunInstances EC2request = new EC2RunInstances();
// -> so in the Amazon docs for this REST call there is no userData even though there is in the SOAP docs
String[] imageId = request.getParameterValues( "ImageId" );
if ( null != imageId && 0 < imageId.length )
EC2request.setTemplateId( imageId[0] );
else { response.sendError(530, "Missing ImageId parameter" ); return; }
String[] minCount = request.getParameterValues( "MinCount" );
if ( null != minCount && 0 < minCount.length )
EC2request.setMinCount( Integer.parseInt( minCount[0] ));
else { response.sendError(530, "Missing MinCount parameter" ); return; }
String[] maxCount = request.getParameterValues( "MaxCount" );
if ( null != maxCount && 0 < maxCount.length )
EC2request.setMaxCount( Integer.parseInt( maxCount[0] ));
else { response.sendError(530, "Missing MaxCount parameter" ); return; }
String[] instanceType = request.getParameterValues( "InstanceType" );
if ( null != instanceType && 0 < instanceType.length )
EC2request.setInstanceType( instanceType[0] );
String[] zoneName = request.getParameterValues( "Placement.AvailabilityZone" );
if ( null != zoneName && 0 < zoneName.length )
EC2request.setZoneName( zoneName[0] );
String[] size = request.getParameterValues("size");
if (size != null) {
EC2request.setSize(Integer.valueOf(size[0]));
}
String[] keyName = request.getParameterValues("KeyName");
if (keyName != null) {
EC2request.setKeyName(keyName[0]);
}
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
RunInstancesResponse EC2response = EC2SoapServiceImpl.toRunInstancesResponse( engine.runInstances( EC2request ), engine);
serializeResponse(response, EC2response);
}
private void rebootInstances( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2RebootInstances EC2request = new EC2RebootInstances();
int count = 0;
// -> load in all the "InstanceId.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("InstanceId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) {
EC2request.addInstanceId( value[0] );
count++;
}
}
}
if (0 == count) { response.sendError(530, "Missing InstanceId parameter" ); return; }
// -> execute the request
RebootInstancesResponse EC2response = EC2SoapServiceImpl.toRebootInstancesResponse( ServiceProvider.getInstance().getEC2Engine().rebootInstances(EC2request));
serializeResponse(response, EC2response);
}
private void startInstances( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2StartInstances EC2request = new EC2StartInstances();
int count = 0;
// -> load in all the "InstanceId.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("InstanceId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) {
EC2request.addInstanceId( value[0] );
count++;
}
}
}
if (0 == count) { response.sendError(530, "Missing InstanceId parameter" ); return; }
// -> execute the request
StartInstancesResponse EC2response = EC2SoapServiceImpl.toStartInstancesResponse( ServiceProvider.getInstance().getEC2Engine().startInstances(EC2request));
serializeResponse(response, EC2response);
}
private void stopInstances( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2StopInstances EC2request = new EC2StopInstances();
int count = 0;
// -> load in all the "InstanceId.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("InstanceId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) {
EC2request.addInstanceId( value[0] );
count++;
}
}
}
if (0 == count) { response.sendError(530, "Missing InstanceId parameter" ); return; }
// -> execute the request
StopInstancesResponse EC2response = EC2SoapServiceImpl.toStopInstancesResponse( ServiceProvider.getInstance().getEC2Engine().stopInstances( EC2request ));
serializeResponse(response, EC2response);
}
private void terminateInstances( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2StopInstances EC2request = new EC2StopInstances();
int count = 0;
// -> load in all the "InstanceId.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("InstanceId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) {
EC2request.addInstanceId( value[0] );
count++;
}
}
}
if (0 == count) { response.sendError(530, "Missing InstanceId parameter" ); return; }
// -> execute the request
EC2request.setDestroyInstances( true );
TerminateInstancesResponse EC2response = EC2SoapServiceImpl.toTermInstancesResponse( ServiceProvider.getInstance().getEC2Engine().stopInstances( EC2request ));
serializeResponse(response, EC2response);
}
/**
* We are reusing the SOAP code to process this request. We then use Axiom to serialize the
* resulting EC2 Amazon object into XML to return to the client.
*/
private void describeAvailabilityZones( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2DescribeAvailabilityZones EC2request = new EC2DescribeAvailabilityZones();
// -> load in all the "ZoneName.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("ZoneName")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) EC2request.addZone( value[0] );
}
}
// -> execute the request
DescribeAvailabilityZonesResponse EC2response = EC2SoapServiceImpl.toDescribeAvailabilityZonesResponse( ServiceProvider.getInstance().getEC2Engine().handleRequest( EC2request ));
serializeResponse(response, EC2response);
}
private void describeImages( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2DescribeImages EC2request = new EC2DescribeImages();
// -> load in all the "ImageId.n" parameters if any, and ignore all other parameters
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("ImageId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) EC2request.addImageSet( value[0] );
}
}
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
DescribeImagesResponse EC2response = EC2SoapServiceImpl.toDescribeImagesResponse( engine.describeImages( EC2request ));
serializeResponse(response, EC2response);
}
private void describeImageAttribute( HttpServletRequest request, HttpServletResponse response )
throws EC2ServiceException, ADBException, XMLStreamException, IOException {
EC2DescribeImageAttributes EC2request = new EC2DescribeImageAttributes();
Enumeration<?> names = request.getParameterNames();
// we only support launchpermissions and imageId
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
if (key.startsWith("requestId") || key.startsWith("productCodes") || key.startsWith("kernel") ||
key.startsWith("ramdisk") || key.startsWith("blockDeviceMapping")) {
throw new EC2ServiceException(ClientError.Unsupported, "The " + key + " parameter is not supported");
}
if (key.startsWith("imageId")) {
String[] values = request.getParameterValues(key);
// in all fairness, there will only be one element in these lists,
EC2request.setImageId(values[0]);
}
if (key.startsWith("launchPermission")) {
String[] values = request.getParameterValues(key);
if (values.length > 0) {
EC2request.setLaunchPermission(true);
}
}
}
// -> execute the request
DescribeImageAttributeResponse EC2response = EC2SoapServiceImpl.toDescribeImageAttributeResponse( ServiceProvider.getInstance().getEC2Engine().describeImageAttributes( EC2request ));
serializeResponse(response, EC2response);
}
private void describeInstances( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException
{
EC2DescribeInstances EC2request = new EC2DescribeInstances();
// -> load in all the "InstanceId.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements())
{
String key = (String)names.nextElement();
if (key.startsWith("InstanceId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) EC2request.addInstanceId( value[0] );
}
}
// -> are there any filters with this request?
EC2Filter[] filterSet = extractFilters( request );
if (null != filterSet)
{
EC2InstanceFilterSet ifs = new EC2InstanceFilterSet();
for( int i=0; i < filterSet.length; i++ ) ifs.addFilter( filterSet[i] );
EC2request.setFilterSet( ifs );
}
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
DescribeInstancesResponse EC2response = EC2SoapServiceImpl.toDescribeInstancesResponse( engine.describeInstances( EC2request ), engine);
serializeResponse(response, EC2response);
}
private void describeAddresses( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2DescribeAddresses ec2Request = new EC2DescribeAddresses();
// -> load in all the "PublicIp.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("PublicIp")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) ec2Request.addPublicIp( value[0] );
}
}
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
serializeResponse(response, EC2SoapServiceImpl.toDescribeAddressesResponse( engine.describeAddresses( ec2Request)));
}
private void allocateAddress( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
AllocateAddressResponse ec2Response = EC2SoapServiceImpl.toAllocateAddressResponse( engine.allocateAddress());
serializeResponse(response, ec2Response);
}
private void releaseAddress( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
String publicIp = request.getParameter( "PublicIp" );
if (publicIp == null) {
response.sendError(530, "Missing PublicIp parameter");
return;
}
EC2ReleaseAddress ec2Request = new EC2ReleaseAddress();
if (ec2Request != null) {
ec2Request.setPublicIp(publicIp);
}
ReleaseAddressResponse EC2Response = EC2SoapServiceImpl.toReleaseAddressResponse( engine.releaseAddress( ec2Request ));
serializeResponse(response, EC2Response);
}
private void associateAddress( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
String publicIp = request.getParameter( "PublicIp" );
if (null == publicIp) {
response.sendError(530, "Missing PublicIp parameter" );
return;
}
String instanceId = request.getParameter( "InstanceId" );
if (null == instanceId) {
response.sendError(530, "Missing InstanceId parameter" );
return;
}
EC2AssociateAddress ec2Request = new EC2AssociateAddress();
if (ec2Request != null) {
ec2Request.setInstanceId(instanceId);
ec2Request.setPublicIp(publicIp);
}
AssociateAddressResponse ec2Response = EC2SoapServiceImpl.toAssociateAddressResponse( engine.associateAddress( ec2Request ));
serializeResponse(response, ec2Response);
}
private void disassociateAddress( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
String publicIp = request.getParameter( "PublicIp" );
if (null == publicIp) {
response.sendError(530, "Missing PublicIp parameter" );
return;
}
EC2DisassociateAddress ec2Request = new EC2DisassociateAddress();
if (ec2Request != null) {
ec2Request.setPublicIp(publicIp);
}
DisassociateAddressResponse ec2Response = EC2SoapServiceImpl.toDisassociateAddressResponse( engine.disassociateAddress( ec2Request ) );
serializeResponse(response, ec2Response);
}
private void describeSecurityGroups( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException
{
EC2DescribeSecurityGroups EC2request = new EC2DescribeSecurityGroups();
// -> load in all the "GroupName.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("GroupName")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) EC2request.addGroupName( value[0] );
}
}
// -> are there any filters with this request?
EC2Filter[] filterSet = extractFilters( request );
if (null != filterSet) {
EC2GroupFilterSet gfs = new EC2GroupFilterSet();
for (EC2Filter filter : filterSet) gfs.addFilter( filter );
EC2request.setFilterSet( gfs );
}
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
DescribeSecurityGroupsResponse EC2response = EC2SoapServiceImpl.toDescribeSecurityGroupsResponse( engine.describeSecurityGroups( EC2request ));
serializeResponse(response, EC2response);
}
private void describeInstanceAttribute( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException {
EC2DescribeInstances EC2request = new EC2DescribeInstances();
String instanceType = null;
// -> we are only handling queries about the "Attribute=instanceType"
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements()) {
String key = (String)names.nextElement();
if (key.startsWith("Attribute")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length && value[0].equalsIgnoreCase( "instanceType" )) {
instanceType = value[0];
break;
}
}
}
if ( null != instanceType ) {
String[] value = request.getParameterValues( "InstanceId" );
EC2request.addInstanceId( value[0] );
}
else {
response.sendError(501, "Unsupported - only instanceType supported" );
return;
}
// -> execute the request
DescribeInstanceAttributeResponse EC2response = EC2SoapServiceImpl.toDescribeInstanceAttributeResponse( ServiceProvider.getInstance().getEC2Engine().describeInstances(EC2request));
serializeResponse(response, EC2response);
}
private void describeSnapshots( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException
{
EC2DescribeSnapshots EC2request = new EC2DescribeSnapshots();
// -> load in all the "SnapshotId.n" parameters if any, and ignore any other parameters
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements())
{
String key = (String)names.nextElement();
if (key.startsWith("SnapshotId")) {
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) EC2request.addSnapshotId( value[0] );
}
}
// -> are there any filters with this request?
EC2Filter[] filterSet = extractFilters( request );
if (null != filterSet)
{
EC2SnapshotFilterSet sfs = new EC2SnapshotFilterSet();
for( int i=0; i < filterSet.length; i++ ) sfs.addFilter( filterSet[i] );
EC2request.setFilterSet( sfs );
}
// -> execute the request
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
DescribeSnapshotsResponse EC2response = EC2SoapServiceImpl.toDescribeSnapshotsResponse( engine.handleRequest( EC2request ));
serializeResponse(response, EC2response);
}
private void describeVolumes( HttpServletRequest request, HttpServletResponse response )
throws ADBException, XMLStreamException, IOException
{
EC2DescribeVolumes EC2request = new EC2DescribeVolumes();
// -> load in all the "VolumeId.n" parameters if any
Enumeration<?> names = request.getParameterNames();
while( names.hasMoreElements())
{
String key = (String)names.nextElement();
if (key.startsWith("VolumeId"))
{
String[] value = request.getParameterValues( key );
if (null != value && 0 < value.length) EC2request.addVolumeId( value[0] );
}
}
// -> are there any filters with this request?
EC2Filter[] filterSet = extractFilters( request );
if (null != filterSet)
{
EC2VolumeFilterSet vfs = new EC2VolumeFilterSet();
for( int i=0; i < filterSet.length; i++ ) vfs.addFilter( filterSet[i] );
EC2request.setFilterSet( vfs );
}
// -> execute the request
DescribeVolumesResponse EC2response = EC2SoapServiceImpl.toDescribeVolumesResponse( ServiceProvider.getInstance().getEC2Engine().handleRequest( EC2request ));
serializeResponse(response, EC2response);
}
/**
* Example of how the filters are defined in a REST request:
* https://<server>/?Action=DescribeVolumes
* &Filter.1.Name=attachment.instance-id
* &Filter.1.Value.1=i-1a2b3c4d
* &Filter.2.Name=attachment.delete-on-termination
* &Filter.2.Value.1=true
*
* @param request
* @return List<EC2Filter>
*/
private EC2Filter[] extractFilters( HttpServletRequest request )
{
String filterName = null;
String value = null;
EC2Filter nextFilter = null;
boolean timeFilter = false;
int filterCount = 1;
int valueCount = 1;
List<EC2Filter> filterSet = new ArrayList<EC2Filter>();
do
{ filterName = request.getParameter( "Filter." + filterCount + ".Name" );
if (null != filterName)
{
nextFilter = new EC2Filter();
nextFilter.setName( filterName );
timeFilter = (filterName.equalsIgnoreCase( "attachment.attach-time" ) || filterName.equalsIgnoreCase( "create-time" ));
valueCount = 1;
do
{
value = request.getParameter( "Filter." + filterCount + ".Value." + valueCount );
if (null != value)
{
// -> time values are not encoded as regexes
if ( timeFilter )
nextFilter.addValue( value );
else nextFilter.addValueEncoded( value );
valueCount++;
}
}
while( null != value );
filterSet.add( nextFilter );
filterCount++;
}
}
while( null != filterName );
if ( 1 == filterCount )
return null;
else return filterSet.toArray(new EC2Filter[0]);
}
private void describeKeyPairs(HttpServletRequest request, HttpServletResponse response)
throws ADBException, XMLStreamException, IOException {
EC2DescribeKeyPairs ec2Request = new EC2DescribeKeyPairs();
String[] keyNames = request.getParameterValues( "KeyName" );
if (keyNames != null) {
for (String keyName : keyNames) {
ec2Request.addKeyName(keyName);
}
}
EC2Filter[] filterSet = extractFilters( request );
if (null != filterSet){
EC2KeyPairFilterSet vfs = new EC2KeyPairFilterSet();
for (EC2Filter filter : filterSet) {
vfs.addFilter(filter);
}
ec2Request.setKeyFilterSet(vfs);
}
DescribeKeyPairsResponse EC2Response = EC2SoapServiceImpl.toDescribeKeyPairs(
ServiceProvider.getInstance().getEC2Engine().describeKeyPairs( ec2Request ));
serializeResponse(response, EC2Response);
}
private void importKeyPair(HttpServletRequest request, HttpServletResponse response)
throws ADBException, XMLStreamException, IOException {
String keyName = request.getParameter("KeyName");
String publicKeyMaterial = request.getParameter("PublicKeyMaterial");
if (keyName==null && publicKeyMaterial==null) {
response.sendError(530, "Missing parameter");
return;
}
if (!publicKeyMaterial.contains(" "))
publicKeyMaterial = new String(Base64.decodeBase64(publicKeyMaterial.getBytes()));
EC2ImportKeyPair ec2Request = new EC2ImportKeyPair();
if (ec2Request != null) {
ec2Request.setKeyName(request.getParameter("KeyName"));
ec2Request.setPublicKeyMaterial(request.getParameter("PublicKeyMaterial"));
}
ImportKeyPairResponse EC2Response = EC2SoapServiceImpl.toImportKeyPair(
ServiceProvider.getInstance().getEC2Engine().importKeyPair( ec2Request ));
serializeResponse(response, EC2Response);
}
private void createKeyPair(HttpServletRequest request, HttpServletResponse response)
throws ADBException, XMLStreamException, IOException {
String keyName = request.getParameter("KeyName");
if (keyName==null) {
response.sendError(530, "Missing KeyName parameter");
return;
}
EC2CreateKeyPair ec2Request = new EC2CreateKeyPair();
if (ec2Request != null) {
ec2Request.setKeyName(keyName);
}
CreateKeyPairResponse EC2Response = EC2SoapServiceImpl.toCreateKeyPair(
ServiceProvider.getInstance().getEC2Engine().createKeyPair(ec2Request));
serializeResponse(response, EC2Response);
}
private void deleteKeyPair(HttpServletRequest request, HttpServletResponse response)
throws ADBException, XMLStreamException, IOException {
String keyName = request.getParameter("KeyName");
if (keyName==null) {
response.sendError(530, "Missing KeyName parameter");
return;
}
EC2DeleteKeyPair ec2Request = new EC2DeleteKeyPair();
ec2Request.setKeyName(keyName);
DeleteKeyPairResponse EC2Response = EC2SoapServiceImpl.toDeleteKeyPair(
ServiceProvider.getInstance().getEC2Engine().deleteKeyPair(ec2Request));
serializeResponse(response, EC2Response);
}
private void getPasswordData(HttpServletRequest request, HttpServletResponse response)
throws ADBException, XMLStreamException, IOException {
String instanceId = request.getParameter("InstanceId");
if (instanceId==null) {
response.sendError(530, "Missing InstanceId parameter");
return;
}
GetPasswordDataResponse EC2Response = EC2SoapServiceImpl.toGetPasswordData(
ServiceProvider.getInstance().getEC2Engine().getPasswordData(instanceId));
serializeResponse(response, EC2Response);
}
/**
* This function implements the EC2 REST authentication algorithm. It uses the given
* "AWSAccessKeyId" parameter to look up the Cloud.com account holder's secret key which is
* used as input to the signature calculation. In addition, it tests the given "Expires"
* parameter to see if the signature has expired and if so the request fails.
*/
private boolean authenticateRequest( HttpServletRequest request, HttpServletResponse response )
throws SignatureException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException, ParseException
{
String cloudSecretKey = null;
String cloudAccessKey = null;
String signature = null;
String sigMethod = null;
// [A] Basic parameters required for an authenticated rest request
// -> note that the Servlet engine will un-URL encode all parameters we extract via "getParameterValues()" calls
String[] awsAccess = request.getParameterValues( "AWSAccessKeyId" );
if ( null != awsAccess && 0 < awsAccess.length )
cloudAccessKey = awsAccess[0];
else { response.sendError(530, "Missing AWSAccessKeyId parameter" ); return false; }
String[] clientSig = request.getParameterValues( "Signature" );
if ( null != clientSig && 0 < clientSig.length )
signature = clientSig[0];
else { response.sendError(530, "Missing Signature parameter" ); return false; }
String[] method = request.getParameterValues( "SignatureMethod" );
if ( null != method && 0 < method.length )
{
sigMethod = method[0];
if (!sigMethod.equals( "HmacSHA256" ) && !sigMethod.equals( "HmacSHA1" )) {
response.sendError(531, "Unsupported SignatureMethod value: " + sigMethod + " expecting: HmacSHA256 or HmacSHA1" );
return false;
}
}
else { response.sendError(530, "Missing SignatureMethod parameter" ); return false; }
String[] version = request.getParameterValues( "Version" );
if ( null != version && 0 < version.length )
{
if (!version[0].equals( wsdlVersion )) {
response.sendError(531, "Unsupported Version value: " + version[0] + " expecting: " + wsdlVersion );
return false;
}
}
else { response.sendError(530, "Missing Version parameter" ); return false; }
String[] sigVersion = request.getParameterValues( "SignatureVersion" );
if ( null != sigVersion && 0 < sigVersion.length )
{
if (!sigVersion[0].equals( "2" )) {
response.sendError(531, "Unsupported SignatureVersion value: " + sigVersion[0] + " expecting: 2" );
return false;
}
}
else { response.sendError(530, "Missing SignatureVersion parameter" ); return false; }
// -> can have only one but not both { Expires | Timestamp } headers
String[] expires = request.getParameterValues( "Expires" );
if ( null != expires && 0 < expires.length )
{
// -> contains the date and time at which the signature included in the request EXPIRES
if (hasSignatureExpired( expires[0] )) {
response.sendError(531, "Expires parameter indicates signature has expired: " + expires[0] );
return false;
}
}
else
{ // -> contains the date and time at which the request is SIGNED
String[] time = request.getParameterValues( "Timestamp" );
if ( null == time || 0 == time.length ) {
response.sendError(530, "Missing Timestamp and Expires parameter, one is required" );
return false;
}
}
// [B] Use the cloudAccessKey to get the users secret key in the db
UserCredentialsDao credentialDao = new UserCredentialsDao();
UserCredentials cloudKeys = credentialDao.getByAccessKey( cloudAccessKey );
if ( null == cloudKeys )
{
logger.debug( cloudAccessKey + " is not defined in the EC2 service - call SetUserKeys" );
response.sendError(404, cloudAccessKey + " is not defined in the EC2 service - call SetUserKeys" );
return false;
}
else cloudSecretKey = cloudKeys.getSecretKey();
// [C] Verify the signature
// -> getting the query-string in this way maintains its URL encoding
EC2RestAuth restAuth = new EC2RestAuth();
restAuth.setHostHeader( request.getHeader( "Host" ));
String requestUri = request.getRequestURI();
//If forwarded from another basepath:
String forwardedPath = (String) request.getAttribute("javax.servlet.forward.request_uri");
if(forwardedPath!=null){
requestUri=forwardedPath;
}
restAuth.setHTTPRequestURI( requestUri);
String queryString = request.getQueryString();
// getQueryString returns null (does it ever NOT return null for these queries),
// we need to construct queryString to avoid changing the auth code...
if (queryString == null) {
// construct our idea of a queryString with parameters!
Enumeration<?> params = request.getParameterNames();
if (params != null) {
while(params.hasMoreElements()) {
String paramName = (String) params.nextElement();
// exclude the signature string obviously. ;)
if (paramName.equalsIgnoreCase("Signature")) continue;
if (queryString == null)
queryString = paramName + "=" + request.getParameter(paramName);
else
queryString = queryString + "&" + paramName + "=" + URLEncoder.encode(request.getParameter(paramName), "UTF-8");
}
}
}
restAuth.setQueryString(queryString);
if ( restAuth.verifySignature( request.getMethod(), cloudSecretKey, signature, sigMethod )) {
UserContext.current().initContext( cloudAccessKey, cloudSecretKey, cloudAccessKey, "REST request", null );
return true;
}
else throw new PermissionDeniedException("Invalid signature");
}
/**
* We check this to reduce replay attacks.
*
* @param timeStamp
* @return true - if the request is not longer valid, false otherwise
* @throws ParseException
*/
private boolean hasSignatureExpired( String timeStamp ) {
Calendar cal = EC2RestAuth.parseDateString( timeStamp );
if (null == cal) return false;
Date expiredTime = cal.getTime();
Date today = new Date(); // -> gets set to time of creation
if ( 0 >= expiredTime.compareTo( today )) {
logger.debug( "timestamp given: [" + timeStamp + "], now: [" + today.toString() + "]" );
return true;
}
else return false;
}
private static void endResponse(HttpServletResponse response, String content) {
try {
byte[] data = content.getBytes();
response.setContentLength(data.length);
OutputStream os = response.getOutputStream();
os.write(data);
os.close();
} catch(Throwable e) {
logger.error("Unexpected exception " + e.getMessage(), e);
}
}
private void logRequest(HttpServletRequest request) {
if(logger.isInfoEnabled()) {
logger.info("EC2 Request method: " + request.getMethod());
logger.info("Request contextPath: " + request.getContextPath());
logger.info("Request pathInfo: " + request.getPathInfo());
logger.info("Request pathTranslated: " + request.getPathTranslated());
logger.info("Request queryString: " + request.getQueryString());
logger.info("Request requestURI: " + request.getRequestURI());
logger.info("Request requestURL: " + request.getRequestURL());
logger.info("Request servletPath: " + request.getServletPath());
Enumeration<?> headers = request.getHeaderNames();
if(headers != null) {
while(headers.hasMoreElements()) {
Object headerName = headers.nextElement();
logger.info("Request header " + headerName + ":" + request.getHeader((String)headerName));
}
}
Enumeration<?> params = request.getParameterNames();
if(params != null) {
while(params.hasMoreElements()) {
Object paramName = params.nextElement();
logger.info("Request parameter " + paramName + ":" +
request.getParameter((String)paramName));
}
}
}
}
/**
* Send out an error response according to Amazon convention.
*/
private void faultResponse(HttpServletResponse response, String errorCode, String errorMessage) {
try {
OutputStreamWriter out = new OutputStreamWriter(response.getOutputStream());
response.setContentType("text/xml; charset=UTF-8");
out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
out.write("<Response><Errors><Error><Code>");
out.write(errorCode);
out.write("</Code><Message>");
out.write(errorMessage);
out.write("</Message></Error></Errors><RequestID>");
out.write(UUID.randomUUID().toString());
out.write("</RequestID></Response>");
out.flush();
out.close();
} catch (IOException e) {
logger.error("Unexpected exception " + e.getMessage(), e);
}
}
/**
* Serialize Axis beans to XML output.
*/
private void serializeResponse(HttpServletResponse response, ADBBean EC2Response)
throws ADBException, XMLStreamException, IOException {
OutputStream os = response.getOutputStream();
response.setStatus(200);
response.setContentType("text/xml; charset=UTF-8");
XMLStreamWriter xmlWriter = xmlOutFactory.createXMLStreamWriter( os );
MTOMAwareXMLSerializer MTOMWriter = new MTOMAwareXMLSerializer( xmlWriter );
MTOMWriter.setDefaultNamespace("http://ec2.amazonaws.com/doc/" + wsdlVersion + "/");
EC2Response.serialize( null, factory, MTOMWriter );
xmlWriter.flush();
xmlWriter.close();
os.close();
}
}