/*************************************************************************
* Copyright 2009-2016 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 java.util.NoSuchElementException;
import javax.annotation.Nonnull;
import org.apache.log4j.Logger;
import com.eucalyptus.address.Address;
import com.eucalyptus.address.Addresses;
import com.eucalyptus.auth.Accounts;
import com.eucalyptus.auth.AuthException;
import com.eucalyptus.auth.principal.AccountIdentifiers;
import com.eucalyptus.compute.ClientComputeException;
import com.eucalyptus.compute.ComputeException;
import com.eucalyptus.compute.common.internal.identifier.ResourceIdentifiers;
import com.eucalyptus.compute.common.internal.util.ResourceAllocationException;
import com.eucalyptus.compute.common.internal.vpc.NatGateway;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterfaceAssociation;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterfaceAttachment;
import com.eucalyptus.compute.common.internal.vpc.Subnet;
import com.eucalyptus.compute.common.internal.vpc.Vpc;
import com.eucalyptus.util.RestrictedTypes;
import com.eucalyptus.util.dns.DomainNames;
import com.eucalyptus.vm.VmInstances;
import com.google.common.base.Optional;
/**
*
*/
public class NatGatewayHelper {
private static final Logger logger = Logger.getLogger( NatGatewayHelper.class );
/**
* Caller must have open transaction for the NAT gateway and subnet.
*
* @param natGateway The NAT gateway to update
* @param subnet The subnet in which to create the network interface.
* @return The network interface to save
*/
static NetworkInterface createNetworkInterface(
@Nonnull final NatGateway natGateway,
@Nonnull final Subnet subnet
) throws ComputeException {
final Vpc vpc = subnet.getVpc( );
final String identifier = ResourceIdentifiers.generateString( "eni" );
final String mac = NetworkInterfaceHelper.mac( identifier );
final String accountNumber;
try {
accountNumber = Accounts.lookupAccountIdentifiersByAlias( AccountIdentifiers.SYSTEM_ACCOUNT ).getAccountNumber( );
} catch ( final AuthException e ) {
throw ( ComputeException )
new ComputeException( "InternalError", "Requester identifier lookup failure" ).initCause( e );
}
final String ip;
try {
ip = NetworkInterfaceHelper.allocate(
vpc.getDisplayName( ),
subnet.getDisplayName( ),
identifier,
mac, null );
} catch ( final ResourceAllocationException e ) {
throw new ClientComputeException(
"InsufficientFreeAddressesInSubnet", "Cannot allocate address for subnet " + subnet.getDisplayName( ) );
}
final NetworkInterface networkInterface = NetworkInterface.create(
natGateway.getOwner( ),
accountNumber,
vpc,
subnet,
identifier,
mac,
ip,
null,
"Interface for NAT Gateway " + natGateway.getDisplayName( ) );
networkInterface.attach( NetworkInterfaceAttachment.create(
ResourceIdentifiers.generateString( "ela-attach" ),
natGateway.getDisplayName( ),
NetworkInterfaceAttachment.Status.attached
) );
natGateway.attach( networkInterface );
return networkInterface;
}
/**
* Caller must have open transaction for NAT gateway
*/
static Address associatePublicAddress(
@Nonnull final NatGateway natGateway
) throws ComputeException {
final String allocationId = natGateway.getAllocationId( );
Address address;
try {
address = RestrictedTypes.resolver( Address.class ).apply( allocationId );
} catch ( final NoSuchElementException e ) {
address = null;
}
if ( address == null ) {
throw new ClientComputeException(
"InvalidAllocationID.NotFound", "Address not found for allocation (" + allocationId + ")" );
}
if ( address.isAssigned( ) ) {
throw new ClientComputeException(
"Resource.AlreadyAssociated", "Elastic IP address ["+allocationId+"] is already associated" );
}
final NetworkInterface networkInterface = natGateway.getNetworkInterface( );
Addresses.getInstance( ).assign( address, networkInterface );
networkInterface.associate( NetworkInterfaceAssociation.create(
address.getAssociationId( ),
address.getAllocationId( ),
address.getOwnerAccountNumber( ),
address.getDisplayName( ),
null
) );
natGateway.associate( address.getDisplayName( ), address.getAssociationId( ) );
return address;
}
/**
* Caller must have open transaction for NAT gateway
*
* @return The network interface to delete (if present)
*/
static Optional<NetworkInterface> cleanupResources( final NatGateway natGateway ) {
final NetworkInterface networkInterface = natGateway.getNetworkInterface( );
if ( networkInterface != null ) {
if ( networkInterface.isAttached( ) ) {
networkInterface.detach( );
}
if ( networkInterface.isAssociated( ) ) {
networkInterface.disassociate( );
}
}
final String associationId = natGateway.getAssociationId( );
if ( associationId != null ) {
Address address;
try {
address = RestrictedTypes.resolver( Address.class ).apply( associationId );
} catch ( final Exception e ) {
address = null;
}
if ( address != null ) {
Addresses.getInstance( ).unassign( address, associationId );
}
}
return Optional.fromNullable( networkInterface );
}
}