com.eucalyptus.compute.service.ComputeService.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.compute.service.ComputeService.java

Source

/*************************************************************************
 * Copyright 2009-2015 Eucalyptus Systems, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 *
 * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
 * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
 * additional information or have any questions.
 ************************************************************************/
package com.eucalyptus.compute.service;

import static com.eucalyptus.util.Strings.append;
import static com.eucalyptus.util.Strings.prepend;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.persistence.EntityNotFoundException;

import org.apache.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
import org.mule.component.ComponentException;

import com.eucalyptus.auth.AuthQuotaException;
import com.eucalyptus.auth.principal.AccountFullName;
import com.eucalyptus.auth.type.RestrictedType;
import com.eucalyptus.binding.Binding;
import com.eucalyptus.binding.BindingException;
import com.eucalyptus.binding.BindingManager;
import com.eucalyptus.component.Topology;
import com.eucalyptus.component.annotation.ComponentNamed;
import com.eucalyptus.component.id.Eucalyptus;
import com.eucalyptus.compute.common.*;
import com.eucalyptus.compute.common.internal.address.AddressI;
import com.eucalyptus.compute.common.internal.address.AllocatedAddressEntity;
import com.eucalyptus.compute.common.internal.blockstorage.Snapshot;
import com.eucalyptus.compute.common.internal.blockstorage.Snapshots;
import com.eucalyptus.compute.common.internal.blockstorage.State;
import com.eucalyptus.compute.common.internal.blockstorage.Volume;
import com.eucalyptus.compute.common.internal.identifier.InvalidResourceIdentifier;
import com.eucalyptus.compute.common.internal.identifier.ResourceIdentifiers;
import com.eucalyptus.compute.common.internal.images.BlockStorageDeviceMapping;
import com.eucalyptus.compute.common.internal.images.BlockStorageImageInfo;
import com.eucalyptus.compute.common.internal.images.DeviceMapping;
import com.eucalyptus.compute.common.internal.images.ImageInfo;
import com.eucalyptus.compute.common.internal.images.Images;
import com.eucalyptus.compute.common.internal.images.MachineImageInfo;
import com.eucalyptus.compute.common.internal.keys.KeyPairs;
import com.eucalyptus.compute.common.internal.keys.SshKeyPair;
import com.eucalyptus.compute.common.internal.network.NetworkGroup;
import com.eucalyptus.compute.common.internal.network.NetworkGroups;
import com.eucalyptus.compute.common.internal.tags.Filter;
import com.eucalyptus.compute.common.internal.tags.Filters;
import com.eucalyptus.compute.common.internal.tags.InvalidFilterException;
import com.eucalyptus.compute.common.internal.tags.Tag;
import com.eucalyptus.compute.common.internal.tags.TagSupport;
import com.eucalyptus.compute.common.internal.tags.Tags;
import com.eucalyptus.compute.common.internal.util.MetadataException;
import com.eucalyptus.compute.common.internal.vm.NetworkGroupId;
import com.eucalyptus.compute.common.internal.vm.VmBootVolumeAttachment;
import com.eucalyptus.compute.common.internal.vm.VmInstance;
import com.eucalyptus.compute.common.internal.vm.VmInstances;
import com.eucalyptus.compute.common.internal.vm.VmStandardVolumeAttachment;
import com.eucalyptus.compute.common.internal.vm.VmVolumeAttachment;
import com.eucalyptus.compute.common.network.Networking;
import com.eucalyptus.compute.common.network.NetworkingFeature;
import com.eucalyptus.compute.common.internal.vpc.DhcpOptionSet;
import com.eucalyptus.compute.common.internal.vpc.DhcpOptionSets;
import com.eucalyptus.compute.common.internal.vpc.InternetGateway;
import com.eucalyptus.compute.common.internal.vpc.InternetGateways;
import com.eucalyptus.compute.common.internal.vpc.Lister;
import com.eucalyptus.compute.common.internal.vpc.NetworkAcl;
import com.eucalyptus.compute.common.internal.vpc.NetworkAcls;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterfaces;
import com.eucalyptus.compute.common.internal.vpc.RouteTable;
import com.eucalyptus.compute.common.internal.vpc.RouteTables;
import com.eucalyptus.compute.common.internal.vpc.Subnet;
import com.eucalyptus.compute.common.internal.vpc.Subnets;
import com.eucalyptus.compute.common.internal.vpc.Vpc;
import com.eucalyptus.compute.common.internal.vpc.VpcMetadataNotFoundException;
import com.eucalyptus.compute.common.internal.vpc.Vpcs;
import com.eucalyptus.context.Context;
import com.eucalyptus.context.Contexts;
import com.eucalyptus.context.ServiceDispatchException;
import com.eucalyptus.entities.AbstractPersistent;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.entities.TransactionException;
import com.eucalyptus.entities.TransactionResource;
import com.eucalyptus.entities.Transactions;
import com.eucalyptus.util.CollectionUtils;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.auth.principal.OwnerFullName;
import com.eucalyptus.util.Pair;
import com.eucalyptus.util.RestrictedTypes;
import com.eucalyptus.util.TypeMappers;
import com.eucalyptus.util.async.AsyncExceptions;
import com.eucalyptus.util.async.AsyncExceptions.AsyncWebServiceError;
import com.eucalyptus.util.async.AsyncRequests;
import com.eucalyptus.util.async.FailedRequestException;
import com.eucalyptus.ws.EucalyptusWebServiceException;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultimap;

import edu.ucsb.eucalyptus.msgs.BaseMessage;
import edu.ucsb.eucalyptus.msgs.BaseMessages;

/**
 *
 */
@SuppressWarnings("UnusedDeclaration")
@ComponentNamed
public class ComputeService implements Callable {
    private static Logger LOG = Logger.getLogger(ComputeService.class);

    private final DhcpOptionSets dhcpOptionSets;
    private final InternetGateways internetGateways;
    private final NetworkAcls networkAcls;
    private final NetworkInterfaces networkInterfaces;
    private final RouteTables routeTables;
    private final Subnets subnets;
    private final Vpcs vpcs;

    @Inject
    public ComputeService(final DhcpOptionSets dhcpOptionSets, final InternetGateways internetGateways,
            final NetworkAcls networkAcls, final NetworkInterfaces networkInterfaces, final RouteTables routeTables,
            final Subnets subnets, final Vpcs vpcs) {
        this.dhcpOptionSets = dhcpOptionSets;
        this.internetGateways = internetGateways;
        this.networkAcls = networkAcls;
        this.networkInterfaces = networkInterfaces;
        this.routeTables = routeTables;
        this.subnets = subnets;
        this.vpcs = vpcs;
    }

    public DescribeImagesResponseType describeImages(final DescribeImagesType request)
            throws EucalyptusCloudException, TransactionException {
        DescribeImagesResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final boolean showAllStates = ctx.isAdministrator() && request.getImagesSet().remove("verbose");
        final String requestAccountId = ctx.getUserFullName().getAccountNumber();
        final List<String> imageIds = normalizeImageIdentifiers(request.getImagesSet());
        final List<String> ownersSet = request.getOwnersSet();
        if (ownersSet.remove(Images.SELF)) {
            ownersSet.add(requestAccountId);
        }
        final Filter filter = Filters.generate(request.getFilterSet(), ImageInfo.class);
        final Filter persistenceFilter = getPersistenceFilter(ImageInfo.class, imageIds, "image-id", filter);
        final Predicate<? super ImageInfo> requestedAndAccessible = CloudMetadatas.filteringFor(ImageInfo.class)
                .byId(imageIds).byOwningAccount(request.getOwnersSet())
                .byPredicate(showAllStates ? Predicates.<ImageInfo>alwaysTrue() : Images.standardStatePredicate())
                .byPredicate(Images.filterExecutableBy(request.getExecutableBySet()))
                .byPredicate(filter.asPredicate()).byPredicate(Images.FilterPermissions.INSTANCE)
                .byPrivilegesWithoutOwner().buildPredicate();
        final List<ImageDetails> imageDetailsList = Transactions.filteredTransform(new ImageInfo(),
                persistenceFilter.asCriterion(), persistenceFilter.getAliases(),
                Predicates.and(new TrackingPredicate<ImageInfo>(imageIds), requestedAndAccessible),
                Images.TO_IMAGE_DETAILS);

        errorIfNotFound("InvalidAMIID.NotFound", "image", imageIds);

        final Map<String, List<Tag>> tagsMap = TagSupport.forResourceClass(ImageInfo.class).getResourceTagMap(
                AccountFullName.getInstance(ctx.getAccountNumber()),
                Iterables.transform(imageDetailsList, ImageDetails.imageId()));

        for (final ImageDetails details : imageDetailsList) {
            Tags.addFromTags(details.getTagSet(), ResourceTag.class, tagsMap.get(details.getImageId()));
        }
        reply.getImagesSet().addAll(imageDetailsList);
        return reply;
    }

    public DescribeImageAttributeResponseType describeImageAttribute(final DescribeImageAttributeType request)
            throws EucalyptusCloudException {
        DescribeImageAttributeResponseType reply = request.getReply();

        if (request.getAttribute() != null)
            request.applyAttribute();

        try (final TransactionResource tx = Entities.transactionFor(ImageInfo.class)) {
            final ImageInfo imgInfo = Entities
                    .uniqueResult(Images.exampleWithImageId(imageIdentifier(request.getImageId())));
            if (!canModifyImage(imgInfo)) {
                throw new EucalyptusCloudException("Not authorized to describe image attribute");
            }
            reply.setImageId(imgInfo.getDisplayName());
            if (request.getKernel() != null) {
                if (imgInfo instanceof MachineImageInfo) {
                    if (((MachineImageInfo) imgInfo).getKernelId() != null) {
                        reply.getKernel().add(((MachineImageInfo) imgInfo).getKernelId());
                    }
                }
            } else if (request.getRamdisk() != null) {
                if (imgInfo instanceof MachineImageInfo) {
                    if (((MachineImageInfo) imgInfo).getRamdiskId() != null) {
                        reply.getRamdisk().add(((MachineImageInfo) imgInfo).getRamdiskId());
                    }
                }
            } else if (request.getLaunchPermission() != null) {
                if (imgInfo.getImagePublic()) {
                    reply.getLaunchPermission().add(LaunchPermissionItemType.newGroupLaunchPermission());
                }
                for (final String permission : imgInfo.getPermissions())
                    reply.getLaunchPermission().add(LaunchPermissionItemType.newUserLaunchPermission(permission));
            } else if (request.getProductCodes() != null) {
                reply.getProductCodes().addAll(imgInfo.getProductCodes());
            } else if (request.getBlockDeviceMapping() != null) {
                if (imgInfo instanceof BlockStorageImageInfo) {
                    BlockStorageImageInfo bfebsImage = (BlockStorageImageInfo) imgInfo;
                    reply.getBlockDeviceMapping().add(new BlockDeviceMappingItemType(
                            VmInstances.getEbsRootDeviceName(), bfebsImage.getRootDeviceName()));
                    reply.getBlockDeviceMapping()
                            .add(new BlockDeviceMappingItemType("root", bfebsImage.getRootDeviceName()));
                    int i = 0;
                    for (DeviceMapping mapping : bfebsImage.getDeviceMappings()) {
                        if (mapping.getDeviceName().equalsIgnoreCase(bfebsImage.getRootDeviceName())) {
                            continue;
                        }
                        switch (mapping.getDeviceMappingType()) {
                        case blockstorage:
                            BlockStorageDeviceMapping bsdm = (BlockStorageDeviceMapping) mapping;
                            BlockDeviceMappingItemType bdmItem = new BlockDeviceMappingItemType("ebs" + (++i),
                                    mapping.getDeviceName());
                            EbsDeviceMapping ebsItem = new EbsDeviceMapping();
                            ebsItem.setSnapshotId(bsdm.getSnapshotId());
                            ebsItem.setVolumeSize(bsdm.getSize());
                            ebsItem.setDeleteOnTermination(bsdm.getDelete());
                            bdmItem.setEbs(ebsItem);
                            reply.getBlockDeviceMapping().add(bdmItem);
                            break;
                        case ephemeral:
                            reply.getBlockDeviceMapping().add(new BlockDeviceMappingItemType(
                                    mapping.getVirtualName(), mapping.getDeviceName()));
                            break;
                        default:
                            break;
                        }
                    }
                } else {
                    reply.getBlockDeviceMapping()
                            .add(new BlockDeviceMappingItemType(VmInstances.getEbsRootDeviceName(), "sda1"));
                    reply.getBlockDeviceMapping().add(new BlockDeviceMappingItemType("ephemeral0", "sda2"));
                    reply.getBlockDeviceMapping().add(new BlockDeviceMappingItemType("swap", "sda3"));
                    reply.getBlockDeviceMapping().add(new BlockDeviceMappingItemType("root", "/dev/sda1"));
                }
            } else if (request.getDescription() != null) {
                if (imgInfo.getDescription() != null) {
                    reply.getDescription().add(imgInfo.getDescription());
                }
            } else {
                throw new EucalyptusCloudException("invalid image attribute request.");
            }
        } catch (final NoSuchElementException e) {
            throw new ComputeServiceClientException("InvalidAMIID.NotFound",
                    "The image '" + request.getImageId() + "' was not found");
        } catch (final TransactionException ex) {
            throw new EucalyptusCloudException("Error handling image attribute request: " + ex.getMessage(), ex);
        }
        return reply;
    }

    public DescribeAddressesResponseType describeAddresses(final DescribeAddressesType request)
            throws EucalyptusCloudException {
        final Context ctx = Contexts.lookup();
        final boolean isAdmin = ctx.isAdministrator();
        final boolean verbose = isAdmin && request.getPublicIpsSet().contains("verbose");
        if (verbose) {
            // dispatch to back end so all addresses can be described
            return (DescribeAddressesResponseType) proxy(request);
        }

        // handle stateless describe for users elastic IPs
        final DescribeAddressesResponseType reply = request.getReply();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final Filter filter = Filters.generateFor(request.getFilterSet(), AllocatedAddressEntity.class)
                .withOptionalInternalFilter("public-ip", request.getPublicIpsSet())
                .withOptionalInternalFilter("allocation-id", request.getAllocationIds()).generate();
        final Predicate<? super AllocatedAddressEntity> requestedAndAccessible = CloudMetadatas
                .filteringFor(AllocatedAddressEntity.class).byId(request.getPublicIpsSet())
                .byProperty(request.getAllocationIds(), AllocatedAddressEntity.allocation())
                .byPredicate(filter.asPredicate())
                .byOwningAccount(Collections.singleton(accountFullName.getAccountNumber())).byPrivileges()
                .buildPredicate();

        try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(AllocatedAddressEntity.class)) {
            final Iterable<AddressInfoType> addresses = Transactions.filteredTransform(
                    AllocatedAddressEntity.exampleWithOwnerAndAddress(accountFullName, null), filter.asCriterion(),
                    filter.getAliases(), requestedAndAccessible,
                    TypeMappers.lookup(AddressI.class, AddressInfoType.class));

            Iterables.addAll(reply.getAddressesSet(), addresses);
        } catch (final Exception e) {
            Exceptions.findAndRethrow(e, ComputeServiceException.class);
            LOG.error(e);
            LOG.debug(e, e);
            throw new EucalyptusCloudException(e.getMessage());
        }

        return reply;
    }

    public DescribeSecurityGroupsResponseType describeSecurityGroups(final DescribeSecurityGroupsType request)
            throws EucalyptusCloudException, MetadataException, TransactionException {
        final DescribeSecurityGroupsResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final boolean showAll = request.getSecurityGroupSet().remove("verbose")
                || request.getSecurityGroupIdSet().remove("verbose");

        NetworkGroups.createDefault(ctx.getUserFullName()); //ensure the default group exists to cover some old broken installs

        final List<String> normalizedIds = normalizeGroupIdentifiers(request.getSecurityGroupIdSet());
        final Filters.FiltersBuilder builder = Filters.generateFor(request.getFilterSet(), NetworkGroup.class);
        if ((request.getSecurityGroupSet().isEmpty() && !request.getSecurityGroupIdSet().isEmpty())
                || (!request.getSecurityGroupSet().isEmpty() && request.getSecurityGroupIdSet().isEmpty())) {
            builder.withOptionalInternalFilter("group-name", request.getSecurityGroupSet());
            builder.withOptionalInternalFilter("group-id", normalizedIds);
        }
        final Filter filter = builder.generate();
        final Filter persistenceFilter = getPersistenceFilter(NetworkGroup.class, normalizedIds, "group-id",
                filter);
        final Predicate<? super NetworkGroup> requestedAndAccessible = CloudMetadatas
                .filteringFor(NetworkGroup.class)
                .byPredicate(Predicates.or(
                        request.getSecurityGroupSet().isEmpty() && request.getSecurityGroupIdSet().isEmpty()
                                ? Predicates.<NetworkGroup>alwaysTrue()
                                : Predicates.<NetworkGroup>alwaysFalse(),
                        request.getSecurityGroupSet().isEmpty() ? Predicates.<NetworkGroup>alwaysFalse()
                                : CloudMetadatas.<NetworkGroup>filterById(request.getSecurityGroupSet()),
                        request.getSecurityGroupIdSet().isEmpty() ? Predicates.<NetworkGroup>alwaysFalse()
                                : CloudMetadatas.filterByProperty(
                                        normalizeGroupIdentifiers(request.getSecurityGroupIdSet()),
                                        NetworkGroup.groupId())))
                .byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();

        final OwnerFullName ownerFn = Contexts.lookup().isAdministrator() && (showAll || !normalizedIds.isEmpty())
                ? null
                : AccountFullName.getInstance(ctx.getAccountNumber());

        final Iterable<SecurityGroupItemType> securityGroupItems = Entities
                .asDistinctTransaction(NetworkGroup.class, new Function<Void, Iterable<SecurityGroupItemType>>() {
                    @Nullable
                    @Override
                    public Iterable<SecurityGroupItemType> apply(@Nullable final Void aVoid) {
                        try {
                            return Transactions.filteredTransform(NetworkGroup.withOwner(ownerFn),
                                    persistenceFilter.asCriterion(), persistenceFilter.getAliases(),
                                    Predicates.and(new TrackingPredicate<>(NetworkGroup.groupId(), normalizedIds),
                                            requestedAndAccessible),
                                    TypeMappers.lookup(NetworkGroup.class, SecurityGroupItemType.class));
                        } catch (TransactionException e) {
                            if (Exceptions.isCausedBy(e, EntityNotFoundException.class)) {
                                // A rule may have been deleted, retry
                                throw new Entities.RetryTransactionException(e, NetworkGroup.class);
                            }
                            throw Exceptions.toUndeclared(e);
                        }
                    }
                }).apply(null);

        errorIfNotFound("InvalidGroup.NotFound", "security group", normalizedIds);

        final Map<String, List<Tag>> tagsMap = TagSupport.forResourceClass(NetworkGroup.class).getResourceTagMap(
                AccountFullName.getInstance(ctx.getAccountNumber()),
                Iterables.transform(securityGroupItems, SecurityGroupItemToGroupId.INSTANCE));
        for (final SecurityGroupItemType securityGroupItem : securityGroupItems) {
            Tags.addFromTags(securityGroupItem.getTagSet(), ResourceTag.class,
                    tagsMap.get(securityGroupItem.getGroupId()));
        }

        Iterables.addAll(reply.getSecurityGroupInfo(), securityGroupItems);

        return reply;
    }

    public DescribeInstancesResponseType describeInstances(final DescribeInstancesType msg)
            throws EucalyptusCloudException {
        final DescribeInstancesResponseType reply = msg.getReply();
        Context ctx = Contexts.lookup();
        boolean showAll = msg.getInstancesSet().remove("verbose") || !msg.getInstancesSet().isEmpty();
        final Multimap<String, RunningInstancesItemType> instanceMap = TreeMultimap.create();
        final Map<String, ReservationInfoType> reservations = Maps.newHashMap();
        final Collection<String> identifiers = normalizeInstanceIdentifiers(msg.getInstancesSet());
        final Filter filter = Filters.generateFor(msg.getFilterSet(), VmInstance.class)
                .withOptionalInternalFilter("instance-id", identifiers).generate();
        final Filter persistenceFilter = getPersistenceFilter(VmInstance.class, identifiers, "instance-id", filter);
        final Predicate<? super VmInstance> requestedAndAccessible = CloudMetadatas.filteringFor(VmInstance.class)
                .byId(identifiers) // filters without wildcard support
                .byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();
        final OwnerFullName ownerFullName = (ctx.isAdministrator() && showAll) ? null
                : ctx.getUserFullName().asAccountFullName();
        try (final TransactionResource db = Entities.readOnlyDistinctTransactionFor(VmInstance.class)) {
            final List<VmInstance> instances = VmInstances.list(ownerFullName,
                    persistenceFilter.asCriterionWithConjunction(
                            Restrictions.not(VmInstance.criterion(VmInstance.VmState.BURIED))),
                    persistenceFilter.getAliases(),
                    Predicates.and(new TrackingPredicate<VmInstance>(identifiers), requestedAndAccessible));
            errorIfNotFound("InvalidInstanceID.NotFound", "instance ID", identifiers);
            final Map<String, List<Tag>> tagsMap = TagSupport.forResourceClass(VmInstance.class).getResourceTagMap(
                    AccountFullName.getInstance(ctx.getAccountNumber()),
                    Iterables.transform(instances, CloudMetadatas.toDisplayName()));

            for (final VmInstance vm : instances) {
                if (instanceMap.put(vm.getReservationId(), VmInstance.transform(vm))
                        && !reservations.containsKey(vm.getReservationId())) {
                    reservations.put(vm.getReservationId(), TypeMappers.transform(vm, ReservationInfoType.class));
                }
            }
            List<ReservationInfoType> replyReservations = reply.getReservationSet();
            for (ReservationInfoType r : reservations.values()) {
                Collection<RunningInstancesItemType> instanceSet = instanceMap.get(r.getReservationId());
                if (!instanceSet.isEmpty()) {
                    for (final RunningInstancesItemType instancesItemType : instanceSet) {
                        Tags.addFromTags(instancesItemType.getTagSet(), ResourceTag.class,
                                tagsMap.get(instancesItemType.getInstanceId()));
                    }
                    r.getInstancesSet().addAll(instanceSet);
                    replyReservations.add(r);
                }
            }
        } catch (final Exception e) {
            Exceptions.findAndRethrow(e, ComputeServiceException.class);
            LOG.error(e);
            LOG.debug(e, e);
            throw new EucalyptusCloudException(e.getMessage());
        }
        return reply;
    }

    public DescribeInstanceStatusResponseType describeInstanceStatus(final DescribeInstanceStatusType msg)
            throws EucalyptusCloudException {
        final DescribeInstanceStatusResponseType reply = msg.getReply();
        final Context ctx = Contexts.lookup();
        final boolean showAll = msg.getInstancesSet().remove("verbose") || !msg.getInstancesSet().isEmpty();
        final boolean includeAllInstances = Objects.firstNonNull(msg.getIncludeAllInstances(), Boolean.FALSE);
        final Collection<String> identifiers = normalizeInstanceIdentifiers(msg.getInstancesSet());
        final Filter filter = Filters.generateFor(msg.getFilterSet(), VmInstance.class, "status")
                .withOptionalInternalFilter("instance-id", identifiers).generate();
        final Filter persistenceFilter = getPersistenceFilter(VmInstance.class, "status", identifiers,
                "instance-id", filter);
        final Predicate<? super VmInstance> requestedAndAccessible = CloudMetadatas.filteringFor(VmInstance.class)
                .byId(identifiers) // filters without wildcard support
                .byPredicate(includeAllInstances ? Predicates.<VmInstance>alwaysTrue() : VmInstance.VmState.RUNNING)
                .byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();
        final OwnerFullName ownerFullName = (ctx.isAdministrator() && showAll) ? null
                : ctx.getUserFullName().asAccountFullName();
        try {
            final List<VmInstance> instances = VmInstances.list(ownerFullName,
                    persistenceFilter.asCriterionWithConjunction(
                            Restrictions.not(VmInstance.criterion(VmInstance.VmState.BURIED))),
                    persistenceFilter.getAliases(),
                    Predicates.and(new TrackingPredicate<VmInstance>(identifiers), requestedAndAccessible));
            errorIfNotFound("InvalidInstanceID.NotFound", "instance ID", identifiers);
            Iterables.addAll(reply.getInstanceStatusSet().getItem(), Iterables.transform(instances,
                    TypeMappers.lookup(VmInstance.class, InstanceStatusItemType.class)));

        } catch (final Exception e) {
            Exceptions.findAndRethrow(e, ComputeServiceException.class);
            LOG.error(e);
            LOG.debug(e, e);
            throw new EucalyptusCloudException(e.getMessage());
        }
        return reply;
    }

    public DescribeInstanceAttributeResponseType describeInstanceAttribute(
            final DescribeInstanceAttributeType request) throws EucalyptusCloudException {
        final DescribeInstanceAttributeResponseType reply = request.getReply();
        final String instanceId = normalizeInstanceIdentifier(request.getInstanceId());
        final String attribute = request.getAttribute();
        if (attribute == null) {
            throw new ComputeServiceClientException(" MissingParameter", "Attribute parameter is required");
        }
        try (final TransactionResource tx = Entities.transactionFor(VmInstance.class)) {
            final VmInstance vm = RestrictedTypes.doPrivileged(instanceId, VmInstance.class);
            reply.setInstanceId(instanceId);
            switch (attribute) {
            case "blockDeviceMapping":
                if (vm.getBootRecord().getMachine() instanceof BlockStorageImageInfo) {
                    final BlockStorageImageInfo bfebsInfo = (BlockStorageImageInfo) vm.getBootRecord().getMachine();
                    for (final VmVolumeAttachment volumeAttachment : vm.getBootRecord().getPersistentVolumes()) {
                        reply.getBlockDeviceMapping()
                                .add(new InstanceBlockDeviceMapping(
                                        volumeAttachment.getIsRootDevice() ? bfebsInfo.getRootDeviceName()
                                                : volumeAttachment.getDevice(),
                                        volumeAttachment.getVolumeId(), volumeAttachment.getStatus(),
                                        volumeAttachment.getAttachTime(), volumeAttachment.getDeleteOnTerminate()));
                    }
                }
                break;
            case "disableApiTermination":
                reply.setDisableApiTermination(false);
                break;
            case "ebsOptimized":
                reply.setEbsOptimized(false);
                break;
            case "groupSet":
                Iterables.addAll(reply.getGroupSet(), Iterables.transform(vm.getNetworkGroupIds(),
                        TypeMappers.lookup(NetworkGroupId.class, GroupItemType.class)));
                break;
            case "instanceInitiatedShutdownBehavior":
                reply.setInstanceInitiatedShutdownBehavior("stop");
                break;
            case "instanceType":
                reply.setInstanceType(vm.getBootRecord().getVmType().getDisplayName());
                break;
            case "kernel":
                reply.setKernel(vm.getKernelId());
                break;
            case "productCodes":
                reply.setProductCodes(false); // set some value so an empty wrapper can be included in the response
                break;
            case "ramdisk":
                reply.setRamdisk(vm.getRamdiskId());
                break;
            case "rootDeviceName":
                reply.setRootDeviceName(vm.getBootRecord().getMachine() == null ? null
                        : vm.getBootRecord().getMachine().getRootDeviceName());
                break;
            case "sourceDestCheck":
                reply.setSourceDestCheck(true);
                break;
            case "sriovNetSupport":
                reply.setSriovNetSupport(false);
                break;
            case "userData":
                reply.setUserData(vm.getUserData() == null ? "" : Base64.toBase64String(vm.getUserData()));
                break;
            default:
                throw new ComputeServiceClientException(" InvalidParameterValue",
                        "Invalid value for attribute (" + attribute + ")");
            }
        } catch (Exception ex) {
            LOG.error(ex);
            throw new ComputeServiceClientException("InvalidInstanceID.NotFound",
                    "The instance ID '" + instanceId + "' does not exist");
        }
        return reply;
    }

    public DescribeKeyPairsResponseType describeKeyPairs(DescribeKeyPairsType request) throws Exception {
        final DescribeKeyPairsResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final List<String> keyNames = request.getKeySet();
        final boolean showAll = keyNames.remove("verbose");
        final OwnerFullName ownerFullName = ctx.isAdministrator() && showAll ? null
                : Contexts.lookup().getUserFullName().asAccountFullName();
        final Filter filter = Filters.generate(request.getFilterSet(), SshKeyPair.class);
        final Filter persistenceFilter = getPersistenceFilter(SshKeyPair.class, keyNames, "key-name", filter);
        final Predicate<? super SshKeyPair> requestedAndAccessible = CloudMetadatas.filteringFor(SshKeyPair.class)
                .byId(keyNames).byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();
        final Iterable<SshKeyPair> keyPairs = KeyPairs.list(ownerFullName,
                Predicates.and(new TrackingPredicate<SshKeyPair>(keyNames), requestedAndAccessible),
                persistenceFilter.asCriterion(), persistenceFilter.getAliases());
        for (final SshKeyPair kp : keyPairs) {
            reply.getKeySet().add(new DescribeKeyPairsResponseItemType(kp.getDisplayName(), kp.getFingerPrint()));
        }
        errorIfNotFound("InvalidKeyPair.NotFound", "key pair", keyNames);
        return reply;
    }

    public CopySnapshotResponseType copySnapshot(final CopySnapshotType request) {
        final CopySnapshotResponseType reply = request.getReply();
        return reply;
    }

    public DescribePlacementGroupsResponseType describePlacementGroups(final DescribePlacementGroupsType request) {
        final DescribePlacementGroupsResponseType reply = request.getReply();
        return reply;
    }

    public DescribeReservedInstancesResponseType describeReservedInstances(
            final DescribeReservedInstancesType request) {
        return request.getReply();
    }

    public DescribeReservedInstancesListingsResponseType describeReservedInstancesListings(
            final DescribeReservedInstancesListingsType request) {
        return request.getReply();
    }

    public DescribeReservedInstancesModificationsResponseType describeReservedInstancesModifications(
            final DescribeReservedInstancesModificationsType request) {
        return request.getReply();
    }

    public DescribeReservedInstancesOfferingsResponseType describeReservedInstancesListings(
            final DescribeReservedInstancesOfferingsType request) {
        return request.getReply();
    }

    public CreateReservedInstancesListingResponseType createReservedInstancesListing(
            final CreateReservedInstancesListingType request) {
        return request.getReply();
    }

    public CancelReservedInstancesListingResponseType cancelReservedInstancesListing(
            final CancelReservedInstancesListingType request) {
        return request.getReply();
    }

    public ModifyReservedInstancesResponseType modifyReservedInstances(final ModifyReservedInstancesType request) {
        return request.getReply();
    }

    public PurchaseReservedInstancesOfferingResponseType purchaseReservedInstancesOffering(
            final PurchaseReservedInstancesOfferingType request) {
        return request.getReply();
    }

    public CancelSpotInstanceRequestsResponseType cancelSpotInstanceRequests(
            CancelSpotInstanceRequestsType request) {
        return request.getReply();
    }

    public CreateSpotDatafeedSubscriptionResponseType createSpotDatafeedSubscription(
            CreateSpotDatafeedSubscriptionType request) {
        return request.getReply();
    }

    public DeleteSpotDatafeedSubscriptionResponseType deleteSpotDatafeedSubscription(
            DeleteSpotDatafeedSubscriptionType request) {
        return request.getReply();
    }

    public DescribeSpotDatafeedSubscriptionResponseType describeSpotDatafeedSubscription(
            DescribeSpotDatafeedSubscriptionType request) {
        return request.getReply();
    }

    public DescribeSpotInstanceRequestsResponseType describeSpotInstances(
            DescribeSpotInstanceRequestsType request) {
        return request.getReply();
    }

    public RequestSpotInstancesResponseType requestSpotInstances(RequestSpotInstancesType request) {
        return request.getReply();
    }

    public CancelSpotFleetRequestsResponseType cancelSpotFleetRequests(CancelSpotFleetRequestsType request) {
        return request.getReply();
    }

    public DescribeSpotFleetInstancesResponseType describeSpotFleetInstances(
            DescribeSpotFleetInstancesType request) {
        return request.getReply();
    }

    public DescribeSpotFleetRequestHistoryResponseType describeSpotFleetRequestHistory(
            DescribeSpotFleetRequestHistoryType request) {
        return request.getReply();
    }

    public DescribeSpotFleetRequestsResponseType describeSpotFleetRequests(DescribeSpotFleetRequestsType request) {
        return request.getReply();
    }

    public RequestSpotFleetResponseType requestSpotFleet(RequestSpotFleetType request) {
        return request.getReply();
    }

    /**
     *
     */
    public DescribeVolumesResponseType describeVolumes(DescribeVolumesType request) throws Exception {
        final DescribeVolumesResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();

        final boolean showAll = request.getVolumeSet().remove("verbose");
        final Set<String> volumeIds = Sets.newLinkedHashSet(normalizeVolumeIdentifiers(request.getVolumeSet()));
        final AccountFullName ownerFullName = (ctx.isAdministrator() && (showAll || !volumeIds.isEmpty())) ? null
                : ctx.getUserFullName().asAccountFullName();

        final Filters.FiltersBuilder filtersBuilder = Filters.generateFor(request.getFilterSet(), Volume.class);
        if (!ctx.isAdministrator()) {
            filtersBuilder.withOptionalInternalFilter("system-managed", Collections.singleton("false"));
        }
        final Filter filter = filtersBuilder.generate();
        final Filter persistenceFilter = getPersistenceFilter(Volume.class, volumeIds, "volume-id", filter);
        final Predicate<? super Volume> requestedAndAccessible = CloudMetadatas.filteringFor(Volume.class)
                .byId(volumeIds).byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();

        final Function<Set<String>, Pair<Set<String>, ArrayList<com.eucalyptus.compute.common.Volume>>> populateVolumeSet = new Function<Set<String>, Pair<Set<String>, ArrayList<com.eucalyptus.compute.common.Volume>>>() {
            public Pair<Set<String>, ArrayList<com.eucalyptus.compute.common.Volume>> apply(
                    final Set<String> input) {
                final Set<String> allowedVolumeIds = Sets.newHashSet();
                final ArrayList<com.eucalyptus.compute.common.Volume> replyVolumes = Lists.newArrayList();
                final List<Volume> volumes = Entities.query(Volume.named(ownerFullName, null), true,
                        persistenceFilter.asCriterion(), persistenceFilter.getAliases());
                final Iterable<Volume> filteredVolumes = Iterables.filter(volumes,
                        Predicates.and(new TrackingPredicate<Volume>(volumeIds), requestedAndAccessible));

                // load attachment info
                final Criterion attachmentCriterion;
                final Map<String, String> attachmentAliases;
                if (Iterables.isEmpty(filteredVolumes)) {
                    attachmentCriterion = Restrictions.disjunction();
                    attachmentAliases = Collections.emptyMap();
                } else if (Iterables.size(Iterables.limit(filteredVolumes, 51)) < 50) { // small # load by id
                    attachmentCriterion = Restrictions.in("volumeId",
                            Sets.newHashSet(Iterables.transform(filteredVolumes, RestrictedTypes.toDisplayName())));
                    attachmentAliases = Collections.emptyMap();
                } else if (ownerFullName == null) { // load attachments for all accounts
                    attachmentCriterion = Restrictions.conjunction();
                    attachmentAliases = Collections.emptyMap();
                } else { // load all attachments for account
                    attachmentCriterion = Restrictions.eq("vmInstance.ownerAccountNumber",
                            ownerFullName.getAccountNumber());
                    ;
                    attachmentAliases = Collections.singletonMap("vmInstance", "vmInstance");
                }
                final Map<String, VmVolumeAttachment> attachmentMap = CollectionUtils.putAll(
                        Iterables.concat(
                                Entities.query(VmBootVolumeAttachment.example(), true, attachmentCriterion,
                                        attachmentAliases),
                                Entities.query(VmStandardVolumeAttachment.example(), true, attachmentCriterion,
                                        attachmentAliases)),
                        Maps.<String, VmVolumeAttachment>newHashMap(), VmVolumeAttachment.volumeId(),
                        Functions.<VmVolumeAttachment>identity());

                // build response volumes
                for (final Volume foundVol : filteredVolumes) {
                    allowedVolumeIds.add(foundVol.getDisplayName());
                    if (State.ANNIHILATED.equals(foundVol.getState())) {
                        Entities.delete(foundVol);
                        replyVolumes.add(foundVol.morph(new com.eucalyptus.compute.common.Volume()));
                    } else {
                        VmVolumeAttachment attachment = attachmentMap.get(foundVol.getDisplayName());
                        AttachedVolume attachedVolume = null;
                        if (attachment != null) {
                            attachedVolume = VmVolumeAttachment.asAttachedVolume(attachment.getVmInstance())
                                    .apply(attachment);
                        } else {
                            if (State.BUSY.equals(foundVol.getState())) {
                                foundVol.setState(State.EXTANT);
                            }
                        }
                        com.eucalyptus.compute.common.Volume msgTypeVolume = foundVol
                                .morph(new com.eucalyptus.compute.common.Volume());
                        if (attachedVolume != null) {
                            msgTypeVolume.setStatus("in-use");
                            msgTypeVolume.getAttachmentSet().add(attachedVolume);
                        }
                        replyVolumes.add(msgTypeVolume);
                    }
                }
                return Pair.pair(allowedVolumeIds, replyVolumes);
            }
        };

        final Pair<Set<String>, ArrayList<com.eucalyptus.compute.common.Volume>> volumeIdsAndVolumes = Entities
                .asTransaction(Volume.class, populateVolumeSet).apply(volumeIds);
        errorIfNotFound("InvalidVolume.NotFound", "volume", volumeIds);
        @SuppressWarnings("ConstantConditions")
        final Set<String> allowedVolumeIds = volumeIdsAndVolumes.getLeft();
        reply.setVolumeSet(volumeIdsAndVolumes.getRight());

        Map<String, List<Tag>> tagsMap = TagSupport.forResourceClass(Volume.class)
                .getResourceTagMap(AccountFullName.getInstance(ctx.getAccountNumber()), allowedVolumeIds);
        for (final com.eucalyptus.compute.common.Volume volume : reply.getVolumeSet()) {
            Tags.addFromTags(volume.getTagSet(), ResourceTag.class, tagsMap.get(volume.getVolumeId()));
        }

        return reply;
    }

    public DescribeVolumeStatusResponseType describeVolumeStatus(final DescribeVolumeStatusType request)
            throws EucalyptusCloudException {
        final DescribeVolumeStatusResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final boolean showAll = request.getVolumeId().remove("verbose");
        final Set<String> volumeIds = Sets.newLinkedHashSet(normalizeVolumeIdentifiers(request.getVolumeId()));
        final AccountFullName ownerFullName = (ctx.isAdministrator() && (showAll || !volumeIds.isEmpty())) ? null
                : ctx.getUserFullName().asAccountFullName();
        final Filters.FiltersBuilder filtersBuilder = Filters.generateFor(request.getFilterSet(), Volume.class,
                "status");
        if (!ctx.isAdministrator()) {
            filtersBuilder.withOptionalInternalFilter("system-managed", Collections.singleton("false"));
        }
        final Filter filter = filtersBuilder.generate();
        final Filter persistenceFilter = getPersistenceFilter(Volume.class, "status", volumeIds, "volume-id",
                filter);
        final Predicate<? super Volume> requestedAndAccessible = CloudMetadatas.filteringFor(Volume.class)
                .byId(volumeIds).byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();
        final Function<Volume, VolumeStatusItemType> volumeTransform = TypeMappers.lookup(Volume.class,
                VolumeStatusItemType.class);
        final Function<Set<String>, ArrayList<VolumeStatusItemType>> populateVolumeSet = new Function<Set<String>, ArrayList<VolumeStatusItemType>>() {
            public ArrayList<VolumeStatusItemType> apply(final Set<String> input) {
                final ArrayList<VolumeStatusItemType> replyVolumes = Lists.newArrayList();
                final List<Volume> volumes = Entities.query(Volume.named(ownerFullName, null), true,
                        persistenceFilter.asCriterion(), persistenceFilter.getAliases());
                final Iterable<Volume> filteredVolumes = Iterables.filter(volumes,
                        Predicates.and(new TrackingPredicate<Volume>(volumeIds), requestedAndAccessible));
                for (final Volume foundVol : filteredVolumes) {
                    if (State.ANNIHILATED.equals(foundVol.getState())) {
                        Entities.delete(foundVol);
                    }
                    replyVolumes.add(volumeTransform.apply(foundVol));
                }
                return replyVolumes;
            }
        };
        final ArrayList<VolumeStatusItemType> volumeStatusItemTypes = Entities
                .asTransaction(Volume.class, populateVolumeSet).apply(volumeIds);
        errorIfNotFound("InvalidVolume.NotFound", "volume", volumeIds);
        reply.setVolumeStatusSet(volumeStatusItemTypes);
        return reply;
    }

    public DescribeSnapshotsResponseType describeSnapshots(final DescribeSnapshotsType request)
            throws EucalyptusCloudException {
        final DescribeSnapshotsResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final String requestAccountId = ctx.getUserFullName().getAccountNumber();
        // verbose does not have any special functionality for snapshots, but is ignored when passed as an identifier
        request.getSnapshotSet().remove("verbose");
        final Set<String> snapshotIds = Sets.newHashSet(normalizeSnapshotIdentifiers(request.getSnapshotSet()));
        final List<String> ownersSet = request.getOwnersSet();
        if (ownersSet.remove(Snapshots.SELF)) {
            ownersSet.add(requestAccountId);
        }
        final Filter filter = Filters.generate(request.getFilterSet(), Snapshot.class);
        final Filter persistenceFilter = getPersistenceFilter(Snapshot.class, snapshotIds, "snapshot-id", filter);
        try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(Snapshot.class)) {
            final List<Snapshot> unfilteredSnapshots = Entities.query(Snapshot.named(null, null), true,
                    persistenceFilter.asCriterion(), persistenceFilter.getAliases());
            final Predicate<? super Snapshot> requestedAndAccessible = CloudMetadatas.filteringFor(Snapshot.class)
                    .byId(snapshotIds).byOwningAccount(request.getOwnersSet())
                    .byPredicate(Snapshots.filterRestorableBy(request.getRestorableBySet(), requestAccountId))
                    .byPredicate(filter.asPredicate()).byPredicate(Snapshots.FilterPermissions.INSTANCE)
                    .byPrivilegesWithoutOwner().buildPredicate();

            final List<Snapshot> snapshots = Lists.newArrayList(Iterables.filter(unfilteredSnapshots,
                    Predicates.and(new TrackingPredicate<>(snapshotIds), requestedAndAccessible)));
            errorIfNotFound("InvalidSnapshot.NotFound", "snapshot", snapshotIds);
            final Map<String, List<Tag>> tagsMap = TagSupport.forResourceClass(Snapshot.class).getResourceTagMap(
                    AccountFullName.getInstance(ctx.getAccountNumber()),
                    Iterables.transform(snapshots, CloudMetadatas.toDisplayName()));
            for (final Snapshot snap : snapshots) {
                try {
                    final com.eucalyptus.compute.common.Snapshot snapReply = snap
                            .morph(new com.eucalyptus.compute.common.Snapshot());
                    Tags.addFromTags(snapReply.getTagSet(), ResourceTag.class,
                            tagsMap.get(snapReply.getSnapshotId()));
                    snapReply.setVolumeId(snap.getParentVolume());
                    snapReply.setOwnerId(snap.getOwnerAccountNumber());
                    reply.getSnapshotSet().add(snapReply);
                } catch (NoSuchElementException e) {
                    LOG.warn("Error getting snapshot information from the Storage Controller: " + e);
                    LOG.debug(e, e);
                }
            }
        }
        return reply;
    }

    public DescribeSnapshotAttributeResponseType describeSnapshotAttribute(DescribeSnapshotAttributeType request)
            throws EucalyptusCloudException {
        DescribeSnapshotAttributeResponseType reply = request.getReply();
        reply.setSnapshotId(request.getSnapshotId());
        final Context ctx = Contexts.lookup();
        final String snapshotId = normalizeSnapshotIdentifier(request.getSnapshotId());
        try (TransactionResource db = Entities.transactionFor(Snapshot.class)) {
            Snapshot result = Entities.uniqueResult(Snapshot
                    .named(ctx.isAdministrator() ? null : ctx.getUserFullName().asAccountFullName(), snapshotId));
            if (!RestrictedTypes.filterPrivileged().apply(result)) {
                throw new EucalyptusCloudException(
                        "Not authorized to describe attributes for snapshot " + request.getSnapshotId());
            }

            ArrayList<CreateVolumePermissionItemType> permissions = Lists.newArrayList();
            for (String id : result.getPermissions()) {
                permissions.add(new CreateVolumePermissionItemType(id, null));
            }
            if (result.getSnapshotPublic()) {
                permissions.add(new CreateVolumePermissionItemType(null, "all"));
            }

            if (result.getProductCodes() != null) {
                reply.setProductCodes(new ArrayList<>(result.getProductCodes()));
            }
            reply.setCreateVolumePermission(permissions);
        } catch (NoSuchElementException ex2) {
            throw new ComputeServiceClientException("InvalidSnapshot.NotFound",
                    "The snapshot '" + request.getSnapshotId() + "' does not exist.");
        } catch (ExecutionException ex1) {
            throw new EucalyptusCloudException(ex1.getCause());
        }
        return reply;
    }

    public DescribeVolumeAttributeResponseType describeVolumeAttribute(DescribeVolumeAttributeType request) {
        return request.getReply();
    }

    public CancelImportTaskResponseType cancelImportTask(CancelImportTaskType request) {
        return request.getReply();
    }

    public DescribeImportImageTasksResponseType describeImportImageTasks(DescribeImportImageTasksType request) {
        return request.getReply();
    }

    public DescribeImportSnapshotTasksResponseType describeImportSnapshotTasks(
            DescribeImportSnapshotTasksType request) {
        return request.getReply();
    }

    public ImportImageResponseType importImage(ImportImageType request) {
        return request.getReply();
    }

    public ImportSnapshotResponseType importSnapshot(ImportSnapshotType request) {
        return request.getReply();
    }

    public DescribeTagsResponseType describeTags(final DescribeTagsType request) throws Exception {
        final DescribeTagsResponseType reply = request.getReply();
        final Context context = Contexts.lookup();

        final Filter filter = Filters.generate(request.getFilterSet(), Tag.class);
        final Predicate<? super Tag> requestedAndAccessible = CloudMetadatas.filteringFor(Tag.class)
                .byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();
        final Ordering<Tag> ordering = Ordering.natural().onResultOf(Tags.resourceId())
                .compound(Ordering.natural().onResultOf(Tags.key()))
                .compound(Ordering.natural().onResultOf(Tags.value()));
        Iterables.addAll(reply.getTagSet(),
                Iterables.transform(
                        ordering.sortedCopy(Tags.list(context.getUserFullName().asAccountFullName(),
                                requestedAndAccessible, filter.asCriterion(), filter.getAliases())),
                        TypeMappers.lookup(Tag.class, TagInfo.class)));

        return reply;
    }

    public DescribeAccountAttributesResponseType describeAccountAttributes(
            final DescribeAccountAttributesType request) throws EucalyptusCloudException {
        final DescribeAccountAttributesResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final List<String> platforms = Lists.newArrayList();
        final Set<NetworkingFeature> features = Networking.getInstance().describeFeatures();
        if (features.contains(NetworkingFeature.Classic))
            platforms.add("EC2");
        if (features.contains(NetworkingFeature.Vpc))
            platforms.add("VPC");
        String vpcId = "none";
        try {
            vpcId = vpcs.lookupDefault(accountFullName, CloudMetadatas.toDisplayName());
        } catch (VpcMetadataNotFoundException e) {
            // no default vpc
        } catch (Exception e) {
            throw handleException(e);
        }
        final Map<String, List<String>> attributes = ImmutableMap.of("supported-platforms", platforms,
                "default-vpc", Lists.newArrayList(vpcId));
        final Set<String> requestedAttributes = Sets.newHashSet(request.attributeNames());
        for (final Map.Entry<String, List<String>> attributeEntry : attributes.entrySet()) {
            if (requestedAttributes.isEmpty() || requestedAttributes.contains(attributeEntry.getKey())) {
                reply.getAccountAttributeSet().getItem()
                        .add(new AccountAttributeSetItemType(attributeEntry.getKey(), attributeEntry.getValue()));
            }
        }
        return reply;
    }

    public DescribeCustomerGatewaysResponseType describeCustomerGateways(DescribeCustomerGatewaysType request)
            throws EucalyptusCloudException {
        DescribeCustomerGatewaysResponseType reply = request.getReply();
        return reply;
    }

    public DescribeDhcpOptionsResponseType describeDhcpOptions(final DescribeDhcpOptionsType request)
            throws EucalyptusCloudException {
        final DescribeDhcpOptionsResponseType reply = request.getReply();
        describe(Identifier.dopt, request.dhcpOptionsIds(), request.getFilterSet(), DhcpOptionSet.class,
                DhcpOptionsType.class, reply.getDhcpOptionsSet().getItem(), DhcpOptionsType.id(), dhcpOptionSets);
        return reply;
    }

    public DescribeInternetGatewaysResponseType describeInternetGateways(final DescribeInternetGatewaysType request)
            throws EucalyptusCloudException {
        final DescribeInternetGatewaysResponseType reply = request.getReply();
        describe(Identifier.igw, request.internetGatewayIds(), request.getFilterSet(), InternetGateway.class,
                InternetGatewayType.class, reply.getInternetGatewaySet().getItem(), InternetGatewayType.id(),
                internetGateways);
        return reply;
    }

    public DescribeNetworkAclsResponseType describeNetworkAcls(final DescribeNetworkAclsType request)
            throws EucalyptusCloudException {
        final DescribeNetworkAclsResponseType reply = request.getReply();
        describe(Identifier.acl, request.networkAclIds(), request.getFilterSet(), NetworkAcl.class,
                NetworkAclType.class, reply.getNetworkAclSet().getItem(), NetworkAclType.id(), networkAcls);
        return reply;
    }

    public DescribeNetworkInterfaceAttributeResponseType describeNetworkInterfaceAttribute(
            final DescribeNetworkInterfaceAttributeType request) throws EucalyptusCloudException {
        final DescribeNetworkInterfaceAttributeResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        try {
            final NetworkInterface networkInterface = networkInterfaces.lookupByName(accountFullName,
                    Identifier.eni.normalize(request.getNetworkInterfaceId()),
                    new Function<NetworkInterface, NetworkInterface>() {
                        @Override
                        public NetworkInterface apply(final NetworkInterface networkInterface) {
                            Entities.initialize(networkInterface.getNetworkGroups());
                            return networkInterface;
                        }
                    });
            if (RestrictedTypes.filterPrivileged().apply(networkInterface)) {
                reply.setNetworkInterfaceId(networkInterface.getDisplayName());
                switch (request.getAttribute()) {
                case "attachment":
                    if (networkInterface.isAttached())
                        reply.setAttachment(TypeMappers.transform(networkInterface.getAttachment(),
                                NetworkInterfaceAttachmentType.class));
                    break;
                case "description":
                    reply.setDescription(new NullableAttributeValueType());
                    reply.getDescription().setValue(networkInterface.getDescription());
                    break;
                case "groupSet":
                    reply.setGroupSet(new GroupSetType(Collections2.transform(networkInterface.getNetworkGroups(),
                            TypeMappers.lookup(NetworkGroup.class, GroupItemType.class))));
                    break;
                case "sourceDestCheck":
                    reply.setSourceDestCheck(new AttributeBooleanValueType());
                    reply.getSourceDestCheck().setValue(networkInterface.getSourceDestCheck());
                    break;
                default:
                    throw new ComputeServiceClientException("InvalidParameterValue",
                            "Value (" + request.getAttribute()
                                    + ") for parameter attribute is invalid. Unknown network interface attribute");
                }
            }
        } catch (final Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public DescribeNetworkInterfacesResponseType describeNetworkInterfaces(
            final DescribeNetworkInterfacesType request) throws EucalyptusCloudException {
        final DescribeNetworkInterfacesResponseType reply = request.getReply();
        describe(Identifier.eni, request.networkInterfaceIds(), request.getFilterSet(), NetworkInterface.class,
                NetworkInterfaceType.class, reply.getNetworkInterfaceSet().getItem(), NetworkInterfaceType.id(),
                networkInterfaces);
        return reply;
    }

    public DescribeRouteTablesResponseType describeRouteTables(final DescribeRouteTablesType request)
            throws EucalyptusCloudException {
        final DescribeRouteTablesResponseType reply = request.getReply();
        describe(Identifier.rtb, request.routeTableIds(), request.getFilterSet(), RouteTable.class,
                RouteTableType.class, reply.getRouteTableSet().getItem(), RouteTableType.id(), routeTables);
        return reply;
    }

    public DescribeSubnetsResponseType describeSubnets(final DescribeSubnetsType request)
            throws EucalyptusCloudException {
        final DescribeSubnetsResponseType reply = request.getReply();
        describe(Identifier.subnet, request.subnetIds(), request.getFilterSet(), Subnet.class, SubnetType.class,
                reply.getSubnetSet().getItem(), SubnetType.id(), subnets);
        return reply;
    }

    public DescribeVpcAttributeResponseType describeVpcAttribute(final DescribeVpcAttributeType request)
            throws EucalyptusCloudException {
        final DescribeVpcAttributeResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        try {
            final Vpc vpc = vpcs.lookupByName(accountFullName, Identifier.vpc.normalize(request.getVpcId()),
                    Functions.<Vpc>identity());
            if (RestrictedTypes.filterPrivileged().apply(vpc)) {
                reply.setVpcId(vpc.getDisplayName());
                switch (request.getAttribute()) {
                case "enableDnsSupport":
                    reply.setEnableDnsSupport(new AttributeBooleanValueType());
                    reply.getEnableDnsSupport().setValue(vpc.getDnsEnabled());
                    break;
                case "enableDnsHostnames":
                    reply.setEnableDnsHostnames(new AttributeBooleanValueType());
                    reply.getEnableDnsHostnames().setValue(vpc.getDnsHostnames());
                    break;
                default:
                    throw new ComputeServiceClientException("InvalidParameterValue",
                            "Value (" + request.getAttribute()
                                    + ") for parameter attribute is invalid. Unknown vpc attribute");
                }
            }
        } catch (final Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public DescribeVpcPeeringConnectionsResponseType describeVpcPeeringConnections(
            DescribeVpcPeeringConnectionsType request) throws EucalyptusCloudException {
        DescribeVpcPeeringConnectionsResponseType reply = request.getReply();
        return reply;
    }

    public DescribeVpcsResponseType describeVpcs(final DescribeVpcsType request) throws EucalyptusCloudException {
        final DescribeVpcsResponseType reply = request.getReply();
        describe(Identifier.vpc, request.vpcIds(), request.getFilterSet(), Vpc.class, VpcType.class,
                reply.getVpcSet().getItem(), VpcType.id(), vpcs);
        return reply;
    }

    public DescribeVpnConnectionsResponseType describeVpnConnections(DescribeVpnConnectionsType request)
            throws EucalyptusCloudException {
        DescribeVpnConnectionsResponseType reply = request.getReply();
        return reply;
    }

    public DescribeVpnGatewaysResponseType describeVpnGateways(DescribeVpnGatewaysType request)
            throws EucalyptusCloudException {
        DescribeVpnGatewaysResponseType reply = request.getReply();
        return reply;
    }

    public DescribeMovingAddressesResponseType describeMovingAddresses(DescribeMovingAddressesType request) {
        return request.getReply();
    }

    public MoveAddressToVpcResponseType moveAddressToVpc(MoveAddressToVpcType request) {
        return request.getReply();
    }

    public RestoreAddressToClassicResponseType restoreAddressToClassic(RestoreAddressToClassicType request) {
        return request.getReply();
    }

    public AttachClassicLinkVpcResponseType attachClassicLinkVpc(AttachClassicLinkVpcType request) {
        return request.getReply();
    }

    public DescribeClassicLinkInstancesResponseType describeClassicLinkInstances(
            DescribeClassicLinkInstancesType request) {
        return request.getReply();
    }

    public DescribeVpcClassicLinkResponseType describeVpcClassicLink(DescribeVpcClassicLinkType request) {
        return request.getReply();
    }

    public DetachClassicLinkVpcResponseType detachClassicLinkVpc(DetachClassicLinkVpcType request) {
        return request.getReply();
    }

    public DisableVpcClassicLinkResponseType disableVpcClassicLink(DisableVpcClassicLinkType request) {
        return request.getReply();
    }

    public EnableVpcClassicLinkResponseType enableVpcClassicLink(EnableVpcClassicLinkType request) {
        return request.getReply();
    }

    public CreateVpcEndpointResponseType createVpcEndpoint(CreateVpcEndpointType request) {
        return request.getReply();
    }

    public DeleteVpcEndpointsResponseType deleteVpcEndpoints(DeleteVpcEndpointsType request) {
        return request.getReply();
    }

    public DescribePrefixListsResponseType describePrefixLists(DescribePrefixListsType request) {
        return request.getReply();
    }

    public DescribeVpcEndpointServicesResponseType describeVpcEndpointServices(
            DescribeVpcEndpointServicesType request) {
        return request.getReply();
    }

    public DescribeVpcEndpointsResponseType describeVpcEndpoints(DescribeVpcEndpointsType request) {
        return request.getReply();
    }

    public ModifyVpcEndpointResponseType modifyVpcEndpoint(ModifyVpcEndpointType request) {
        return request.getReply();
    }

    @Override
    public ComputeMessage onCall(final MuleEventContext muleEventContext) throws EucalyptusCloudException {
        final ComputeMessage request = (ComputeMessage) muleEventContext.getMessage().getPayload();
        return proxy(request);
    }

    private ComputeMessage proxy(final ComputeMessage request) throws EucalyptusCloudException {
        LOG.debug(request.toSimpleString());

        // Dispatch
        try {
            BaseMessage backendRequest = BaseMessages.deepCopy(request, getBackendMessageClass(request));
            final BaseMessage backendResponse = send(backendRequest);
            final ComputeMessage response = (ComputeMessage) BaseMessages.deepCopy(backendResponse,
                    request.getReply().getClass());
            response.setCorrelationId(request.getCorrelationId());
            LOG.debug(response.toSimpleString());
            return response;
        } catch (Exception e) {
            handleServiceException(e);
            Exceptions.findAndRethrow(e, EucalyptusWebServiceException.class, EucalyptusCloudException.class);
            throw new EucalyptusCloudException(e);
        }
    }

    private static <AP extends AbstractPersistent & CloudMetadata, AT extends VpcTagged> void describe(
            final Identifier identifier, final Collection<String> ids,
            final Collection<com.eucalyptus.compute.common.Filter> filters, final Class<AP> persistent,
            final Class<AT> api, final List<AT> results, final Function<AT, String> idFunction,
            final Lister<AP> lister) throws EucalyptusCloudException {
        final boolean showAll = ids.remove("verbose");
        final List<String> normalizedIds = identifier.normalize(ids);
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final OwnerFullName ownerFullName = ctx.isAdministrator() && (showAll || !normalizedIds.isEmpty()) ? null
                : accountFullName;
        final Filter filter = Filters.generate(filters, persistent);
        final Filter persistenceFilter = getPersistenceFilter(persistent, normalizedIds, identifier.getFilterName(),
                filter);
        final Predicate<? super AP> requestedAndAccessible = CloudMetadatas.filteringFor(persistent)
                .byId(normalizedIds).byPredicate(filter.asPredicate()).byPrivileges().buildPredicate();

        try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(persistent)) {
            results.addAll(
                    lister.list(ownerFullName, persistenceFilter.asCriterion(), persistenceFilter.getAliases(),
                            Predicates.and(new TrackingPredicate<>(normalizedIds), requestedAndAccessible),
                            TypeMappers.lookup(persistent, api)));

            identifier.errorIfNotFound(normalizedIds);

            populateTags(accountFullName, persistent, results, idFunction);
        } catch (Exception e) {
            throw handleException(e);
        }
    }

    private static <AP extends AbstractPersistent> Filter getPersistenceFilter(final Class<AP> persistent,
            final Collection<String> identifiers, final String identifierFilterName, final Filter filter)
            throws InvalidFilterException {
        return getPersistenceFilter(persistent, Filters.DEFAULT_FILTERS, identifiers, identifierFilterName, filter);
    }

    private static <AP extends AbstractPersistent> Filter getPersistenceFilter(final Class<AP> persistent,
            final String qualifier, final Collection<String> identifiers, final String identifierFilterName,
            final Filter filter) throws InvalidFilterException {
        return !identifiers.isEmpty()
                ? Filters.generateFor(Collections.<com.eucalyptus.compute.common.Filter>emptySet(), persistent,
                        qualifier).withOptionalInternalFilter(identifierFilterName, identifiers).generate()
                : filter;
    }

    private static boolean canModifyImage(final ImageInfo imgInfo) {
        final Context ctx = Contexts.lookup();
        final String requestAccountId = ctx.getUserFullName().getAccountNumber();
        return (ctx.isAdministrator() || imgInfo.getOwnerAccountNumber().equals(requestAccountId))
                && RestrictedTypes.filterPrivileged().apply(imgInfo);
    }

    private static <VT extends VpcTagged> void populateTags(final AccountFullName accountFullName,
            final Class<? extends CloudMetadata> resourceType, final List<? extends VT> items,
            final Function<? super VT, String> idFunction) {
        final Map<String, List<Tag>> tagsMap = TagSupport.forResourceClass(resourceType)
                .getResourceTagMap(accountFullName, Iterables.transform(items, idFunction));
        for (final VT item : items) {
            final ResourceTagSetType tags = new ResourceTagSetType();
            Tags.addFromTags(tags.getItem(), ResourceTagSetItemType.class, tagsMap.get(idFunction.apply(item)));
            if (!tags.getItem().isEmpty()) {
                item.setTagSet(tags);
            }
        }
    }

    private static String imageIdentifier(final String identifier) throws EucalyptusCloudException {
        if (!CloudMetadatas.isImageIdentifier(identifier))
            throw new EucalyptusCloudException("Invalid id: " + "\"" + identifier + "\"");
        return normalizeImageIdentifier(identifier);
    }

    private static String normalizeInstanceIdentifier(final String identifier) throws EucalyptusCloudException {
        try {
            return ResourceIdentifiers.parse(VmInstance.ID_PREFIX, identifier).getIdentifier();
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidInstanceID.Malformed",
                    "Invalid id: \"" + e.getIdentifier() + "\"");
        }
    }

    private static List<String> normalizeInstanceIdentifiers(final List<String> identifiers)
            throws EucalyptusCloudException {
        try {
            return ResourceIdentifiers.normalize(VmInstance.ID_PREFIX, identifiers);
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidInstanceID.Malformed",
                    "Invalid id: \"" + e.getIdentifier() + "\"");
        }
    }

    private static String normalizeIdentifier(final String identifier, final String prefix, final boolean required,
            final String message) throws ComputeServiceClientException {
        try {
            return Strings.emptyToNull(identifier) == null && !required ? null
                    : ResourceIdentifiers.parse(prefix, identifier).getIdentifier();
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidParameterValue",
                    String.format(message, e.getIdentifier()));
        }
    }

    private static String normalizeImageIdentifier(final String identifier) throws EucalyptusCloudException {
        return normalizeIdentifier(identifier, null, true, "Value (%s) for parameter image is invalid.");
    }

    @Nullable
    private static String normalizeOptionalImageIdentifier(final String identifier)
            throws EucalyptusCloudException {
        return normalizeIdentifier(identifier, null, false, "Value (%s) for parameter image is invalid.");
    }

    private static List<String> normalizeImageIdentifiers(final List<String> identifiers)
            throws EucalyptusCloudException {
        try {
            return ResourceIdentifiers.normalize(identifiers);
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidParameterValue",
                    "Value (" + e.getIdentifier() + ") for parameter images is invalid.");
        }
    }

    private static List<String> normalizeVolumeIdentifiers(final List<String> identifiers)
            throws EucalyptusCloudException {
        try {
            return ResourceIdentifiers.normalize(Volume.ID_PREFIX, identifiers);
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidParameterValue",
                    "Value (" + e.getIdentifier() + ") for parameter volumes is invalid. Expected: 'vol-...'.");
        }
    }

    private static String normalizeSnapshotIdentifier(final String identifier) throws EucalyptusCloudException {
        return normalizeIdentifier(identifier, Snapshot.ID_PREFIX, true,
                "Value (%s) for parameter snapshotId is invalid. Expected: 'snap-...'.");
    }

    private static List<String> normalizeSnapshotIdentifiers(final List<String> identifiers)
            throws EucalyptusCloudException {
        try {
            return ResourceIdentifiers.normalize(Snapshot.ID_PREFIX, identifiers);
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidParameterValue",
                    "Value (" + e.getIdentifier() + ") for parameter snapshots is invalid. Expected: 'snap-...'.");
        }
    }

    private enum Identifier {
        acl("networkAcl", "network-acl-id", "InvalidNetworkAclID.NotFound"), dopt("DHCPOption", "dhcp-options-id",
                "InvalidDhcpOptionID.NotFound"), eni("networkInterface", "network-interface-id",
                        "InvalidNetworkInterfaceID.NotFound"), igw("internetGateway", "internet-gateway-id",
                                "InvalidInternetGatewayID.NotFound"), rtb("routeTable", "route-table-id",
                                        "InvalidRouteTableID.NotFound"), subnet("subnet", "subnet-id",
                                                "InvalidSubnetID.NotFound"), vpc("vpc", "vpc-id",
                                                        "InvalidVpcID.NotFound"),;

        private final String code;
        private final String defaultParameter;
        private final String defaultListParameter;
        private final String filterName;
        private final String notFoundErrorCode;

        Identifier(final String defaultParameter, final String filterName, final String notFoundErrorCode) {
            this(defaultParameter, defaultParameter + "s", filterName, notFoundErrorCode);
        }

        Identifier(final String defaultParameter, final String defaultListParameter, final String filterName,
                final String notFoundErrorCode) {
            this.code = "InvalidParameterValue";
            this.defaultParameter = defaultParameter;
            this.defaultListParameter = defaultListParameter;
            this.filterName = filterName;
            this.notFoundErrorCode = notFoundErrorCode;
        }

        public String getFilterName() {
            return filterName;
        }

        public String generate() {
            return ResourceIdentifiers.generateString(name());
        }

        public String normalize(final String identifier) throws EucalyptusCloudException {
            return normalize(identifier, defaultParameter);
        }

        public String normalize(final String identifier, final String parameter) throws EucalyptusCloudException {
            return normalize(Collections.singleton(identifier), parameter).get(0);
        }

        public List<String> normalize(final Iterable<String> identifiers) throws EucalyptusCloudException {
            return normalize(identifiers, defaultListParameter);
        }

        public List<String> normalize(final Iterable<String> identifiers, final String parameter)
                throws EucalyptusCloudException {
            try {
                return ResourceIdentifiers.normalize(name(), identifiers);
            } catch (final InvalidResourceIdentifier e) {
                throw new ComputeServiceClientException(code, "Value (" + e.getIdentifier() + ") for parameter "
                        + parameter + " is invalid. Expected: '" + name() + "-...'.");
            }
        }

        public void errorIfNotFound(final Iterable<String> identifiers) throws EucalyptusCloudException {
            ComputeService.errorIfNotFound(notFoundErrorCode, defaultParameter + " ID", identifiers);

            if (Iterables.size(identifiers) == 1) {
                throw new ComputeServiceClientException(notFoundErrorCode, "The " + defaultParameter + " ID '"
                        + Iterables.getOnlyElement(identifiers) + "' does not exist");
            } else if (!Iterables.isEmpty(identifiers)) {
                final Iterable<String> quotedIdentifiers = Iterables.transform(identifiers,
                        Functions.compose(append("'"), prepend("'")));
                throw new ComputeServiceClientException(notFoundErrorCode, "The " + defaultParameter + " IDs "
                        + Joiner.on(", ").join(quotedIdentifiers) + " do not exist");
            }
        }
    }

    private static void errorIfNotFound(final String notFoundErrorCode, final String identifierDescription,
            final Iterable<String> identifiers) throws EucalyptusCloudException {
        if (Iterables.size(identifiers) == 1) {
            throw new ComputeServiceClientException(notFoundErrorCode, "The " + identifierDescription + " '"
                    + Iterables.getOnlyElement(identifiers) + "' does not exist");
        } else if (!Iterables.isEmpty(identifiers)) {
            final Iterable<String> quotedIdentifiers = Iterables.transform(identifiers,
                    Functions.compose(append("'"), prepend("'")));
            throw new ComputeServiceClientException(notFoundErrorCode, "The " + identifierDescription + "s "
                    + Joiner.on(", ").join(quotedIdentifiers) + " do not exist");
        }
    }

    private static List<String> normalizeGroupIdentifiers(final List<String> identifiers)
            throws EucalyptusCloudException {
        try {
            return ResourceIdentifiers.normalize(NetworkGroup.ID_PREFIX, identifiers);
        } catch (final InvalidResourceIdentifier e) {
            throw new ComputeServiceClientException("InvalidGroupId.Malformed",
                    "Invalid id: \"" + e.getIdentifier() + "\" (expecting \"sg-...\")");
        }
    }

    private enum SecurityGroupItemToGroupId implements Function<SecurityGroupItemType, String> {
        INSTANCE {
            @Override
            public String apply(SecurityGroupItemType securityGroupItemType) {
                return securityGroupItemType.getGroupId();
            }
        }
    }

    private static Class getBackendMessageClass(final BaseMessage request) throws BindingException {
        final Binding binding = BindingManager.getDefaultBinding();
        return binding.getElementClass("Eucalyptus." + request.getClass().getSimpleName());
    }

    private static BaseMessage send(final BaseMessage request) throws Exception {
        try {
            return AsyncRequests.sendSyncWithCurrentIdentity(Topology.lookup(Eucalyptus.class), request);
        } catch (final NoSuchElementException e) {
            throw new ComputeServiceUnavailableException("Service Unavailable");
        } catch (final ServiceDispatchException e) {
            final ComponentException componentException = Exceptions.findCause(e, ComponentException.class);
            if (componentException != null && componentException.getCause() instanceof Exception) {
                throw (Exception) componentException.getCause();
            }
            throw e;
        } catch (final FailedRequestException e) {
            if (request.getReply().getClass().isInstance(e.getRequest())) {
                return e.getRequest();
            }
            throw e.getRequest() == null ? e
                    : new ComputeServiceException("InternalError",
                            "Internal error " + e.getRequest().getClass().getSimpleName() + ":false");
        }
    }

    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
    private void handleServiceException(final Exception e) throws EucalyptusCloudException {
        final Optional<AsyncWebServiceError> serviceErrorOption = AsyncExceptions.asWebServiceError(e);
        if (serviceErrorOption.isPresent()) {
            final AsyncWebServiceError serviceError = serviceErrorOption.get();
            switch (serviceError.getHttpErrorCode()) {
            case 400:
                throw new ComputeServiceClientException(serviceError.getCode(), serviceError.getMessage());
            case 403:
                throw new ComputeServiceAuthorizationException(serviceError.getCode(), serviceError.getMessage());
            case 503:
                throw new ComputeServiceUnavailableException(serviceError.getMessage());
            default:
                throw new ComputeServiceException(serviceError.getCode(), serviceError.getMessage());
            }
        }
    }

    /**
     * Method always throws, signature allows use of "throw handleException ..."
     */
    private static ComputeServiceException handleException(final Exception e) throws ComputeServiceException {
        final ComputeServiceException cause = Exceptions.findCause(e, ComputeServiceException.class);
        if (cause != null) {
            throw cause;
        }

        final AuthQuotaException quotaCause = Exceptions.findCause(e, AuthQuotaException.class);
        if (quotaCause != null) {
            String code = "ResourceLimitExceeded";
            switch (quotaCause.getType()) {
            case "vpc":
                code = "VpcLimitExceeded";
                break;
            case "internet-gateway":
                code = "InternetGatewayLimitExceeded";
                break;
            }
            throw new ComputeServiceClientException(code,
                    "Request would exceed quota for type: " + quotaCause.getType());
        }

        LOG.error(e, e);

        final ComputeServiceException exception = new ComputeServiceException("InternalError",
                String.valueOf(e.getMessage()));
        if (Contexts.lookup().hasAdministrativePrivileges()) {
            exception.initCause(e);
        }
        throw exception;
    }

    private static class TrackingPredicate<T extends RestrictedType> implements Predicate<T> {
        private final Function<? super T, String> idFunction;
        private final Collection<String> identifiers;

        public TrackingPredicate(final Collection<String> identifiers) {
            this(CloudMetadatas.toDisplayName(), identifiers);
        }

        public TrackingPredicate(final Function<? super T, String> idFunction,
                final Collection<String> identifiers) {
            this.idFunction = idFunction;
            this.identifiers = identifiers;
        }

        @Override
        public boolean apply(@Nullable final T t) {
            if (t != null) {
                //noinspection StatementWithEmptyBody
                while (identifiers.remove(idFunction.apply(t)))
                    ;
            }
            return true;
        }
    }
}