You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/01/15 03:04:54 UTC

[36/44] Revert "Merge remote-tracking branch 'origin/javelin' into javelin"

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/110465b5/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
index eb25249..0f8eded 100644
--- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
@@ -22,9 +22,6 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.security.SignatureException;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.text.ParseException;
 import java.util.ArrayList;
@@ -32,6 +29,7 @@ import java.util.List;
 import java.util.Properties;
 import java.util.UUID;
 
+import javax.inject.Inject;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.log4j.Logger;
@@ -39,13 +37,9 @@ import org.xml.sax.SAXException;
 
 import com.cloud.bridge.model.CloudStackServiceOfferingVO;
 import com.cloud.bridge.persist.dao.CloudStackAccountDao;
-import com.cloud.bridge.persist.dao.CloudStackAccountDaoImpl;
 import com.cloud.bridge.persist.dao.CloudStackSvcOfferingDao;
-import com.cloud.bridge.persist.dao.CloudStackSvcOfferingDaoImpl;
-import com.cloud.bridge.persist.dao.OfferingDaoImpl;
-import com.cloud.bridge.persist.dao.SObjectItemDaoImpl;
+import com.cloud.bridge.persist.dao.OfferingDao;
 import com.cloud.bridge.service.UserContext;
-
 import com.cloud.bridge.service.core.ec2.EC2ImageAttributes.ImageAttribute;
 import com.cloud.bridge.service.exception.EC2ServiceException;
 import com.cloud.bridge.service.exception.EC2ServiceException.ClientError;
@@ -68,7 +62,6 @@ import com.cloud.stack.models.CloudStackResourceLimit;
 import com.cloud.stack.models.CloudStackResourceTag;
 import com.cloud.stack.models.CloudStackSecurityGroup;
 import com.cloud.stack.models.CloudStackSecurityGroupIngress;
-import com.cloud.stack.models.CloudStackServiceOffering;
 import com.cloud.stack.models.CloudStackSnapshot;
 import com.cloud.stack.models.CloudStackTemplate;
 import com.cloud.stack.models.CloudStackTemplatePermission;
@@ -76,453 +69,451 @@ import com.cloud.stack.models.CloudStackUser;
 import com.cloud.stack.models.CloudStackUserVm;
 import com.cloud.stack.models.CloudStackVolume;
 import com.cloud.stack.models.CloudStackZone;
-import com.cloud.utils.component.ComponentLocator;
-import com.cloud.utils.db.Transaction;
 
 /**
  * EC2Engine processes the ec2 commands and calls their cloudstack analogs
  *
  */
 public class EC2Engine {
-	protected final static Logger logger = Logger.getLogger(EC2Engine.class);
-	String managementServer = null;
-	String cloudAPIPort = null;
-
-	protected final CloudStackSvcOfferingDao scvoDao = ComponentLocator.inject(CloudStackSvcOfferingDaoImpl.class);
-    protected final OfferingDaoImpl ofDao = ComponentLocator.inject(OfferingDaoImpl.class);
-    CloudStackAccountDao accDao = ComponentLocator.inject(CloudStackAccountDaoImpl.class);
-	private CloudStackApi _eng = null;
-	
-	private CloudStackAccount currentAccount = null;
-
-	public EC2Engine() throws IOException {
-		loadConfigValues();
-	}
-
-	/**
-	 * Which management server to we talk to?  
-	 * Load a mapping form Amazon values for 'instanceType' to cloud defined
-	 * diskOfferingId and serviceOfferingId.
-	 * 
-	 * @throws IOException
-	 */
-	private void loadConfigValues() throws IOException {
-		File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
-		if (null != propertiesFile) {
-			logger.info("Use EC2 properties file: " + propertiesFile.getAbsolutePath());
-			Properties EC2Prop = new Properties();
-			try {
-				EC2Prop.load( new FileInputStream( propertiesFile ));
-			} catch (FileNotFoundException e) {
-				logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
-			} catch (IOException e) {
-				logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
-			}
-			managementServer = EC2Prop.getProperty( "managementServer" );
-			cloudAPIPort = EC2Prop.getProperty( "cloudAPIPort", null );
-			
-			try {
-				if(ofDao.getOfferingCount() == 0) {
-					String strValue = EC2Prop.getProperty("m1.small.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("m1.small", strValue);
-
-					strValue = EC2Prop.getProperty("m1.large.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("m1.large", strValue);
-
-					strValue = EC2Prop.getProperty("m1.xlarge.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("m1.xlarge", strValue);
-
-					strValue = EC2Prop.getProperty("c1.medium.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("c1.medium", strValue);
-
-					strValue = EC2Prop.getProperty("c1.xlarge.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("c1.xlarge", strValue);
-
-					strValue = EC2Prop.getProperty("m2.xlarge.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("m2.xlarge", strValue);
-
-					strValue = EC2Prop.getProperty("m2.2xlarge.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("m2.2xlarge", strValue);
-
-					strValue = EC2Prop.getProperty("m2.4xlarge.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("m2.4xlarge", strValue);
-
-					strValue = EC2Prop.getProperty("cc1.4xlarge.serviceId");
-					if(strValue != null) ofDao.setOfferMapping("cc1.4xlarge", strValue);
-				}
-			} catch(Exception e) {
-				logger.error("Unexpected exception ", e);
-			}
-		} else logger.error( "ec2-service.properties not found" );
-	}
-	
-	/**
-	 * Helper function to manage the api connection
-	 * 
-	 * @return
-	 */
-	private CloudStackApi getApi() {
-		if (_eng == null) {
-		    _eng = new CloudStackApi(managementServer, cloudAPIPort, false);
-		}
-		// regardless of whether _eng is initialized, we must make sure 
-		// access/secret keys are current with what's in the UserCredentials
+    protected final static Logger logger = Logger.getLogger(EC2Engine.class);
+    String managementServer = null;
+    String cloudAPIPort = null;
+
+    @Inject CloudStackSvcOfferingDao scvoDao;
+    @Inject OfferingDao ofDao;
+    @Inject CloudStackAccountDao accDao;
+    private CloudStackApi _eng = null;
+
+    private CloudStackAccount currentAccount = null;
+
+    public EC2Engine() throws IOException {
+        loadConfigValues();
+    }
+
+    /**
+     * Which management server to we talk to?  
+     * Load a mapping form Amazon values for 'instanceType' to cloud defined
+     * diskOfferingId and serviceOfferingId.
+     * 
+     * @throws IOException
+     */
+    private void loadConfigValues() throws IOException {
+        File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
+        if (null != propertiesFile) {
+            logger.info("Use EC2 properties file: " + propertiesFile.getAbsolutePath());
+            Properties EC2Prop = new Properties();
+            try {
+                EC2Prop.load( new FileInputStream( propertiesFile ));
+            } catch (FileNotFoundException e) {
+                logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
+            } catch (IOException e) {
+                logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
+            }
+            managementServer = EC2Prop.getProperty( "managementServer" );
+            cloudAPIPort = EC2Prop.getProperty( "cloudAPIPort", null );
+
+            try {
+                if(ofDao.getOfferingCount() == 0) {
+                    String strValue = EC2Prop.getProperty("m1.small.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("m1.small", strValue);
+
+                    strValue = EC2Prop.getProperty("m1.large.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("m1.large", strValue);
+
+                    strValue = EC2Prop.getProperty("m1.xlarge.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("m1.xlarge", strValue);
+
+                    strValue = EC2Prop.getProperty("c1.medium.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("c1.medium", strValue);
+
+                    strValue = EC2Prop.getProperty("c1.xlarge.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("c1.xlarge", strValue);
+
+                    strValue = EC2Prop.getProperty("m2.xlarge.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("m2.xlarge", strValue);
+
+                    strValue = EC2Prop.getProperty("m2.2xlarge.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("m2.2xlarge", strValue);
+
+                    strValue = EC2Prop.getProperty("m2.4xlarge.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("m2.4xlarge", strValue);
+
+                    strValue = EC2Prop.getProperty("cc1.4xlarge.serviceId");
+                    if(strValue != null) ofDao.setOfferMapping("cc1.4xlarge", strValue);
+                }
+            } catch(Exception e) {
+                logger.error("Unexpected exception ", e);
+            }
+        } else logger.error( "ec2-service.properties not found" );
+    }
+
+    /**
+     * Helper function to manage the api connection
+     * 
+     * @return
+     */
+    private CloudStackApi getApi() {
+        if (_eng == null) {
+            _eng = new CloudStackApi(managementServer, cloudAPIPort, false);
+        }
+        // regardless of whether _eng is initialized, we must make sure 
+        // access/secret keys are current with what's in the UserCredentials
         _eng.setApiKey(UserContext.current().getAccessKey());
         _eng.setSecretKey(UserContext.current().getSecretKey());
-		return _eng;
-	}
-
-
-	/**
-	 * Verifies account can access CloudStack
-	 * 
-	 * @param accessKey
-	 * @param secretKey
-	 * @return
-	 * @throws EC2ServiceException
-	 */
-	public boolean validateAccount( String accessKey, String secretKey ) throws EC2ServiceException {
-		String oldApiKey = null;
-		String oldSecretKey = null;
-
-		if (accessKey == null || secretKey == null) {
+        return _eng;
+    }
+
+
+    /**
+     * Verifies account can access CloudStack
+     * 
+     * @param accessKey
+     * @param secretKey
+     * @return
+     * @throws EC2ServiceException
+     */
+    public boolean validateAccount( String accessKey, String secretKey ) throws EC2ServiceException {
+        String oldApiKey = null;
+        String oldSecretKey = null;
+
+        if (accessKey == null || secretKey == null) {
             return false;
         }
-		
-		// okay, instead of using the getApi() nonsense for validate, we are going to manage _eng
-		if (_eng == null) {
+
+        // okay, instead of using the getApi() nonsense for validate, we are going to manage _eng
+        if (_eng == null) {
             _eng = new CloudStackApi(managementServer, cloudAPIPort, false);
-		}
-		
-		try {
-		    oldApiKey = _eng.getApiKey(); 
-		    oldSecretKey = _eng.getSecretKey();
-		} catch(Exception e) {
-		    // we really don't care, and expect this
-		}
+        }
+
+        try {
+            oldApiKey = _eng.getApiKey(); 
+            oldSecretKey = _eng.getSecretKey();
+        } catch(Exception e) {
+            // we really don't care, and expect this
+        }
+        try {
+            _eng.setApiKey(accessKey);
+            _eng.setSecretKey(secretKey);
+            List<CloudStackAccount> accts = _eng.listAccounts(null, null, null, null, null, null, null, null);
+            if (oldApiKey != null && oldSecretKey != null) {
+                _eng.setApiKey(oldApiKey);
+                _eng.setSecretKey(oldSecretKey);
+            }
+            if (accts == null) {
+                return false;
+            }
+            return true;
+        } catch(Exception e) {
+            logger.error("Validate account failed!");
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * Creates a security group
+     * 
+     * @param groupName
+     * @param groupDesc
+     * @return
+     */
+    public Boolean createSecurityGroup(String groupName, String groupDesc) {
+        try {
+            CloudStackSecurityGroup grp = getApi().createSecurityGroup(groupName, null, groupDesc, null);
+            if (grp != null && grp.getId() != null) {
+                return true;
+            }
+            return false;
+        } catch( Exception e ) {
+            logger.error( "EC2 CreateSecurityGroup - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * Deletes a security group
+     * 
+     * @param groupName
+     * @return
+     */
+    public boolean deleteSecurityGroup(String groupName) {
+        try {
+            CloudStackInfoResponse resp = getApi().deleteSecurityGroup(null, null, null, groupName);
+            if (resp != null) {
+                return resp.getSuccess();
+            }
+            return false;
+        } catch( Exception e ) {
+            logger.error( "EC2 DeleteSecurityGroup - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * returns a list of security groups
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeSecurityGroupsResponse describeSecurityGroups(EC2DescribeSecurityGroups request) 
+    {
+        try {
+            EC2DescribeSecurityGroupsResponse response = listSecurityGroups( request.getGroupSet());
+            EC2GroupFilterSet gfs = request.getFilterSet();
+
+            if ( null == gfs )
+                return response;
+            else return gfs.evaluate( response );     
+        } catch( Exception e ) {
+            logger.error( "EC2 DescribeSecurityGroups - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * CloudStack supports revoke only by using the ruleid of the ingress rule.   
+     * We list all security groups and find the matching group and use the first ruleId we find.
+     * 
+     * @param request
+     * @return
+     */
+    public boolean revokeSecurityGroup( EC2AuthorizeRevokeSecurityGroup request ) 
+    {
+        if (null == request.getName()) throw new EC2ServiceException(ServerError.InternalError, "Name is a required parameter");
+        try {   
+            String[] groupSet = new String[1];
+            groupSet[0] = request.getName();
+            String ruleId = null;
+
+            EC2IpPermission[] items = request.getIpPermissionSet();
+
+            EC2DescribeSecurityGroupsResponse response = listSecurityGroups( groupSet );
+            EC2SecurityGroup[] groups = response.getGroupSet();
+
+            for (EC2SecurityGroup group : groups) {
+                EC2IpPermission[] perms = group.getIpPermissionSet();
+                for (EC2IpPermission perm : perms) {
+                    ruleId = doesRuleMatch( items[0], perm );
+                    if (ruleId != null) break;
+                }
+            }
+
+            if (null == ruleId)
+                throw new EC2ServiceException(ClientError.InvalidGroup_NotFound, "Cannot find matching ruleid.");
+
+            CloudStackInfoResponse resp = getApi().revokeSecurityGroupIngress(ruleId);
+            if (resp != null && resp.getId() != null) {
+                return resp.getSuccess();
+            }
+            return false;
+        } catch( Exception e ) {
+            logger.error( "EC2 revokeSecurityGroupIngress" + " - " + e.getMessage());
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        } 	
+    }
+
+    /**
+     * authorizeSecurityGroup
+     * 
+     * @param request - ip permission parameters
+     */
+    public boolean authorizeSecurityGroup(EC2AuthorizeRevokeSecurityGroup request ) 
+    {
+        if (null == request.getName()) throw new EC2ServiceException(ServerError.InternalError, "Name is a required parameter");
+
+        EC2IpPermission[] items = request.getIpPermissionSet();
+
         try {
-			_eng.setApiKey(accessKey);
-			_eng.setSecretKey(secretKey);
-			List<CloudStackAccount> accts = _eng.listAccounts(null, null, null, null, null, null, null, null);
-			if (oldApiKey != null && oldSecretKey != null) {
-				_eng.setApiKey(oldApiKey);
-				_eng.setSecretKey(oldSecretKey);
-			}
-			if (accts == null) {
-				return false;
-			}
-			return true;
-		} catch(Exception e) {
-			logger.error("Validate account failed!");
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * Creates a security group
-	 * 
-	 * @param groupName
-	 * @param groupDesc
-	 * @return
-	 */
-	public Boolean createSecurityGroup(String groupName, String groupDesc) {
-		try {
-			CloudStackSecurityGroup grp = getApi().createSecurityGroup(groupName, null, groupDesc, null);
-			if (grp != null && grp.getId() != null) {
-				return true;
-			}
-			return false;
-		} catch( Exception e ) {
-			logger.error( "EC2 CreateSecurityGroup - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * Deletes a security group
-	 * 
-	 * @param groupName
-	 * @return
-	 */
-	public boolean deleteSecurityGroup(String groupName) {
-		try {
-			CloudStackInfoResponse resp = getApi().deleteSecurityGroup(null, null, null, groupName);
-			if (resp != null) {
-				return resp.getSuccess();
-			}
-			return false;
-		} catch( Exception e ) {
-			logger.error( "EC2 DeleteSecurityGroup - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * returns a list of security groups
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeSecurityGroupsResponse describeSecurityGroups(EC2DescribeSecurityGroups request) 
-	{
-		try {
-			EC2DescribeSecurityGroupsResponse response = listSecurityGroups( request.getGroupSet());
-			EC2GroupFilterSet gfs = request.getFilterSet();
-
-			if ( null == gfs )
-				return response;
-			else return gfs.evaluate( response );     
-		} catch( Exception e ) {
-			logger.error( "EC2 DescribeSecurityGroups - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * CloudStack supports revoke only by using the ruleid of the ingress rule.   
-	 * We list all security groups and find the matching group and use the first ruleId we find.
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public boolean revokeSecurityGroup( EC2AuthorizeRevokeSecurityGroup request ) 
-	{
-		if (null == request.getName()) throw new EC2ServiceException(ServerError.InternalError, "Name is a required parameter");
-		try {   
-			String[] groupSet = new String[1];
-			groupSet[0] = request.getName();
-			String ruleId = null;
-	
-			EC2IpPermission[] items = request.getIpPermissionSet();
-
-			EC2DescribeSecurityGroupsResponse response = listSecurityGroups( groupSet );
-			EC2SecurityGroup[] groups = response.getGroupSet();
-
-			for (EC2SecurityGroup group : groups) {
-				EC2IpPermission[] perms = group.getIpPermissionSet();
-				for (EC2IpPermission perm : perms) {
-					ruleId = doesRuleMatch( items[0], perm );
-					if (ruleId != null) break;
-				}
-			}
-
-			if (null == ruleId)
-				throw new EC2ServiceException(ClientError.InvalidGroup_NotFound, "Cannot find matching ruleid.");
-
-			CloudStackInfoResponse resp = getApi().revokeSecurityGroupIngress(ruleId);
-			if (resp != null && resp.getId() != null) {
-				return resp.getSuccess();
-			}
-			return false;
-		} catch( Exception e ) {
-			logger.error( "EC2 revokeSecurityGroupIngress" + " - " + e.getMessage());
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		} 	
-	}
-
-	/**
-	 * authorizeSecurityGroup
-	 * 
-	 * @param request - ip permission parameters
-	 */
-	public boolean authorizeSecurityGroup(EC2AuthorizeRevokeSecurityGroup request ) 
-	{
-		if (null == request.getName()) throw new EC2ServiceException(ServerError.InternalError, "Name is a required parameter");
-
-		EC2IpPermission[] items = request.getIpPermissionSet();
-
-		try {
-			for (EC2IpPermission ipPerm : items) {
-				EC2SecurityGroup[] groups = ipPerm.getUserSet();
-				
-				List<CloudStackKeyValue> secGroupList = new ArrayList<CloudStackKeyValue>(); 
-				for (EC2SecurityGroup group : groups) {
-					CloudStackKeyValue pair = new CloudStackKeyValue();
-					pair.setKeyValue(group.getAccount(), group.getName());
-					secGroupList.add(pair);
-				}
-				CloudStackSecurityGroupIngress resp = null;
-				if (ipPerm.getProtocol().equalsIgnoreCase("icmp")) {
-					resp = getApi().authorizeSecurityGroupIngress(null, constructList(ipPerm.getIpRangeSet()), null, null, 
-							ipPerm.getIcmpCode(), ipPerm.getIcmpType(), ipPerm.getProtocol(), null, 
-							request.getName(), null, secGroupList);
-				} else {
-					resp = getApi().authorizeSecurityGroupIngress(null, constructList(ipPerm.getIpRangeSet()), null, 
-							ipPerm.getToPort().longValue(), null, null, ipPerm.getProtocol(), null, request.getName(), 
-							ipPerm.getFromPort().longValue(), secGroupList);
-				}
-				if (resp != null && resp.getRuleId() != null) {
-					return true;
-				}
-				return false;
-			}
-		} catch(Exception e) {
-			logger.error( "EC2 AuthorizeSecurityGroupIngress - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-		return true;
-	}
-
-	/**
-	 * Does the permission from the request (left) match the permission from the cloudStack query (right).
-	 * If the cloudStack rule matches then we return its ruleId.
-	 * 
-	 * @param permLeft
-	 * @param permRight
-	 * @return ruleId of the cloudstack rule
-	 */
-	private String doesRuleMatch(EC2IpPermission permLeft, EC2IpPermission permRight)
-	{
-		int matches = 0;
-
-		if (null != permLeft.getIcmpType() && null != permLeft.getIcmpCode()) {
-			if (null == permRight.getIcmpType() || null == permRight.getIcmpCode()) return null;
-
-			if (!permLeft.getIcmpType().equalsIgnoreCase( permRight.getIcmpType())) return null;
-			if (!permLeft.getIcmpCode().equalsIgnoreCase( permRight.getIcmpCode())) return null;
-			matches++;
-		}
-
-		// -> "Valid Values for EC2 security groups: tcp | udp | icmp or the corresponding protocol number (6 | 17 | 1)."
-		if (null != permLeft.getProtocol()) {
-			if (null == permRight.getProtocol()) return null;
-
-			String protocol = permLeft.getProtocol();
-			if (protocol.equals( "6"  )) protocol = "tcp";
-			else if (protocol.equals( "17" )) protocol = "udp";
-			else if (protocol.equals( "1"  )) protocol = "icmp";
-
-			if (!protocol.equalsIgnoreCase( permRight.getProtocol())) return null;
-			matches++;
-		}
-
-
-		if (null != permLeft.getCIDR()) {
-			if (null == permRight.getCIDR()) return null;
-
-			if (!permLeft.getCIDR().equalsIgnoreCase( permRight.getCIDR())) return null;
-			matches++;
-		}
-
-		// -> is the port(s) from the request (left) a match of the rule's port(s) 
-		if (0 != permLeft.getFromPort()) {
-			// -> -1 means all ports match
-			if (-1 != permLeft.getFromPort()) {
-				if (permLeft.getFromPort().compareTo(permRight.getFromPort()) != 0 || 
-						permLeft.getToPort().compareTo(permRight.getToPort()) != 0) 
-					return null;
-			}
-			matches++;
-		}
-
-
-		// -> was permLeft set up properly with at least one property to match?
-		if ( 0 == matches ) 
-			return null;
-		else return permRight.getRuleId();
-	}
-	
-	/**
-	 * Returns a list of all snapshots
-	 * 
-	 * @param request
-	 * @return
-	 */
+            for (EC2IpPermission ipPerm : items) {
+                EC2SecurityGroup[] groups = ipPerm.getUserSet();
+
+                List<CloudStackKeyValue> secGroupList = new ArrayList<CloudStackKeyValue>(); 
+                for (EC2SecurityGroup group : groups) {
+                    CloudStackKeyValue pair = new CloudStackKeyValue();
+                    pair.setKeyValue(group.getAccount(), group.getName());
+                    secGroupList.add(pair);
+                }
+                CloudStackSecurityGroupIngress resp = null;
+                if (ipPerm.getProtocol().equalsIgnoreCase("icmp")) {
+                    resp = getApi().authorizeSecurityGroupIngress(null, constructList(ipPerm.getIpRangeSet()), null, null, 
+                            ipPerm.getIcmpCode(), ipPerm.getIcmpType(), ipPerm.getProtocol(), null, 
+                            request.getName(), null, secGroupList);
+                } else {
+                    resp = getApi().authorizeSecurityGroupIngress(null, constructList(ipPerm.getIpRangeSet()), null, 
+                            ipPerm.getToPort().longValue(), null, null, ipPerm.getProtocol(), null, request.getName(), 
+                            ipPerm.getFromPort().longValue(), secGroupList);
+                }
+                if (resp != null && resp.getRuleId() != null) {
+                    return true;
+                }
+                return false;
+            }
+        } catch(Exception e) {
+            logger.error( "EC2 AuthorizeSecurityGroupIngress - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * Does the permission from the request (left) match the permission from the cloudStack query (right).
+     * If the cloudStack rule matches then we return its ruleId.
+     * 
+     * @param permLeft
+     * @param permRight
+     * @return ruleId of the cloudstack rule
+     */
+    private String doesRuleMatch(EC2IpPermission permLeft, EC2IpPermission permRight)
+    {
+        int matches = 0;
+
+        if (null != permLeft.getIcmpType() && null != permLeft.getIcmpCode()) {
+            if (null == permRight.getIcmpType() || null == permRight.getIcmpCode()) return null;
+
+            if (!permLeft.getIcmpType().equalsIgnoreCase( permRight.getIcmpType())) return null;
+            if (!permLeft.getIcmpCode().equalsIgnoreCase( permRight.getIcmpCode())) return null;
+            matches++;
+        }
+
+        // -> "Valid Values for EC2 security groups: tcp | udp | icmp or the corresponding protocol number (6 | 17 | 1)."
+        if (null != permLeft.getProtocol()) {
+            if (null == permRight.getProtocol()) return null;
+
+            String protocol = permLeft.getProtocol();
+            if (protocol.equals( "6"  )) protocol = "tcp";
+            else if (protocol.equals( "17" )) protocol = "udp";
+            else if (protocol.equals( "1"  )) protocol = "icmp";
+
+            if (!protocol.equalsIgnoreCase( permRight.getProtocol())) return null;
+            matches++;
+        }
+
+
+        if (null != permLeft.getCIDR()) {
+            if (null == permRight.getCIDR()) return null;
+
+            if (!permLeft.getCIDR().equalsIgnoreCase( permRight.getCIDR())) return null;
+            matches++;
+        }
+
+        // -> is the port(s) from the request (left) a match of the rule's port(s) 
+        if (0 != permLeft.getFromPort()) {
+            // -> -1 means all ports match
+            if (-1 != permLeft.getFromPort()) {
+                if (permLeft.getFromPort().compareTo(permRight.getFromPort()) != 0 || 
+                        permLeft.getToPort().compareTo(permRight.getToPort()) != 0) 
+                    return null;
+            }
+            matches++;
+        }
+
+
+        // -> was permLeft set up properly with at least one property to match?
+        if ( 0 == matches ) 
+            return null;
+        else return permRight.getRuleId();
+    }
+
+    /**
+     * Returns a list of all snapshots
+     * 
+     * @param request
+     * @return
+     */
     public EC2DescribeSnapshotsResponse handleRequest( EC2DescribeSnapshots request ) 
-	{
-		EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
-		EC2SnapshotFilterSet sfs = request.getFilterSet();
+    {
+        EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
+        EC2SnapshotFilterSet sfs = request.getFilterSet();
         EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet();
 
-		try { 
-			// -> query to get the volume size for each snapshot
+        try { 
+            // -> query to get the volume size for each snapshot
             EC2DescribeSnapshotsResponse response = listSnapshots( request.getSnapshotSet(),
                     getResourceTags(tagKeyValueSet));
-			if (response == null) {
-				return new EC2DescribeSnapshotsResponse();
-			}
-			EC2Snapshot[] snapshots = response.getSnapshotSet();
-			for (EC2Snapshot snap : snapshots) {
-				volumes = listVolumes(snap.getVolumeId(), null, volumes, null);
-				EC2Volume[] volSet = volumes.getVolumeSet();
-				if (0 < volSet.length) snap.setVolumeSize(volSet[0].getSize());
-				volumes.reset();
-			}
-
-			if ( null == sfs )
-				return response;
-			else return sfs.evaluate( response );
-		} catch( EC2ServiceException error ) {
-			logger.error( "EC2 DescribeSnapshots - ", error);
-			throw error;
-
-		} catch( Exception e ) {
-			logger.error( "EC2 DescribeSnapshots - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * Creates a snapshot
-	 * 
-	 * @param volumeId
-	 * @return
-	 */
-	public EC2Snapshot createSnapshot( String volumeId ) {
-		try {
-			
-			CloudStackSnapshot snap = getApi().createSnapshot(volumeId, null, null, null);
-			if (snap == null) {
-				throw new EC2ServiceException(ServerError.InternalError, "Unable to create snapshot!");
-			}
-			EC2Snapshot ec2Snapshot = new EC2Snapshot();
-
-			ec2Snapshot.setId(snap.getId());
-			ec2Snapshot.setName(snap.getName());
-			ec2Snapshot.setType(snap.getSnapshotType());
-			ec2Snapshot.setAccountName(snap.getAccountName());
-			ec2Snapshot.setDomainId(snap.getDomainId());
-			ec2Snapshot.setCreated(snap.getCreated());
-			ec2Snapshot.setVolumeId(snap.getVolumeId());
-			
-			List<CloudStackVolume> vols = getApi().listVolumes(null, null, null, snap.getVolumeId(), null, null, null, null, null, null, null, null);
-
-			if(vols.size() > 0) {
-				assert(vols.get(0).getSize() != null);
-				Long sizeInGB = vols.get(0).getSize().longValue()/1073741824;
-				ec2Snapshot.setVolumeSize(sizeInGB);
-			}
-
-			return ec2Snapshot;
-		} catch( Exception e ) {
-			logger.error( "EC2 CreateSnapshot - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * Deletes a snapshot
-	 * 
-	 * @param snapshotId
-	 * @return
-	 */
-	public boolean deleteSnapshot(String snapshotId) {
-		try {
-			
-			CloudStackInfoResponse resp = getApi().deleteSnapshot(snapshotId);
-			if(resp != null) {
-			    return resp.getSuccess();
-			}
-
-			return false;
-		} catch(Exception e) {
-			logger.error( "EC2 DeleteSnapshot - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-	
-	
-	/** REST API calls this method.
+            if (response == null) {
+                return new EC2DescribeSnapshotsResponse();
+            }
+            EC2Snapshot[] snapshots = response.getSnapshotSet();
+            for (EC2Snapshot snap : snapshots) {
+                volumes = listVolumes(snap.getVolumeId(), null, volumes, null);
+                EC2Volume[] volSet = volumes.getVolumeSet();
+                if (0 < volSet.length) snap.setVolumeSize(volSet[0].getSize());
+                volumes.reset();
+            }
+
+            if ( null == sfs )
+                return response;
+            else return sfs.evaluate( response );
+        } catch( EC2ServiceException error ) {
+            logger.error( "EC2 DescribeSnapshots - ", error);
+            throw error;
+
+        } catch( Exception e ) {
+            logger.error( "EC2 DescribeSnapshots - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * Creates a snapshot
+     * 
+     * @param volumeId
+     * @return
+     */
+    public EC2Snapshot createSnapshot( String volumeId ) {
+        try {
+
+            CloudStackSnapshot snap = getApi().createSnapshot(volumeId, null, null, null);
+            if (snap == null) {
+                throw new EC2ServiceException(ServerError.InternalError, "Unable to create snapshot!");
+            }
+            EC2Snapshot ec2Snapshot = new EC2Snapshot();
+
+            ec2Snapshot.setId(snap.getId());
+            ec2Snapshot.setName(snap.getName());
+            ec2Snapshot.setType(snap.getSnapshotType());
+            ec2Snapshot.setAccountName(snap.getAccountName());
+            ec2Snapshot.setDomainId(snap.getDomainId());
+            ec2Snapshot.setCreated(snap.getCreated());
+            ec2Snapshot.setVolumeId(snap.getVolumeId());
+
+            List<CloudStackVolume> vols = getApi().listVolumes(null, null, null, snap.getVolumeId(), null, null, null, null, null, null, null, null);
+
+            if(vols.size() > 0) {
+                assert(vols.get(0).getSize() != null);
+                Long sizeInGB = vols.get(0).getSize().longValue()/1073741824;
+                ec2Snapshot.setVolumeSize(sizeInGB);
+            }
+
+            return ec2Snapshot;
+        } catch( Exception e ) {
+            logger.error( "EC2 CreateSnapshot - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * Deletes a snapshot
+     * 
+     * @param snapshotId
+     * @return
+     */
+    public boolean deleteSnapshot(String snapshotId) {
+        try {
+
+            CloudStackInfoResponse resp = getApi().deleteSnapshot(snapshotId);
+            if(resp != null) {
+                return resp.getSuccess();
+            }
+
+            return false;
+        } catch(Exception e) {
+            logger.error( "EC2 DeleteSnapshot - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+
+    /** REST API calls this method.
      * Modify an existing template
      * 
      * @param request
@@ -536,7 +527,7 @@ public class EC2Engine {
         try {
             images = listTemplates( request.getId(), images );
             EC2Image[] imageSet = images.getImageSet();
-            
+
             CloudStackTemplate resp = getApi().updateTemplate(request.getId(), null, request.getDescription(), null, imageSet[0].getName(), null, null);
             if (resp != null) {
                 return true;
@@ -549,21 +540,21 @@ public class EC2Engine {
     }
 
 
-	/**
-	 * Modify an existing template
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public boolean modifyImageAttribute( EC2ModifyImageAttribute request ) 
-	{
+    /**
+     * Modify an existing template
+     * 
+     * @param request
+     * @return
+     */
+    public boolean modifyImageAttribute( EC2ModifyImageAttribute request ) 
+    {
         try {
             if(request.getAttribute().equals(ImageAttribute.launchPermission)){
-                
+
                 String accounts = "";
                 Boolean isPublic = null;
                 EC2ModifyImageAttribute.Operation operation = request.getLaunchPermOperation();
-                
+
                 List<String> accountOrGroupList = request.getLaunchPermissionAccountsList();
                 if(accountOrGroupList != null && !accountOrGroupList.isEmpty()){
                     boolean first = true;
@@ -597,25 +588,25 @@ public class EC2Engine {
             logger.error( "EC2 modifyImageAttribute - ", e);
             throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
         }
-        
+
         return false;
-	    
-	    
-	}
-	
+
+
+    }
+
     public EC2ImageAttributes describeImageAttribute(EC2DescribeImageAttribute request) {
         EC2ImageAttributes imageAtts = new EC2ImageAttributes();
-        
+
         try {
             imageAtts.setImageId(request.getImageId());
             if(request.getAttribute().equals(ImageAttribute.launchPermission)){
                 CloudStackTemplatePermission tempPerm = getApi().listTemplatePermissions(request.getImageId(), null, null);
                 if(tempPerm != null){
                     imageAtts.setDomainId(tempPerm.getDomainId());
-                    
+
                     List<String> accntList = tempPerm.getAccounts();
                     imageAtts.setAccountNamesWithLaunchPermission(accntList);
-                    
+
                     imageAtts.setIsPublic(tempPerm.getIsPublic());
                 }
             }else if(request.getAttribute().equals(ImageAttribute.description)){
@@ -631,47 +622,47 @@ public class EC2Engine {
             logger.error( "EC2 describeImageAttribute - ", e);
             throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
         }
-        
+
         return imageAtts;
     }
 
-    
 
-	/**
-	 * If given a specific list of snapshots of interest, then only values from those snapshots are returned.
-	 * 
-	 * @param interestedShots - can be null, should be a subset of all snapshots
-	 */
+
+    /**
+     * If given a specific list of snapshots of interest, then only values from those snapshots are returned.
+     * 
+     * @param interestedShots - can be null, should be a subset of all snapshots
+     */
     private EC2DescribeSnapshotsResponse listSnapshots( String[] interestedShots, List<CloudStackKeyValue> resourceTagSet ) throws Exception {
-		EC2DescribeSnapshotsResponse snapshots = new EC2DescribeSnapshotsResponse();
+        EC2DescribeSnapshotsResponse snapshots = new EC2DescribeSnapshotsResponse();
 
-		List<CloudStackSnapshot> cloudSnaps;
-		if (interestedShots == null || interestedShots.length == 0) {
+        List<CloudStackSnapshot> cloudSnaps;
+        if (interestedShots == null || interestedShots.length == 0) {
             cloudSnaps = getApi().listSnapshots(null, null, null, null, null, null, null, null, null, resourceTagSet);
-		} else {
-			cloudSnaps = new ArrayList<CloudStackSnapshot>();
+        } else {
+            cloudSnaps = new ArrayList<CloudStackSnapshot>();
 
-			for(String id : interestedShots) {
+            for(String id : interestedShots) {
                 List<CloudStackSnapshot> tmpList = getApi().listSnapshots(null, null, id, null, null, null, null,
-                    null, null, resourceTagSet);
-				cloudSnaps.addAll(tmpList);
-			}
-		}
-
-		if (cloudSnaps == null) { 
-			return null;
-		}
-
-		for(CloudStackSnapshot cloudSnapshot : cloudSnaps) {
-			EC2Snapshot shot  = new EC2Snapshot();
-			shot.setId(cloudSnapshot.getId());
-			shot.setName(cloudSnapshot.getName());
-			shot.setVolumeId(cloudSnapshot.getVolumeId());
-			shot.setType(cloudSnapshot.getSnapshotType());
-			shot.setState(cloudSnapshot.getState());
-			shot.setCreated(cloudSnapshot.getCreated());
-			shot.setAccountName(cloudSnapshot.getAccountName());
-			shot.setDomainId(cloudSnapshot.getDomainId());
+                        null, null, resourceTagSet);
+                cloudSnaps.addAll(tmpList);
+            }
+        }
+
+        if (cloudSnaps == null) { 
+            return null;
+        }
+
+        for(CloudStackSnapshot cloudSnapshot : cloudSnaps) {
+            EC2Snapshot shot  = new EC2Snapshot();
+            shot.setId(cloudSnapshot.getId());
+            shot.setName(cloudSnapshot.getName());
+            shot.setVolumeId(cloudSnapshot.getVolumeId());
+            shot.setType(cloudSnapshot.getSnapshotType());
+            shot.setState(cloudSnapshot.getState());
+            shot.setCreated(cloudSnapshot.getCreated());
+            shot.setAccountName(cloudSnapshot.getAccountName());
+            shot.setDomainId(cloudSnapshot.getDomainId());
 
             List<CloudStackKeyValue> resourceTags = cloudSnapshot.getTags();
             for(CloudStackKeyValue resourceTag : resourceTags) {
@@ -682,663 +673,663 @@ public class EC2Engine {
                 shot.addResourceTag(param);
             }
 
-			snapshots.addSnapshot(shot);
-		}
-		return snapshots;
-	}
-
-
-	// handlers
-	/**
-	 * return password data from the instance
-	 * 
-	 * @param instanceId
-	 * @return
-	 */
-	public EC2PasswordData getPasswordData(String instanceId) {
-		try {
-			CloudStackPasswordData resp = getApi().getVMPassword(instanceId);
-			EC2PasswordData passwdData = new EC2PasswordData();
-			if (resp != null) {
-				passwdData.setInstanceId(instanceId);
-				passwdData.setEncryptedPassword(resp.getEncryptedpassword());
-			}
-			return passwdData;
-		} catch(Exception e) {
-			logger.error("EC2 GetPasswordData - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-	/**
-	 * Lists SSH KeyPairs on the systme
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeKeyPairsResponse describeKeyPairs( EC2DescribeKeyPairs request ) {
-		try {
-			EC2KeyPairFilterSet filterSet = request.getKeyFilterSet();
-			String[] keyNames = request.getKeyNames();
-			List<CloudStackKeyPair> keyPairs = getApi().listSSHKeyPairs(null, null, null);
-			List<EC2SSHKeyPair> keyPairsList = new ArrayList<EC2SSHKeyPair>();
-	
-			if (keyPairs != null) {
-				// Let's trim the list of keypairs to only the ones listed in keyNames
-			    List<CloudStackKeyPair> matchedKeyPairs = new ArrayList<CloudStackKeyPair>();
-				if (keyNames != null && keyNames.length > 0) {
-					for (CloudStackKeyPair keyPair : keyPairs) {
-						boolean matched = false;
-						for (String keyName : keyNames) {
-							if (keyPair.getName().equalsIgnoreCase(keyName)) {
-								matched = true;
-								break;
-							}
-						}
-						if (matched) {
-						    matchedKeyPairs.add(keyPair);
-						}
-					}
-	                if (matchedKeyPairs.isEmpty()) {
-	                    throw new EC2ServiceException(ServerError.InternalError, "No matching keypairs found");
-	                }
-				}else{
-				    matchedKeyPairs = keyPairs;
-				}
-	
-	
-				// this should be reworked... converting from CloudStackKeyPairResponse to EC2SSHKeyPair is dumb
-				for (CloudStackKeyPair respKeyPair: matchedKeyPairs) {
-					EC2SSHKeyPair ec2KeyPair = new EC2SSHKeyPair();
-					ec2KeyPair.setFingerprint(respKeyPair.getFingerprint());
-					ec2KeyPair.setKeyName(respKeyPair.getName());
-					ec2KeyPair.setPrivateKey(respKeyPair.getPrivatekey());
-					keyPairsList.add(ec2KeyPair);
-				}
-			}
-			return filterSet.evaluate(keyPairsList);
-		} catch(Exception e) {
-			logger.error("EC2 DescribeKeyPairs - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * Delete SSHKeyPair
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public boolean deleteKeyPair( EC2DeleteKeyPair request ) {
-		try {
-			CloudStackInfoResponse resp = getApi().deleteSSHKeyPair(request.getKeyName(), null, null);
-			if (resp == null) { 
-				throw new Exception("Ivalid CloudStack API response");
-			}
-
-			return resp.getSuccess();
-		} catch(Exception e) {
-			logger.error("EC2 DeleteKeyPair - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * Create SSHKeyPair
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2SSHKeyPair createKeyPair(EC2CreateKeyPair request) {
-		try {
-			CloudStackKeyPair resp = getApi().createSSHKeyPair(request.getKeyName(), null, null);
-			if (resp == null) {
-				throw new Exception("Ivalid CloudStack API response");
-			}
-
-			EC2SSHKeyPair response = new EC2SSHKeyPair();
-			response.setFingerprint(resp.getFingerprint());
-			response.setKeyName(resp.getName());
-			response.setPrivateKey(resp.getPrivatekey());
-
-			return response;
-		} catch (Exception e) {
-			logger.error("EC2 CreateKeyPair - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * Import an existing SSH KeyPair
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2SSHKeyPair importKeyPair( EC2ImportKeyPair request ) {
-		try {
-			CloudStackKeyPair resp = getApi().registerSSHKeyPair(request.getKeyName(), request.getPublicKeyMaterial());
-			if (resp == null) {
-				throw new Exception("Ivalid CloudStack API response");
-			}
-
-			EC2SSHKeyPair response = new EC2SSHKeyPair();
-			response.setFingerprint(resp.getFingerprint());
-			response.setKeyName(resp.getName());
-			response.setPrivateKey(resp.getPrivatekey());
-
-			return response;
-		} catch (Exception e) {
-			logger.error("EC2 ImportKeyPair - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * list ip addresses that have been allocated
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeAddressesResponse describeAddresses( EC2DescribeAddresses request ) {
-		try {
-			List<CloudStackIpAddress> addrList = getApi().listPublicIpAddresses(null, null, null, null, null, null, null, null, null);
-
-			EC2AddressFilterSet filterSet = request.getFilterSet();
-			List<EC2Address> addressList = new ArrayList<EC2Address>();
-			if (addrList != null && addrList.size() > 0) {
-				for (CloudStackIpAddress addr: addrList) {
-					// remember, if no filters are set, request.inPublicIpSet always returns true
-					if (request.inPublicIpSet(addr.getIpAddress())) {
-						EC2Address ec2Address = new EC2Address();
-						ec2Address.setIpAddress(addr.getIpAddress());
-						if (addr.getVirtualMachineId() != null) 
-							ec2Address.setAssociatedInstanceId(addr.getVirtualMachineId().toString());
-						addressList.add(ec2Address);
-					}
-				}
-			}
-
-			return filterSet.evaluate(addressList);
-		} catch(Exception e) {
-			logger.error("EC2 DescribeAddresses - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-	}
-
-	/**
-	 * release an IP Address
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public boolean releaseAddress(EC2ReleaseAddress request) {
-		try {
-			CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0);
-			CloudStackInfoResponse resp = getApi().disassociateIpAddress(cloudIp.getId());
-			if (resp != null) {
-				return resp.getSuccess();
-			}
-		} catch(Exception e) {
-			logger.error("EC2 ReleaseAddress - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
-		}
-		return false;
-	}
-
-	/**
-	 * Associate an address with an instance
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public boolean associateAddress( EC2AssociateAddress request ) {
-		try {
-			CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0);
-	        CloudStackUserVm cloudVm = getApi().listVirtualMachines(null, null, true, null, null, null, null, request.getInstanceId(), null, null, null, null, null, null, null, null, null).get(0);
-
-			CloudStackInfoResponse resp = getApi().enableStaticNat(cloudIp.getId(), cloudVm.getId());
-			if (resp != null) {
-				return resp.getSuccess();
-			}
-		} catch(Exception e) {
-			logger.error( "EC2 AssociateAddress - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-		return false;
-	}
-
-	/**
-	 * Disassociate an address from an instance
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public boolean disassociateAddress( EC2DisassociateAddress request ) {
-		try {
-			CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0);
-			CloudStackInfoResponse resp = getApi().disableStaticNat(cloudIp.getId());
-			if (resp != null) {
-				return resp.getSuccess();
-			}
-		} catch(Exception e) {
-			logger.error( "EC2 DisassociateAddress - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-		return false;
-	}
-
-	/**
-	 * Allocate an address
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2Address allocateAddress()
-	{
-		try {
-            EC2Address ec2Address = new EC2Address();
-            // this gets our networkId
-            CloudStackAccount caller = getCurrentAccount();
-            
-            CloudStackZone zone = findZone();
-            CloudStackNetwork net = findNetwork(zone);
-//			CloudStackIpAddress resp = getApi().associateIpAddress(null, null, null, "0036952d-48df-4422-9fd0-94b0885e18cb");
-            CloudStackIpAddress resp = getApi().associateIpAddress(zone.getId(), caller.getName(), caller.getDomainId(), net != null ? net.getId():null);
-			ec2Address.setAssociatedInstanceId(resp.getId());
-			
-			if (resp.getIpAddress() == null) {
-			    List<CloudStackIpAddress> addrList = getApi().listPublicIpAddresses(null, null, null, null, null, null, null, null, null);
-			    if (addrList != null && addrList.size() > 0) {
-			        for (CloudStackIpAddress addr: addrList) {
-			            if (addr.getId().equalsIgnoreCase(resp.getId())) {
-			                ec2Address.setIpAddress(addr.getIpAddress());
-			            }
-			        }
-			    }
-			} else {
-			    ec2Address.setIpAddress(resp.getIpAddress());
-			}
-
-			return ec2Address;
-		} catch(Exception e) { 
-			logger.error( "EC2 AllocateAddress - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * List of templates available.  We only support the imageSet version of this call or when no search parameters are passed
-	 * which results in asking for all templates.
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeImagesResponse describeImages(EC2DescribeImages request) 
-	{
-		EC2DescribeImagesResponse images = new EC2DescribeImagesResponse();
-
-		try {
-			String[] templateIds = request.getImageSet();
-
-			if ( 0 == templateIds.length ) {
-				return listTemplates(null, images);
-			}
-			for (String s : templateIds) {
-				images = listTemplates(s, images);
-			}
-			return images;
-
-		} catch( Exception e ) {
-			logger.error( "EC2 DescribeImages - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * Create a template
-	 * Amazon API just gives us the instanceId to create the template from.
-	 * But our createTemplate function requires the volumeId and osTypeId.  
-	 * So to get that we must make the following sequence of cloud API calls:
-	 * 1) listVolumes&virtualMachineId=   -- gets the volumeId
-	 * 2) listVirtualMachinees&id=        -- gets the templateId
-	 * 3) listTemplates&id=               -- gets the osTypeId
-	 * 
-	 * If we have to start and stop the VM in question then this function is
-	 * going to take a long time to complete.
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2CreateImageResponse createImage(EC2CreateImage request) 
-	{
-		EC2CreateImageResponse response = null;
-		boolean needsRestart = false;
-		String volumeId      = null;
-
-		try {
-			// [A] Creating a template from a VM volume should be from the ROOT volume
-			//     Also for this to work the VM must be in a Stopped state so we 'reboot' it if its not
-			EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
-			volumes = listVolumes( null, request.getInstanceId(), volumes, null );
-			EC2Volume[] volSet = volumes.getVolumeSet();
-			for (EC2Volume vol : volSet) {
-				if (vol.getType().equalsIgnoreCase( "ROOT" )) {
-					String vmState = vol.getVMState();
-					if (vmState.equalsIgnoreCase( "running" ) || vmState.equalsIgnoreCase( "starting" )) {
-						needsRestart = true;
-						if (!stopVirtualMachine( request.getInstanceId() ))
-							throw new EC2ServiceException(ClientError.IncorrectState, "CreateImage - instance must be in a stopped state");
-					}           		 
-					volumeId = vol.getId();
-					break;
-				}
-			}
-
-			// [B] The parameters must be in sorted order for proper signature generation
-			EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse();
-			instances = lookupInstances( request.getInstanceId(), instances, null );
-			EC2Instance[] instanceSet = instances.getInstanceSet();
-			String templateId = instanceSet[0].getTemplateId();
-
-			EC2DescribeImagesResponse images = new EC2DescribeImagesResponse();
-			images = listTemplates( templateId, images );
-			EC2Image[] imageSet = images.getImageSet();
-			String osTypeId = imageSet[0].getOsTypeId();
-			
-			CloudStackTemplate resp = getApi().createTemplate((request.getDescription() == null ? "" : request.getDescription()), request.getName(), 
-					osTypeId, null, null, null, null, null, null, volumeId);
-			if (resp == null || resp.getId() == null) {
-				throw new EC2ServiceException(ServerError.InternalError, "An upexpected error occurred.");
-			}
-			
-			//if template was created succesfully, create the new image response
-			response = new EC2CreateImageResponse();
-			response.setId(resp.getId());
-
-			// [C] If we stopped the virtual machine now we need to restart it
-			if (needsRestart) {
-				if (!startVirtualMachine( request.getInstanceId() )) 
-					throw new EC2ServiceException(ServerError.InternalError, 
-							"CreateImage - restarting instance " + request.getInstanceId() + " failed");
-			}
-			return response;
-
-		} catch( Exception e ) {
-			logger.error( "EC2 CreateImage - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * Register a template
-	 *  
-	 * @param request
-	 * @return
-	 */
-	public EC2CreateImageResponse registerImage(EC2RegisterImage request) 
-	{
-		try {
-		    CloudStackAccount caller = getCurrentAccount();
-            if (null == request.getName())
-                throw new EC2ServiceException(ClientError.Unsupported, "Missing parameter - name");
-
-			List<CloudStackTemplate> templates = getApi().registerTemplate((request.getDescription() == null ? request.getName() : request.getDescription()), 
-					request.getFormat(), request.getHypervisor(), request.getName(), toOSTypeId(request.getOsTypeName()), request.getLocation(), 
-					toZoneId(request.getZoneName(), null), null, null, null, null, null, null, null, null, null);
-			if (templates != null) {
-			    // technically we will only ever register a single template...
-			    for (CloudStackTemplate template : templates) {
-        			if (template != null && template.getId() != null) {
-        				EC2CreateImageResponse image = new EC2CreateImageResponse();
-        				image.setId(template.getId().toString());
-        				return image;
-        			}
-			    }
-			}
-			return null;
-		} catch( Exception e ) {
-			logger.error( "EC2 RegisterImage - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * Deregister a template(image)
-	 * Our implementation is different from Amazon in that we do delete the template
-	 * when we deregister it.   The cloud API has not deregister call.
-	 * 
-	 * @param image
-	 * @return
-	 */
-	public boolean deregisterImage( EC2Image image ) 
-	{
-		try {
-			CloudStackInfoResponse resp = getApi().deleteTemplate(image.getId(), null);
-			return resp.getSuccess();
-		} catch( Exception e ) {
-			logger.error( "EC2 DeregisterImage - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * list instances
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeInstancesResponse describeInstances(EC2DescribeInstances request ) {
-		try {
-            EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet();
-            return listVirtualMachines( request.getInstancesSet(), request.getFilterSet(),
-                    getResourceTags(tagKeyValueSet));
-		} catch( Exception e ) {
-			logger.error( "EC2 DescribeInstances - " ,e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * list Zones
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeAvailabilityZonesResponse handleRequest(EC2DescribeAvailabilityZones request) {	
-		try {
-		    EC2DescribeAvailabilityZonesResponse availableZones = listZones(request.getZoneSet(), null);
-            EC2AvailabilityZonesFilterSet azfs = request.getFilterSet();
-            if ( null == azfs )
-                return availableZones;
-            else {
-                List<String> matchedAvailableZones = azfs.evaluate(availableZones);
-                if (matchedAvailableZones.isEmpty())
-                    return new EC2DescribeAvailabilityZonesResponse();
-                return listZones(matchedAvailableZones.toArray(new String[0]), null);
-            }
-		} catch( EC2ServiceException error ) {
-			logger.error( "EC2 DescribeAvailabilityZones - ", error);
-			throw error;
-
-		} catch( Exception e ) {
-			logger.error( "EC2 DescribeAvailabilityZones - " ,e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * list volumes
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2DescribeVolumesResponse handleRequest( EC2DescribeVolumes request ) {
-		EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
-		EC2VolumeFilterSet vfs = request.getFilterSet();
-        EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet();
-		try {   
-			String[] volumeIds = request.getVolumeSet();
-			if ( 0 == volumeIds.length ){
-                volumes = listVolumes( null, null, volumes, getResourceTags(tagKeyValueSet) );
-			} else {     
-				for (String s : volumeIds) 
-                    volumes = listVolumes(s, null, volumes, getResourceTags(tagKeyValueSet) );
-			}
-
-			if ( null == vfs )
-				return volumes;
-			else return vfs.evaluate( volumes );     
-		}  catch( Exception e ) {
-			logger.error( "EC2 DescribeVolumes - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}
-	}
-
-	/**
-	 * Attach a volume to an instance
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2Volume attachVolume( EC2Volume request ) {
-		try {   
-			request.setDeviceId(mapDeviceToCloudDeviceId(request.getDevice()));
-			EC2Volume resp = new EC2Volume();
-			
-			CloudStackVolume vol = getApi().attachVolume(request.getId(), request.getInstanceId(), request.getDeviceId());
-			if(vol != null) {
-				resp.setAttached(vol.getAttached());
-				resp.setCreated(vol.getCreated());
-				resp.setDevice(request.getDevice());
-				resp.setDeviceId(vol.getDeviceId());
-				resp.setHypervisor(vol.getHypervisor());
-				resp.setId(vol.getId());
-				resp.setInstanceId(vol.getVirtualMachineId());
-				resp.setSize(vol.getSize());
-				resp.setSnapshotId(vol.getSnapshotId());
-				resp.setState(vol.getState());
-				resp.setType(vol.getVolumeType());
-				resp.setVMState(vol.getVirtualMachineState());
-				resp.setZoneName(vol.getZoneName());
-				return resp;
-			}
-			throw new EC2ServiceException( ServerError.InternalError, "An unexpected error occurred." );
-		} catch( Exception e ) {
-			logger.error( "EC2 AttachVolume 2 - ", e);
-			throw new EC2ServiceException( ServerError.InternalError, e.getMessage() != null ? e.getMessage() : e.toString());
-		}   	    
-	}
-
-	/**
-	 * Detach a volume from an instance
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2Volume detachVolume(EC2Volume request) {
-		try {
-			CloudStackVolume vol = getApi().detachVolume(null, request.getId(), null);
-			EC2Volume resp = new EC2Volume();
-						
-			if(vol != null) {
-				resp.setAttached(vol.getAttached());
-				resp.setCreated(vol.getCreated());
-				resp.setDevice(request.getDevice());
-				resp.setDeviceId(vol.getDeviceId());
-				resp.setHypervisor(vol.getHypervisor());
-				resp.setId(vol.getId());
-				resp.setInstanceId(vol.getVirtualMachineId());
-				resp.setSize(vol.getSize());
-				resp.setSnapshotId(vol.getSnapshotId());
-				resp.setState(vol.getState());
-				resp.setType(vol.getVolumeType());
-				resp.setVMState(vol.getVirtualMachineState());
-				resp.setZoneName(vol.getZoneName());
-				return resp;
-			}
-
-			throw new EC2ServiceException( ServerError.InternalError, "An unexpected error occurred." );
-		} catch( Exception e ) {
-			logger.error( "EC2 DetachVolume - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}   	    
-	}
-
-	/**
-	 * Create a volume
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2Volume createVolume( EC2CreateVolume request ) {
-		try {
-		    
-		    CloudStackAccount caller = getCurrentAccount();
-			// -> put either snapshotid or diskofferingid on the request
-			String snapshotId = request.getSnapshotId();
-			Long size = request.getSize();
-			String diskOfferingId = null;
-
-			if (snapshotId == null) {
-				List<CloudStackDiskOffering> disks = getApi().listDiskOfferings(null, null, null, null);
-				for (CloudStackDiskOffering offer : disks) {
-					if (offer.isCustomized()) {
-						diskOfferingId = offer.getId();
-					}
-				}
-				if (diskOfferingId == null) throw new EC2ServiceException(ServerError.InternalError, "No Customize Disk Offering Found");
-			}
+            snapshots.addSnapshot(shot);
+        }
+        return snapshots;
+    }
 
-//			// -> no volume name is given in the Amazon request but is required in the cloud API
-			CloudStackVolume vol = getApi().createVolume(UUID.randomUUID().toString(), null, diskOfferingId, null, size, snapshotId, toZoneId(request.getZoneName(), null));
-			if (vol != null) {
-				EC2Volume resp = new EC2Volume();
-				resp.setAttached(vol.getAttached());
-				resp.setCreated(vol.getCreated());
-//				resp.setDevice();
-				resp.setDeviceId(vol.getDeviceId());
-				resp.setHypervisor(vol.getHypervisor());
-				resp.setId(vol.getId());
-				resp.setInstanceId(vol.getVirtualMachineId());
-				resp.setSize(vol.getSize());
-				resp.setSnapshotId(vol.getSnapshotId());
-				resp.setState(vol.getState());
-				resp.setType(vol.getVolumeType());
-				resp.setVMState(vol.getVirtualMachineState());
-				resp.setZoneName(vol.getZoneName());
-				return resp;
-			}
-			return null;
-		} catch( Exception e ) {
-			logger.error( "EC2 CreateVolume - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}   	    
-	}
-
-	/**
-	 * Delete a volume
-	 * 
-	 * @param request
-	 * @return
-	 */
-	public EC2Volume deleteVolume( EC2Volume request ) {
-		try {
-			CloudStackInfoResponse resp = getApi().deleteVolume(request.getId());
-			if(resp != null) {
-				request.setState("deleted");
-				return request;
-			}
-
-			throw new EC2ServiceException(ServerError.InternalError, "An unexpected error occurred.");
-		} catch( Exception e ) {
-			logger.error( "EC2 DeleteVolume 2 - ", e);
-			throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
-		}   	    
-	}
 
+    // handlers
     /**
-     * Create/Delete tags
-     *
-     * @param request
+     * return password data from the instance
+     * 
+     * @param instanceId
+     * @return
+     */
+    public EC2PasswordData getPasswordData(String instanceId) {
+        try {
+            CloudStackPasswordData resp = getApi().getVMPassword(instanceId);
+            EC2PasswordData passwdData = new EC2PasswordData();
+            if (resp != null) {
+                passwdData.setInstanceId(instanceId);
+                passwdData.setEncryptedPassword(resp.getEncryptedpassword());
+            }
+            return passwdData;
+        } catch(Exception e) {
+            logger.error("EC2 GetPasswordData - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+    /**
+     * Lists SSH KeyPairs on the systme
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeKeyPairsResponse describeKeyPairs( EC2DescribeKeyPairs request ) {
+        try {
+            EC2KeyPairFilterSet filterSet = request.getKeyFilterSet();
+            String[] keyNames = request.getKeyNames();
+            List<CloudStackKeyPair> keyPairs = getApi().listSSHKeyPairs(null, null, null);
+            List<EC2SSHKeyPair> keyPairsList = new ArrayList<EC2SSHKeyPair>();
+
+            if (keyPairs != null) {
+                // Let's trim the list of keypairs to only the ones listed in keyNames
+                List<CloudStackKeyPair> matchedKeyPairs = new ArrayList<CloudStackKeyPair>();
+                if (keyNames != null && keyNames.length > 0) {
+                    for (CloudStackKeyPair keyPair : keyPairs) {
+                        boolean matched = false;
+                        for (String keyName : keyNames) {
+                            if (keyPair.getName().equalsIgnoreCase(keyName)) {
+                                matched = true;
+                                break;
+                            }
+                        }
+                        if (matched) {
+                            matchedKeyPairs.add(keyPair);
+                        }
+                    }
+                    if (matchedKeyPairs.isEmpty()) {
+                        throw new EC2ServiceException(ServerError.InternalError, "No matching keypairs found");
+                    }
+                }else{
+                    matchedKeyPairs = keyPairs;
+                }
+
+
+                // this should be reworked... converting from CloudStackKeyPairResponse to EC2SSHKeyPair is dumb
+                for (CloudStackKeyPair respKeyPair: matchedKeyPairs) {
+                    EC2SSHKeyPair ec2KeyPair = new EC2SSHKeyPair();
+                    ec2KeyPair.setFingerprint(respKeyPair.getFingerprint());
+                    ec2KeyPair.setKeyName(respKeyPair.getName());
+                    ec2KeyPair.setPrivateKey(respKeyPair.getPrivatekey());
+                    keyPairsList.add(ec2KeyPair);
+                }
+            }
+            return filterSet.evaluate(keyPairsList);
+        } catch(Exception e) {
+            logger.error("EC2 DescribeKeyPairs - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * Delete SSHKeyPair
+     * 
+     * @param request
+     * @return
+     */
+    public boolean deleteKeyPair( EC2DeleteKeyPair request ) {
+        try {
+            CloudStackInfoResponse resp = getApi().deleteSSHKeyPair(request.getKeyName(), null, null);
+            if (resp == null) { 
+                throw new Exception("Ivalid CloudStack API response");
+            }
+
+            return resp.getSuccess();
+        } catch(Exception e) {
+            logger.error("EC2 DeleteKeyPair - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * Create SSHKeyPair
+     * 
+     * @param request
+     * @return
+     */
+    public EC2SSHKeyPair createKeyPair(EC2CreateKeyPair request) {
+        try {
+            CloudStackKeyPair resp = getApi().createSSHKeyPair(request.getKeyName(), null, null);
+            if (resp == null) {
+                throw new Exception("Ivalid CloudStack API response");
+            }
+
+            EC2SSHKeyPair response = new EC2SSHKeyPair();
+            response.setFingerprint(resp.getFingerprint());
+            response.setKeyName(resp.getName());
+            response.setPrivateKey(resp.getPrivatekey());
+
+            return response;
+        } catch (Exception e) {
+            logger.error("EC2 CreateKeyPair - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * Import an existing SSH KeyPair
+     * 
+     * @param request
+     * @return
+     */
+    public EC2SSHKeyPair importKeyPair( EC2ImportKeyPair request ) {
+        try {
+            CloudStackKeyPair resp = getApi().registerSSHKeyPair(request.getKeyName(), request.getPublicKeyMaterial());
+            if (resp == null) {
+                throw new Exception("Ivalid CloudStack API response");
+            }
+
+            EC2SSHKeyPair response = new EC2SSHKeyPair();
+            response.setFingerprint(resp.getFingerprint());
+            response.setKeyName(resp.getName());
+            response.setPrivateKey(resp.getPrivatekey());
+
+            return response;
+        } catch (Exception e) {
+            logger.error("EC2 ImportKeyPair - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * list ip addresses that have been allocated
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeAddressesResponse describeAddresses( EC2DescribeAddresses request ) {
+        try {
+            List<CloudStackIpAddress> addrList = getApi().listPublicIpAddresses(null, null, null, null, null, null, null, null, null);
+
+            EC2AddressFilterSet filterSet = request.getFilterSet();
+            List<EC2Address> addressList = new ArrayList<EC2Address>();
+            if (addrList != null && addrList.size() > 0) {
+                for (CloudStackIpAddress addr: addrList) {
+                    // remember, if no filters are set, request.inPublicIpSet always returns true
+                    if (request.inPublicIpSet(addr.getIpAddress())) {
+                        EC2Address ec2Address = new EC2Address();
+                        ec2Address.setIpAddress(addr.getIpAddress());
+                        if (addr.getVirtualMachineId() != null) 
+                            ec2Address.setAssociatedInstanceId(addr.getVirtualMachineId().toString());
+                        addressList.add(ec2Address);
+                    }
+                }
+            }
+
+            return filterSet.evaluate(addressList);
+        } catch(Exception e) {
+            logger.error("EC2 DescribeAddresses - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
+    /**
+     * release an IP Address
+     * 
+     * @param request
+     * @return
+     */
+    public boolean releaseAddress(EC2ReleaseAddress request) {
+        try {
+            CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0);
+            CloudStackInfoResponse resp = getApi().disassociateIpAddress(cloudIp.getId());
+            if (resp != null) {
+                return resp.getSuccess();
+            }
+        } catch(Exception e) {
+            logger.error("EC2 ReleaseAddress - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * Associate an address with an instance
+     * 
+     * @param request
+     * @return
+     */
+    public boolean associateAddress( EC2AssociateAddress request ) {
+        try {
+            CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0);
+            CloudStackUserVm cloudVm = getApi().listVirtualMachines(null, null, true, null, null, null, null, request.getInstanceId(), null, null, null, null, null, null, null, null, null).get(0);
+
+            CloudStackInfoResponse resp = getApi().enableStaticNat(cloudIp.getId(), cloudVm.getId());
+            if (resp != null) {
+                return resp.getSuccess();
+            }
+        } catch(Exception e) {
+            logger.error( "EC2 AssociateAddress - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+        return false;
+    }
+
+    /**
+     * Disassociate an address from an instance
+     * 
+     * @param request
+     * @return
+     */
+    public boolean disassociateAddress( EC2DisassociateAddress request ) {
+        try {
+            CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0);
+            CloudStackInfoResponse resp = getApi().disableStaticNat(cloudIp.getId());
+            if (resp != null) {
+                return resp.getSuccess();
+            }
+        } catch(Exception e) {
+            logger.error( "EC2 DisassociateAddress - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+        return false;
+    }
+
+    /**
+     * Allocate an address
+     * 
+     * @param request
+     * @return
+     */
+    public EC2Address allocateAddress()
+    {
+        try {
+            EC2Address ec2Address = new EC2Address();
+            // this gets our networkId
+            CloudStackAccount caller = getCurrentAccount();
+
+            CloudStackZone zone = findZone();
+            CloudStackNetwork net = findNetwork(zone);
+//			CloudStackIpAddress resp = getApi().associateIpAddress(null, null, null, "0036952d-48df-4422-9fd0-94b0885e18cb");
+            CloudStackIpAddress resp = getApi().associateIpAddress(zone.getId(), caller.getName(), caller.getDomainId(), net != null ? net.getId():null);
+            ec2Address.setAssociatedInstanceId(resp.getId());
+
+            if (resp.getIpAddress() == null) {
+                List<CloudStackIpAddress> addrList = getApi().listPublicIpAddresses(null, null, null, null, null, null, null, null, null);
+                if (addrList != null && addrList.size() > 0) {
+                    for (CloudStackIpAddress addr: addrList) {
+                        if (addr.getId().equalsIgnoreCase(resp.getId())) {
+                            ec2Address.setIpAddress(addr.getIpAddress());
+                        }
+                    }
+                }
+            } else {
+                ec2Address.setIpAddress(resp.getIpAddress());
+            }
+
+            return ec2Address;
+        } catch(Exception e) { 
+            logger.error( "EC2 AllocateAddress - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * List of templates available.  We only support the imageSet version of this call or when no search parameters are passed
+     * which results in asking for all templates.
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeImagesResponse describeImages(EC2DescribeImages request) 
+    {
+        EC2DescribeImagesResponse images = new EC2DescribeImagesResponse();
+
+        try {
+            String[] templateIds = request.getImageSet();
+
+            if ( 0 == templateIds.length ) {
+                return listTemplates(null, images);
+            }
+            for (String s : templateIds) {
+                images = listTemplates(s, images);
+            }
+            return images;
+
+        } catch( Exception e ) {
+            logger.error( "EC2 DescribeImages - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * Create a template
+     * Amazon API just gives us the instanceId to create the template from.
+     * But our createTemplate function requires the volumeId and osTypeId.  
+     * So to get that we must make the following sequence of cloud API calls:
+     * 1) listVolumes&virtualMachineId=   -- gets the volumeId
+     * 2) listVirtualMachinees&id=        -- gets the templateId
+     * 3) listTemplates&id=               -- gets the osTypeId
+     * 
+     * If we have to start and stop the VM in question then this function is
+     * going to take a long time to complete.
+     * 
+     * @param request
+     * @return
+     */
+    public EC2CreateImageResponse createImage(EC2CreateImage request) 
+    {
+        EC2CreateImageResponse response = null;
+        boolean needsRestart = false;
+        String volumeId      = null;
+
+        try {
+            // [A] Creating a template from a VM volume should be from the ROOT volume
+            //     Also for this to work the VM must be in a Stopped state so we 'reboot' it if its not
+            EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
+            volumes = listVolumes( null, request.getInstanceId(), volumes, null );
+            EC2Volume[] volSet = volumes.getVolumeSet();
+            for (EC2Volume vol : volSet) {
+                if (vol.getType().equalsIgnoreCase( "ROOT" )) {
+                    String vmState = vol.getVMState();
+                    if (vmState.equalsIgnoreCase( "running" ) || vmState.equalsIgnoreCase( "starting" )) {
+                        needsRestart = true;
+                        if (!stopVirtualMachine( request.getInstanceId() ))
+                            throw new EC2ServiceException(ClientError.IncorrectState, "CreateImage - instance must be in a stopped state");
+                    }           		 
+                    volumeId = vol.getId();
+                    break;
+                }
+            }
+
+            // [B] The parameters must be in sorted order for proper signature generation
+            EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse();
+            instances = lookupInstances( request.getInstanceId(), instances, null );
+            EC2Instance[] instanceSet = instances.getInstanceSet();
+            String templateId = instanceSet[0].getTemplateId();
+
+            EC2DescribeImagesResponse images = new EC2DescribeImagesResponse();
+            images = listTemplates( templateId, images );
+            EC2Image[] imageSet = images.getImageSet();
+            String osTypeId = imageSet[0].getOsTypeId();
+
+            CloudStackTemplate resp = getApi().createTemplate((request.getDescription() == null ? "" : request.getDescription()), request.getName(), 
+                    osTypeId, null, null, null, null, null, null, volumeId);
+            if (resp == null || resp.getId() == null) {
+                throw new EC2ServiceException(ServerError.InternalError, "An upexpected error occurred.");
+            }
+
+            //if template was created succesfully, create the new image response
+            response = new EC2CreateImageResponse();
+            response.setId(resp.getId());
+
+            // [C] If we stopped the virtual machine now we need to restart it
+            if (needsRestart) {
+                if (!startVirtualMachine( request.getInstanceId() )) 
+                    throw new EC2ServiceException(ServerError.InternalError, 
+                            "CreateImage - restarting instance " + request.getInstanceId() + " failed");
+            }
+            return response;
+
+        } catch( Exception e ) {
+            logger.error( "EC2 CreateImage - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * Register a template
+     *  
+     * @param request
+     * @return
+     */
+    public EC2CreateImageResponse registerImage(EC2RegisterImage request) 
+    {
+        try {
+            CloudStackAccount caller = getCurrentAccount();
+            if (null == request.getName())
+                throw new EC2ServiceException(ClientError.Unsupported, "Missing parameter - name");
+
+            List<CloudStackTemplate> templates = getApi().registerTemplate((request.getDescription() == null ? request.getName() : request.getDescription()), 
+                    request.getFormat(), request.getHypervisor(), request.getName(), toOSTypeId(request.getOsTypeName()), request.getLocation(), 
+                    toZoneId(request.getZoneName(), null), null, null, null, null, null, null, null, null, null);
+            if (templates != null) {
+                // technically we will only ever register a single template...
+                for (CloudStackTemplate template : templates) {
+                    if (template != null && template.getId() != null) {
+                        EC2CreateImageResponse image = new EC2CreateImageResponse();
+                        image.setId(template.getId().toString());
+                        return image;
+                    }
+                }
+            }
+            return null;
+        } catch( Exception e ) {
+            logger.error( "EC2 RegisterImage - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * Deregister a template(image)
+     * Our implementation is different from Amazon in that we do delete the template
+     * when we deregister it.   The cloud API has not deregister call.
+     * 
+     * @param image
+     * @return
+     */
+    public boolean deregisterImage( EC2Image image ) 
+    {
+        try {
+            CloudStackInfoResponse resp = getApi().deleteTemplate(image.getId(), null);
+            return resp.getSuccess();
+        } catch( Exception e ) {
+            logger.error( "EC2 DeregisterImage - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * list instances
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeInstancesResponse describeInstances(EC2DescribeInstances request ) {
+        try {
+            EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet();
+            return listVirtualMachines( request.getInstancesSet(), request.getFilterSet(),
+                    getResourceTags(tagKeyValueSet));
+        } catch( Exception e ) {
+            logger.error( "EC2 DescribeInstances - " ,e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * list Zones
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeAvailabilityZonesResponse handleRequest(EC2DescribeAvailabilityZones request) {	
+        try {
+            EC2DescribeAvailabilityZonesResponse availableZones = listZones(request.getZoneSet(), null);
+            EC2AvailabilityZonesFilterSet azfs = request.getFilterSet();
+            if ( null == azfs )
+                return availableZones;
+            else {
+                List<String> matchedAvailableZones = azfs.evaluate(availableZones);
+                if (matchedAvailableZones.isEmpty())
+                    return new EC2DescribeAvailabilityZonesResponse();
+                return listZones(matchedAvailableZones.toArray(new String[0]), null);
+            }
+        } catch( EC2ServiceException error ) {
+            logger.error( "EC2 DescribeAvailabilityZones - ", error);
+            throw error;
+
+        } catch( Exception e ) {
+            logger.error( "EC2 DescribeAvailabilityZones - " ,e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * list volumes
+     * 
+     * @param request
+     * @return
+     */
+    public EC2DescribeVolumesResponse handleRequest( EC2DescribeVolumes request ) {
+        EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
+        EC2VolumeFilterSet vfs = request.getFilterSet();
+        EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet();
+        try {   
+            String[] volumeIds = request.getVolumeSet();
+            if ( 0 == volumeIds.length ){
+                volumes = listVolumes( null, null, volumes, getResourceTags(tagKeyValueSet) );
+            } else {     
+                for (String s : volumeIds) 
+                    volumes = listVolumes(s, null, volumes, getResourceTags(tagKeyValueSet) );
+            }
+
+            if ( null == vfs )
+                return volumes;
+            else return vfs.evaluate( volumes );     
+        }  catch( Exception e ) {
+            logger.error( "EC2 DescribeVolumes - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * Attach a volume to an instance
+     * 
+     * @param request
+     * @return
+     */
+    public EC2Volume attachVolume( EC2Volume request ) {
+        try {   
+            request.setDeviceId(mapDeviceToCloudDeviceId(request.getDevice()));
+            EC2Volume resp = new EC2Volume();
+
+            CloudStackVolume vol = getApi().attachVolume(request.getId(), request.getInstanceId(), request.getDeviceId());
+            if(vol != null) {
+                resp.setAttached(vol.getAttached());
+                resp.setCreated(vol.getCreated());
+                resp.setDevice(request.getDevice());
+                resp.setDeviceId(vol.getDeviceId());
+                resp.setHypervisor(vol.getHypervisor());
+                resp.setId(vol.getId());
+                resp.setInstanceId(vol.getVirtualMachineId());
+                resp.setSize(vol.getSize());
+                resp.setSnapshotId(vol.getSnapshotId());
+                resp.setState(vol.getState());
+                resp.setType(vol.getVolumeType());
+                resp.setVMState(vol.getVirtualMachineState());
+                resp.setZoneName(vol.getZoneName());
+                return resp;
+            }
+            throw new EC2ServiceException( ServerError.InternalError, "An unexpected error occurred." );
+        } catch( Exception e ) {
+            logger.error( "EC2 AttachVolume 2 - ", e);
+            throw new EC2ServiceException( ServerError.InternalError, e.getMessage() != null ? e.getMessage() : e.toString());
+        }   	    
+    }
+
+    /**
+     * Detach a volume from an instance
+     * 
+     * @param request
+     * @return
+     */
+    public EC2Volume detachVolume(EC2Volume request) {
+        try {
+            CloudStackVolume vol = getApi().detachVolume(null, request.getId(), null);
+            EC2Volume resp = new EC2Volume();
+
+            if(vol != null) {
+                resp.setAttached(vol.getAttached());
+                resp.setCreated(vol.getCreated());
+                resp.setDevice(request.getDevice());
+                resp.setDeviceId(vol.getDeviceId());
+                resp.setHypervisor(vol.getHypervisor());
+                resp.setId(vol.getId());
+                resp.setInstanceId(vol.getVirtualMachineId());
+                resp.setSize(vol.getSize());
+                resp.setSnapshotId(vol.getSnapshotId());
+                resp.setState(vol.getState());
+                resp.setType(vol.getVolumeType());
+                resp.setVMState(vol.getVirtualMachineState());
+                resp.setZoneName(vol.getZoneName());
+                return resp;
+            }
+
+            throw new EC2ServiceException( ServerError.InternalError, "An unexpected error occurred." );
+        } catch( Exception e ) {
+            logger.error( "EC2 DetachVolume - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
+        }   	    
+    }
+
+    /**
+     * Create a volume
+     * 
+     * @param request
+     * @return
+     */
+    public EC2Volume createVolume( EC2CreateVolume request ) {
+        try {
+
+            CloudStackAccount caller = getCurrentAccount();
+            // -> put either snapshotid or diskofferingid on the request
+            String snapshotId = request.getSnapshotId();
+            Long size = request.getSize();
+            String diskOfferingId = null;
+
+            if (snapshotId == null) {
+                List<CloudStackDiskOffering> disks = getApi().listDiskOfferings(null, null, null, null);
+                for (CloudStackDiskOffering offer : disks) {
+                    if (offer.isCustomized()) {
+                        diskOfferingId = offer.ge

<TRUNCATED>