com.eucalyptus.compute.vpc.VpcManager.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.compute.vpc.VpcManager.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.vpc;

import static com.google.common.base.Objects.firstNonNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Restrictions;
import org.hibernate.exception.ConstraintViolationException;
import com.eucalyptus.auth.Accounts;
import com.eucalyptus.auth.AuthQuotaException;
import com.eucalyptus.auth.principal.AccountFullName;
import com.eucalyptus.auth.principal.UserFullName;
import com.eucalyptus.auth.principal.UserPrincipal;
import com.eucalyptus.compute.common.internal.util.NoSuchMetadataException;
import com.eucalyptus.compute.common.internal.util.ResourceAllocationException;
import com.eucalyptus.cluster.Clusters;
import com.eucalyptus.component.annotation.ComponentNamed;
import com.eucalyptus.compute.ClientComputeException;
import com.eucalyptus.compute.ClientUnauthorizedComputeException;
import com.eucalyptus.compute.ComputeException;
import com.eucalyptus.compute.common.AttributeBooleanValueType;
import com.eucalyptus.compute.common.CloudMetadatas;
import com.eucalyptus.compute.common.DhcpConfigurationItemType;
import com.eucalyptus.compute.common.DhcpOptionsType;
import com.eucalyptus.compute.common.InternetGatewayType;
import com.eucalyptus.compute.common.NetworkAclType;
import com.eucalyptus.compute.common.NetworkInterfaceType;
import com.eucalyptus.compute.common.RouteTableType;
import com.eucalyptus.compute.common.SubnetType;
import com.eucalyptus.compute.common.VpcType;
import com.eucalyptus.compute.common.internal.identifier.InvalidResourceIdentifier;
import com.eucalyptus.compute.common.internal.identifier.ResourceIdentifiers;
import com.eucalyptus.compute.common.internal.vpc.DhcpOption;
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.NetworkAcl;
import com.eucalyptus.compute.common.internal.vpc.NetworkAclEntry;
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.Route;
import com.eucalyptus.compute.common.internal.vpc.RouteTable;
import com.eucalyptus.compute.common.internal.vpc.RouteTableAssociation;
import com.eucalyptus.compute.common.internal.vpc.RouteTables;
import com.eucalyptus.compute.common.internal.vpc.SecurityGroups;
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.entities.AbstractPersistent;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.network.IPRange;
import com.eucalyptus.compute.common.internal.network.NetworkGroup;
import com.eucalyptus.network.NetworkGroups;
import com.eucalyptus.compute.common.internal.network.NetworkPeer;
import com.eucalyptus.compute.common.internal.network.NetworkRule;
import com.eucalyptus.network.PrivateAddresses;
import com.eucalyptus.util.Callback;
import com.eucalyptus.util.Cidr;
import com.eucalyptus.util.CollectionUtils;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.util.Pair;
import com.eucalyptus.auth.type.RestrictedType;
import com.eucalyptus.util.RestrictedTypes;
import com.eucalyptus.util.TypeMappers;
import com.eucalyptus.util.dns.DomainNames;
import com.eucalyptus.vm.VmInstances;
import com.google.common.base.Enums;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;
import com.google.common.net.InetAddresses;
import com.google.common.net.InternetDomainName;
import com.google.common.primitives.Ints;
import com.eucalyptus.compute.common.backend.*;

/**
 *
 */
@SuppressWarnings({ "UnnecessaryLocalVariable", "UnusedDeclaration" })
@ComponentNamed
public class VpcManager {

    private static final Logger logger = Logger.getLogger(VpcManager.class);

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

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

    public AcceptVpcPeeringConnectionResponseType acceptVpcPeeringConnection(AcceptVpcPeeringConnectionType request)
            throws EucalyptusCloudException {
        AcceptVpcPeeringConnectionResponseType reply = request.getReply();
        return reply;
    }

    public AssignPrivateIpAddressesResponseType assignPrivateIpAddresses(AssignPrivateIpAddressesType request)
            throws EucalyptusCloudException {
        AssignPrivateIpAddressesResponseType reply = request.getReply();
        return reply;
    }

    public AssociateDhcpOptionsResponseType associateDhcpOptions(final AssociateDhcpOptionsType request)
            throws EucalyptusCloudException {
        final AssociateDhcpOptionsResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String dhcpOptionsId = "default".equals(request.getDhcpOptionsId()) ? "default"
                : Identifier.dopt.normalize(request.getDhcpOptionsId());
        final String vpcId = Identifier.vpc.normalize(request.getVpcId());
        try {
            vpcs.updateByExample(Vpc.exampleWithName(accountFullName, vpcId), accountFullName, request.getVpcId(),
                    new Callback<Vpc>() {
                        @Override
                        public void fire(final Vpc vpc) {
                            if (RestrictedTypes.filterPrivileged().apply(vpc))
                                try {
                                    final DhcpOptionSet dhcpOptionSet = "default".equals(dhcpOptionsId)
                                            ? dhcpOptionSets.lookupByExample(
                                                    DhcpOptionSet.exampleDefault(accountFullName), accountFullName,
                                                    "default", Predicates.alwaysTrue(),
                                                    Functions.<DhcpOptionSet>identity())
                                            : dhcpOptionSets.lookupByName(accountFullName, dhcpOptionsId,
                                                    Functions.<DhcpOptionSet>identity());
                                    vpc.setDhcpOptionSet(dhcpOptionSet);
                                } catch (VpcMetadataNotFoundException e) {
                                    throw Exceptions.toUndeclared(
                                            new ClientComputeException("InvalidDhcpOptionsID.NotFound",
                                                    "DHCP options not found '" + request.getDhcpOptionsId() + "'"));
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to associate DHCP options"));
                            }
                        }
                    });
            invalidate(vpcId);
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidVpcID.NotFound", "Vpc not found '" + request.getVpcId() + "'");
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public AssociateRouteTableResponseType associateRouteTable(final AssociateRouteTableType request)
            throws EucalyptusCloudException {
        final AssociateRouteTableResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String routeTableId = Identifier.rtb.normalize(request.getRouteTableId());
        final String subnetId = Identifier.subnet.normalize(request.getSubnetId());
        try {
            final RouteTable routeTable = routeTables.updateByExample(
                    RouteTable.exampleWithName(accountFullName, routeTableId), accountFullName,
                    request.getRouteTableId(), new Callback<RouteTable>() {
                        @Override
                        public void fire(final RouteTable routeTable) {
                            if (RestrictedTypes.filterPrivileged().apply(routeTable))
                                try {
                                    final Subnet subnet = subnets.lookupByName(accountFullName, subnetId,
                                            Functions.<Subnet>identity());

                                    if (!subnet.getVpc().getDisplayName()
                                            .equals(routeTable.getVpc().getDisplayName())) {
                                        throw Exceptions
                                                .toUndeclared(new ClientComputeException("InvalidParameterValue",
                                                        "Route table " + routeTableId + " and subnet " + subnetId
                                                                + " belong to different networks"));
                                    }

                                    if (!Iterables
                                            .tryFind(routeTable.getRouteTableAssociations(),
                                                    CollectionUtils.propertyPredicate(subnetId,
                                                            RouteTables.AssociationFilterStringFunctions.SUBNET_ID))
                                            .isPresent()) {
                                        routeTable.associate(subnet);
                                    }
                                } catch (VpcMetadataNotFoundException e) {
                                    throw Exceptions
                                            .toUndeclared(new ClientComputeException("InvalidSubnetID.NotFound",
                                                    "Subnet (" + request.getSubnetId() + ") not found"));
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to associate route table"));
                            }
                        }
                    });
            final RouteTableAssociation association = Iterables.find(routeTable.getRouteTableAssociations(),
                    CollectionUtils.propertyPredicate(subnetId,
                            RouteTables.AssociationFilterStringFunctions.SUBNET_ID));
            reply.setAssociationId(association.getAssociationId());
            invalidate(subnetId);
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidRouteTableID.NotFound",
                    "Route table not found '" + request.getRouteTableId() + "'");
        } catch (Exception e) {
            if (Exceptions.isCausedBy(e, ConstraintViolationException.class)) {
                throw new ClientComputeException("InvalidParameterValue",
                        "Subnet " + subnetId + " already associated.");
            }
            throw handleException(e);
        }
        return reply;
    }

    public AttachInternetGatewayResponseType attachInternetGateway(final AttachInternetGatewayType request)
            throws EucalyptusCloudException {
        final AttachInternetGatewayResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String gatewayId = Identifier.igw.normalize(request.getInternetGatewayId());
        final String vpcId = Identifier.vpc.normalize(request.getVpcId());
        try {
            internetGateways.updateByExample(InternetGateway.exampleWithName(accountFullName, gatewayId),
                    accountFullName, request.getInternetGatewayId(), new Callback<InternetGateway>() {
                        @Override
                        public void fire(final InternetGateway internetGateway) {
                            if (RestrictedTypes.filterPrivileged().apply(internetGateway))
                                try {
                                    final Vpc vpc = vpcs.lookupByName(accountFullName, vpcId,
                                            Functions.<Vpc>identity());
                                    if (internetGateway.getVpc() != null) {
                                        throw Exceptions.toUndeclared(
                                                new ClientComputeException("Resource.AlreadyAssociated",
                                                        "resource " + gatewayId + " is already attached to network "
                                                                + internetGateway.getVpc().getDisplayName()));
                                    }
                                    internetGateway.setVpc(vpc);
                                } catch (VpcMetadataNotFoundException e) {
                                    throw Exceptions.toUndeclared(new ClientComputeException(
                                            "InvalidVpcID.NotFound", "Vpc not found '" + request.getVpcId() + "'"));
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to attach internet gateway"));
                            }
                        }
                    });
            invalidate(vpcId);
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidInternetGatewayID.NotFound",
                    "Internet gateway (" + request.getInternetGatewayId() + ") not found ");
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public AttachNetworkInterfaceResponseType attachNetworkInterface(AttachNetworkInterfaceType request)
            throws EucalyptusCloudException {
        AttachNetworkInterfaceResponseType reply = request.getReply();
        return reply;
    }

    public AttachVpnGatewayResponseType attachVpnGateway(AttachVpnGatewayType request)
            throws EucalyptusCloudException {
        AttachVpnGatewayResponseType reply = request.getReply();
        return reply;
    }

    public CreateCustomerGatewayResponseType createCustomerGateway(CreateCustomerGatewayType request)
            throws EucalyptusCloudException {
        CreateCustomerGatewayResponseType reply = request.getReply();
        return reply;
    }

    public CreateDhcpOptionsResponseType createDhcpOptions(final CreateDhcpOptionsType request)
            throws EucalyptusCloudException {
        final CreateDhcpOptionsResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final Supplier<DhcpOptionSet> allocator = new Supplier<DhcpOptionSet>() {
            @Override
            public DhcpOptionSet get() {
                try {
                    final DhcpOptionSet dhcpOptionSet = DhcpOptionSet.create(ctx.getUserFullName(),
                            Identifier.dopt.generate());
                    for (final DhcpConfigurationItemType item : request.getDhcpConfigurationSet().getItem()) {
                        final List<String> values = item.values();
                        boolean validValue = false;
                        out: switch (item.getKey()) {
                        case DhcpOptionSets.DHCP_OPTION_DOMAIN_NAME:
                            validValue = values.size() == 1 && InternetDomainName.isValid(values.get(0));
                            break;
                        case DhcpOptionSets.DHCP_OPTION_DOMAIN_NAME_SERVERS:
                            validValue = values.size() == 1 && "AmazonProvidedDNS".equals(values.get(0));
                            if (validValue)
                                break; // else fallthrough
                        case DhcpOptionSets.DHCP_OPTION_NTP_SERVERS: // fallthrough
                        case DhcpOptionSets.DHCP_OPTION_NETBIOS_NAME_SERVERS:
                            for (final String value : values) {
                                validValue = InetAddresses.isInetAddress(value);
                                if (!validValue)
                                    break out;
                            }
                            break;
                        case DhcpOptionSets.DHCP_OPTION_NETBIOS_NODE_TYPE:
                            validValue = values.size() == 1 && Optional.fromNullable(Ints.tryParse(values.get(0)))
                                    .transform(
                                            Functions.forPredicate(Predicates.in(Lists.newArrayList(1, 2, 4, 8))))
                                    .or(false);
                            break;
                        default:
                            throw new ClientComputeException("InvalidParameterValue", "Value (" + item.getKey()
                                    + ") for parameter name is invalid. Unknown DHCP option");
                        }
                        if (!validValue || values.isEmpty()) {
                            throw new ClientComputeException("InvalidParameterValue",
                                    "Value (" + Joiner.on(',').join(values)
                                            + ") for parameter value is invalid. Invalid DHCP option value.");
                        }
                        dhcpOptionSet.getDhcpOptions()
                                .add(DhcpOption.create(dhcpOptionSet, item.getKey(), item.values()));
                    }
                    return dhcpOptionSets.save(dhcpOptionSet);
                } catch (Exception ex) {
                    throw Exceptions.toUndeclared(ex);
                }
            }
        };
        reply.setDhcpOptions(allocate(allocator, DhcpOptionSet.class, DhcpOptionsType.class));
        return reply;
    }

    public CreateInternetGatewayResponseType createInternetGateway(final CreateInternetGatewayType request)
            throws EucalyptusCloudException {
        final CreateInternetGatewayResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final Supplier<InternetGateway> allocator = new Supplier<InternetGateway>() {
            @Override
            public InternetGateway get() {
                try {
                    return internetGateways
                            .save(InternetGateway.create(ctx.getUserFullName(), Identifier.igw.generate()));
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        };
        reply.setInternetGateway(allocate(allocator, InternetGateway.class, InternetGatewayType.class));
        return reply;
    }

    public CreateNetworkAclResponseType createNetworkAcl(final CreateNetworkAclType request)
            throws EucalyptusCloudException {
        final CreateNetworkAclResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final String vpcId = Identifier.vpc.normalize(request.getVpcId());
        final Supplier<NetworkAcl> allocator = new Supplier<NetworkAcl>() {
            @Override
            public NetworkAcl get() {
                try {
                    final Vpc vpc = vpcs.lookupByName(ctx.getUserFullName().asAccountFullName(), vpcId,
                            Functions.<Vpc>identity());
                    final long networkAclsForVpc = networkAcls.countByExample(
                            NetworkAcl.exampleWithOwner(ctx.getUserFullName().asAccountFullName()),
                            Restrictions.eq("vpc.displayName", vpcId), Collections.singletonMap("vpc", "vpc"));
                    if (networkAclsForVpc >= VpcConfiguration.getNetworkAclsPerVpc()) {
                        throw new ClientComputeException("NetworkAclLimitExceeded",
                                "Network ACL limit exceeded for " + vpc.getDisplayName());
                    }
                    return networkAcls
                            .save(NetworkAcl.create(ctx.getUserFullName(), vpc, Identifier.acl.generate(), false));
                } catch (VpcMetadataNotFoundException ex) {
                    throw Exceptions.toUndeclared(new ClientComputeException("InvalidVpcID.NotFound",
                            "Vpc not found '" + request.getVpcId() + "'"));
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        };
        reply.setNetworkAcl(allocate(allocator, NetworkAcl.class, NetworkAclType.class));
        return reply;
    }

    public CreateNetworkAclEntryResponseType createNetworkAclEntry(final CreateNetworkAclEntryType request)
            throws EucalyptusCloudException {
        final CreateNetworkAclEntryResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String networkAclId = Identifier.acl.normalize(request.getNetworkAclId());
        final String cidr = request.getCidrBlock();
        final Optional<Cidr> cidrOptional = Cidr.parse().apply(cidr);
        if (!cidrOptional.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Cidr invalid: " + cidr);
        }
        final Optional<Integer> protocolOptional = protocolNumber(request.getProtocol());
        if (!protocolOptional.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Protocol invalid: " + request.getProtocol());
        }
        if (!Range.closed(1, 32766).apply(request.getRuleNumber())) {
            throw new ClientComputeException("InvalidParameterValue",
                    "Rule number invalid: " + request.getRuleNumber());
        }
        final Supplier<NetworkAclEntry> allocator = transactional(new Supplier<NetworkAclEntry>() {
            @Override
            public NetworkAclEntry get() {
                try {
                    networkAcls.updateByExample(NetworkAcl.exampleWithName(accountFullName, networkAclId),
                            accountFullName, request.getNetworkAclId(), new Callback<NetworkAcl>() {
                                @Override
                                public void fire(final NetworkAcl networkAcl) {
                                    if (RestrictedTypes.filterPrivileged().apply(networkAcl))
                                        try {
                                            final List<NetworkAclEntry> entries = networkAcl.getEntries();
                                            final Optional<NetworkAclEntry> existingEntry = Iterables.tryFind(
                                                    entries,
                                                    entryPredicate(request.getEgress(), request.getRuleNumber()));

                                            if (existingEntry.isPresent()) {
                                                throw new ClientComputeException("NetworkAclEntryAlreadyExists",
                                                        "Entry exists with rule number: "
                                                                + request.getRuleNumber());
                                            }

                                            if (CollectionUtils.reduce(entries, 0, CollectionUtils.count(
                                                    entryPredicate(request.getEgress(), null))) >= VpcConfiguration
                                                            .getRulesPerNetworkAcl()) {
                                                throw new ClientComputeException("NetworkAclEntryLimitExceeded",
                                                        "Network ACL entry limit exceeded for "
                                                                + request.getNetworkAclId());
                                            }

                                            final NetworkAclEntry entry;
                                            switch (protocolOptional.get()) {
                                            case 1:
                                                entry = NetworkAclEntry.createIcmpEntry(networkAcl,
                                                        request.getRuleNumber(),
                                                        Enums.valueOfFunction(NetworkAclEntry.RuleAction.class)
                                                                .apply(request.getRuleAction()),
                                                        request.getEgress(), cidr,
                                                        request.getIcmpTypeCode().getCode(),
                                                        request.getIcmpTypeCode().getType());
                                                break;
                                            case 6:
                                            case 17:
                                                entry = NetworkAclEntry.createTcpUdpEntry(networkAcl,
                                                        request.getRuleNumber(), protocolOptional.get(),
                                                        Enums.valueOfFunction(NetworkAclEntry.RuleAction.class)
                                                                .apply(request.getRuleAction()),
                                                        request.getEgress(), cidr, request.getPortRange().getFrom(),
                                                        request.getPortRange().getTo());
                                                break;
                                            default:
                                                entry = NetworkAclEntry.createEntry(networkAcl,
                                                        request.getRuleNumber(), protocolOptional.get(),
                                                        Enums.valueOfFunction(NetworkAclEntry.RuleAction.class)
                                                                .apply(request.getRuleAction()),
                                                        request.getEgress(), cidr);
                                            }

                                            entries.add(entry);
                                            networkAcl.updateTimeStamps(); // ensure version of table increments also
                                        } catch (Exception e) {
                                            throw Exceptions.toUndeclared(e);
                                        }
                                    else {
                                        throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                                "Not authorized to create network ACL entry"));
                                    }
                                }
                            });
                    return null;
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        });

        try {
            allocator.get();
            invalidate(networkAclId);
        } catch (Exception e) {
            throw handleException(e);
        }

        return reply;
    }

    public CreateNetworkInterfaceResponseType createNetworkInterface(final CreateNetworkInterfaceType request)
            throws EucalyptusCloudException {
        final CreateNetworkInterfaceResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String subnetId = Identifier.subnet.normalize(request.getSubnetId());
        final String privateIp = request.getPrivateIpAddress() != null ? request.getPrivateIpAddress()
                : request.getPrivateIpAddressesSet() != null
                        && !request.getPrivateIpAddressesSet().getItem().isEmpty()
                                ? request.getPrivateIpAddressesSet().getItem().get(0).getPrivateIpAddress()
                                : null;
        final Supplier<NetworkInterface> allocator = new Supplier<NetworkInterface>() {
            @Override
            public NetworkInterface get() {
                try {
                    final Subnet subnet = subnets.lookupByName(accountFullName, subnetId,
                            Functions.<Subnet>identity());
                    final Vpc vpc = subnet.getVpc();
                    final Set<NetworkGroup> groups = request.getGroupSet() == null
                            || request.getGroupSet().groupIds().isEmpty()
                                    ? Sets.newHashSet(securityGroups.lookupDefault(vpc.getDisplayName(),
                                            Functions.<NetworkGroup>identity()))
                                    : Sets.newHashSet(Iterables.transform(request.getGroupSet().groupIds(),
                                            RestrictedTypes.resolver(NetworkGroup.class)));
                    if (groups.size() > VpcConfiguration.getSecurityGroupsPerNetworkInterface()) {
                        throw new ClientComputeException("SecurityGroupsPerInterfaceLimitExceeded",
                                "Security group limit exceeded");
                    }
                    if (!Collections.singleton(vpc.getDisplayName())
                            .equals(Sets.newHashSet(Iterables.transform(groups, NetworkGroup.vpcId())))) {
                        throw Exceptions.toUndeclared(new ClientComputeException("InvalidParameterValue",
                                "Invalid security groups (inconsistent VPC)"));
                    }
                    final String identifier = Identifier.eni.generate();
                    if (privateIp != null) {
                        final Cidr cidr = Cidr.parse(subnet.getCidr());
                        if (!cidr.contains(privateIp)) {
                            throw new ClientComputeException("InvalidParameterValue",
                                    "Address does not fall within the subnet's address range");
                        } else if (!Iterables.contains(Iterables.skip(IPRange.fromCidr(cidr), 3),
                                PrivateAddresses.asInteger(privateIp))) {
                            throw new ClientComputeException("InvalidParameterValue",
                                    "Address is in subnet's reserved address range");
                        }
                    }
                    final String mac = NetworkInterfaceHelper.mac(identifier);
                    final String ip = NetworkInterfaceHelper.allocate(vpc.getDisplayName(), subnet.getDisplayName(),
                            identifier, mac, privateIp);
                    return networkInterfaces.save(NetworkInterface.create(ctx.getUserFullName(), vpc, subnet,
                            groups, identifier, mac, ip,
                            vpc.getDnsHostnames() ? VmInstances.dnsName(ip, DomainNames.internalSubdomain()) : null,
                            firstNonNull(request.getDescription(), "")));
                } catch (VpcMetadataNotFoundException ex) {
                    throw Exceptions.toUndeclared(new ClientComputeException("InvalidSubnetID.NotFound",
                            "Subnet not found '" + request.getSubnetId() + "'"));
                } catch (ResourceAllocationException ex) {
                    throw Exceptions
                            .toUndeclared(new ClientComputeException("InvalidParameterValue", ex.getMessage()));
                } catch (Exception ex) {
                    final NoSuchMetadataException e = Exceptions.findCause(ex, NoSuchMetadataException.class);
                    if (e != null) {
                        throw Exceptions.toUndeclared(
                                new ClientComputeException("InvalidSecurityGroupID.NotFound", e.getMessage()));
                    }
                    throw new RuntimeException(ex);
                }
            }
        };
        reply.setNetworkInterface(allocate(allocator, NetworkInterface.class, NetworkInterfaceType.class));
        return reply;
    }

    public CreateRouteResponseType createRoute(final CreateRouteType request) throws EucalyptusCloudException {
        final CreateRouteResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String gatewayId = Identifier.igw.normalize(request.getGatewayId());
        final String routeTableId = Identifier.rtb.normalize(request.getRouteTableId());
        final String destinationCidr = request.getDestinationCidrBlock();
        final Optional<Cidr> destinationCidrOption = Cidr.parse().apply(destinationCidr);
        if (!destinationCidrOption.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Cidr invalid: " + destinationCidr);
        }
        final Supplier<Route> allocator = transactional(new Supplier<Route>() {
            @Override
            public Route get() {
                try {
                    final InternetGateway internetGateway = internetGateways.lookupByName(accountFullName,
                            gatewayId, Functions.<InternetGateway>identity());
                    routeTables.updateByExample(RouteTable.exampleWithName(accountFullName, routeTableId),
                            accountFullName, request.getRouteTableId(), new Callback<RouteTable>() {
                                @Override
                                public void fire(final RouteTable routeTable) {
                                    try {
                                        if (RestrictedTypes.filterPrivileged().apply(routeTable)) {
                                            final Optional<Route> existingRoute = Iterables.tryFind(
                                                    routeTable.getRoutes(),
                                                    CollectionUtils.propertyPredicate(destinationCidr,
                                                            RouteTables.RouteFilterStringFunctions.DESTINATION_CIDR));

                                            if (existingRoute.isPresent()) {
                                                throw new ClientComputeException("RouteAlreadyExists",
                                                        "Route exists for cidr: " + destinationCidr);
                                            }

                                            if (routeTable.getRoutes().size() >= VpcConfiguration
                                                    .getRoutesPerTable()) {
                                                throw new ClientComputeException("RouteLimitExceeded",
                                                        "Route limit exceeded for " + request.getRouteTableId());
                                            }

                                            routeTable.getRoutes()
                                                    .add(Route.create(routeTable, Route.RouteOrigin.CreateRoute,
                                                            destinationCidr, internetGateway));
                                            routeTable.updateTimeStamps(); // ensure version of table increments also
                                        } else {
                                            throw new ClientUnauthorizedComputeException(
                                                    "Not authorized to create route");
                                        }
                                    } catch (Exception e) {
                                        throw Exceptions.toUndeclared(e);
                                    }
                                }
                            });
                    return null;
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        });

        try {
            allocator.get();
            invalidate(routeTableId);
        } catch (Exception e) {
            throw handleException(e);
        }

        return reply;
    }

    public CreateRouteTableResponseType createRouteTable(final CreateRouteTableType request)
            throws EucalyptusCloudException {
        final CreateRouteTableResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final String vpcId = Identifier.vpc.normalize(request.getVpcId());
        final Supplier<RouteTable> allocator = new Supplier<RouteTable>() {
            @Override
            public RouteTable get() {
                try {
                    final Vpc vpc = vpcs.lookupByName(ctx.getUserFullName().asAccountFullName(), vpcId,
                            Functions.<Vpc>identity());

                    final long routeTablesForVpc = routeTables.countByExample(
                            RouteTable.exampleWithOwner(ctx.getUserFullName().asAccountFullName()),
                            Restrictions.eq("vpc.displayName", vpcId), Collections.singletonMap("vpc", "vpc"));
                    if (routeTablesForVpc >= VpcConfiguration.getRouteTablesPerVpc()) {
                        throw new ClientComputeException(" RouteTableLimitExceeded",
                                "Route table limit exceeded for " + vpc.getDisplayName());
                    }
                    return routeTables.save(RouteTable.create(ctx.getUserFullName(), vpc, Identifier.rtb.generate(),
                            vpc.getCidr(), false));
                } catch (VpcMetadataNotFoundException ex) {
                    throw Exceptions.toUndeclared(new ClientComputeException("InvalidVpcID.NotFound",
                            "Vpc not found '" + request.getVpcId() + "'"));
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        };
        reply.setRouteTable(allocate(allocator, RouteTable.class, RouteTableType.class));
        return reply;
    }

    public CreateSubnetResponseType createSubnet(final CreateSubnetType request) throws EucalyptusCloudException {
        final CreateSubnetResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String vpcId = Identifier.vpc.normalize(request.getVpcId());
        final Optional<String> availabilityZone = Iterables.tryFind(Clusters.getInstance().listValues(),
                Predicates.and(
                        request.getAvailabilityZone() == null ? Predicates.<RestrictedType>alwaysTrue()
                                : CollectionUtils.propertyPredicate(request.getAvailabilityZone(),
                                        CloudMetadatas.toDisplayName()),
                        RestrictedTypes.filterPrivilegedWithoutOwner()))
                .transform(CloudMetadatas.toDisplayName());
        final Optional<Cidr> subnetCidr = Cidr.parse().apply(request.getCidrBlock());
        if (!subnetCidr.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Cidr invalid: " + request.getCidrBlock());
        }
        if (!availabilityZone.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue",
                    "Availability zone invalid: " + request.getAvailabilityZone());
        }
        final Supplier<Subnet> allocator = new Supplier<Subnet>() {
            @Override
            public Subnet get() {
                try {
                    final Vpc vpc = vpcs.lookupByName(accountFullName, vpcId, Functions.<Vpc>identity());
                    final Iterable<Subnet> subnetsInVpc = subnets.listByExample(
                            Subnet.exampleWithOwner(accountFullName), CollectionUtils
                                    .propertyPredicate(vpc.getDisplayName(), Subnets.FilterStringFunctions.VPC_ID),
                            Functions.<Subnet>identity());
                    if (Iterables.size(subnetsInVpc) >= VpcConfiguration.getSubnetsPerVpc()) {
                        throw new ClientComputeException("SubnetLimitExceeded",
                                "Subnet limit exceeded for " + vpc.getDisplayName());
                    }
                    if (!Cidr.parse(vpc.getCidr()).contains(subnetCidr.get())) {
                        throw new ClientComputeException("InvalidParameterValue",
                                "Cidr not valid for vpc " + request.getCidrBlock());
                    }
                    final Iterable<Cidr> existingCidrs = Iterables.transform(subnetsInVpc,
                            Functions.compose(Cidr.parseUnsafe(), Subnets.FilterStringFunctions.CIDR));
                    if (Iterables.any(existingCidrs, subnetCidr.get().contains())
                            || Iterables.any(existingCidrs, subnetCidr.get().containedBy())) {
                        throw new ClientComputeException("InvalidSubnet.Conflict",
                                "Cidr conflict for " + request.getCidrBlock());
                    }
                    final NetworkAcl networkAcl = networkAcls.lookupDefault(vpc.getDisplayName(),
                            Functions.<NetworkAcl>identity());
                    return subnets.save(Subnet.create(ctx.getUserFullName(), vpc, networkAcl,
                            Identifier.subnet.generate(), request.getCidrBlock(), availabilityZone.get()));
                } catch (VpcMetadataNotFoundException ex) {
                    throw Exceptions.toUndeclared(new ClientComputeException("InvalidVpcID.NotFound",
                            "Vpc not found '" + request.getVpcId() + "'"));
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        };
        reply.setSubnet(allocate(allocator, Subnet.class, SubnetType.class));
        invalidate(reply.getSubnet().getSubnetId());
        return reply;
    }

    public CreateVpcResponseType createVpc(final CreateVpcType request) throws EucalyptusCloudException {
        final CreateVpcResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final UserFullName userFullName = ctx.getUserFullName();
        final boolean createDefault = ctx.isAdministrator() && request.getCidrBlock().matches("[0-9]{12}");
        if (!Cidr.parse().apply(request.getCidrBlock()).transform(Cidr.prefix())
                .transform(Functions.forPredicate(Range.closed(16, 28))).or(createDefault)) {
            throw new ClientComputeException("InvalidVpcRange", "Cidr range invalid: " + request.getCidrBlock());
        }
        final Supplier<Vpc> allocator = new Supplier<Vpc>() {
            @Override
            public Vpc get() {
                try {
                    final String vpcCidr;
                    final AccountFullName vpcAccountFullName;
                    final UserFullName vpcOwnerFullName;
                    Vpc vpc = null;
                    RouteTable routeTable = null;
                    NetworkAcl networkAcl = null;
                    if (createDefault) {
                        final UserPrincipal user = Accounts.lookupPrincipalByAccountNumber(request.getCidrBlock());
                        vpcCidr = Vpcs.DEFAULT_VPC_CIDR;
                        vpcAccountFullName = AccountFullName.getInstance(user.getAccountNumber());
                        vpcOwnerFullName = UserFullName.getInstance(user);

                        // check for existing vpc
                        try {
                            vpc = vpcs.lookupDefault(vpcAccountFullName, Functions.<Vpc>identity());
                            routeTable = routeTables.lookupMain(vpc.getDisplayName(),
                                    Functions.<RouteTable>identity());
                            networkAcl = networkAcls.lookupDefault(vpc.getDisplayName(),
                                    Functions.<NetworkAcl>identity());
                        } catch (final VpcMetadataNotFoundException e) {
                            // so create it
                        }
                    } else {
                        vpcCidr = request.getCidrBlock();
                        vpcAccountFullName = userFullName.asAccountFullName();
                        vpcOwnerFullName = userFullName;
                    }
                    if (vpc == null) {
                        DhcpOptionSet options;
                        try {
                            options = dhcpOptionSets.lookupByExample(
                                    DhcpOptionSet.exampleDefault(vpcAccountFullName), vpcAccountFullName, "default",
                                    Predicates.alwaysTrue(), Functions.<DhcpOptionSet>identity());
                        } catch (VpcMetadataNotFoundException e) {
                            options = dhcpOptionSets.save(DhcpOptionSet.createDefault(vpcOwnerFullName,
                                    Identifier.dopt.generate(), VmInstances.INSTANCE_SUBDOMAIN));
                        }
                        vpc = vpcs.save(Vpc.create(vpcOwnerFullName, Identifier.vpc.generate(), options, vpcCidr,
                                createDefault));
                        routeTable = routeTables.save(RouteTable.create(vpcOwnerFullName, vpc,
                                Identifier.rtb.generate(), vpc.getCidr(), true));
                        networkAcl = networkAcls
                                .save(NetworkAcl.create(vpcOwnerFullName, vpc, Identifier.acl.generate(), true));
                        final NetworkGroup group = NetworkGroup.create(vpcOwnerFullName, vpc,
                                ResourceIdentifiers.generateString(NetworkGroup.ID_PREFIX),
                                NetworkGroups.defaultNetworkName(), "default VPC security group");
                        final Collection<NetworkPeer> peers = Lists.newArrayList(NetworkPeer
                                .create(group.getOwnerAccountNumber(), group.getName(), group.getGroupId()));
                        group.addNetworkRules(Lists.newArrayList(
                                NetworkRule.create(null/*protocol name*/, -1, null/*low port*/, null/*high port*/,
                                        peers, null/*cidrs*/ ),
                                NetworkRule.createEgress(null/*protocol name*/, -1, null/*low port*/,
                                        null/*high port*/, null/*peers*/, Collections.singleton("0.0.0.0/0"))));
                        securityGroups.save(group);
                    }
                    if (createDefault && routeTable != null && networkAcl != null) {
                        // ensure there is an internet gateway for the vpc and a route in place
                        InternetGateway internetGateway;
                        try {
                            internetGateway = internetGateways.lookupByVpc(vpcAccountFullName, vpc.getDisplayName(),
                                    Functions.<InternetGateway>identity());
                        } catch (final VpcMetadataNotFoundException e) {
                            internetGateway = internetGateways
                                    .save(InternetGateway.create(vpcOwnerFullName, Identifier.igw.generate()));
                            internetGateway.setVpc(vpc);
                        }

                        final Optional<Route> defaultRoute = Iterables.tryFind(routeTable.getRoutes(),
                                CollectionUtils.propertyPredicate("0.0.0.0/0",
                                        RouteTables.RouteFilterStringFunctions.DESTINATION_CIDR));

                        if (!defaultRoute.isPresent()) {
                            routeTable.getRoutes().add(Route.create(routeTable, Route.RouteOrigin.CreateRouteTable,
                                    "0.0.0.0/0", internetGateway));
                            routeTable.updateTimeStamps(); // ensure version of table increments also
                        }

                        // ensure there is a default subnet in each availability zone
                        final Set<String> cidrsInUse = Sets.newHashSet();
                        final Set<String> zonesWithoutSubnets = Sets.newTreeSet();
                        for (final String zone : Iterables.transform(Clusters.getInstance().listValues(),
                                CloudMetadatas.toDisplayName())) {
                            try {
                                cidrsInUse.add(subnets.lookupDefault(vpcAccountFullName, zone,
                                        Subnets.FilterStringFunctions.CIDR));
                            } catch (final VpcMetadataNotFoundException e) {
                                zonesWithoutSubnets.add(zone);
                            }
                        }
                        final List<String> subnetCidrs = Lists.newArrayList(
                                Iterables.transform(Cidr.parseUnsafe().apply(Vpcs.DEFAULT_VPC_CIDR).split(16),
                                        Functions.toStringFunction()));
                        subnetCidrs.removeAll(cidrsInUse);
                        for (final String zone : zonesWithoutSubnets) {
                            final Subnet subnet = subnets.save(Subnet.create(vpcOwnerFullName, vpc, networkAcl,
                                    Identifier.subnet.generate(), subnetCidrs.remove(0), zone));
                            subnet.setDefaultForAz(true);
                            subnet.setMapPublicIpOnLaunch(true);
                        }
                    }
                    return vpc;
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        };
        reply.setVpc(allocate(allocator, Vpc.class, VpcType.class));
        invalidate(reply.getVpc().getVpcId());
        return reply;
    }

    public CreateVpcPeeringConnectionResponseType createVpcPeeringConnection(CreateVpcPeeringConnectionType request)
            throws EucalyptusCloudException {
        CreateVpcPeeringConnectionResponseType reply = request.getReply();
        return reply;
    }

    public CreateVpnConnectionResponseType createVpnConnection(CreateVpnConnectionType request)
            throws EucalyptusCloudException {
        CreateVpnConnectionResponseType reply = request.getReply();
        return reply;
    }

    public CreateVpnConnectionRouteResponseType createVpnConnectionRoute(CreateVpnConnectionRouteType request)
            throws EucalyptusCloudException {
        CreateVpnConnectionRouteResponseType reply = request.getReply();
        return reply;
    }

    public CreateVpnGatewayResponseType createVpnGateway(CreateVpnGatewayType request)
            throws EucalyptusCloudException {
        CreateVpnGatewayResponseType reply = request.getReply();
        return reply;
    }

    public DeleteCustomerGatewayResponseType deleteCustomerGateway(DeleteCustomerGatewayType request)
            throws EucalyptusCloudException {
        DeleteCustomerGatewayResponseType reply = request.getReply();
        return reply;
    }

    public DeleteDhcpOptionsResponseType deleteDhcpOptions(final DeleteDhcpOptionsType request)
            throws EucalyptusCloudException {
        final DeleteDhcpOptionsResponseType reply = request.getReply();
        delete(Identifier.dopt, request.getDhcpOptionsId(),
                new Function<Pair<Optional<AccountFullName>, String>, DhcpOptionSet>() {
                    @Override
                    public DhcpOptionSet apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                        try {
                            final DhcpOptionSet dhcpOptionSet = dhcpOptionSets.lookupByName(
                                    accountAndId.getLeft().orNull(), accountAndId.getRight(),
                                    Functions.<DhcpOptionSet>identity());
                            if (RestrictedTypes.filterPrivileged().apply(dhcpOptionSet)) {
                                dhcpOptionSets.delete(dhcpOptionSet);
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to delete DHCP options"));
                            }
                            return null;
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                });
        return reply;
    }

    public DeleteInternetGatewayResponseType deleteInternetGateway(final DeleteInternetGatewayType request)
            throws EucalyptusCloudException {
        final DeleteInternetGatewayResponseType reply = request.getReply();
        delete(Identifier.igw, request.getInternetGatewayId(),
                new Function<Pair<Optional<AccountFullName>, String>, InternetGateway>() {
                    @Override
                    public InternetGateway apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                        try {
                            final InternetGateway internetGateway = internetGateways.lookupByName(
                                    accountAndId.getLeft().orNull(), accountAndId.getRight(),
                                    Functions.<InternetGateway>identity());
                            if (RestrictedTypes.filterPrivileged().apply(internetGateway)) {
                                internetGateways.delete(internetGateway);
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to delete internet gateway"));
                            }
                        } catch (VpcMetadataNotFoundException e) {
                            // so nothing to delete, move along
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                        return null;
                    }
                });
        return reply;
    }

    public DeleteNetworkAclResponseType deleteNetworkAcl(final DeleteNetworkAclType request)
            throws EucalyptusCloudException {
        final DeleteNetworkAclResponseType reply = request.getReply();
        delete(Identifier.acl, request.getNetworkAclId(),
                new Function<Pair<Optional<AccountFullName>, String>, NetworkAcl>() {
                    @Override
                    public NetworkAcl apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                        try {
                            final NetworkAcl networkAcl = networkAcls.lookupByName(accountAndId.getLeft().orNull(),
                                    accountAndId.getRight(), Functions.<NetworkAcl>identity());
                            if (RestrictedTypes.filterPrivileged().apply(networkAcl)) {
                                if (networkAcl.getDefaultForVpc()) {
                                    throw new ClientComputeException("InvalidParameterValue",
                                            "Cannot delete default network ACL " + accountAndId.getRight());
                                }
                                networkAcls.delete(networkAcl);
                            } else {
                                throw new ClientUnauthorizedComputeException(
                                        "Not authorized to delete network ACL");
                            }
                            return null;
                        } catch (Exception ex) {
                            throw Exceptions.toUndeclared(ex);
                        }
                    }
                });
        return reply;
    }

    public DeleteNetworkAclEntryResponseType deleteNetworkAclEntry(final DeleteNetworkAclEntryType request)
            throws EucalyptusCloudException {
        final DeleteNetworkAclEntryResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.isAdministrator() ? null
                : ctx.getUserFullName().asAccountFullName();
        final String networkAclId = Identifier.acl.normalize(request.getNetworkAclId());
        try {
            networkAcls.withRetries().updateByExample(NetworkAcl.exampleWithName(accountFullName, networkAclId),
                    accountFullName, request.getNetworkAclId(), new Callback<NetworkAcl>() {
                        @Override
                        public void fire(final NetworkAcl networkAcl) {
                            try {
                                if (RestrictedTypes.filterPrivileged().apply(networkAcl)) {
                                    final Optional<NetworkAclEntry> entry = Iterables.tryFind(
                                            networkAcl.getEntries(),
                                            entryPredicate(request.getEgress(), request.getRuleNumber()));
                                    if (entry.isPresent()) {
                                        networkAcl.getEntries().remove(entry.get());
                                        networkAcl.updateTimeStamps(); // ensure version of table increments also
                                    } else {
                                        throw new ClientComputeException("InvalidNetworkAclEntry.NotFound",
                                                "Entry not found for number: " + request.getRuleNumber());
                                    }
                                } else {
                                    throw new ClientUnauthorizedComputeException(
                                            "Not authorized to delete network ACL entry");
                                }
                            } catch (Exception e) {
                                throw Exceptions.toUndeclared(e);
                            }
                        }
                    });
            invalidate(networkAclId);
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public DeleteNetworkInterfaceResponseType deleteNetworkInterface(final DeleteNetworkInterfaceType request)
            throws EucalyptusCloudException {
        final DeleteNetworkInterfaceResponseType reply = request.getReply();
        delete(Identifier.eni, request.getNetworkInterfaceId(),
                new Function<Pair<Optional<AccountFullName>, String>, NetworkInterface>() {
                    @Override
                    public NetworkInterface apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                        try {
                            final NetworkInterface networkInterface = networkInterfaces.lookupByName(
                                    accountAndId.getLeft().orNull(), accountAndId.getRight(),
                                    Functions.<NetworkInterface>identity());
                            if (RestrictedTypes.filterPrivileged().apply(networkInterface)) {
                                if (networkInterface.isAttached()) {
                                    throw new ClientComputeException("" + "InvalidNetworkInterface.InUse",
                                            "The network interface is in use '" + request.getNetworkInterfaceId()
                                                    + "'");
                                }
                                NetworkInterfaceHelper.release(networkInterface);
                                networkInterfaces.delete(networkInterface);
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to delete network interface"));
                            }
                            return null;
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                });
        return reply;
    }

    public DeleteRouteResponseType deleteRoute(final DeleteRouteType request) throws EucalyptusCloudException {
        final DeleteRouteResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.isAdministrator() ? null
                : ctx.getUserFullName().asAccountFullName();
        final String routeTableId = Identifier.rtb.normalize(request.getRouteTableId());
        try {
            routeTables.withRetries().updateByExample(RouteTable.exampleWithName(accountFullName, routeTableId),
                    accountFullName, request.getRouteTableId(), new Callback<RouteTable>() {
                        @Override
                        public void fire(final RouteTable routeTable) {
                            try {
                                if (RestrictedTypes.filterPrivileged().apply(routeTable)) {
                                    final Optional<Route> route = Iterables.tryFind(routeTable.getRoutes(),
                                            CollectionUtils.propertyPredicate(request.getDestinationCidrBlock(),
                                                    RouteTables.RouteFilterStringFunctions.DESTINATION_CIDR));
                                    if (route.isPresent()) {
                                        routeTable.getRoutes().remove(route.get());
                                        routeTable.updateTimeStamps(); // ensure version of table increments also
                                    } else {
                                        throw new ClientComputeException("InvalidRoute.NotFound",
                                                "Route not found for cidr: " + request.getDestinationCidrBlock());
                                    }
                                } else {
                                    throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                            "Not authorized to delete route"));
                                }
                            } catch (Exception e) {
                                throw Exceptions.toUndeclared(e);
                            }
                        }
                    });
            invalidate(routeTableId);
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public DeleteRouteTableResponseType deleteRouteTable(final DeleteRouteTableType request)
            throws EucalyptusCloudException {
        final DeleteRouteTableResponseType reply = request.getReply();
        delete(Identifier.rtb, request.getRouteTableId(),
                new Function<Pair<Optional<AccountFullName>, String>, RouteTable>() {
                    @Override
                    public RouteTable apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                        try {
                            final RouteTable routeTable = routeTables.lookupByName(accountAndId.getLeft().orNull(),
                                    accountAndId.getRight(), Functions.<RouteTable>identity());
                            if (RestrictedTypes.filterPrivileged().apply(routeTable)) {
                                if (routeTable.getMain()) {
                                    throw new ClientComputeException("InvalidParameterValue",
                                            "Cannot delete main route table " + accountAndId.getRight());
                                }
                                routeTables.delete(routeTable);
                            } else {
                                throw new ClientUnauthorizedComputeException(
                                        "Not authorized to delete route table");
                            }
                            return null;
                        } catch (Exception ex) {
                            throw Exceptions.toUndeclared(ex);
                        }
                    }
                });
        return reply;
    }

    public DeleteSubnetResponseType deleteSubnet(final DeleteSubnetType request) throws EucalyptusCloudException {
        final DeleteSubnetResponseType reply = request.getReply();
        delete(Identifier.subnet, request.getSubnetId(),
                new Function<Pair<Optional<AccountFullName>, String>, Subnet>() {
                    @Override
                    public Subnet apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                        try {
                            final Subnet subnet = subnets.lookupByName(accountAndId.getLeft().orNull(),
                                    accountAndId.getRight(), Functions.<Subnet>identity());
                            if (RestrictedTypes.filterPrivileged().apply(subnet)) {
                                subnets.delete(subnet);
                            } else {
                                throw Exceptions.toUndeclared(
                                        new ClientUnauthorizedComputeException("Not authorized to delete subnet"));
                            }
                            return null;
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                });
        return reply;
    }

    public DeleteVpcResponseType deleteVpc(final DeleteVpcType request) throws EucalyptusCloudException {
        final DeleteVpcResponseType reply = request.getReply();
        delete(Identifier.vpc, request.getVpcId(), new Function<Pair<Optional<AccountFullName>, String>, Vpc>() {
            @Override
            public Vpc apply(final Pair<Optional<AccountFullName>, String> accountAndId) {
                try {
                    final Vpc vpc = vpcs.lookupByName(accountAndId.getLeft().orNull(), accountAndId.getRight(),
                            Functions.<Vpc>identity());
                    if (RestrictedTypes.filterPrivileged().apply(vpc)) {
                        if (Boolean.TRUE.equals(vpc.getDefaultVpc()) && Contexts.lookup().isAdministrator()) {
                            final List<Subnet> defaultSubnets = subnets
                                    .listByExample(
                                            Subnet.exampleDefault(
                                                    AccountFullName.getInstance(vpc.getOwnerAccountNumber()), null),
                                            Predicates.alwaysTrue(), Functions.<Subnet>identity());
                            for (final Subnet subnet : defaultSubnets) {
                                subnets.delete(subnet);
                            }
                            try {
                                final InternetGateway internetGateway = internetGateways.lookupByVpc(null,
                                        vpc.getDisplayName(), Functions.<InternetGateway>identity());
                                internetGateways.delete(internetGateway);
                            } catch (VpcMetadataNotFoundException e) {
                                /* so no need to delete */ }
                        }
                        try {
                            networkAcls.delete(networkAcls.lookupDefault(vpc.getDisplayName(),
                                    Functions.<NetworkAcl>identity()));
                        } catch (VpcMetadataNotFoundException e) {
                            /* so no need to delete */ }
                        try {
                            routeTables.delete(
                                    routeTables.lookupMain(vpc.getDisplayName(), Functions.<RouteTable>identity()));
                        } catch (VpcMetadataNotFoundException e) {
                            /* so no need to delete */ }
                        try {
                            securityGroups.delete(securityGroups.lookupDefault(vpc.getDisplayName(),
                                    Functions.<NetworkGroup>identity()));
                        } catch (VpcMetadataNotFoundException e) {
                            /* so no need to delete */ }
                        vpcs.delete(vpc);
                    } else {
                        throw Exceptions.toUndeclared(
                                new ClientUnauthorizedComputeException("Not authorized to delete vpc"));
                    }
                    return null;
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        });
        return reply;
    }

    public DeleteVpcPeeringConnectionResponseType deleteVpcPeeringConnection(DeleteVpcPeeringConnectionType request)
            throws EucalyptusCloudException {
        DeleteVpcPeeringConnectionResponseType reply = request.getReply();
        return reply;
    }

    public DeleteVpnConnectionResponseType deleteVpnConnection(DeleteVpnConnectionType request)
            throws EucalyptusCloudException {
        DeleteVpnConnectionResponseType reply = request.getReply();
        return reply;
    }

    public DeleteVpnConnectionRouteResponseType deleteVpnConnectionRoute(DeleteVpnConnectionRouteType request)
            throws EucalyptusCloudException {
        DeleteVpnConnectionRouteResponseType reply = request.getReply();
        return reply;
    }

    public DeleteVpnGatewayResponseType deleteVpnGateway(DeleteVpnGatewayType request)
            throws EucalyptusCloudException {
        DeleteVpnGatewayResponseType reply = request.getReply();
        return reply;
    }

    public DetachInternetGatewayResponseType detachInternetGateway(final DetachInternetGatewayType request)
            throws EucalyptusCloudException {
        final DetachInternetGatewayResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String gatewayId = Identifier.igw.normalize(request.getInternetGatewayId());
        final String vpcId = Identifier.vpc.normalize(request.getVpcId());
        try {
            internetGateways.updateByExample(InternetGateway.exampleWithName(accountFullName, gatewayId),
                    accountFullName, request.getInternetGatewayId(), new Callback<InternetGateway>() {
                        @Override
                        public void fire(final InternetGateway internetGateway) {
                            if (RestrictedTypes.filterPrivileged().apply(internetGateway))
                                try {
                                    final Vpc vpc = vpcs.lookupByName(accountFullName, vpcId,
                                            Functions.<Vpc>identity());
                                    if (internetGateway.getVpc() == null || !vpc.getDisplayName()
                                            .equals(internetGateway.getVpc().getDisplayName())) {
                                        throw Exceptions.toUndeclared(new ClientComputeException(
                                                "Gateway.NotAttached",
                                                "resource " + gatewayId + " is not attached to network " + vpcId));
                                    }
                                    internetGateway.setVpc(null);
                                } catch (VpcMetadataNotFoundException e) {
                                    throw Exceptions.toUndeclared(new ClientComputeException(
                                            "InvalidVpcID.NotFound", "Vpc not found '" + request.getVpcId() + "'"));
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to detach internet gateway"));
                            }
                        }
                    });
            invalidate(vpcId);
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidInternetGatewayID.NotFound",
                    "Internet gateway (" + request.getInternetGatewayId() + ") not found ");
        } catch (Exception e) {
            throw handleException(e);
        }

        return reply;
    }

    public DetachNetworkInterfaceResponseType detachNetworkInterface(DetachNetworkInterfaceType request)
            throws EucalyptusCloudException {
        DetachNetworkInterfaceResponseType reply = request.getReply();
        return reply;
    }

    public DetachVpnGatewayResponseType detachVpnGateway(DetachVpnGatewayType request)
            throws EucalyptusCloudException {
        DetachVpnGatewayResponseType reply = request.getReply();
        return reply;
    }

    public DisableVgwRoutePropagationResponseType disableVgwRoutePropagation(DisableVgwRoutePropagationType request)
            throws EucalyptusCloudException {
        DisableVgwRoutePropagationResponseType reply = request.getReply();
        return reply;
    }

    public DisassociateRouteTableResponseType disassociateRouteTable(final DisassociateRouteTableType request)
            throws EucalyptusCloudException {
        final DisassociateRouteTableResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String associationId = Identifier.rtbassoc.normalize(request.getAssociationId());
        try {
            final String subnetId = routeTables.updateByAssociationId(associationId, accountFullName,
                    new Function<RouteTable, String>() {
                        @Override
                        public String apply(final RouteTable routeTable) {
                            if (RestrictedTypes.filterPrivileged().apply(routeTable))
                                try {
                                    final RouteTableAssociation association = Iterables.find(
                                            routeTable.getRouteTableAssociations(),
                                            CollectionUtils.propertyPredicate(associationId,
                                                    RouteTables.AssociationFilterStringFunctions.ASSOCIATION_ID));
                                    if (association.getMain()) {
                                        throw new ClientComputeException("InvalidParameterValue",
                                                "Cannot disassociate the main route table association "
                                                        + request.getAssociationId());
                                    }
                                    routeTable.disassociate(associationId);
                                    return association.getSubnetId();
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            return null;
                        }
                    });
            if (subnetId != null)
                invalidate(subnetId);
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidAssociationID.NotFound",
                    "Route table association (" + request.getAssociationId() + ") not found ");
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public EnableVgwRoutePropagationResponseType enableVgwRoutePropagation(EnableVgwRoutePropagationType request)
            throws EucalyptusCloudException {
        EnableVgwRoutePropagationResponseType reply = request.getReply();
        return reply;
    }

    public ModifyNetworkInterfaceAttributeResponseType modifyNetworkInterfaceAttribute(
            final ModifyNetworkInterfaceAttributeType request) throws EucalyptusCloudException {
        final ModifyNetworkInterfaceAttributeResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String eniId = Identifier.eni.normalize(request.getNetworkInterfaceId());
        try {
            final AtomicBoolean invalidate = new AtomicBoolean(false);
            networkInterfaces.updateByExample(NetworkInterface.exampleWithName(accountFullName, eniId),
                    accountFullName, request.getNetworkInterfaceId(), new Callback<NetworkInterface>() {
                        @Override
                        public void fire(final NetworkInterface networkInterface) {
                            if (RestrictedTypes.filterPrivileged().apply(networkInterface)) {
                                if (request.getAttachment() != null) {
                                    if (networkInterface.isAttached() && networkInterface.getAttachment()
                                            .getAttachmentId().equals(request.getAttachment().getAttachmentId())) {
                                        networkInterface.getAttachment().setDeleteOnTerminate(
                                                request.getAttachment().getDeleteOnTermination());
                                    }
                                } else if (request.getDescription() != null) {
                                    networkInterface.setDescription(request.getDescription().getValue());
                                } else if (request.getGroupSet() != null
                                        && !request.getGroupSet().getItem().isEmpty()) {
                                    try {
                                        networkInterface.setNetworkGroups(Sets
                                                .newHashSet(Iterables.transform(request.getGroupSet().groupIds(),
                                                        RestrictedTypes.resolver(NetworkGroup.class))));
                                        if (!Collections.singleton(networkInterface.getVpc().getDisplayName())
                                                .equals(Sets.newHashSet(
                                                        Iterables.transform(networkInterface.getNetworkGroups(),
                                                                NetworkGroup.vpcId())))) {
                                            throw Exceptions.toUndeclared(
                                                    new ClientComputeException("InvalidParameterValue",
                                                            "Invalid security groups (inconsistent VPC)"));
                                        }
                                        if (networkInterface.getNetworkGroups().size() > VpcConfiguration
                                                .getSecurityGroupsPerNetworkInterface()) {
                                            throw Exceptions.toUndeclared(new ClientComputeException(
                                                    "SecurityGroupsPerInterfaceLimitExceeded",
                                                    "Security group limit exceeded"));
                                        }
                                        if (networkInterface.isAttached()
                                                && networkInterface.getAttachment().getDeviceIndex() == 0) {
                                            final Set<NetworkGroup> instanceGroups = networkInterface
                                                    .getAttachment().getInstance().getNetworkGroups();
                                            instanceGroups.clear();
                                            instanceGroups.addAll(networkInterface.getNetworkGroups());
                                        }
                                        invalidate.set(true);
                                    } catch (RuntimeException e) {
                                        final NoSuchMetadataException nsme = Exceptions.findCause(e,
                                                NoSuchMetadataException.class);
                                        if (nsme != null) {
                                            throw Exceptions.toUndeclared(new ClientComputeException(
                                                    "InvalidSecurityGroupID.NotFound", nsme.getMessage()));
                                        }
                                        throw e;
                                    }
                                } else if (request.getSourceDestCheck() != null) {
                                    networkInterface.setSourceDestCheck(request.getSourceDestCheck().getValue());
                                    invalidate.set(true);
                                } else {
                                    throw Exceptions.toUndeclared(new ClientComputeException("MissingParameter",
                                            "Missing attribute value"));
                                }
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to modify network interface attribute"));
                            }
                        }
                    });
            if (invalidate.get())
                invalidate(eniId);
        } catch (final Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public ModifySubnetAttributeResponseType modifySubnetAttribute(final ModifySubnetAttributeType request)
            throws EucalyptusCloudException {
        final ModifySubnetAttributeResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        try {
            subnets.updateByExample(
                    Subnet.exampleWithName(ctx.isAdministrator() ? null : accountFullName,
                            Identifier.subnet.normalize(request.getSubnetId())),
                    accountFullName, request.getSubnetId(), new Callback<Subnet>() {
                        @Override
                        public void fire(final Subnet subnet) {
                            if (RestrictedTypes.filterPrivileged().apply(subnet)) {
                                final AttributeBooleanValueType value = request.getMapPublicIpOnLaunch();
                                if (value != null && value.getValue() != null) {
                                    subnet.setMapPublicIpOnLaunch(value.getValue());
                                }
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to modify subnet attribute"));
                            }
                        }
                    });
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public ModifyVpcAttributeResponseType modifyVpcAttribute(final ModifyVpcAttributeType request)
            throws EucalyptusCloudException {
        final ModifyVpcAttributeResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        try {
            vpcs.updateByExample(
                    Vpc.exampleWithName(ctx.isAdministrator() ? null : accountFullName,
                            Identifier.vpc.normalize(request.getVpcId())),
                    accountFullName, request.getVpcId(), new Callback<Vpc>() {
                        @Override
                        public void fire(final Vpc vpc) {
                            if (RestrictedTypes.filterPrivileged().apply(vpc)) {
                                final AttributeBooleanValueType dnsHostnames = request.getEnableDnsHostnames();
                                if (dnsHostnames != null && dnsHostnames.getValue() != null) {
                                    vpc.setDnsHostnames(dnsHostnames.getValue());
                                }
                                final AttributeBooleanValueType dnsSupport = request.getEnableDnsSupport();
                                if (dnsSupport != null && dnsSupport.getValue() != null) {
                                    vpc.setDnsEnabled(dnsSupport.getValue());
                                }
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to modify VPC attribute"));
                            }
                        }
                    });
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public RejectVpcPeeringConnectionResponseType rejectVpcPeeringConnection(RejectVpcPeeringConnectionType request)
            throws EucalyptusCloudException {
        RejectVpcPeeringConnectionResponseType reply = request.getReply();
        return reply;
    }

    public ReplaceNetworkAclAssociationResponseType replaceNetworkAclAssociation(
            final ReplaceNetworkAclAssociationType request) throws EucalyptusCloudException {
        final ReplaceNetworkAclAssociationResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String networkAclId = Identifier.acl.normalize(request.getNetworkAclId());
        final String associationId = Identifier.aclassoc.normalize(request.getAssociationId());
        try {
            final Subnet subnet = subnets.updateByExample(
                    Subnet.exampleWithNetworkAclAssociation(accountFullName, associationId), accountFullName,
                    request.getAssociationId(), new Callback<Subnet>() {
                        @Override
                        public void fire(final Subnet subnet) {
                            if (RestrictedTypes.filterPrivileged().apply(subnet))
                                try {
                                    final NetworkAcl networkAcl = networkAcls.lookupByName(accountFullName,
                                            networkAclId, Functions.<NetworkAcl>identity());
                                    if (!subnet.getVpc().getDisplayName()
                                            .equals(networkAcl.getVpc().getDisplayName())) {
                                        throw new ClientComputeException("InvalidParameterValue",
                                                "Network ACL " + networkAclId + " and subnet "
                                                        + subnet.getDisplayName()
                                                        + " belong to different networks");
                                    }
                                    subnet.setNetworkAcl(networkAcl);
                                    subnet.setNetworkAclAssociationId(Identifier.aclassoc.generate());
                                } catch (VpcMetadataNotFoundException e) {
                                    throw Exceptions
                                            .toUndeclared(new ClientComputeException("InvalidNetworkAclID.NotFound",
                                                    "Network ACL not found '" + request.getAssociationId() + "'"));
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to replace network ACL association"));
                            }
                        }
                    });
            invalidate(networkAclId);
            reply.setNewAssociationId(subnet.getNetworkAclAssociationId());
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidAssociationID.NotFound",
                    "Network ACL association (" + request.getAssociationId() + ") not found ");
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public ReplaceNetworkAclEntryResponseType replaceNetworkAclEntry(final ReplaceNetworkAclEntryType request)
            throws EucalyptusCloudException {
        final ReplaceNetworkAclEntryResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String networkAclId = Identifier.acl.normalize(request.getNetworkAclId());
        final String cidr = request.getCidrBlock();
        final Optional<Cidr> cidrOptional = Cidr.parse().apply(cidr);
        if (!cidrOptional.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Cidr invalid: " + cidr);
        }
        final Optional<Integer> protocolOptional = protocolNumber(request.getProtocol());
        if (!protocolOptional.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Protocol invalid: " + request.getProtocol());
        }
        if (!Range.closed(1, 32766).apply(request.getRuleNumber())) {
            throw new ClientComputeException("InvalidParameterValue",
                    "Rule number invalid: " + request.getRuleNumber());
        }
        try {
            networkAcls.updateByExample(NetworkAcl.exampleWithName(accountFullName, networkAclId), accountFullName,
                    request.getNetworkAclId(), new Callback<NetworkAcl>() {
                        @Override
                        public void fire(final NetworkAcl networkAcl) {
                            if (RestrictedTypes.filterPrivileged().apply(networkAcl))
                                try {
                                    final List<NetworkAclEntry> entries = networkAcl.getEntries();
                                    final Optional<NetworkAclEntry> oldEntry = Iterables.tryFind(entries,
                                            entryPredicate(request.getEgress(), request.getRuleNumber()));

                                    if (!oldEntry.isPresent()) {
                                        throw new ClientComputeException("InvalidNetworkAclEntry.NotFound",
                                                "Entry not found for rule number: " + request.getRuleNumber());
                                    }

                                    final NetworkAclEntry entry;
                                    switch (protocolOptional.get()) {
                                    case 1:
                                        entry = NetworkAclEntry.createIcmpEntry(networkAcl, request.getRuleNumber(),
                                                Enums.valueOfFunction(NetworkAclEntry.RuleAction.class)
                                                        .apply(request.getRuleAction()),
                                                request.getEgress(), cidr, request.getIcmpTypeCode().getCode(),
                                                request.getIcmpTypeCode().getType());
                                        break;
                                    case 6:
                                    case 17:
                                        entry = NetworkAclEntry.createTcpUdpEntry(networkAcl,
                                                request.getRuleNumber(), protocolOptional.get(),
                                                Enums.valueOfFunction(NetworkAclEntry.RuleAction.class)
                                                        .apply(request.getRuleAction()),
                                                request.getEgress(), cidr, request.getPortRange().getFrom(),
                                                request.getPortRange().getTo());
                                        break;
                                    default:
                                        entry = NetworkAclEntry
                                                .createEntry(networkAcl, request.getRuleNumber(),
                                                        protocolOptional.get(),
                                                        Enums.valueOfFunction(NetworkAclEntry.RuleAction.class)
                                                                .apply(request.getRuleAction()),
                                                        request.getEgress(), cidr);
                                    }

                                    entries.set(entries.indexOf(oldEntry.get()), entry);
                                    networkAcl.updateTimeStamps(); // ensure version of table increments also
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to replace network ACL entry"));
                            }
                        }
                    });
            invalidate(networkAclId);
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public ReplaceRouteResponseType replaceRoute(final ReplaceRouteType request) throws EucalyptusCloudException {
        final ReplaceRouteResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String gatewayId = Identifier.igw.normalize(request.getGatewayId());
        final String routeTableId = Identifier.rtb.normalize(request.getRouteTableId());
        final String destinationCidr = request.getDestinationCidrBlock();
        final Optional<Cidr> destinationCidrOption = Cidr.parse().apply(destinationCidr);
        if (!destinationCidrOption.isPresent()) {
            throw new ClientComputeException("InvalidParameterValue", "Cidr invalid: " + destinationCidr);
        }
        try {
            routeTables.updateByExample(RouteTable.exampleWithName(accountFullName, routeTableId), accountFullName,
                    request.getRouteTableId(), new Callback<RouteTable>() {
                        @Override
                        public void fire(final RouteTable routeTable) {
                            if (RestrictedTypes.filterPrivileged().apply(routeTable))
                                try {
                                    final InternetGateway internetGateway = internetGateways.lookupByName(
                                            accountFullName, gatewayId, Functions.<InternetGateway>identity());

                                    final List<Route> routes = routeTable.getRoutes();
                                    final Optional<Route> oldRoute = Iterables.tryFind(routes,
                                            CollectionUtils.propertyPredicate(destinationCidr,
                                                    RouteTables.RouteFilterStringFunctions.DESTINATION_CIDR));

                                    if (!oldRoute.isPresent()) {
                                        throw new ClientComputeException("InvalidRoute.NotFound",
                                                "Route not found for cidr: " + destinationCidr);
                                    }

                                    routes.set(routes.indexOf(oldRoute.get()), Route.create(routeTable,
                                            Route.RouteOrigin.CreateRoute, destinationCidr, internetGateway));
                                    routeTable.updateTimeStamps(); // ensure version of table increments also
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(
                                        new ClientUnauthorizedComputeException("Not authorized to replace route"));
                            }
                        }
                    });
            invalidate(routeTableId);
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public ReplaceRouteTableAssociationResponseType replaceRouteTableAssociation(
            final ReplaceRouteTableAssociationType request) throws EucalyptusCloudException {
        final ReplaceRouteTableAssociationResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String routeTableId = Identifier.rtb.normalize(request.getRouteTableId());
        final String associationId = Identifier.rtbassoc.normalize(request.getAssociationId());
        try {
            final String newAssociationId = routeTables.updateByAssociationId(associationId, accountFullName,
                    new Function<RouteTable, String>() {
                        @Override
                        public String apply(final RouteTable routeTable) {
                            if (RestrictedTypes.filterPrivileged().apply(routeTable))
                                try {
                                    final RouteTable newRouteTable = routeTables.lookupByName(accountFullName,
                                            routeTableId, Functions.<RouteTable>identity());
                                    final RouteTableAssociation association = Iterables.find(
                                            routeTable.getRouteTableAssociations(),
                                            CollectionUtils.propertyPredicate(associationId,
                                                    RouteTables.AssociationFilterStringFunctions.ASSOCIATION_ID));
                                    if (!newRouteTable.getVpc().getDisplayName()
                                            .equals(routeTable.getVpc().getDisplayName())) {
                                        throw Exceptions.toUndeclared(new ClientComputeException(
                                                "InvalidParameterValue",
                                                "Route table " + routeTableId + " belongs to different network"));
                                    }
                                    final RouteTableAssociation oldAssociation = routeTable
                                            .disassociate(associationId);
                                    Entities.delete(oldAssociation);
                                    Entities.flush(oldAssociation);
                                    final RouteTableAssociation newAssociation;
                                    if (association.getMain()) { // replacing main route table for VPC
                                        newAssociation = newRouteTable.associateMain();
                                    } else {
                                        newAssociation = newRouteTable.associate(association.getSubnet());
                                    }
                                    return newAssociation.getAssociationId();
                                } catch (VpcMetadataNotFoundException e) {
                                    throw Exceptions
                                            .toUndeclared(new ClientComputeException("InvalidRouteTableID.NotFound",
                                                    "Route table not found '" + request.getRouteTableId() + "'"));
                                } catch (Exception e) {
                                    throw Exceptions.toUndeclared(e);
                                }
                            else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to replace route table association"));
                            }
                        }
                    });
            invalidate(routeTableId);
            reply.setNewAssociationId(newAssociationId);
        } catch (VpcMetadataNotFoundException e) {
            throw new ClientComputeException("InvalidAssociationID.NotFound",
                    "Route table association (" + request.getAssociationId() + ") not found ");
        } catch (Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public ResetNetworkInterfaceAttributeResponseType resetNetworkInterfaceAttribute(
            final ResetNetworkInterfaceAttributeType request) throws EucalyptusCloudException {
        final ResetNetworkInterfaceAttributeResponseType reply = request.getReply();
        final Context ctx = Contexts.lookup();
        final AccountFullName accountFullName = ctx.getUserFullName().asAccountFullName();
        final String eniId = Identifier.eni.normalize(request.getNetworkInterfaceId());
        try {
            networkInterfaces.updateByExample(NetworkInterface.exampleWithName(accountFullName, eniId),
                    accountFullName, request.getNetworkInterfaceId(), new Callback<NetworkInterface>() {
                        @Override
                        public void fire(final NetworkInterface networkInterface) {
                            if (RestrictedTypes.filterPrivileged().apply(networkInterface)) {
                                switch (request.getAttribute()) {
                                case "sourceDestCheck":
                                    networkInterface.setSourceDestCheck(true);
                                    break;
                                default:
                                    throw Exceptions.toUndeclared(new ClientComputeException(
                                            "InvalidParameterValue", "Value (" + request.getAttribute()
                                                    + ") for parameter attribute is invalid. Unknown network interface attribute"));
                                }
                            } else {
                                throw Exceptions.toUndeclared(new ClientUnauthorizedComputeException(
                                        "Not authorized to reset network interface attribute"));
                            }
                        }
                    });
            invalidate(eniId);
        } catch (final Exception e) {
            throw handleException(e);
        }
        return reply;
    }

    public UnassignPrivateIpAddressesResponseType unassignPrivateIpAddresses(UnassignPrivateIpAddressesType request)
            throws EucalyptusCloudException {
        UnassignPrivateIpAddressesResponseType reply = request.getReply();
        return reply;
    }

    private enum Identifier {
        acl("networkAcl"), aclassoc("networkAclAssociation"), dopt("DHCPOption"), eni("networkInterface"), igw(
                "internetGateway"), rtb(
                        "routeTable"), rtbassoc("routeTableAssociation"), subnet("subnet"), vpc("vpc"),;

        private final String code;
        private final String defaultParameter;
        private final String defaultListParameter;

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

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

        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 ClientComputeException(code, "Value (" + e.getIdentifier() + ") for parameter "
                        + parameter + " is invalid. Expected: '" + name() + "-...'.");
            }
        }
    }

    private <T extends AbstractPersistent & RestrictedType, AT> AT allocate(final Supplier<T> allocator,
            final Class<T> type, final Class<AT> apiType) throws EucalyptusCloudException {
        try {
            return TypeMappers.transform(
                    RestrictedTypes.allocateUnitlessResources(type, 1, transactional(allocator)).get(0), apiType);
        } catch (Exception e) {
            throw handleException(e, true);
        }
    }

    private <E extends AbstractPersistent> void delete(final Identifier identifier, final String idParam,
            final Function<Pair<Optional<AccountFullName>, String>, E> deleter) throws EucalyptusCloudException {
        final Context ctx = Contexts.lookup();
        final AccountFullName accountName = ctx.isAdministrator() ? null
                : ctx.getUserFullName().asAccountFullName();
        final String id = identifier.normalize(idParam);
        try {
            transactional(deleter).apply(Pair.lopair(accountName, id));
        } catch (Exception e) {
            if (Exceptions.isCausedBy(e, ConstraintViolationException.class)) {
                throw new ClientComputeException("DependencyViolation", "Resource (" + idParam + ") is in use");
            }
            if (!Exceptions.isCausedBy(e, VpcMetadataNotFoundException.class)) {
                throw handleException(e);
            } // else ignore missing on delete?
        }
    }

    protected <E extends AbstractPersistent> Supplier<E> transactional(final Supplier<E> supplier) {
        return Entities.asTransaction(supplier);
    }

    protected <E extends AbstractPersistent, P> Function<P, E> transactional(final Function<P, E> function) {
        return Entities.asTransaction(function);
    }

    private static Optional<Integer> protocolNumber(final String protocol) {
        switch (Objects.toString(protocol, "-1").toLowerCase()) {
        case "tcp":
        case "6":
            return Optional.of(6);
        case "udp":
        case "17":
            return Optional.of(17);
        case "icmp":
        case "1":
            return Optional.of(1);
        default:
            return Iterables.tryFind(Optional.fromNullable(Ints.tryParse(protocol)).asSet(), Range.closed(-1, 255));
        }
    }

    private static Predicate<NetworkAclEntry> entryPredicate(final Boolean egress, final Integer ruleNumber) {
        return Predicates.and(
                ruleNumber == null ? Predicates.<NetworkAclEntry>alwaysTrue()
                        : CollectionUtils.propertyPredicate(ruleNumber,
                                NetworkAcls.NetworkAclEntryFilterIntegerFunctions.RULE_NUMBER),
                CollectionUtils.propertyPredicate(egress,
                        NetworkAcls.NetworkAclEntryFilterBooleanFunctions.EGRESS));
    }

    private void invalidate(final String resourceIdentifier) {
        vpcInvalidator.invalidate(resourceIdentifier);
    }

    private static ComputeException handleException(final Exception e) throws ComputeException {
        throw handleException(e, false);
    }

    /**
     * Method always throws, signature allows use of "throw handleException ..."
     */
    private static ComputeException handleException(final Exception e, final boolean isCreate)
            throws ComputeException {
        final ComputeException cause = Exceptions.findCause(e, ComputeException.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 ClientComputeException(code, "Request would exceed quota for type: " + quotaCause.getType());
        }

        logger.error(e, e);

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