com.cloud.bridge.service.jclouds.JCloudsEC2Engine.java Source code

Java tutorial

Introduction

Here is the source code for com.cloud.bridge.service.jclouds.JCloudsEC2Engine.java

Source

// 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.jclouds;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jclouds.Constants;
import org.jclouds.ContextBuilder;
import org.jclouds.enterprise.config.EnterpriseConfigurationModule;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorContext;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType;
import org.jclouds.vcloud.director.v1_5.admin.VCloudDirectorAdminApi;
import org.jclouds.vcloud.director.v1_5.domain.Link;
import org.jclouds.vcloud.director.v1_5.domain.Reference;
import org.jclouds.vcloud.director.v1_5.domain.VAppTemplate;
import org.jclouds.vcloud.director.v1_5.domain.network.FirewallRule;
import org.jclouds.vcloud.director.v1_5.domain.network.FirewallService;
import org.jclouds.vcloud.director.v1_5.domain.org.Org;
import org.jclouds.vcloud.director.v1_5.predicates.LinkPredicates;
import org.jclouds.vcloud.director.v1_5.predicates.ReferencePredicates;
import org.jclouds.vcloud.director.v1_5.user.VCloudDirectorApi;

import com.cloud.bridge.service.EC2Engine;
import com.cloud.bridge.service.core.ec2.EC2Address;
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.EC2CreateImageResponse;
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.EC2DescribeAddressesResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZones;
import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZonesResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeImageAttribute;
import com.cloud.bridge.service.core.ec2.EC2DescribeImages;
import com.cloud.bridge.service.core.ec2.EC2DescribeImagesResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeInstances;
import com.cloud.bridge.service.core.ec2.EC2DescribeInstancesResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairs;
import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairsResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeRegions;
import com.cloud.bridge.service.core.ec2.EC2DescribeRegionsResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroups;
import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroupsResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshots;
import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshotsResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeTags;
import com.cloud.bridge.service.core.ec2.EC2DescribeTagsResponse;
import com.cloud.bridge.service.core.ec2.EC2DescribeVolumes;
import com.cloud.bridge.service.core.ec2.EC2DescribeVolumesResponse;
import com.cloud.bridge.service.core.ec2.EC2DisassociateAddress;
import com.cloud.bridge.service.core.ec2.EC2GroupFilterSet;
import com.cloud.bridge.service.core.ec2.EC2Image;
import com.cloud.bridge.service.core.ec2.EC2ImageAttributes;
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.EC2ModifyImageAttribute;
import com.cloud.bridge.service.core.ec2.EC2PasswordData;
import com.cloud.bridge.service.core.ec2.EC2RebootInstances;
import com.cloud.bridge.service.core.ec2.EC2RegionsFilterSet;
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.EC2RunInstancesResponse;
import com.cloud.bridge.service.core.ec2.EC2SSHKeyPair;
import com.cloud.bridge.service.core.ec2.EC2SecurityGroup;
import com.cloud.bridge.service.core.ec2.EC2Snapshot;
import com.cloud.bridge.service.core.ec2.EC2SnapshotFilterSet;
import com.cloud.bridge.service.core.ec2.EC2StartInstances;
import com.cloud.bridge.service.core.ec2.EC2StartInstancesResponse;
import com.cloud.bridge.service.core.ec2.EC2StopInstances;
import com.cloud.bridge.service.core.ec2.EC2StopInstancesResponse;
import com.cloud.bridge.service.core.ec2.EC2TagKeyValue;
import com.cloud.bridge.service.core.ec2.EC2Tags;
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.EC2ServiceException.ServerError;
import com.cloud.bridge.util.ConfigurationHelper;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.inject.Module;

/**
 * EC2Engine processes the ec2 commands and calls their cloudstack analogs
 *
 */
public class JCloudsEC2Engine implements EC2Engine {
    protected final static Logger logger = Logger.getLogger(JCloudsEC2Engine.class);
    private String endpoint = null;
    private String useratorg = null;
    private String password = null;

    private VCloudDirectorContext context;
    private VCloudDirectorApi vcloudApi;
    private VCloudDirectorAdminApi vcloudAdminApi;

    Properties ec2properties = null;

    public JCloudsEC2Engine() {
        loadConfigValues();
    }

    /**
     * Which management server to we talk to?
     * Load a mapping form Amazon values for 'instanceType' to cloud defined
     * diskOfferingId and serviceOfferingId.
     *
     * @throws java.io.IOException
     */
    private void loadConfigValues() {
        ConfigurationHelper.preSetConfigPath(System.getProperty("user.home", "/etc") + "/.cinderella");
        File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
        ec2properties = new Properties();

        if (null != propertiesFile) {
            logger.info("Use EC2 properties file: " + propertiesFile.getAbsolutePath());
            try {
                ec2properties.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);
            }
            endpoint = ec2properties.getProperty("endpoint");
            useratorg = ec2properties.getProperty("useratorg");
            password = ec2properties.getProperty("password");

        } else
            logger.error("ec2-service.properties not found");
    }

    /**
     * Helper function to manage the api connection
     *
     * @return
     */
    private VCloudDirectorApi getApi() {
        if (vcloudApi == null) {
            Properties overrides = new Properties();
            overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
            overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
            ContextBuilder builder = ContextBuilder.newBuilder("vcloud-director").endpoint(endpoint)
                    .credentials(useratorg, password).modules(ImmutableSet.<Module>builder()
                            .add(new SLF4JLoggingModule()).add(new EnterpriseConfigurationModule()).build())
                    .overrides(overrides);

            context = VCloudDirectorContext.class.cast(builder.build());

            context.utils().injector().injectMembers(this);
            vcloudApi = context.getApi();
        }
        return (vcloudApi != null ? vcloudApi : null);
    }

    /**
     * Verifies account can access CloudStack
     *
     * @param accessKey
     * @param secretKey
     * @return
     * @throws com.cloud.bridge.service.exception.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 vcloudApi
          if (vcloudApi == null) {
     vcloudApi = new CloudStackApi(managementServer, cloudAPIPort, false);
          }
        
          try {
     oldApiKey = vcloudApi.getApiKey();
     oldSecretKey = vcloudApi.getSecretKey();
          } catch(Exception e) {
     // we really don't care, and expect this
          }
          try {
     vcloudApi.setApiKey(accessKey);
     vcloudApi.setSecretKey(secretKey);
     List<CloudStackAccount> accts = vcloudApi.listAccounts(null, null, null, null, null, null, null, null);
     if (oldApiKey != null && oldSecretKey != null) {
        vcloudApi.setApiKey(oldApiKey);
        vcloudApi.setSecretKey(oldSecretKey);
     }
     if (accts == null) {
        return false;
     }
     return true;
          } catch(Exception e) {
     logger.error("Validate account failed!");
     throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
          }
       }
    */

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#createSecurityGroup(java.lang.String, java.lang.String)
     */
    @Override
    public Boolean createSecurityGroup(String groupName, String groupDesc) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#deleteSecurityGroup(java.lang.String)
     */
    @Override
    public boolean deleteSecurityGroup(String groupName) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeSecurityGroups(com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroups)
     */
    @Override
    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.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#revokeSecurityGroup(com.cloud.bridge.service.core.ec2.EC2AuthorizeRevokeSecurityGroup)
     */
    @Override
    public boolean revokeSecurityGroup(EC2AuthorizeRevokeSecurityGroup request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#authorizeSecurityGroup(com.cloud.bridge.service.core.ec2.EC2AuthorizeRevokeSecurityGroup)
     */
    @Override
    public boolean authorizeSecurityGroup(EC2AuthorizeRevokeSecurityGroup request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              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();
            
        Multimap<String, String> secGroupList = new ArrayMultimap<String, String>();
        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();
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#handleRequest(com.cloud.bridge.service.core.ec2.EC2DescribeSnapshots)
     */
    @Override
    public EC2DescribeSnapshotsResponse handleRequest(EC2DescribeSnapshots request) {
        EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse();
        EC2SnapshotFilterSet sfs = request.getFilterSet();
        EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet();

        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 );
            return null;
        } 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.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#createSnapshot(java.lang.String)
     */
    @Override
    public EC2Snapshot createSnapshot(String volumeId) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#deleteSnapshot(java.lang.String)
     */
    @Override
    public boolean deleteSnapshot(String snapshotId) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#modifyImageAttribute(com.cloud.bridge.service.core.ec2.EC2Image)
     */
    @Override
    public boolean modifyImageAttribute(EC2Image request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              // TODO: This is incomplete
              EC2DescribeImagesResponse images = new EC2DescribeImagesResponse();
            
              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;
                 }
                 return false;
              } catch( Exception e ) {
                 logger.error( "EC2 ModifyImage - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#modifyImageAttribute(com.cloud.bridge.service.core.ec2.EC2ModifyImageAttribute)
     */
    @Override
    public boolean modifyImageAttribute(EC2ModifyImageAttribute request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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;
           for(String accountOrGroup : accountOrGroupList){
              if("all".equalsIgnoreCase(accountOrGroup)){
                 if(operation.equals(EC2ModifyImageAttribute.Operation.add)){
                    isPublic = true;
                 }else{
                    isPublic = false;
                 }
              }else{
                 if(!first){
                    accounts = accounts + ",";
                 }
                 accounts = accounts + accountOrGroup;
                 first = false;
              }
           }
        }
        CloudStackInfoResponse resp = getApi().updateTemplatePermissions(request.getImageId(), accounts, null, null, isPublic, operation.toString());
        return resp.getSuccess();
                 }else if(request.getAttribute().equals(ImageAttribute.description)){
        CloudStackTemplate resp = getApi().updateTemplate(request.getImageId(), null, request.getDescription(), null, null, null, null);
        if (resp != null) {
           return true;
        }
        return false;
                 }
            
              } catch (Exception e) {
                 logger.error( "EC2 modifyImageAttribute - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
              }
            
              return false;
            
            
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeImageAttribute(com.cloud.bridge.service.core.ec2.EC2DescribeImageAttribute)
     */
    @Override
    public EC2ImageAttributes describeImageAttribute(EC2DescribeImageAttribute request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              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)){
        EC2DescribeImagesResponse descriptionResp = new EC2DescribeImagesResponse();
        listTemplates(request.getImageId(), descriptionResp);
        if(descriptionResp.getImageSet() != null){
           EC2Image[] images = descriptionResp.getImageSet();
           imageAtts.setDescription(images[0].getDescription());
        }
                 }
            
              } catch (Exception e) {
                 logger.error( "EC2 describeImageAttribute - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
              }
            
              return imageAtts;
        */
    }

    // handlers
    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#getPasswordData(java.lang.String)
     */
    @Override
    public EC2PasswordData getPasswordData(String instanceId) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeKeyPairs(com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairs)
     */
    @Override
    public EC2DescribeKeyPairsResponse describeKeyPairs(EC2DescribeKeyPairs request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#deleteKeyPair(com.cloud.bridge.service.core.ec2.EC2DeleteKeyPair)
     */
    @Override
    public boolean deleteKeyPair(EC2DeleteKeyPair request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#createKeyPair(com.cloud.bridge.service.core.ec2.EC2CreateKeyPair)
     */
    @Override
    public EC2SSHKeyPair createKeyPair(EC2CreateKeyPair request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#importKeyPair(com.cloud.bridge.service.core.ec2.EC2ImportKeyPair)
     */
    @Override
    public EC2SSHKeyPair importKeyPair(EC2ImportKeyPair request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeAddresses(com.cloud.bridge.service.core.ec2.EC2DescribeAddresses)
     */
    @Override
    public EC2DescribeAddressesResponse describeAddresses(EC2DescribeAddresses request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#releaseAddress(com.cloud.bridge.service.core.ec2.EC2ReleaseAddress)
     */
    @Override
    public boolean releaseAddress(EC2ReleaseAddress request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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;
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#associateAddress(com.cloud.bridge.service.core.ec2.EC2AssociateAddress)
     */
    @Override
    public boolean associateAddress(EC2AssociateAddress request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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;
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#disassociateAddress(com.cloud.bridge.service.core.ec2.EC2DisassociateAddress)
     */
    @Override
    public boolean disassociateAddress(EC2DisassociateAddress request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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;
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#allocateAddress()
     */
    @Override
    public EC2Address allocateAddress() {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeImages(com.cloud.bridge.service.core.ec2.EC2DescribeImages)
     */
    @Override
    public EC2DescribeImagesResponse describeImages(EC2DescribeImages request) {
        EC2DescribeImagesResponse images = new EC2DescribeImagesResponse();

        try {
            String[] templateIds = request.getImageSet();
            return listTemplates(Arrays.asList(templateIds), images);
            // TODO: This should work but does not, need to fix this
            // return listTemplates(ImmutableSet.<String>copyOf(templateIds), images);
        } catch (Exception e) {
            logger.error("EC2 DescribeImages - ", e);
            throw new EC2ServiceException(ServerError.InternalError,
                    e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#createImage(com.cloud.bridge.service.core.ec2.EC2CreateImage)
     */
    @Override
    public EC2CreateImageResponse createImage(EC2CreateImage request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#registerImage(com.cloud.bridge.service.core.ec2.EC2RegisterImage)
     */
    @Override
    public EC2CreateImageResponse registerImage(EC2RegisterImage request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#deregisterImage(com.cloud.bridge.service.core.ec2.EC2Image)
     */
    @Override
    public boolean deregisterImage(EC2Image image) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeInstances(com.cloud.bridge.service.core.ec2.EC2DescribeInstances)
     */
    @Override
    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.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#handleRequest(com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZones)
     */
    @Override
    public EC2DescribeAvailabilityZonesResponse handleRequest(EC2DescribeAvailabilityZones request) {
        try {
            EC2DescribeAvailabilityZonesResponse availableZones = listZones(Arrays.asList(request.getZoneSet()));
            // TODO: This should work but does not, need to fix this
            // EC2DescribeAvailabilityZonesResponse availableZones = listZones(ImmutableSet.<String>copyOf(request.getZoneSet()));
            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);
            }
        } 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.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#handleRequest(com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZones)
     */
    @Override
    public EC2DescribeRegionsResponse handleRequest(EC2DescribeRegions request) {
        try {
            EC2DescribeRegionsResponse availableRegions = listRegions(Arrays.asList(request.getRegionSet()));
            // TODO: This should work but does not, need to fix this
            // EC2DescribeRegionsResponse availableRegions = listRegions(ImmutableSet.<String>copyOf(request.getRegionSet()));
            EC2RegionsFilterSet regionsFilterSet = request.getFilterSet();
            if (null == regionsFilterSet)
                return availableRegions;
            else {
                List<String> matchedRegions = regionsFilterSet.evaluate(availableRegions);
                if (matchedRegions.isEmpty())
                    return new EC2DescribeRegionsResponse();
                return listRegions(matchedRegions);
            }
        } catch (EC2ServiceException error) {
            logger.error("EC2 EC2DescribeRegions - ", error);
            throw error;

        } catch (Exception e) {
            logger.error("EC2 EC2DescribeRegions - ", e);
            throw new EC2ServiceException(ServerError.InternalError,
                    e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#handleRequest(com.cloud.bridge.service.core.ec2.EC2DescribeVolumes)
     */
    @Override
    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.");
        }
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#attachVolume(com.cloud.bridge.service.core.ec2.EC2Volume)
     */
    @Override
    public EC2Volume attachVolume(EC2Volume request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#detachVolume(com.cloud.bridge.service.core.ec2.EC2Volume)
     */
    @Override
    public EC2Volume detachVolume(EC2Volume request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#createVolume(com.cloud.bridge.service.core.ec2.EC2CreateVolume)
     */
    @Override
    public EC2Volume createVolume(EC2CreateVolume request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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");
                 }
            
        //         // -> 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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#deleteVolume(com.cloud.bridge.service.core.ec2.EC2Volume)
     */
    @Override
    public EC2Volume deleteVolume(EC2Volume request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              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.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#modifyTags(com.cloud.bridge.service.core.ec2.EC2Tags, java.lang.String)
     */
    @Override
    public boolean modifyTags(EC2Tags request, String operation) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              try {
                 Multimap<String, String> resourceTagList = new ArrayMultimap<String, String>();
                 for ( EC2TagKeyValue resourceTag : request.getResourceTags()){
        CloudStackKeyValue pair = new CloudStackKeyValue();
        pair.setKeyValue(resourceTag.getKey(), resourceTag.getValue());
        resourceTagList.add(pair);
                 }
                 EC2TagTypeId[] resourceTypeSet = request.getResourceTypeSet();
                 for (EC2TagTypeId resourceType : resourceTypeSet) {
        String cloudStackResourceType = mapToCloudStackResourceType(resourceType.getResourceType());
        List<String> resourceIdList = new ArrayList<String>();
        for ( String resourceId : resourceType.getResourceIds())
           resourceIdList.add(resourceId);
        CloudStackInfoResponse resp = new CloudStackInfoResponse();
        if (operation.equalsIgnoreCase("create"))
           resp = getApi().createTags(cloudStackResourceType, resourceIdList, resourceTagList);
        else if(operation.equalsIgnoreCase("delete"))
           resp = getApi().deleteTags(cloudStackResourceType, resourceIdList, resourceTagList);
        else
           throw new EC2ServiceException( ServerError.InternalError, "Unknown operation." );
        if (resp.getSuccess() == false)
           return false;
                 }
                 return true;
              } catch (Exception e){
                 logger.error( "EC2 Create/Delete Tags - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ?
                 e.getMessage() : "An unexpected error occurred.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#describeTags(com.cloud.bridge.service.core.ec2.EC2DescribeTags)
     */
    @Override
    public EC2DescribeTagsResponse describeTags(EC2DescribeTags request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              try {
                 EC2DescribeTagsResponse tagResponse = new EC2DescribeTagsResponse();
                 List<CloudStackResourceTag> resourceTagList = getApi().listTags(null, null, null, true, null);
            
                 List<EC2ResourceTag> tagList = new ArrayList<EC2ResourceTag>();
                 if (resourceTagList != null && resourceTagList.size() > 0) {
        for (CloudStackResourceTag resourceTag: resourceTagList) {
           EC2ResourceTag tag = new EC2ResourceTag();
           tag.setResourceId(resourceTag.getResourceId());
           tag.setResourceType(mapToAmazonResourceType(resourceTag.getResourceType()));
           tag.setKey(resourceTag.getKey());
           if (resourceTag.getValue() != null)
              tag.setValue(resourceTag.getValue());
           tagResponse.addTags(tag);
        }
                 }
            
                 EC2TagsFilterSet tfs = request.getFilterSet();
                 if (tfs == null)
        return tagResponse;
                 else
        return tfs.evaluate(tagResponse);
              } catch(Exception e) {
                 logger.error("EC2 DescribeTags - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#rebootInstances(com.cloud.bridge.service.core.ec2.EC2RebootInstances)
     */
    @Override
    public boolean rebootInstances(EC2RebootInstances request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              EC2Instance[] vms = null;
            
              // -> reboot is not allowed on destroyed (i.e., terminated) instances
              try {
                 String[] instanceSet = request.getInstancesSet();
                 EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null );
                 vms = previousState.getInstanceSet();
            
                 // -> send reboot requests for each found VM
                 for (EC2Instance vm : vms) {
        if (vm.getState().equalsIgnoreCase( "Destroyed" )) continue;
            
        CloudStackUserVm resp = getApi().rebootVirtualMachine(vm.getId());
        if (logger.isDebugEnabled())
           logger.debug("Rebooting VM " + resp.getId() + " job " + resp.getJobId());
                 }
            
                 // -> if some specified VMs where not found we have to tell the caller
                 if (instanceSet.length != vms.length)
        throw new EC2ServiceException(ClientError.InvalidAMIID_NotFound, "One or more instanceIds do not exist, other instances rebooted.");
            
                 return true;
              } catch( Exception e ) {
                 logger.error( "EC2 RebootInstances - ", e );
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#runInstances(com.cloud.bridge.service.core.ec2.EC2RunInstances)
     */
    @Override
    public EC2RunInstancesResponse runInstances(EC2RunInstances request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              EC2RunInstancesResponse instances = new EC2RunInstancesResponse();
              int createInstances    = 0;
              int canCreateInstances = -1;
              int countCreated       = 0;
            
              try {
                 CloudStackAccount caller = getCurrentAccount();
            
                 // ugly...
                 canCreateInstances = calculateAllowedInstances();
                 if (-1 == canCreateInstances) canCreateInstances = request.getMaxCount();
            
                 if (canCreateInstances < request.getMinCount()) {
        logger.info( "EC2 RunInstances - min count too big (" + request.getMinCount() + "), " + canCreateInstances + " left to allocate");
        throw new EC2ServiceException(ClientError.InstanceLimitExceeded ,"Only " + canCreateInstances + " instance(s) left to allocate");
                 }
            
                 if ( canCreateInstances < request.getMaxCount())
        createInstances = request.getMinCount();
                 else
        createInstances = request.getMaxCount();
            
                 //find CS service Offering ID
                 String instanceType = "m1.small";
                 if(request.getInstanceType() != null){
        instanceType = request.getInstanceType();
                 }
                 CloudStackServiceOffering svcOffering = null; //getCSServiceOfferingId(instanceType);
                 if(svcOffering == null){
        logger.info("No ServiceOffering found to be defined by name, please contact the administrator "+instanceType );
        throw new EC2ServiceException(ClientError.Unsupported, "instanceType: [" + instanceType + "] not found!");
                 }
            
                 // zone stuff
                 String zoneId = toZoneId(request.getZoneName(), null);
            
                 List<CloudStackZone> zones = getApi().listZones(null, null, zoneId, null);
                 if (zones == null || zones.size() == 0) {
        logger.info("EC2 RunInstances - zone [" + request.getZoneName() + "] not found!");
        throw new EC2ServiceException(ClientError.InvalidZone_NotFound, "ZoneId [" + request.getZoneName() + "] not found!");
                 }
                 // we choose first zone?
                 CloudStackZone zone = zones.get(0);
            
                 // network
                 CloudStackNetwork network = findNetwork(zone);
            
                 // now actually deploy the vms
                 for( int i=0; i < createInstances; i++ ) {
        CloudStackUserVm resp = getApi().deployVirtualMachine(svcOffering.getId(),
        request.getTemplateId(), zoneId, null, null, null, null,
        null, null, null, request.getKeyName(), null, (network != null ? network.getId() : null),
        null, constructList(request.getGroupSet()), request.getSize().longValue(), request.getUserData());
        EC2Instance vm = new EC2Instance();
        vm.setId(resp.getId().toString());
        vm.setName(resp.getName());
        vm.setZoneName(resp.getZoneName());
        vm.setTemplateId(resp.getTemplateId().toString());
        if (resp.getSecurityGroupList() != null && resp.getSecurityGroupList().size() > 0) {
           // TODO, we have a list of security groups, just return the first one?
           List<CloudStackSecurityGroup> securityGroupList = resp.getSecurityGroupList();
           for (CloudStackSecurityGroup securityGroup : securityGroupList) {
              vm.addGroupName(securityGroup.getName());
           }
        }
        vm.setState(resp.getState());
        vm.setCreated(resp.getCreated());
        List <CloudStackNic> nicList = resp.getNics();
        for (CloudStackNic nic : nicList) {
           if (nic.getIsDefault()) {
              vm.setPrivateIpAddress(nic.getIpaddress());
              break;
           }
        }
        vm.setIpAddress(resp.getIpAddress());
        vm.setAccountName(resp.getAccountName());
        vm.setDomainId(resp.getDomainId());
        vm.setHypervisor(resp.getHypervisor());
        vm.setServiceOffering( svcOffering.getName());
        instances.addInstance(vm);
        countCreated++;
                 }
            
                 if (0 == countCreated) {
        // TODO, we actually need to destroy left-over VMs when the exception is thrown
        throw new EC2ServiceException(ServerError.InsufficientInstanceCapacity, "Insufficient Instance Capacity" );
                 }
            
                 return instances;
              } catch( Exception e ) {
                 logger.error( "EC2 RunInstances - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#startInstances(com.cloud.bridge.service.core.ec2.EC2StartInstances)
     */
    @Override
    public EC2StartInstancesResponse startInstances(EC2StartInstances request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              EC2StartInstancesResponse instances = new EC2StartInstancesResponse();
              EC2Instance[] vms = null;
            
              // -> first determine the current state of each VM (becomes it previous state)
              try {
                 EC2DescribeInstancesResponse previousState = listVirtualMachines( request.getInstancesSet(), null, null );
                 vms = previousState.getInstanceSet();
            
                 // -> send start requests for each item
                 for (EC2Instance vm : vms) {
        vm.setPreviousState(vm.getState());
            
        // -> if its already running then we don't care
        if (vm.getState().equalsIgnoreCase( "Running" ) || vm.getState().equalsIgnoreCase( "Destroyed" )) {
           instances.addInstance(vm);
           continue;
        }
            
        CloudStackUserVm resp = getApi().startVirtualMachine(vm.getId());
        if(resp != null){
           vm.setState(resp.getState());
           if(logger.isDebugEnabled())
              logger.debug("Starting VM " + vm.getId() + " job " + resp.getJobId());
        }
        instances.addInstance(vm);
                 }
                 return instances;
              } catch( Exception e ) {
                 logger.error( "EC2 StartInstances - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
              }
        */
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#stopInstances(com.cloud.bridge.service.core.ec2.EC2StopInstances)
     */
    @Override
    public EC2StopInstancesResponse stopInstances(EC2StopInstances request) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              EC2StopInstancesResponse instances = new EC2StopInstancesResponse();
              EC2Instance[] virtualMachines = null;
            
              // -> first determine the current state of each VM (becomes it previous state)
              try {
                 String[] instanceSet = request.getInstancesSet();
            
                 EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null );
                 virtualMachines = previousState.getInstanceSet();
            
                 // -> send stop requests for each item
                 for (EC2Instance vm : virtualMachines) {
        vm.setPreviousState( vm.getState());
        CloudStackUserVm resp = null;
        if (request.getDestroyInstances()) {
           if (vm.getState().equalsIgnoreCase( "Destroyed" )) {
              instances.addInstance(vm);
              continue;
           }
           resp = getApi().destroyVirtualMachine(vm.getId());
           if(logger.isDebugEnabled())
              logger.debug("Destroying VM " + vm.getId() + " job " + resp.getJobId());
        } else {
           if (vm.getState().equalsIgnoreCase("Stopped") || vm.getState().equalsIgnoreCase("Destroyed")) {
              instances.addInstance(vm);
              continue;
           }
           resp = getApi().stopVirtualMachine(vm.getId(), false);
           if(logger.isDebugEnabled())
              logger.debug("Stopping VM " + vm.getId() + " job " + resp.getJobId());
        }
        if (resp != null) {
           vm.setState(resp.getState());
           instances.addInstance(vm);
        }
                 }
                 return instances;
              } catch( Exception e ) {
                 logger.error( "EC2 StopInstances - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() + ", might already be destroyed" : "An unexpected error occurred.");
              }
        */
    }

    /**
     * RunInstances includes a min and max count of requested instances to create.
     * We have to be able to create the min number for the user or none at all.  So
     * here we determine what the user has left to create.
     *
     * @return -1 means no limit exists, other positive numbers give max number left that
     *         the user can create.
     */
    private int calculateAllowedInstances() throws Exception {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              int maxAllowed = -1;
            
              CloudStackAccount ourAccount = getCurrentAccount();
            
              if (ourAccount == null) {
                 // This should never happen, but
                 // we will return -99999 if this happens...
                 return -99999;
              }
            
              // if accountType is Admin == 1, then let's return -1
              if (ourAccount.getAccountType() == 1) return -1;
            
              // -> get the user limits on instances
              // "0" represents instances:
              // http://download.cloud.com/releases/2.2.0/api_2.2.8/user/listResourceLimits.html
              List<CloudStackResourceLimit> limits = getApi().listResourceLimits(null, null, null, null, "0");
              if (limits != null && limits.size() > 0) {
                 maxAllowed = (int)limits.get(0).getMax().longValue();
                 if (maxAllowed == -1)
        return -1;   // no limit
            
                 EC2DescribeInstancesResponse existingVMS = listVirtualMachines( null, null, null );
                 EC2Instance[] vmsList = existingVMS.getInstanceSet();
                 return (maxAllowed - vmsList.length);
              } else {
                 return 0;
              }
        */
    }

    /**
     * Performs the cloud API listVirtualMachines one or more times.
     *
     * @param virtualMachineIds - an array of instances we are interested in getting information on
     * @param ifs - filter out unwanted instances
     */
    private EC2DescribeInstancesResponse listVirtualMachines(String[] virtualMachineIds, EC2InstanceFilterSet ifs,
            Multimap<String, String> resourceTags) throws Exception {
        EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse();

        if (null == virtualMachineIds || 0 == virtualMachineIds.length) {
            instances = lookupInstances(null, instances, resourceTags);
        } else {
            for (int i = 0; i < virtualMachineIds.length; i++) {
                instances = lookupInstances(virtualMachineIds[i], instances, resourceTags);
            }
        }

        if (null == ifs)
            return instances;
        else
            return ifs.evaluate(instances);
    }

    /**
     * Get one or more templates depending on the volumeId parameter.
     *
     * @param volumeId   - if interested in one specific volume, null if want to list all volumes
     * @param instanceId - if interested in volumes for a specific instance, null if instance is not important
     */
    private EC2DescribeVolumesResponse listVolumes(String volumeId, String instanceId,
            EC2DescribeVolumesResponse volumes, Multimap<String, String> resourceTagSet) throws Exception {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              List<CloudStackVolume> vols = getApi().listVolumes(null, null, null, volumeId, null, null, null, null, null,
              instanceId, null, resourceTagSet);
              if(vols != null && vols.size() > 0) {
                 for(CloudStackVolume vol : vols) {
        EC2Volume ec2Vol = new EC2Volume();
        ec2Vol.setId(vol.getId());
        if(vol.getAttached() != null)
           ec2Vol.setAttached(vol.getAttached());
        ec2Vol.setCreated(vol.getCreated());
            
        if(vol.getDeviceId() != null)
           ec2Vol.setDeviceId(vol.getDeviceId());
        ec2Vol.setHypervisor(vol.getHypervisor());
            
        if(vol.getSnapshotId() != null)
           ec2Vol.setSnapshotId(vol.getSnapshotId());
        ec2Vol.setState(mapToAmazonVolState(vol.getState()));
        ec2Vol.setSize(vol.getSize());
        ec2Vol.setType(vol.getVolumeType());
            
        if(vol.getVirtualMachineId() != null)
           ec2Vol.setInstanceId(vol.getVirtualMachineId());
            
        if(vol.getVirtualMachineState() != null)
           ec2Vol.setVMState(vol.getVirtualMachineState());
        ec2Vol.setZoneName(vol.getZoneName());
            
        Multimap<String, String> resourceTags = vol.getTags();
        for(CloudStackKeyValue resourceTag : resourceTags) {
           EC2TagKeyValue param = new EC2TagKeyValue();
           param.setKey(resourceTag.getKey());
           if (resourceTag.getValue() != null)
              param.setValue(resourceTag.getValue());
           ec2Vol.addResourceTag(param);
        }
            
        volumes.addVolume(ec2Vol);
                 }
              }
            
              return volumes;
        */
    }

    /**
     * More than one place we need to access the defined list of zones.  If given a specific
     * list of zones of interest, then only values from those zones are returned.
     *
     * @param interestedZones - can be null, should be a subset of all zones
     *
     * @return EC2DescribeAvailabilityZonesResponse
     */
    private EC2DescribeAvailabilityZonesResponse listZones(Iterable<String> interestedZones) throws Exception {
        EC2DescribeAvailabilityZonesResponse zones = new EC2DescribeAvailabilityZonesResponse();
        if (Iterables.size(interestedZones) == 0 || Iterables.contains(interestedZones, "default")) {
            zones.addZone("default", "default");
        }
        return zones;
    }

    /**
     * More than one place we need to access the defined list of zones.  If given a specific
     * list of zones of interest, then only values from those zones are returned.
     *
     * @param interestedZones - can be null, should be a subset of all zones
     *
     * @return EC2DescribeAvailabilityZonesResponse
     */
    private EC2DescribeRegionsResponse listRegions(Iterable<String> interestedRegions) throws Exception {
        EC2DescribeRegionsResponse regions = new EC2DescribeRegionsResponse();
        for (Reference orgRef : getApi().getOrgApi().list()) {
            Org org = getApi().getOrgApi().get(orgRef.getHref());
            if (Iterables.size(interestedRegions) == 0 || Iterables.contains(interestedRegions, org.getId()))
                regions.addRegion(org.getId(), org.getName());
        }
        return regions;
    }

    /**
     * Get information on one or more virtual machines depending on the instanceId parameter.
     *
     * @param instanceId - if null then return information on all existing instances, otherwise
     *                     just return information on the matching instance.
     * @param instances  - a container object to fill with one or more EC2Instance objects
     *
     * @return the same object passed in as the "instances" parameter modified with one or more
     *         EC2Instance objects loaded.
     */
    private EC2DescribeInstancesResponse lookupInstances(String instanceId, EC2DescribeInstancesResponse instances,
            Multimap<String, String> resourceTagSet) throws Exception {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
            
              String instId = instanceId != null ? instanceId : null;
              List<CloudStackUserVm> vms = getApi().listVirtualMachines(null, null, true, null, null, null, null,
              instId, null, null, null, null, null, null, null, null, resourceTagSet);
            
              if(vms != null && vms.size() > 0) {
                 for(CloudStackUserVm cloudVm : vms) {
        EC2Instance ec2Vm = new EC2Instance();
            
        ec2Vm.setId(cloudVm.getId().toString());
        ec2Vm.setName(cloudVm.getName());
        ec2Vm.setZoneName(cloudVm.getZoneName());
        ec2Vm.setTemplateId(cloudVm.getTemplateId().toString());
        ec2Vm.setGroup(cloudVm.getGroup());
        ec2Vm.setState(cloudVm.getState());
        ec2Vm.setCreated(cloudVm.getCreated());
        ec2Vm.setIpAddress(cloudVm.getIpAddress());
        ec2Vm.setAccountName(cloudVm.getAccountName());
        ec2Vm.setDomainId(cloudVm.getDomainId());
        ec2Vm.setHypervisor(cloudVm.getHypervisor());
        ec2Vm.setRootDeviceType(cloudVm.getRootDeviceType());
        ec2Vm.setRootDeviceId(cloudVm.getRootDeviceId());
        //             ec2Vm.setServiceOffering(serviceOfferingIdToInstanceType(cloudVm.getServiceOfferingId().toString()));
            
        List<CloudStackNic> nics = cloudVm.getNics();
        for(CloudStackNic nic : nics) {
           if(nic.getIsDefault()) {
              ec2Vm.setPrivateIpAddress(nic.getIpaddress());
              break;
           }
        }
            
        Multimap<String, String> resourceTags = cloudVm.getTags();
        for(CloudStackKeyValue resourceTag : resourceTags) {
           EC2TagKeyValue param = new EC2TagKeyValue();
           param.setKey(resourceTag.getKey());
           if (resourceTag.getValue() != null)
              param.setValue(resourceTag.getValue());
           ec2Vm.addResourceTag(param);
        }
            
        if (cloudVm.getSecurityGroupList() != null && cloudVm.getSecurityGroupList().size() > 0) {
           // TODO, we have a list of security groups, just return the first one?
           List<CloudStackSecurityGroup> securityGroupList = cloudVm.getSecurityGroupList();
           for (CloudStackSecurityGroup securityGroup : securityGroupList) {
              ec2Vm.addGroupName(securityGroup.getName());
           }
        }
            
        instances.addInstance(ec2Vm);
                 }
              }else{
                 if(instanceId != null){
        //no such instance found
        throw new EC2ServiceException(ServerError.InternalError, "Instance:" + instanceId + " not found");
                 }
              }
              return instances;
        */
    }

    /**
     * Get one or more templates depending on the templateId parameter.
     *
     * @param immutableSet - if null then return information on all existing templates, otherwise
     *                     just return information on the matching template.
     * @param images     - a container object to fill with one or more EC2Image objects
     *
     * @return the same object passed in as the "images" parameter modified with one or more
     *         EC2Image objects loaded.
     */
    private EC2DescribeImagesResponse listTemplates(Iterable<String> imageIds, EC2DescribeImagesResponse images)
            throws EC2ServiceException {
        ImmutableSet<VAppTemplate> templates = FluentIterable.from(getApi().getOrgApi().list())
                .transformAndConcat(new Function<Reference, Iterable<Link>>() {
                    @Override
                    public Iterable<Link> apply(Reference in) {
                        return getApi().getOrgApi().get(in.getHref()).getLinks();
                    }
                }).filter(LinkPredicates.typeEquals(VCloudDirectorMediaType.VDC))
                .transformAndConcat(new Function<Link, Iterable<Reference>>() {
                    @Override
                    public Iterable<Reference> apply(Link in) {
                        return getApi().getVdcApi().get(in.getHref()).getResourceEntities();
                    }
                }).filter(ReferencePredicates.typeEquals(VCloudDirectorMediaType.VAPP_TEMPLATE))
                .transform(new Function<Reference, VAppTemplate>() {
                    @Override
                    public VAppTemplate apply(Reference in) {
                        return getApi().getVAppTemplateApi().get(in.getHref());
                    }
                }).toImmutableSet();
        for (VAppTemplate template : templates) {
            EC2Image ec2Image = new EC2Image();
            ec2Image.setId(template.getId());
            ec2Image.setAccountName(getApi().getCurrentSession().getUser());
            ec2Image.setName(template.getName());
            ec2Image.setDescription(template.getDescription());
            // ec2Image.setOsTypeId(temp.getOsTypeId().toString());
            //TODO use the catalog api to determine if this template is published
            // ec2Image.setIsPublic(temp.getIsPublic());
            ec2Image.setIsReady(template.isOvfDescriptorUploaded());
            // TODO: domain is not an EC2 Concept.. probably this should be looked at.
            // ec2Image.setDomainId(temp.getDomainId());
            for (Entry<String, String> resourceTag : getApi().getVAppTemplateApi().getMetadataApi(template.getId())
                    .get().entrySet()) {
                EC2TagKeyValue param = new EC2TagKeyValue();
                param.setKey(resourceTag.getKey());
                if (resourceTag.getValue() != null)
                    param.setValue(resourceTag.getValue());
                ec2Image.addResourceTag(param);
            }
            images.addImage(ec2Image);

        }
        return images;
    }

    /* (non-Javadoc)
     * @see com.cloud.bridge.service.core.ec2.EC2Engine1#listSecurityGroups(java.lang.String[])
     */
    @Override
    public EC2DescribeSecurityGroupsResponse listSecurityGroups(String[] interestedGroups) {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              try {
                 EC2DescribeSecurityGroupsResponse groupSet = new EC2DescribeSecurityGroupsResponse();
            
                 List<CloudStackSecurityGroup> groups = getApi().listSecurityGroups(null, null, null, true, null, null, null);
                 if (groups != null && groups.size() > 0)
        for (CloudStackSecurityGroup group : groups) {
           boolean matched = false;
           if (interestedGroups.length > 0) {
              for (String groupName :interestedGroups) {
                 if (groupName.equalsIgnoreCase(group.getName())) {
                    matched = true;
                    break;
                 }
              }
           } else {
              matched = true;
           }
           if (!matched) continue;
           EC2SecurityGroup ec2Group = new EC2SecurityGroup();
           // not sure if we should set both account and account name to accountname
           ec2Group.setAccount(group.getAccountName());
           ec2Group.setAccountName(group.getAccountName());
           ec2Group.setName(group.getName());
           ec2Group.setDescription(group.getDescription());
           ec2Group.setDomainId(group.getDomainId());
           ec2Group.setId(group.getId().toString());
           toPermission(ec2Group, group);
            
           groupSet.addGroup(ec2Group);
        }
                 return groupSet;
              } catch(Exception e) {
                 logger.error( "List Security Groups - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
              }
        */
    }

    /**
     * Convert ingress rule to EC2IpPermission records
     *
     * @param response
     * @param group
     * @return
     */
    private boolean toPermission(EC2SecurityGroup response, FirewallService fw) {
        Set<FirewallRule> rules = fw.getFirewallRules();

        if (rules == null || rules.isEmpty())
            return false;

        for (FirewallRule rule : rules) {
            EC2IpPermission perm = new EC2IpPermission();
            //         perm.setProtocol(rule.getProtocol());
            //         perm.setFromPort(rule.getStartPort());
            //         perm.setToPort(rule.getEndPort());
            //         perm.setRuleId(rule.getRuleId() != null ? rule.getRuleId().toString() : new String());
            //         perm.setIcmpCode(rule.getIcmpCode() != null ? rule.getIcmpCode().toString() : new String());
            //         perm.setIcmpType(rule.getIcmpType() != null ? rule.getIcmpType().toString() : new String());
            //         perm.setCIDR(rule.getCidr());
            //         perm.addIpRange(rule.getCidr());
            //
            //         if (rule.getAccountName() != null && rule.getSecurityGroupName() != null) {
            //            EC2SecurityGroup newGroup = new EC2SecurityGroup();
            //            newGroup.setAccount(rule.getAccountName());
            //            newGroup.setName(rule.getSecurityGroupName());
            //            perm.addUser(newGroup);
            //         }
            response.addIpPermission(perm);
        }
        return true;
    }

    /**
     * Windows has its own device strings.
     *
     * @param hypervisor
     * @param deviceId
     * @return
     */
    public static String cloudDeviceIdToDevicePath(String hypervisor, String deviceId) {
        Integer devId = new Integer(deviceId);
        if (null != hypervisor && hypervisor.toLowerCase().contains("windows")) {
            switch (devId) {
            case 1:
                return "xvdb";
            case 2:
                return "xvdc";
            case 3:
                return "xvdd";
            case 4:
                return "xvde";
            case 5:
                return "xvdf";
            case 6:
                return "xvdg";
            case 7:
                return "xvdh";
            case 8:
                return "xvdi";
            case 9:
                return "xvdj";
            default:
                return new String("" + deviceId);
            }
        } else { // -> assume its unix
            switch (devId) {
            case 1:
                return "/dev/sdb";
            case 2:
                return "/dev/sdc";
            case 3:
                return "/dev/sdd";
            case 4:
                return "/dev/sde";
            case 5:
                return "/dev/sdf";
            case 6:
                return "/dev/sdg";
            case 7:
                return "/dev/sdh";
            case 8:
                return "/dev/sdi";
            case 9:
                return "/dev/sdj";
            default:
                return new String("" + deviceId);
            }
        }
    }

    /**
     * Translate the device name string into a Cloud Stack deviceId.
     * deviceId 3 is reserved for CDROM and 0 for the ROOT disk
     *
     * @param device string
     * @return deviceId value
     */
    private String mapDeviceToCloudDeviceId(String device) {
        if (device.equalsIgnoreCase("/dev/sdb"))
            return "1";
        else if (device.equalsIgnoreCase("/dev/sdc"))
            return "2";
        else if (device.equalsIgnoreCase("/dev/sde"))
            return "4";
        else if (device.equalsIgnoreCase("/dev/sdf"))
            return "5";
        else if (device.equalsIgnoreCase("/dev/sdg"))
            return "6";
        else if (device.equalsIgnoreCase("/dev/sdh"))
            return "7";
        else if (device.equalsIgnoreCase("/dev/sdi"))
            return "8";
        else if (device.equalsIgnoreCase("/dev/sdj"))
            return "9";

        else if (device.equalsIgnoreCase("/dev/xvdb"))
            return "1";
        else if (device.equalsIgnoreCase("/dev/xvdc"))
            return "2";
        else if (device.equalsIgnoreCase("/dev/xvde"))
            return "4";
        else if (device.equalsIgnoreCase("/dev/xvdf"))
            return "5";
        else if (device.equalsIgnoreCase("/dev/xvdg"))
            return "6";
        else if (device.equalsIgnoreCase("/dev/xvdh"))
            return "7";
        else if (device.equalsIgnoreCase("/dev/xvdi"))
            return "8";
        else if (device.equalsIgnoreCase("/dev/xvdj"))
            return "9";

        else if (device.equalsIgnoreCase("xvdb"))
            return "1";
        else if (device.equalsIgnoreCase("xvdc"))
            return "2";
        else if (device.equalsIgnoreCase("xvde"))
            return "4";
        else if (device.equalsIgnoreCase("xvdf"))
            return "5";
        else if (device.equalsIgnoreCase("xvdg"))
            return "6";
        else if (device.equalsIgnoreCase("xvdh"))
            return "7";
        else if (device.equalsIgnoreCase("xvdi"))
            return "8";
        else if (device.equalsIgnoreCase("xvdj"))
            return "9";

        else
            throw new EC2ServiceException(ClientError.Unsupported, device + " is not supported");
    }

    /**
     * Map CloudStack instance state to Amazon state strings
     *
     * @param state
     * @return
     */
    private String mapToAmazonVolState(String state) {
        if (state.equalsIgnoreCase("Allocated") || state.equalsIgnoreCase("Creating")
                || state.equalsIgnoreCase("Ready"))
            return "available";

        if (state.equalsIgnoreCase("Destroy"))
            return "deleting";

        return "error";
    }

    /**
     * Map Amazon resourceType to CloudStack resourceType
     *
     * @param Amazon resourceType
     * @return CloudStack resourceType
     */
    private String mapToCloudStackResourceType(String resourceType) {
        if (resourceType.equalsIgnoreCase("image"))
            return ("template");
        else if (resourceType.equalsIgnoreCase("instance"))
            return ("userVm");
        else
            return resourceType;
    }

    /**
     * Map Amazon resourceType to CloudStack resourceType
     *
     * @param CloudStack resourceType
     * @return Amazon resourceType
     */
    private String mapToAmazonResourceType(String resourceType) {
        if (resourceType.equalsIgnoreCase("template"))
            return ("image");
        else if (resourceType.equalsIgnoreCase("userVm"))
            return ("instance");
        else
            return (resourceType.toLowerCase());
    }

    /**
     * Stop an instance
     * Wait until one specific VM has stopped
     *
     * @param instanceId
     * @return
     * @throws Exception
     */
    private boolean stopVirtualMachine(String instanceId) throws Exception {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              try {
                 CloudStackUserVm resp = getApi().stopVirtualMachine(instanceId, false);
                 if (logger.isDebugEnabled())
        logger.debug("Stopping VM " + instanceId );
                 return resp != null;
              } catch(Exception e) {
                 logger.error( "StopVirtualMachine - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
              }
        */
    }

    /**
     * Start an existing stopped instance(VM)
     *
     * @param instanceId
     * @return
     * @throws Exception
     */
    private boolean startVirtualMachine(String instanceId) throws Exception {
        throw new EC2ServiceException(ServerError.InternalError, "Not implemented in Cinderella");
        /*
              try {
                 CloudStackUserVm resp = getApi().startVirtualMachine(instanceId);
                 if (logger.isDebugEnabled())
        logger.debug("Starting VM " + instanceId );
                 return resp != null;
              } catch(Exception e) {
                 logger.error("StartVirtualMachine - ", e);
                 throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred.");
              }
        */
    }

    private Multimap<String, String> getResourceTags(EC2TagKeyValue[] tagKeyValueSet) {
        Builder<String, String> builder = ImmutableMultimap.<String, String>builder();
        for (EC2TagKeyValue tagKeyValue : tagKeyValueSet) {
            builder.put(tagKeyValue.getKey(), tagKeyValue.getValue());
        }
        return builder.build();
    }

}