Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
EC2 VPC private addresses now owned by enis - EUCA-12558
Browse files Browse the repository at this point in the history
  • Loading branch information
sjones4 committed Jul 15, 2016
1 parent 783d0ca commit bbd029b
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,9 @@ class VmInstanceLifecycleHelpers {
builder.onBuild({ VmInstance instance ->
instance.updateMacAddress( resource.mac )
VmInstances.updatePrivateAddress( instance, resource.value )
PrivateAddresses.associate( resource.value, instance )
if ( !instance.vpcId ) {
PrivateAddresses.associate( resource.value, instance )
}
} as Callback<VmInstance>)
}
}
Expand Down Expand Up @@ -443,7 +445,9 @@ class VmInstanceLifecycleHelpers {
resource?.with{
instance.updateMacAddress( resource.mac )
VmInstances.updatePrivateAddress( instance, resource.value )
PrivateAddresses.associate( resource.value, instance )
if ( !instance.vpcId ) {
PrivateAddresses.associate( resource.value, instance )
}
}
}

Expand Down Expand Up @@ -1215,7 +1219,6 @@ class VmInstanceLifecycleHelpers {
final VpcNetworkInterfaceResource resource = resources.find{ NetworkResource networkResource ->
networkResource instanceof VpcNetworkInterfaceResource && ((VpcNetworkInterfaceResource)networkResource).device == 0
} as VpcNetworkInterfaceResource
if ( resource.privateIp!=null ) PrivateAddresses.associate( resource.privateIp, instance )
VpcNetworkInterface networkInterface = resource.mac == null ?
RestrictedTypes.resolver( VpcNetworkInterface ).apply( resource.value ) :
networkInterfaces.save( VpcNetworkInterface.create(
Expand All @@ -1233,6 +1236,9 @@ class VmInstanceLifecycleHelpers {
null as String,
firstNonNull( resource.description, "" )
) )
if ( resource.privateIp != null ) {
PrivateAddresses.associate( resource.privateIp, networkInterface )
}
instance.updateMacAddress( networkInterface.macAddress )
VmInstances.updatePrivateAddress( instance, networkInterface.privateIpAddress )
resource.privateIp = networkInterface.privateIpAddress
Expand Down Expand Up @@ -1270,9 +1276,6 @@ class VmInstanceLifecycleHelpers {
{ VpcNetworkInterfaceResource networkInterfaceResource -> networkInterfaceResource.device }
)
secondaryResources.each { VpcNetworkInterfaceResource secondaryResource ->
if ( secondaryResource.privateIp ) {
PrivateAddresses.associate( secondaryResource.privateIp, instance )
}
final Subnet subnet = secondaryResource.subnet == null ?
null :
RestrictedTypes.resolver( Subnet ).apply( secondaryResource.subnet )
Expand All @@ -1293,6 +1296,9 @@ class VmInstanceLifecycleHelpers {
null as String,
firstNonNull( secondaryResource.description, "" )
) )
if ( secondaryResource.privateIp ) {
PrivateAddresses.associate( secondaryResource.privateIp, secondaryNetworkInterface )
}
secondaryResource.privateIp = secondaryNetworkInterface.privateIpAddress
secondaryResource.mac = secondaryNetworkInterface.macAddress
secondaryNetworkInterface.attach( NetworkInterfaceAttachment.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ public NetworkInterface get( ) {
}
final String mac = NetworkInterfaceHelper.mac( identifier );
final String ip = NetworkInterfaceHelper.allocate( vpc.getDisplayName( ), subnet.getDisplayName( ), identifier, mac, privateIp );
return networkInterfaces.save( NetworkInterface.create(
final NetworkInterface networkInterface = networkInterfaces.save( NetworkInterface.create(
ctx.getUserFullName(),
vpc,
subnet,
Expand All @@ -703,6 +703,8 @@ public NetworkInterface get( ) {
VmInstances.dnsName( ip, DomainNames.internalSubdomain( ) ) :
null,
firstNonNull( request.getDescription( ), "" ) ) );
PrivateAddresses.associate( ip, networkInterface );
return networkInterface;
} catch ( VpcMetadataNotFoundException ex ) {
throw Exceptions.toUndeclared( new ClientComputeException( "InvalidSubnetID.NotFound", "Subnet not found '" + request.getSubnetId() + "'" ) );
} catch ( ResourceAllocationException ex ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class DatabasePrivateAddressPersistence implements PrivateAddressPersistence {
asTransaction( PrivateAddress, { PrivateAddress privateAddress ->
Entities.query( privateAddress )?.getAt( 0 )?.with{
PrivateAddress entity ->
if ( ownerId == null || entity.instanceId == ownerId ) {
if ( ownerId == null || entity.ownerId == ownerId ) {
Optional.fromNullable( closure.call( entity ) )
} else {
Optional.absent( )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ class EdgeNetworkingService extends NetworkingServiceSupport {
}
break
case PrivateIPResource:
releasePrivateIp( request.vpc, networkResource.value, networkResource.ownerId, networkResource.ownerId )
releasePrivateIp( request.vpc, networkResource.value, networkResource.ownerId )
break
case VpcNetworkInterfaceResource:
String ip = ((VpcNetworkInterfaceResource)networkResource).privateIp
releasePrivateIp( request.vpc, ip, networkResource.ownerId, networkResource.value )
releasePrivateIp( request.vpc, ip, networkResource.value )
break
}
}
Expand Down Expand Up @@ -169,7 +169,7 @@ class EdgeNetworkingService extends NetworkingServiceSupport {
vpcNetworkInterfaceResource.vpc ?: request.vpc,
vpcNetworkInterfaceResource.subnet ?: request.subnet,
new PrivateIPResource(
ownerId: vpcNetworkInterfaceResource.ownerId,
ownerId: vpcNetworkInterfaceResource.value,
value: vpcNetworkInterfaceResource.privateIp
)
).getAt( 0 )?.with{
Expand Down Expand Up @@ -259,15 +259,14 @@ class EdgeNetworkingService extends NetworkingServiceSupport {

private void releasePrivateIp( final String vpcId,
final String ip,
final String ownerId,
final String relatedResource ) {
final String ownerId ) {
try {
String tag = PrivateAddresses.release( vpcId, ip, ownerId )
if ( Strings.startsWith( 'subnet-' ).apply( tag ) ) {
updateFreeAddressesForSubnet( tag )
}
} catch ( e ) {
logger.error( "Error releasing private IP address ${ip} for ${relatedResource}", e )
logger.error( "Error releasing private IP address ${ip} for ${ownerId}", e )
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
************************************************************************/
package com.eucalyptus.network;

import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import javax.persistence.Column;
Expand All @@ -30,16 +31,26 @@
import javax.persistence.Table;
import org.apache.log4j.Logger;
import com.eucalyptus.auth.principal.Principals;
import com.eucalyptus.compute.common.internal.network.PrivateAddressReferrer;
import com.eucalyptus.compute.common.internal.util.PersistentReference;
import com.eucalyptus.compute.common.internal.util.ResourceAllocationException;
import com.eucalyptus.component.ComponentIds;
import com.eucalyptus.component.id.Eucalyptus;
import com.eucalyptus.compute.common.CloudMetadatas;
import com.eucalyptus.compute.common.internal.vm.VmInstance_;
import com.eucalyptus.compute.common.internal.vm.VmNetworkConfig_;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterfaceAttachment_;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface_;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.entities.TransactionResource;
import com.eucalyptus.upgrade.Upgrades;
import com.eucalyptus.auth.principal.FullName;
import com.eucalyptus.auth.type.RestrictedType;
import com.eucalyptus.compute.common.internal.vm.VmInstance;
import com.google.common.base.Objects;
import com.google.common.base.MoreObjects;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import groovy.sql.Sql;

/**
Expand All @@ -48,12 +59,16 @@
@Entity
@PersistenceContext( name = "eucalyptus_cloud" )
@Table( name = "metadata_private_addresses" )
public class PrivateAddress extends PersistentReference<PrivateAddress, VmInstance> implements RestrictedType {
public class PrivateAddress extends PersistentReference<PrivateAddress, PrivateAddressReferrer> implements RestrictedType {
private static final long serialVersionUID = 1L;

@OneToOne( fetch = FetchType.LAZY )
@JoinColumn( name = "metadata_instance_fk" )
private VmInstance instance;
private VmInstance instance;

@OneToOne( fetch = FetchType.LAZY )
@JoinColumn( name = "metadata_network_interface_fk" )
private NetworkInterface networkInterface;

@Column( name = "metadata_address_scope" )
private String scope;
Expand Down Expand Up @@ -124,14 +139,27 @@ private static String buildUniqueName( final String scope, final String name ) {
}

@Override
protected void setReference( VmInstance referrer ) {
this.setInstance( referrer );
protected void setReference( PrivateAddressReferrer referrer ) {
if ( referrer instanceof VmInstance ) {
this.setInstance( (VmInstance) referrer );
this.setNetworkInterface( null );
} else if ( referrer instanceof NetworkInterface ) {
this.setInstance( null );
this.setNetworkInterface( (NetworkInterface) referrer );
} else if ( referrer == null ) {
this.setInstance( null );
this.setNetworkInterface( null );
} else {
throw new IllegalArgumentException( "Unknown referrer type " + referrer.getClass( ) );
}
this.setAssignedPartition( referrer==null ? null : referrer.getPartition() );
}

@Override
protected VmInstance getReference( ) {
return this.getInstance( );
protected PrivateAddressReferrer getReference( ) {
return this.getInstance( ) != null ?
this.getInstance( ) :
this.getNetworkInterface( );
}

public void releasing( ) throws ResourceAllocationException {
Expand All @@ -149,8 +177,8 @@ public String toString( ) {
}

@Nullable
public String getInstanceId( ) {
return CloudMetadatas.toDisplayName( ).apply( instance );
public String getOwnerId( ) {
return CloudMetadatas.toDisplayName( ).apply( getReference( ) );
}

private VmInstance getInstance( ) {
Expand All @@ -161,6 +189,14 @@ private void setInstance( VmInstance instance ) {
this.instance = instance;
}

public NetworkInterface getNetworkInterface() {
return networkInterface;
}

public void setNetworkInterface( final NetworkInterface networkInterface ) {
this.networkInterface = networkInterface;
}

public String getScope( ) {
return scope;
}
Expand Down Expand Up @@ -202,14 +238,15 @@ public FullName getFullName( ) {
.region( ComponentIds.lookup( Eucalyptus.class ).name( ) )
.namespace( this.getOwnerAccountNumber( ) )
.relativeId(
"scope", Objects.firstNonNull( this.getScope( ), "global" ),
"scope", MoreObjects.firstNonNull( this.getScope( ), "global" ),
"private-address", this.getDisplayName( ) );
}

@Override
protected void ensureTransaction() {
}

@SuppressWarnings( { "unused", "WeakerAccess" } )
@Upgrades.PreUpgrade( value = Eucalyptus.class, since = Upgrades.Version.v4_1_0 )
public static class PrivateAddressPreUpgrade41 implements Callable<Boolean> {
private static final Logger logger = Logger.getLogger( PrivateAddressPreUpgrade41.class );
Expand All @@ -231,4 +268,51 @@ public Boolean call( ) throws Exception {
}
}
}

@SuppressWarnings( { "unused", "WeakerAccess" } )
@Upgrades.EntityUpgrade( entities = PrivateAddress.class, since = Upgrades.Version.v4_3_0, value = Eucalyptus.class )
public enum PrivateAddressEntityUpgrade43 implements Predicate<Class> {
INSTANCE;
private static Logger LOG = Logger.getLogger( PrivateAddress.PrivateAddressEntityUpgrade43.class );

@Override
public boolean apply( Class arg0 ) {
updatePrivateAddressOwnership( );
return true;
}

/**
* Update private addresses owned by instances to be owned by the primary network interface instead
*/
private void updatePrivateAddressOwnership( ) {
try ( final TransactionResource tx = Entities.transactionFor( PrivateAddress.class ) ) {
final List<PrivateAddress> addresses = Entities.criteriaQuery( PrivateAddress.class )
.join( PrivateAddress_.instance )
.join( VmInstance_.networkConfig )
.join( VmNetworkConfig_.networkInterfaces )
.join( NetworkInterface_.attachment )
.whereEqual( NetworkInterfaceAttachment_.deviceIndex, 0 )
.list( );

for ( final PrivateAddress address : addresses ) {
final PrivateAddressReferrer referrer = address.getReference( );
if ( referrer instanceof VmInstance ) {
final VmInstance instance = (VmInstance) referrer;
final NetworkInterface networkInterface = Iterables.get( instance.getNetworkInterfaces( ), 0, null );
if ( networkInterface != null ) {
LOG.info( "Updating private ip " + address.getDisplayName( ) + " owner from " +
instance.getDisplayName( ) + " to " + networkInterface.getDisplayName( ) );
try {
address.reclaim( networkInterface );
} catch ( final ResourceAllocationException e ) {
LOG.error( "Error changing owner for private ip " + address.getDisplayName( ), e );
}
}
}
}

tx.commit( );
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package com.eucalyptus.network
import com.eucalyptus.compute.common.internal.util.NotEnoughResourcesException
import com.eucalyptus.compute.common.internal.util.ResourceAllocationException
import com.eucalyptus.compute.common.internal.vm.VmInstance
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface as VpcNetworkInterface
import groovy.transform.CompileStatic

/**
Expand All @@ -45,6 +46,8 @@ interface PrivateAddressAllocator {

void associate( String address, VmInstance instance ) throws ResourceAllocationException

void associate( String address, VpcNetworkInterface networkInterface ) throws ResourceAllocationException

/**
* Release an address
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.eucalyptus.compute.common.internal.util.ResourceAllocationException
import com.eucalyptus.util.Pair
import com.eucalyptus.util.RestrictedTypes
import com.eucalyptus.compute.common.internal.vm.VmInstance
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface as VpcNetworkInterface
import com.google.common.base.Function
import com.google.common.base.Strings
import com.google.common.base.Supplier
Expand Down Expand Up @@ -77,6 +78,13 @@ abstract class PrivateAddressAllocatorSupport implements PrivateAddressAllocator
}
}

@Override
void associate( String address, VpcNetworkInterface networkInterface ) throws ResourceAllocationException {
getPersistence( ).withFirstMatch( PrivateAddress.named( networkInterface.getVpc( ).getDisplayName( ), address ), null ) { PrivateAddress privateAddress ->
privateAddress.set( networkInterface )
}
}

@Override
String release( String scope, String address, String ownerId ) {
boolean torndown = false
Expand All @@ -97,7 +105,7 @@ abstract class PrivateAddressAllocatorSupport implements PrivateAddressAllocator
@Override
boolean verify( String scope, String address, String ownerId ) {
getPersistence( ).withFirstMatch( PrivateAddress.named( scope, address ), ownerId ) { PrivateAddress privateAddress ->
ownerId != null && ownerId == privateAddress.instanceId
ownerId != null && ownerId == privateAddress.ownerId
}.with{
present ? get( ) : false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package com.eucalyptus.network
import com.eucalyptus.compute.common.internal.util.NotEnoughResourcesException
import com.eucalyptus.compute.common.internal.util.ResourceAllocationException
import com.eucalyptus.compute.common.internal.vm.VmInstance
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface as VpcNetworkInterface
import com.google.common.base.Function
import com.google.common.net.InetAddresses
import groovy.transform.CompileStatic
Expand Down Expand Up @@ -73,6 +74,10 @@ class PrivateAddresses {
allocator.associate( address, instance )
}

static void associate( String address, VpcNetworkInterface networkInterface ) throws ResourceAllocationException {
allocator.associate( address, networkInterface )
}

/**
* Release a private address.
*
Expand Down
Loading

0 comments on commit bbd029b

Please sign in to comment.