mirror of https://github.com/apache/cloudstack.git
2211 lines
102 KiB
Java
2211 lines
102 KiB
Java
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you 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.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Properties;
|
|
import java.util.UUID;
|
|
|
|
import javax.inject.Inject;
|
|
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.commons.io.IOUtils;
|
|
import org.apache.log4j.Logger;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
|
|
|
|
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.CreateTagsResponse;
|
|
import com.amazon.ec2.CreateVolumeResponse;
|
|
import com.amazon.ec2.DeleteKeyPairResponse;
|
|
import com.amazon.ec2.DeleteSecurityGroupResponse;
|
|
import com.amazon.ec2.DeleteSnapshotResponse;
|
|
import com.amazon.ec2.DeleteTagsResponse;
|
|
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.DescribeTagsResponse;
|
|
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.ModifyInstanceAttributeResponse;
|
|
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.cloud.bridge.model.UserCredentialsVO;
|
|
import com.cloud.bridge.persist.dao.CloudStackUserDaoImpl;
|
|
import com.cloud.bridge.persist.dao.OfferingDaoImpl;
|
|
import com.cloud.bridge.persist.dao.UserCredentialsDaoImpl;
|
|
import com.cloud.bridge.service.controller.s3.ServiceProvider;
|
|
import com.cloud.bridge.service.core.ec2.EC2AddressFilterSet;
|
|
import com.cloud.bridge.service.core.ec2.EC2AssociateAddress;
|
|
import com.cloud.bridge.service.core.ec2.EC2AuthorizeRevokeSecurityGroup;
|
|
import com.cloud.bridge.service.core.ec2.EC2AvailabilityZonesFilterSet;
|
|
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.EC2DescribeImageAttribute;
|
|
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.EC2DescribeTags;
|
|
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.EC2ImageAttributes.ImageAttribute;
|
|
import com.cloud.bridge.service.core.ec2.EC2ImageFilterSet;
|
|
import com.cloud.bridge.service.core.ec2.EC2ImageLaunchPermission;
|
|
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.EC2Tags;
|
|
import com.cloud.bridge.service.core.ec2.EC2TagsFilterSet;
|
|
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.EC2ServiceException.ClientError;
|
|
import com.cloud.bridge.service.exception.NoSuchObjectException;
|
|
import com.cloud.bridge.service.exception.PermissionDeniedException;
|
|
import com.cloud.bridge.util.AuthenticationUtils;
|
|
import com.cloud.bridge.util.ConfigurationHelper;
|
|
import com.cloud.bridge.util.EC2RestAuth;
|
|
import com.cloud.stack.models.CloudStackAccount;
|
|
import com.cloud.utils.db.TransactionLegacy;
|
|
|
|
@Component("EC2RestServlet")
|
|
public class EC2RestServlet extends HttpServlet {
|
|
|
|
private static final long serialVersionUID = -6168996266762804888L;
|
|
@Inject
|
|
UserCredentialsDaoImpl ucDao;
|
|
@Inject
|
|
OfferingDaoImpl ofDao;
|
|
@Inject
|
|
CloudStackUserDaoImpl userDao;
|
|
|
|
public static final Logger logger = Logger.getLogger(EC2RestServlet.class);
|
|
|
|
private final OMFactory factory = OMAbstractFactory.getOMFactory();
|
|
private final XMLOutputFactory xmlOutFactory = XMLOutputFactory.newInstance();
|
|
|
|
private String pathToKeystore = null;
|
|
private String keystorePassword = null;
|
|
private String wsdlVersion = null;
|
|
private String version = null;
|
|
|
|
boolean debug = true;
|
|
|
|
public EC2RestServlet() {
|
|
}
|
|
|
|
/**
|
|
* We build the path to where the keystore holding the WS-Security X509 certificates
|
|
* are stored.
|
|
*/
|
|
@Override
|
|
public void init(ServletConfig config) throws ServletException {
|
|
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
|
|
|
|
File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
|
|
Properties EC2Prop = null;
|
|
|
|
if (null != propertiesFile) {
|
|
logger.info("Use EC2 properties file: " + propertiesFile.getAbsolutePath());
|
|
EC2Prop = new Properties();
|
|
FileInputStream ec2PropFile = null;
|
|
try {
|
|
ec2PropFile = new FileInputStream(propertiesFile);
|
|
EC2Prop.load(ec2PropFile);
|
|
} 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);
|
|
} finally {
|
|
IOUtils.closeQuietly(ec2PropFile);
|
|
}
|
|
String keystore = EC2Prop.getProperty("keystore");
|
|
keystorePassword = EC2Prop.getProperty("keystorePass");
|
|
wsdlVersion = EC2Prop.getProperty("WSDLVersion", "2012-08-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 + File.separator + "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("CreateTags"))
|
|
createTags(request, response);
|
|
else if (action.equalsIgnoreCase("DeleteTags"))
|
|
deleteTags(request, response);
|
|
else if (action.equalsIgnoreCase("DescribeTags"))
|
|
describeTags(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) {
|
|
String errorCode = ((AxisFault)e.getCause()).getFaultCode().getLocalPart();
|
|
if (errorCode.startsWith("Client.")) // only in a SOAP API client error code is prefixed with Client.
|
|
errorCode = errorCode.split("Client.")[1];
|
|
else if (errorCode.startsWith("Server.")) // only in a SOAP API server error code is prefixed with Server.
|
|
errorCode = errorCode.split("Server.")[1];
|
|
faultResponse(response, errorCode, 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;
|
|
TransactionLegacy txn = 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;
|
|
}
|
|
try {
|
|
txn = TransactionLegacy.open(TransactionLegacy.AWSAPI_DB);
|
|
txn.start();
|
|
// -> use the keys to see if the account actually exists
|
|
ServiceProvider.getInstance().getEC2Engine().validateAccount(accessKey[0], secretKey[0]);
|
|
UserCredentialsVO user = new UserCredentialsVO(accessKey[0], secretKey[0]);
|
|
ucDao.persist(user);
|
|
txn.commit();
|
|
} catch (Exception e) {
|
|
logger.error("SetUserKeys " + e.getMessage(), e);
|
|
response.setStatus(401);
|
|
endResponse(response, e.toString());
|
|
txn.close();
|
|
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 {
|
|
TransactionLegacy txn = null;
|
|
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);
|
|
txn = TransactionLegacy.open(TransactionLegacy.AWSAPI_DB);
|
|
txn.start();
|
|
UserCredentialsVO user = ucDao.getByAccessKey(accessKey[0]);
|
|
user.setCertUniqueId(uniqueId);
|
|
ucDao.update(user.getId(), user);
|
|
response.setStatus(200);
|
|
endResponse(response, "User certificate set successfully");
|
|
txn.commit();
|
|
|
|
} 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());
|
|
} finally {
|
|
txn.close();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 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 {
|
|
TransactionLegacy txn = null;
|
|
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 );
|
|
|
|
*/txn = TransactionLegacy.open(TransactionLegacy.AWSAPI_DB);
|
|
UserCredentialsVO user = ucDao.getByAccessKey(accessKey[0]);
|
|
user.setCertUniqueId(null);
|
|
ucDao.update(user.getId(), user);
|
|
response.setStatus(200);
|
|
endResponse(response, "User certificate deleted successfully");
|
|
txn.commit();
|
|
} 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());
|
|
} finally {
|
|
txn.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
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 {
|
|
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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - VolumeId");
|
|
}
|
|
|
|
String[] instanceId = request.getParameterValues("InstanceId");
|
|
if (null != instanceId && 0 < instanceId.length)
|
|
EC2request.setInstanceId(instanceId[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
String[] device = request.getParameterValues("Device");
|
|
if (null != device && 0 < device.length)
|
|
EC2request.setDevice(device[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Device");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - GroupName");
|
|
}
|
|
|
|
// -> not clear how many parameters there are until we fail to get IpPermissions.n.IpProtocol
|
|
int nCount = 1, mCount;
|
|
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) {
|
|
if (protocol[0].equalsIgnoreCase("icmp"))
|
|
perm.setIcmpType(fromPort[0]);
|
|
else
|
|
perm.setFromPort(Integer.parseInt(fromPort[0]));
|
|
}
|
|
|
|
String[] toPort = request.getParameterValues("IpPermissions." + nCount + ".ToPort");
|
|
if (null != toPort && 0 < toPort.length) {
|
|
if (protocol[0].equalsIgnoreCase("icmp"))
|
|
perm.setIcmpCode(toPort[0]);
|
|
else
|
|
perm.setToPort(Integer.parseInt(toPort[0]));
|
|
}
|
|
|
|
// -> list: IpPermissions.n.IpRanges.m.CidrIp
|
|
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 {
|
|
EC2SecurityGroup group = new EC2SecurityGroup();
|
|
|
|
String[] user = request.getParameterValues("IpPermissions." + nCount + ".Groups." + mCount + ".UserId");
|
|
if (null != user && 0 < user.length)
|
|
group.setAccount(user[0]);
|
|
else
|
|
break;
|
|
|
|
String[] name = request.getParameterValues("IpPermissions." + nCount + ".Groups." + mCount + ".GroupName");
|
|
if (null != name && 0 < name.length)
|
|
group.setName(name[0]);
|
|
else
|
|
break;
|
|
|
|
perm.addUser(group);
|
|
mCount++;
|
|
} while (true);
|
|
|
|
// -> multiple IP permissions can be specified per group name
|
|
EC2request.addIpPermission(perm);
|
|
nCount++;
|
|
} while (true);
|
|
|
|
if (1 == nCount) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - IpPermissions");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter 'Groupname'");
|
|
}
|
|
|
|
// -> 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) {
|
|
if (protocol[0].equalsIgnoreCase("icmp"))
|
|
perm.setIcmpType(fromPort[0]);
|
|
else
|
|
perm.setFromPort(Integer.parseInt(fromPort[0]));
|
|
}
|
|
|
|
String[] toPort = request.getParameterValues("IpPermissions." + nCount + ".ToPort");
|
|
if (null != toPort && 0 < toPort.length) {
|
|
if (protocol[0].equalsIgnoreCase("icmp"))
|
|
perm.setIcmpCode(toPort[0]);
|
|
else
|
|
perm.setToPort(Integer.parseInt(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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - IpPermissions");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter 'VolumeId'");
|
|
}
|
|
|
|
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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - VolumeId");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing parameter - AvailabilityZone");
|
|
}
|
|
|
|
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) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterCombination, "Parameters 'Size' and 'SnapshotId' are mutually exclusive");
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Parameter 'Size' or 'SnapshotId' has to be specified");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - GroupName");
|
|
}
|
|
String[] desc = request.getParameterValues("GroupDescription");
|
|
if (null != desc && 0 < desc.length)
|
|
groupDescription = desc[0];
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - GroupDescription");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - GroupName");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - SnapshotId");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - VolumeId");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ImageId");
|
|
}
|
|
|
|
// -> 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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
String[] name = request.getParameterValues("Name");
|
|
if (null != name && 0 < name.length)
|
|
EC2request.setName(name[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Name");
|
|
}
|
|
|
|
String[] description = request.getParameterValues("Description");
|
|
if (null != description && 0 < description.length) {
|
|
if (description[0].length() > 255)
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Length of the value of parameter Description should be less than 255");
|
|
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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing parameter - ImageLocation");
|
|
}
|
|
|
|
String[] cloudRedfined = request.getParameterValues("Architecture");
|
|
if (null != cloudRedfined && 0 < cloudRedfined.length)
|
|
EC2request.setArchitecture(cloudRedfined[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Architecture");
|
|
}
|
|
|
|
String[] name = request.getParameterValues("Name");
|
|
if (null != name && 0 < name.length)
|
|
EC2request.setName(name[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Name");
|
|
}
|
|
|
|
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 (imageId != null && imageId.length > 0)
|
|
ec2request.setImageId(imageId[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ImageId");
|
|
}
|
|
|
|
String[] description = request.getParameterValues("Description.Value");
|
|
if (description != null && description.length > 0) {
|
|
ec2request.setAttribute(ImageAttribute.description);
|
|
ec2request.setDescription(description[0]);
|
|
} else {
|
|
//add all launch permissions to ec2request
|
|
ec2request = addLaunchPermImageAttribute(request, ec2request);
|
|
if (ec2request.getLaunchPermissionSet().length > 0)
|
|
ec2request.setAttribute(ImageAttribute.launchPermission);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Description/LaunchPermission should be provided");
|
|
}
|
|
}
|
|
|
|
// -> execute the request
|
|
ModifyImageAttributeResponse EC2response =
|
|
EC2SoapServiceImpl.toModifyImageAttributeResponse(ServiceProvider.getInstance().getEC2Engine().modifyImageAttribute(ec2request));
|
|
serializeResponse(response, EC2response);
|
|
}
|
|
|
|
private EC2ModifyImageAttribute addLaunchPermImageAttribute(HttpServletRequest request, EC2ModifyImageAttribute ec2request) {
|
|
String[] users = {".UserId", ".Group"};
|
|
String[] operations = {"LaunchPermission.Add.", "LaunchPermission.Remove."};
|
|
int nCount = 1;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int j = 0; j < 2; j++) {
|
|
List<String> launchPermissionList = new ArrayList<String>();
|
|
do {
|
|
String[] launchPermissionAddGroup = request.getParameterValues(operations[j] + nCount + users[i]);
|
|
if (launchPermissionAddGroup != null && launchPermissionAddGroup.length > 0)
|
|
launchPermissionList.add(launchPermissionAddGroup[0]);
|
|
else
|
|
break;
|
|
nCount++;
|
|
} while (true);
|
|
if (nCount != 1) {
|
|
EC2ImageLaunchPermission ec2LaunchPermission = new EC2ImageLaunchPermission();
|
|
if (operations[j].contains("Add"))
|
|
ec2LaunchPermission.setLaunchPermOp(EC2ImageLaunchPermission.Operation.add);
|
|
else
|
|
ec2LaunchPermission.setLaunchPermOp(EC2ImageLaunchPermission.Operation.remove);
|
|
for (String launchPerm : launchPermissionList) {
|
|
ec2LaunchPermission.addLaunchPermission(launchPerm);
|
|
}
|
|
ec2request.addLaunchPermission(ec2LaunchPermission);
|
|
nCount = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ec2request;
|
|
}
|
|
|
|
private void resetImageAttribute(HttpServletRequest request, HttpServletResponse response) throws ADBException, XMLStreamException, IOException {
|
|
EC2ModifyImageAttribute ec2request = new EC2ModifyImageAttribute();
|
|
|
|
String[] imageId = request.getParameterValues("ImageId");
|
|
if (imageId != null && imageId.length > 0)
|
|
ec2request.setImageId(imageId[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ImageId");
|
|
}
|
|
|
|
String[] attribute = request.getParameterValues("Attribute");
|
|
if (attribute != null && attribute.length > 0) {
|
|
if (attribute[0].equalsIgnoreCase("launchPermission"))
|
|
ec2request.setAttribute(ImageAttribute.launchPermission);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Description/LaunchPermission should be provided");
|
|
}
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Attribute");
|
|
}
|
|
|
|
EC2ImageLaunchPermission launchPermission = new EC2ImageLaunchPermission();
|
|
launchPermission.setLaunchPermOp(EC2ImageLaunchPermission.Operation.reset);
|
|
ec2request.addLaunchPermission(launchPermission);
|
|
|
|
// -> execute the request
|
|
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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ImageId");
|
|
}
|
|
|
|
String[] minCount = request.getParameterValues("MinCount");
|
|
if (minCount == null || minCount.length < 1) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - MinCount");
|
|
} else if (Integer.parseInt(minCount[0]) < 1) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Value of parameter MinCount should be greater than 0");
|
|
} else {
|
|
EC2request.setMinCount(Integer.parseInt(minCount[0]));
|
|
}
|
|
|
|
String[] maxCount = request.getParameterValues("MaxCount");
|
|
if (maxCount == null || maxCount.length < 1) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - MaxCount");
|
|
} else if (Integer.parseInt(maxCount[0]) < 1) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Value of parameter MaxCount should be greater than 0");
|
|
} else {
|
|
EC2request.setMaxCount(Integer.parseInt(maxCount[0]));
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
String[] userData = request.getParameterValues("UserData");
|
|
if (userData != null) {
|
|
EC2request.setUserData(userData[0]);
|
|
}
|
|
|
|
Enumeration<?> names = request.getParameterNames();
|
|
while (names.hasMoreElements()) {
|
|
String key = (String)names.nextElement();
|
|
if (key.startsWith("SecurityGroup")) {
|
|
String[] value = request.getParameterValues(key);
|
|
if (null != value && 0 < value.length) {
|
|
if (key.startsWith("SecurityGroupId"))
|
|
EC2request.addSecuritGroupId(value[0]);
|
|
else
|
|
EC2request.addSecuritGroupName(value[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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
// -> 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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
// -> 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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
String[] force = request.getParameterValues("Force");
|
|
if (force != null) {
|
|
EC2request.setForce(Boolean.parseBoolean(force[0]));
|
|
}
|
|
|
|
// -> 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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
// -> 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]);
|
|
}
|
|
}
|
|
|
|
// add filters
|
|
EC2Filter[] filterSet = extractFilters(request);
|
|
if (filterSet != null) {
|
|
EC2AvailabilityZonesFilterSet afs = new EC2AvailabilityZonesFilterSet();
|
|
for (int i = 0; i < filterSet.length; i++) {
|
|
afs.addFilter(filterSet[i]);
|
|
}
|
|
EC2request.setFilterSet(afs);
|
|
}
|
|
|
|
// -> execute the request
|
|
DescribeAvailabilityZonesResponse EC2response =
|
|
EC2SoapServiceImpl.toDescribeAvailabilityZonesResponse(ServiceProvider.getInstance().getEC2Engine().describeAvailabilityZones(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]);
|
|
}
|
|
}
|
|
// add filters
|
|
EC2Filter[] filterSet = extractFilters(request);
|
|
if (filterSet != null) {
|
|
EC2ImageFilterSet ifs = new EC2ImageFilterSet();
|
|
for (int i = 0; i < filterSet.length; i++) {
|
|
ifs.addFilter(filterSet[i]);
|
|
}
|
|
EC2request.setFilterSet(ifs);
|
|
}
|
|
// -> 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 ADBException, XMLStreamException, IOException {
|
|
EC2DescribeImageAttribute ec2request = new EC2DescribeImageAttribute();
|
|
|
|
String[] imageId = request.getParameterValues("ImageId");
|
|
if (imageId != null && imageId.length > 0)
|
|
ec2request.setImageId(imageId[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ImageId");
|
|
}
|
|
|
|
String[] attribute = request.getParameterValues("Attribute");
|
|
if (attribute != null && attribute.length > 0) {
|
|
if (attribute[0].equalsIgnoreCase("description"))
|
|
ec2request.setAttribute(ImageAttribute.description);
|
|
else if (attribute[0].equalsIgnoreCase("launchPermission"))
|
|
ec2request.setAttribute(ImageAttribute.launchPermission);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Only values supported for paramter Attribute are - Description/LaunchPermission");
|
|
}
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Attribute");
|
|
}
|
|
|
|
DescribeImageAttributeResponse EC2response =
|
|
EC2SoapServiceImpl.toDescribeImageAttributeResponse(ServiceProvider.getInstance().getEC2Engine().describeImageAttribute(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]);
|
|
}
|
|
}
|
|
|
|
// add filters
|
|
EC2Filter[] filterSet = extractFilters(request);
|
|
if (filterSet != null) {
|
|
EC2AddressFilterSet afs = new EC2AddressFilterSet();
|
|
for (int i = 0; i < filterSet.length; i++)
|
|
afs.addFilter(filterSet[i]);
|
|
ec2Request.setFilterSet(afs);
|
|
}
|
|
// -> 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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - PublicIp");
|
|
}
|
|
|
|
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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - PublicIp");
|
|
}
|
|
String instanceId = request.getParameter("InstanceId");
|
|
if (null == instanceId) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - PublicIp");
|
|
}
|
|
|
|
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[] instanceId = request.getParameterValues("InstanceId");
|
|
if (instanceId != null && instanceId.length > 0)
|
|
EC2request.addInstanceId(instanceId[0]);
|
|
else
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
|
|
String[] attribute = request.getParameterValues("Attribute");
|
|
if (attribute != null && attribute.length > 0) {
|
|
if (!attribute[0].equalsIgnoreCase("instanceType")) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Only value supported for paramter Attribute is 'instanceType'");
|
|
}
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Attribute");
|
|
}
|
|
|
|
// -> execute the request
|
|
DescribeInstanceAttributeResponse EC2response =
|
|
EC2SoapServiceImpl.toDescribeInstanceAttributeResponse(ServiceProvider.getInstance().getEC2Engine().describeInstances(EC2request));
|
|
serializeResponse(response, EC2response);
|
|
}
|
|
|
|
private void modifyInstanceAttribute(HttpServletRequest request, HttpServletResponse response) throws ADBException, XMLStreamException, IOException {
|
|
EC2ModifyInstanceAttribute ec2Request = new EC2ModifyInstanceAttribute();
|
|
|
|
String[] instanceId = request.getParameterValues("InstanceId");
|
|
if (instanceId != null && instanceId.length > 0)
|
|
ec2Request.setInstanceId(instanceId[0]);
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
String[] instanceType = request.getParameterValues("InstanceType.Value");
|
|
String[] userData = request.getParameterValues("UserData.Value");
|
|
|
|
if (instanceType != null && userData != null) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterCombination, "Only one attribute can be" + " specified at a time");
|
|
}
|
|
if (instanceType != null && instanceType.length > 0) {
|
|
ec2Request.setInstanceType(instanceType[0]);
|
|
} else if (userData != null && userData.length > 0) {
|
|
ec2Request.setUserData(userData[0]);
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing parameter - InstanceType/UserData should be provided");
|
|
}
|
|
|
|
// -> execute the request
|
|
ModifyInstanceAttributeResponse EC2response =
|
|
EC2SoapServiceImpl.toModifyInstanceAttributeResponse(ServiceProvider.getInstance().getEC2Engine().modifyInstanceAttribute(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.describeSnapshots(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
|
|
EC2Engine engine = ServiceProvider.getInstance().getEC2Engine();
|
|
DescribeVolumesResponse EC2response =
|
|
EC2SoapServiceImpl.toDescribeVolumesResponse(ServiceProvider.getInstance().getEC2Engine().describeVolumes(EC2request), engine);
|
|
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();
|
|
|
|
Enumeration<?> names = request.getParameterNames();
|
|
while (names.hasMoreElements()) {
|
|
String key = (String)names.nextElement();
|
|
if (key.startsWith("KeyName")) {
|
|
String[] value = request.getParameterValues(key);
|
|
if (null != value && 0 < value.length)
|
|
ec2Request.addKeyName(value[0]);
|
|
}
|
|
}
|
|
|
|
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");
|
|
if (keyName == null) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - KeyName");
|
|
}
|
|
|
|
String publicKeyMaterial = request.getParameter("PublicKeyMaterial");
|
|
if (publicKeyMaterial == null) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - PublicKeyMaterial");
|
|
}
|
|
|
|
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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - KeyName");
|
|
}
|
|
|
|
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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - KeyName");
|
|
}
|
|
|
|
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) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - InstanceId");
|
|
}
|
|
|
|
GetPasswordDataResponse EC2Response = EC2SoapServiceImpl.toGetPasswordData(ServiceProvider.getInstance().getEC2Engine().getPasswordData(instanceId));
|
|
serializeResponse(response, EC2Response);
|
|
}
|
|
|
|
private void createTags(HttpServletRequest request, HttpServletResponse response) throws ADBException, XMLStreamException, IOException {
|
|
EC2Tags ec2Request = createTagsRequest(request, response);
|
|
if (ec2Request == null)
|
|
return;
|
|
CreateTagsResponse EC2Response = EC2SoapServiceImpl.toCreateTagsResponse(ServiceProvider.getInstance().getEC2Engine().modifyTags(ec2Request, "create"));
|
|
serializeResponse(response, EC2Response);
|
|
}
|
|
|
|
private void deleteTags(HttpServletRequest request, HttpServletResponse response) throws ADBException, XMLStreamException, IOException {
|
|
EC2Tags ec2Request = createTagsRequest(request, response);
|
|
if (ec2Request == null)
|
|
return;
|
|
DeleteTagsResponse EC2Response = EC2SoapServiceImpl.toDeleteTagsResponse(ServiceProvider.getInstance().getEC2Engine().modifyTags(ec2Request, "delete"));
|
|
serializeResponse(response, EC2Response);
|
|
}
|
|
|
|
private EC2Tags createTagsRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
|
EC2Tags ec2Request = new EC2Tags();
|
|
ArrayList<String> resourceIdList = new ArrayList<String>();
|
|
Map<String, String> resourceTagList = new HashMap<String, String>();
|
|
|
|
int nCount = 1;
|
|
do {
|
|
String[] resourceIds = request.getParameterValues("ResourceId." + nCount);
|
|
if (resourceIds != null && resourceIds.length > 0)
|
|
resourceIdList.add(resourceIds[0]);
|
|
else
|
|
break;
|
|
nCount++;
|
|
} while (true);
|
|
if (resourceIdList.isEmpty()) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ResourceId");
|
|
}
|
|
ec2Request = EC2SoapServiceImpl.toResourceTypeAndIds(ec2Request, resourceIdList);
|
|
|
|
nCount = 1;
|
|
do {
|
|
String[] tagKey = request.getParameterValues("Tag." + nCount + ".Key");
|
|
if (tagKey != null && tagKey.length > 0) {
|
|
String[] tagValue = request.getParameterValues("Tag." + nCount + ".Value");
|
|
if (tagValue != null && tagValue.length > 0) {
|
|
resourceTagList.put(tagKey[0], tagValue[0]);
|
|
} else
|
|
resourceTagList.put(tagKey[0], null);
|
|
} else
|
|
break;
|
|
nCount++;
|
|
} while (true);
|
|
if (resourceTagList.isEmpty()) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - ResourceTag");
|
|
}
|
|
ec2Request = EC2SoapServiceImpl.toResourceTag(ec2Request, resourceTagList);
|
|
|
|
return ec2Request;
|
|
}
|
|
|
|
private void describeTags(HttpServletRequest request, HttpServletResponse response) throws ADBException, XMLStreamException, IOException {
|
|
EC2DescribeTags ec2Request = new EC2DescribeTags();
|
|
|
|
EC2Filter[] filterSet = extractFilters(request);
|
|
if (null != filterSet) {
|
|
EC2TagsFilterSet tfs = new EC2TagsFilterSet();
|
|
for (int i = 0; i < filterSet.length; i++)
|
|
tfs.addFilter(filterSet[i]);
|
|
ec2Request.setFilterSet(tfs);
|
|
}
|
|
DescribeTagsResponse EC2Response = EC2SoapServiceImpl.toDescribeTagsResponse(ServiceProvider.getInstance().getEC2Engine().describeTags(ec2Request));
|
|
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 {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - AWSAccessKeyId");
|
|
}
|
|
|
|
String[] clientSig = request.getParameterValues("Signature");
|
|
if (null != clientSig && 0 < clientSig.length)
|
|
signature = clientSig[0];
|
|
else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Signature");
|
|
}
|
|
|
|
String[] method = request.getParameterValues("SignatureMethod");
|
|
if (null != method && 0 < method.length) {
|
|
sigMethod = method[0];
|
|
if (!sigMethod.equals("HmacSHA256") && !sigMethod.equals("HmacSHA1")) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Unsupported SignatureMethod value: " + sigMethod + " expecting: HmacSHA256 or HmacSHA1");
|
|
}
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - SignatureMethod");
|
|
}
|
|
|
|
String[] version = request.getParameterValues("Version");
|
|
if (null != version && 0 < version.length) {
|
|
if (!version[0].equals(wsdlVersion)) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Unsupported Version value: " + version[0] + " expecting: " + wsdlVersion);
|
|
}
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - Version");
|
|
}
|
|
|
|
String[] sigVersion = request.getParameterValues("SignatureVersion");
|
|
if (null != sigVersion && 0 < sigVersion.length) {
|
|
if (!sigVersion[0].equals("2")) {
|
|
throw new EC2ServiceException(ClientError.InvalidParameterValue, "Unsupported SignatureVersion value: " + sigVersion[0] + " expecting: 2");
|
|
}
|
|
} else {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter - SignatureVersion");
|
|
}
|
|
|
|
// -> 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])) { //InvalidSecurity.RequestHasExpired
|
|
throw new EC2ServiceException(ClientError.InvalidSecurity_RequestHasExpired, "Expires parameter indicates signature has expired: " + expires[0]);
|
|
}
|
|
} else { // -> contains the date and time at which the request is SIGNED
|
|
String[] time = request.getParameterValues("Timestamp");
|
|
if (null == time || 0 == time.length) {
|
|
throw new EC2ServiceException(ClientError.MissingParamter, "Missing required parameter -" + " Timestamp/Expires");
|
|
}
|
|
}
|
|
|
|
// [B] Use the access key to get the users secret key from the cloud DB
|
|
cloudSecretKey = userDao.getSecretKeyByAccessKey(cloudAccessKey);
|
|
if (cloudSecretKey == null) {
|
|
logger.debug("Access key '" + cloudAccessKey + "' not found in the the EC2 service ");
|
|
throw new EC2ServiceException(ClientError.AuthFailure, "Access key '" + cloudAccessKey + "' not found in the the EC2 service ");
|
|
}
|
|
|
|
// [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),
|
|
// 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;
|
|
// URLEncoder performs application/x-www-form-urlencoded-type encoding and not Percent encoding
|
|
// according to RFC 3986 as required by Amazon, we need to Percent-encode (URL Encode)
|
|
String encodedValue = URLEncoder.encode(request.getParameter(paramName), "UTF-8").replace("+", "%20").replace("*", "%2A");
|
|
if (queryString == null)
|
|
queryString = paramName + "=" + encodedValue;
|
|
else
|
|
queryString = queryString + "&" + paramName + "=" + encodedValue;
|
|
}
|
|
}
|
|
}
|
|
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 EC2ServiceException(ClientError.SignatureDoesNotMatch, "The request signature calculated does not match the signature provided by the user.");
|
|
}
|
|
|
|
/**
|
|
* 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");
|
|
XMLStreamWriter xmlWriter = xmlOutFactory.createXMLStreamWriter(os);
|
|
xmlWriter.writeStartDocument("UTF-8", "1.0");
|
|
MTOMAwareXMLSerializer MTOMWriter = new MTOMAwareXMLSerializer(xmlWriter);
|
|
MTOMWriter.setDefaultNamespace("http://ec2.amazonaws.com/doc/" + wsdlVersion + "/");
|
|
EC2Response.serialize(null, factory, MTOMWriter);
|
|
xmlWriter.flush();
|
|
xmlWriter.close();
|
|
os.close();
|
|
}
|
|
}
|