/*************************************************************************
* 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.
*
* This file may incorporate work covered under the following copyright
* and permission notice:
*
* Software License Agreement (BSD License)
*
* Copyright (c) 2008, Regents of the University of California
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
* with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE
* THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL,
* COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE,
* AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA,
* SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY,
* WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION,
* REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO
* IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT
* NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS.
************************************************************************/
package com.eucalyptus.compute.common.internal.vm;
import static com.eucalyptus.util.Strings.truncate;
import java.lang.Object;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityTransaction;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceContext;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import org.apache.log4j.Logger;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import com.eucalyptus.auth.Accounts;
import com.eucalyptus.auth.principal.BaseInstanceProfile;
import com.eucalyptus.compute.common.CloudMetadata.VmInstanceMetadata;
import com.eucalyptus.compute.common.Compute;
import com.eucalyptus.compute.common.GroupItemType;
import com.eucalyptus.compute.common.GroupSetType;
import com.eucalyptus.compute.common.IamInstanceProfile;
import com.eucalyptus.compute.common.ImageMetadata.Platform;
import com.eucalyptus.compute.common.internal.images.Images;
import com.eucalyptus.compute.common.internal.network.PrivateAddressReferrer;
import com.eucalyptus.compute.common.internal.util.ResourceAllocationException;
import com.eucalyptus.component.ComponentIds;
import com.eucalyptus.component.Partition;
import com.eucalyptus.component.id.Dns;
import com.eucalyptus.component.id.Eucalyptus;
import com.eucalyptus.compute.common.InstanceBlockDeviceMapping;
import com.eucalyptus.compute.common.InstanceNetworkInterfaceAssociationType;
import com.eucalyptus.compute.common.InstanceNetworkInterfaceAttachmentType;
import com.eucalyptus.compute.common.InstanceNetworkInterfaceSetItemType;
import com.eucalyptus.compute.common.InstanceNetworkInterfaceSetType;
import com.eucalyptus.compute.common.InstancePrivateIpAddressesSetItemType;
import com.eucalyptus.compute.common.InstancePrivateIpAddressesSetType;
import com.eucalyptus.compute.common.InstanceStateType;
import com.eucalyptus.compute.common.InstanceStatusDetailsSetItemType;
import com.eucalyptus.compute.common.InstanceStatusDetailsSetType;
import com.eucalyptus.compute.common.InstanceStatusEventType;
import com.eucalyptus.compute.common.InstanceStatusEventsSetType;
import com.eucalyptus.compute.common.InstanceStatusItemType;
import com.eucalyptus.compute.common.InstanceStatusType;
import com.eucalyptus.compute.common.ReservationInfoType;
import com.eucalyptus.compute.common.RunningInstancesItemType;
import com.eucalyptus.compute.common.internal.images.BlockStorageImageInfo;
import com.eucalyptus.compute.common.internal.vpc.NetworkInterface;
import com.eucalyptus.compute.common.internal.vpc.Vpc;
import com.eucalyptus.entities.UserMetadata;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.entities.TransientEntityException;
import com.eucalyptus.event.ListenerRegistry;
import com.eucalyptus.compute.common.internal.keys.SshKeyPair;
import com.eucalyptus.compute.common.internal.network.NetworkGroup;
import com.eucalyptus.records.Logs;
import com.eucalyptus.reporting.event.InstanceCreationEvent;
import com.eucalyptus.upgrade.Upgrades;
import com.eucalyptus.upgrade.Upgrades.EntityUpgrade;
import com.eucalyptus.upgrade.Upgrades.PreUpgrade;
import com.eucalyptus.upgrade.Upgrades.Version;
import com.eucalyptus.util.CollectionUtils;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.auth.principal.FullName;
import com.eucalyptus.auth.principal.OwnerFullName;
import com.eucalyptus.util.Pair;
import com.eucalyptus.util.TypeMapper;
import com.eucalyptus.util.TypeMappers;
import com.eucalyptus.compute.common.internal.vm.VmInstance.VmState;
import com.eucalyptus.compute.common.internal.vmtypes.VmType;
import com.eucalyptus.ws.StackConfiguration;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import groovy.sql.Sql;
@Entity
@PersistenceContext( name = "eucalyptus_cloud" )
@Table( name = "metadata_instances", indexes = {
@Index( name = "metadata_instances_user_id_idx", columnList = "metadata_user_id" ),
@Index( name = "metadata_instances_account_id_idx", columnList = "metadata_account_id" ),
@Index( name = "metadata_instances_display_name_idx", columnList = "metadata_display_name" ),
@Index( name = "metadata_vm_private_address_idx", columnList = "metadata_vm_private_address" ),
@Index( name = "metadata_vm_public_address_idx", columnList = "metadata_vm_public_address" ),
} )
public class VmInstance extends UserMetadata<VmState> implements VmInstanceMetadata, PrivateAddressReferrer {
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger.getLogger( VmInstance.class );
public static final String DEFAULT_TYPE = "m1.small";
public static final String ROOT_DEVICE_TYPE_EBS = "ebs";
public static final String ROOT_DEVICE_TYPE_INSTANCE_STORE = "instance-store";
public static final String ID_PREFIX = "i";
public static final String VM_NC_HOST_TAG = "euca:node";
@Embedded
private VmNetworkConfig networkConfig;
@Embedded
private final VmId vmId;
@Embedded
private VmBootRecord bootRecord;
@Embedded
private final VmUsageStats usageStats;
@Embedded
private final VmLaunchRecord launchRecord;
@Embedded
private VmRuntimeState runtimeState;
@Embedded
private VmVolumeState transientVolumeState;
@Embedded
private final VmPlacement placement;
@Column( name = "metadata_vm_expiration" )
private final Date expiration;
@Column( name = "metadata_vm_private_networking" )
private final Boolean privateNetwork;
@Column( name = "metadata_vm_disable_api_termination" )
private Boolean disableApiTermination;
@NotFound( action = NotFoundAction.IGNORE )
@ManyToMany( cascade = { CascadeType.ALL },
fetch = FetchType.LAZY )
private Set<NetworkGroup> networkGroups = Sets.newHashSet( );
@ElementCollection
@CollectionTable(
name = "metadata_vm_instance_groups",
joinColumns = @JoinColumn( name = "vminstance_id", referencedColumnName = "id" ),
indexes = @Index( name = "metadata_vm_instance_groups_vminstance_idx", columnList = "vminstance_id" )
)
private Set<NetworkGroupId> networkGroupIds = Sets.newHashSet( );
@OneToMany( fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy = "instance" )
private Collection<VmInstanceTag> tags;
public static Criterion criterion( VmState... state ) {
return Restrictions.in( "state", state );
}
public static Criterion zoneCriterion( String... zone ) {
return Restrictions.in( "placement.partitionName", zone );
}
public static Criterion nonNullNodeCriterion( ) {
return Restrictions.isNotNull( "runtimeState.serviceTag" );
}
public static Criterion nullNodeCriterion( ) {
return Restrictions.isNull( "runtimeState.serviceTag" );
}
public static Criterion lastUpdatedCriterion( final long timestamp ) {
return Restrictions.lt( "lastUpdateTimestamp", new Date( timestamp ) );
}
public static Projection instanceIdProjection( ) {
return Projections.property( "displayName" );
}
public static Projection instanceUuidProjection( ) {
return Projections.property( "naturalId" );
}
/**
*
*/
public static RunningInstancesItemType transform( final VmInstance vm ) {
return Transform.INSTANCE.apply( vm );
}
private enum StringPropertyFunctions implements Function<VmInstance,String> {
CLIENT_TOKEN {
@Override
public String apply( final VmInstance instance ) {
return instance.getClientToken( );
}
},
}
public enum Filters implements Predicate<VmInstance> {
BUNDLING {
@Override
public boolean apply( final VmInstance arg0 ) {
return arg0.getRuntimeState( ).isBundling( );
}
}
}
public enum VmStateSet implements Predicate<VmInstance> {
RUN( VmState.PENDING, VmState.RUNNING ),
CHANGING( VmState.PENDING, VmState.STOPPING, VmState.SHUTTING_DOWN ) {
@Override
public boolean apply( final VmInstance arg0 ) {
return super.apply( arg0 ) || !arg0.eachVolumeAttachment( new Predicate<VmVolumeAttachment>( ) {
@Override
public boolean apply( final VmVolumeAttachment input ) {
return !input.getAttachmentState( ).isVolatile( );
}
} );
}
},
EXPECTING_TEARDOWN( VmState.STOPPING, VmState.SHUTTING_DOWN ),
TORNDOWN( VmState.STOPPED, VmState.TERMINATED, VmState.BURIED ),
STOP( VmState.STOPPING, VmState.STOPPED ),
NOT_RUNNING( VmState.STOPPING, VmState.STOPPED, VmState.SHUTTING_DOWN, VmState.TERMINATED, VmState.BURIED ),
DONE( VmState.TERMINATED, VmState.BURIED );
private final Set<VmState> states;
VmStateSet( final VmState... states ) {
this.states = Collections.unmodifiableSet( EnumSet.copyOf( Sets.newHashSet( states ) ) );
}
@Override
public boolean apply( final VmInstance arg0 ) {
return this.states.contains( arg0.getState( ) );
}
public boolean contains( final VmState state ) {
return this.states.contains( state );
}
public Predicate<VmInstance> not( ) {
return Predicates.not( this );
}
public Set<VmState> set( ) {
return states;
}
public VmState[] array( ) {
return states.toArray( new VmState[ states.size( ) ] );
}
}
public enum VmState implements Predicate<VmInstance> {
PENDING( 0 ),
RUNNING( 16 ),
SHUTTING_DOWN( 32 ),
TERMINATED( 48 ),
STOPPING( 64 ),
STOPPED( 80 ),
BURIED( 128, TERMINATED );
private final String name;
private final int code;
private final VmState displayState;
VmState( final int code ) {
this( code, null );
}
VmState( final int code, final VmState displayState ) {
this.name = this.name( ).toLowerCase( ).replace( "_", "-" );
this.code = code;
this.displayState = Objects.firstNonNull( displayState, this );
}
public String getName( ) {
return this.name;
}
public int getCode( ) {
return this.code;
}
public VmState getDisplayState( ) {
return this.displayState;
}
public static class Mapper {
private static Map<String, VmState> stateMap = getStateMap( );
private static Map<String, VmState> getStateMap( ) {
final Map<String, VmState> map = new HashMap<String, VmState>( );
map.put( "Extant", VmState.RUNNING );
map.put( "Pending", VmState.PENDING );
map.put( "Teardown", VmState.SHUTTING_DOWN );
return map;
}
public static VmState get( final String stateName ) {
return Mapper.stateMap.get( stateName );
}
}
@Override
public boolean apply( final VmInstance arg0 ) {
return this.equals( arg0.getState( ) );
}
public Predicate<VmInstance> not( ) {
return Predicates.not( this );
}
}
public enum Lookup implements Function<String, VmInstance> {
INSTANCE {
@Nonnull
@Override
public VmInstance apply( final String arg0 ) {
final EntityTransaction db = Entities.get( VmInstance.class );
try {
final VmInstance vm = Entities.uniqueResult( VmInstance.named( null, arg0 ) );
if ( ( vm == null ) ) {
throw new NoSuchElementException( "Failed to lookup vm instance: " + arg0 );
}
db.commit( );
return vm;
} catch ( final NoSuchElementException ex ) {
throw ex;
} catch ( final Exception ex ) {
throw new NoSuchElementException( "An error occurred while trying to lookup vm instance " + arg0 + ": " + ex.getMessage( ) + "\n"
+ Exceptions.causeString( ex ) );
} finally {
if ( db.isActive() ) db.rollback();
}
}
};
@Nonnull
@Override
public abstract VmInstance apply( final String arg0 );
}
public VmInstance( final OwnerFullName owner,
final VmId vmId,
final VmBootRecord bootRecord,
final VmLaunchRecord launchRecord,
final VmPlacement placement,
final List<NetworkGroup> networkRulesGroups,
final Boolean usePrivateAddressing,
final Boolean disableApiTermination,
final Date expiration ) throws ResourceAllocationException {
super( owner, vmId.getInstanceId( ) );
this.setState( VmState.PENDING );
this.vmId = vmId;
this.expiration = expiration;
this.bootRecord = bootRecord;
this.launchRecord = launchRecord;
this.placement = placement;
this.privateNetwork = Boolean.FALSE;
this.disableApiTermination = disableApiTermination;
this.usageStats = new VmUsageStats( this );
this.runtimeState = new VmRuntimeState( this );
this.transientVolumeState = new VmVolumeState( this );
this.networkConfig = new VmNetworkConfig( this, usePrivateAddressing );
final Function<NetworkGroup, NetworkGroup> func = Entities.merge( );
this.networkGroups.addAll( Collections2.transform( networkRulesGroups, func ) );
this.store( );
}
private VmInstance( final OwnerFullName owner, final VmId vmId ) {
super( owner, null );
this.vmId = vmId;
this.expiration = null;
this.runtimeState = null;
this.bootRecord = null;
this.launchRecord = null;
this.placement = null;
this.privateNetwork = null;
this.usageStats = null;
this.networkConfig = null;
this.transientVolumeState = null;
}
protected VmInstance( final OwnerFullName ownerFullName, final String instanceId2 ) {
super( ownerFullName, instanceId2 );
this.expiration = null;
this.runtimeState = null;
this.vmId = null;
this.bootRecord = null;
this.launchRecord = null;
this.placement = null;
this.privateNetwork = null;
this.usageStats = null;
this.networkConfig = null;
this.transientVolumeState = null;
}
protected VmInstance( ) {
this.expiration = null;
this.vmId = null;
this.bootRecord = null;
this.launchRecord = null;
this.placement = null;
this.privateNetwork = null;
this.usageStats = null;
this.runtimeState = null;
this.networkConfig = null;
this.transientVolumeState = null;
}
@Override
protected String createUniqueName() {
return getDisplayName( ) == null ? null : truncate( getDisplayName( ), 10 );
}
/**
* Clear references that are not valid for a terminated instance
*/
public void clearReferences( ) {
if (bootRecord.getArchitecture() == null) bootRecord.setArchitecture(bootRecord.getMachine().getArchitecture());
bootRecord.setMachine( );
bootRecord.setKernel();
bootRecord.setRamdisk();
bootRecord.setVpc( null );
bootRecord.setSubnet( null );
clearRunReferences( );
}
/**
* Clear any references that are not valid for a stopped instance
*/
public void clearRunReferences( ) {
getRuntimeState( ).setServiceTag( null );
}
public void updatePublicAddress( final String publicAddr, final String publicDnsName ) {
this.getNetworkConfig( ).setPublicAddress( publicAddr );
this.getNetworkConfig( ).setPublicDnsName( dnsHostnamesEnabled( ) ? publicDnsName : "" );
}
public void updatePrivateAddress( final String privateAddr, final String privateDnsName ) {
this.getNetworkConfig( ).setPrivateAddress( privateAddr );
this.getNetworkConfig( ).setPrivateDnsName( privateDnsName );
}
public void updateMacAddress( final String macAddress ) {
if ( getMacAddress( ) == null ) {
getNetworkConfig().setMacAddress( macAddress );
}
}
public VmRuntimeState getRuntimeState( ) {
if ( this.runtimeState == null ) {
this.runtimeState = new VmRuntimeState( this );
}
return this.runtimeState;
}
private boolean dnsHostnamesEnabled( ) {
final Vpc vpc = getBootRecord( ).getVpc( );
return vpc == null || Objects.firstNonNull( vpc.getDnsHostnames(), Boolean.FALSE );
}
public void store( ) {
this.updateTimeStamps( );
this.firePersist( );
this.fireUsageEvent( );
}
private void firePersist( ) {
final EntityTransaction db = Entities.get( VmInstance.class );
try {
if ( Entities.isPersistent( this ) ) try {
Entities.merge( this );
db.commit( );
} catch ( final Exception ex ) {
LOG.debug( ex );
}
} catch ( final Exception ex ) {
Logs.extreme( ).error( ex, ex );
} finally {
if ( db.isActive() ) db.rollback();
}
}
private void fireUsageEvent( ) {
if ( VmState.RUNNING.equals( this.getState( ) ) ) {
try {
final OwnerFullName owner = this.getOwner();
final String userId = owner.getUserId();
final String userName = owner.getUserName();
final String accountId = owner.getAccountNumber();
ListenerRegistry.getInstance( ).fireEvent( new InstanceCreationEvent(
getInstanceUuid(),
getDisplayName(),
this.bootRecord.getVmType().getName(),
userId,
userName,
accountId,
Accounts.lookupAccountAliasById(accountId),
this.placement.getPartitionName()));
} catch ( final Exception ex ) {
LOG.error( ex, ex );
}
}
}
public synchronized long getSplitTime( ) {
final long time = System.currentTimeMillis( );
final long split = time - super.getLastUpdateTimestamp( ).getTime( );
return split;
}
public synchronized long getCreationSplitTime( ) {
final long time = System.currentTimeMillis( );
final long split = time - super.getCreationTimestamp( ).getTime( );
return split;
}
public String getImageId( ) {
return this.bootRecord.getDisplayMachineImageId();
}
@Nullable
public String getRamdiskId( ) {
return this.bootRecord.getDisplayRamdiskImageId();
}
@Nullable
public String getKernelId( ) {
return this.bootRecord.getDisplayKernelImageId();
}
public boolean hasPublicAddress( ) {
return ( this.networkConfig != null )
&& !( VmNetworkConfig.DEFAULT_IP.equals( this.getNetworkConfig( ).getPublicAddress( ) ) || this.getNetworkConfig( ).getPrivateAddress( ).equals(
this.getNetworkConfig( ).getPublicAddress( ) ) );
}
public String getInstanceId( ) {
return super.getDisplayName( );
}
public VmType getVmType( ) {
return this.bootRecord.getVmType( );
}
public boolean isUsePrivateAddressing() {
// allow for null value
return Boolean.TRUE.equals( this.getNetworkConfig( ).getUsePrivateAddressing( ) );
}
public String getPrivateAddress( ) {
return this.getNetworkConfig( ).getPrivateAddress( );
}
public String getPublicAddress( ) {
return this.getNetworkConfig( ).getPublicAddress( );
}
public String getPrivateDnsName( ) {
return this.getNetworkConfig( ).getPrivateDnsName( );
}
public String getPublicDnsName( ) {
return this.getNetworkConfig( ).getPublicDnsName( );
}
public String getMacAddress( ) {
return this.getNetworkConfig( ).getMacAddress( );
}
public List<NetworkInterface> getNetworkInterfaces( ) {
return ImmutableList.copyOf( Iterables.filter(
this.getNetworkConfig( ).getNetworkInterfaces( ),
Predicates.<NetworkInterface>notNull( )
) );
}
public void addNetworkInterface( final NetworkInterface networkInterface ) {
final List<NetworkInterface> networkInterfaces = this.getNetworkConfig( ).getNetworkInterfaces( );
final int index = networkInterface.getAttachment( ).getDeviceIndex( );
if ( networkInterfaces.size( ) > index ) {
networkInterfaces.set( index, networkInterface );
} else {
while ( networkInterfaces.size( ) < index ) networkInterfaces.add( null );
networkInterfaces.add( networkInterface );
}
}
public String getPasswordData( ) {
return this.getRuntimeState( ).getPasswordData( );
}
public void updatePasswordData( final String passwordData ) {
this.getRuntimeState( ).setPasswordData( passwordData );
}
/**
* @return the platform
*/
public String getPlatform( ) {
return this.bootRecord.getPlatform( ).toString( );
}
public String getDisplayPlatform( ) {
return Platform.windows == this.bootRecord.getPlatform( ) ?
Platform.windows.name() :
"";
}
@Nullable
public String getSubnetId( ) {
return this.bootRecord.getSubnetId( );
}
@Nullable
public String getVpcId( ) {
return this.bootRecord.getVpcId( );
}
@Override
public String getPartition( ) {
return this.placement.getPartitionName( );
}
public String getInstanceUuid( ) {
return this.getNaturalId( );
}
public static VmInstance named( final String instanceId ) {
return new VmInstance( null, instanceId );
}
public static VmInstance named( final OwnerFullName ownerFullName, final String instanceId ) {
return new VmInstance( ownerFullName, instanceId );
}
public static VmInstance withToken( final OwnerFullName ownerFullName, final String clientToken ) {
return new VmInstance( ownerFullName, new VmId( null, null, clientToken, null ) );
}
public static VmInstance withUuid( final String uuid ) {
final VmInstance example = new VmInstance( );
example.setNaturalId( uuid );
return example;
}
@Override
public FullName getFullName( ) {
return FullName.create.vendor( "euca" )
.region( ComponentIds.lookup( Eucalyptus.class ).name( ) )
.namespace( this.getOwnerAccountNumber( ) )
.relativeId( "instance", this.getDisplayName( ) );
}
public enum Reason implements Predicate<VmInstance> {
NORMAL( "" ),
EXPIRED( "Instance expired after not being reported." ),
FAILED( "The instance failed to start on the NC." ),
USER_TERMINATED( true, "User terminated." ),
USER_STOPPED( true, "User stopped." ),
USER_STARTED( true, "User started." ),
APPEND( "" );
private final boolean user;
private final String message;
Reason( final String message ) {
this( false, message );
}
Reason( final boolean user, final String message ) {
this.user = user;
this.message = message;
}
public boolean user( ) {
return user;
}
@Override
public String toString( ) {
return this.message;
}
@Override
public boolean apply( final VmInstance vmInstance ) {
return this.equals( vmInstance.getRuntimeState().reason() );
}
}
private Boolean getPrivateNetwork( ) {
return this.privateNetwork;
}
@Nullable
public Boolean getDisableApiTermination( ) {
return disableApiTermination;
}
public Collection<VmInstanceTag> getTags() {
return tags;
}
public Set<NetworkGroup> getNetworkGroups( ) {
return ( Set<NetworkGroup> ) ( this.networkGroups != null
? this.networkGroups
: Sets.newHashSet( ) );
}
public Set<NetworkGroupId> getNetworkGroupIds( ) {
return this.networkGroupIds;
}
static long getSerialversionuid( ) {
return serialVersionUID;
}
static Logger getLOG( ) {
return LOG;
}
static String getDEFAULT_IP( ) {
return VmNetworkConfig.DEFAULT_IP;
}
static String getDEFAULT_TYPE( ) {
return DEFAULT_TYPE;
}
VmId getVmId( ) {
return this.vmId;
}
public VmBootRecord getBootRecord( ) {
return this.bootRecord;
}
VmUsageStats getUsageStats( ) {
return this.usageStats;
}
public VmLaunchRecord getLaunchRecord( ) {
return this.launchRecord;
}
VmPlacement getPlacement( ) {
return this.placement;
}
public Partition lookupPartition( ) {
return this.placement.lookupPartition( );
}
/**
*
*/
public VmVolumeAttachment lookupVolumeAttachmentByDevice( final String volumeDevice ) {
final EntityTransaction db = Entities.get( VmInstance.class );
try {
final VmInstance entity = Entities.merge( this );
VmVolumeAttachment ret;
try {
ret = entity.getTransientVolumeState( ).lookupVolumeAttachmentByDevice( volumeDevice );
} catch ( final Exception ex ) {
ret = Iterables.find( entity.getBootRecord( ).getPersistentVolumes( ), VmVolumeAttachment.volumeDeviceFilter( volumeDevice ) );
}
db.commit( );
return ret;
} catch ( final NoSuchElementException ex ) {
Logs.extreme( ).error( ex, ex );
throw ex;
} catch ( final Exception ex ) {
Logs.extreme( ).error( ex, ex );
throw new NoSuchElementException( "Failed to lookup volume with device: " + volumeDevice );
} finally {
if ( db.isActive() ) db.rollback();
}
}
/**
*
*/
public VmVolumeAttachment lookupVolumeAttachment( final String volumeId ) {
final EntityTransaction db = Entities.get( VmInstance.class );
try {
final VmInstance entity = Entities.isPersistent( this ) ?
this :
Entities.uniqueResult( this );
VmVolumeAttachment volumeAttachment;
try {
volumeAttachment = entity.getTransientVolumeState( ).lookupVolumeAttachment( volumeId );
} catch ( final NoSuchElementException ex ) {
volumeAttachment = Iterables.find( entity.getBootRecord( ).getPersistentVolumes( ), VmVolumeAttachment.volumeIdFilter( volumeId ) );
}
db.commit( );
return volumeAttachment;
} catch ( final Exception ex ) {
throw new NoSuchElementException( "Failed to lookup volume: " + volumeId );
} finally {
if ( db.isActive() ) db.rollback();
}
}
/**
*
*/
public boolean eachVolumeAttachment( final Predicate<VmVolumeAttachment> predicate ) {
if ( VmStateSet.DONE.contains( this.getState( ) ) && !VmStateSet.EXPECTING_TEARDOWN.contains( this.getLastState( ) ) ) {
return false;
} else {
final EntityTransaction db = Entities.get( VmInstance.class );
try {
final VmInstance entity = Entities.merge( this );
Set<VmVolumeAttachment> persistentAttachments = Sets.<VmVolumeAttachment>newHashSet( entity.getBootRecord( ).getPersistentVolumes( ) );
boolean ret = Iterables.all( persistentAttachments, new Predicate<VmVolumeAttachment>( ) {
@Override
public boolean apply( final VmVolumeAttachment arg0 ) {
return predicate.apply( arg0 );
}
} );
ret |= entity.getTransientVolumeState( ).eachVolumeAttachment( new Predicate<VmVolumeAttachment>( ) {
@Override
public boolean apply( final VmVolumeAttachment arg0 ) {
return predicate.apply( arg0 );
}
} );
db.commit( );
return ret;
} catch ( final Exception ex ) {
Logs.extreme( ).error( ex, ex );
db.rollback( );
return false;
}
}
}
/**
*
*/
public String getServiceTag( ) {
return this.getRuntimeState( ).getServiceTag( );
}
/**
*
*/
public String getReservationId( ) {
return this.vmId.getReservationId( );
}
/**
*
*/
public byte[] getUserData( ) {
return this.bootRecord.getUserData( );
}
public void setUserDataAsString( final String userData ){
if(userData == null || userData.length()<=0){
this.bootRecord.setUserData(new byte[0]);
} else {
this.bootRecord.setUserData(userData.getBytes());
}
}
public void setDisableApiTermination( final Boolean disableApiTermination ) {
this.disableApiTermination = disableApiTermination;
}
/**
* Get the state suitable for EC2 API.
*
* @see #getState
*/
public VmState getDisplayState( ) {
return getState( ).getDisplayState( );
}
@Nonnull
public String getDisplayPublicDnsName( ) {
return VmStateSet.TORNDOWN.apply( this ) ?
"" :
dns() ?
getPublicDnsName( ) :
getDisplayPublicAddress( );
}
@Nonnull
public String getDisplayPublicAddress( ) {
return VmStateSet.TORNDOWN.apply( this ) ?
"" :
VmNetworkConfig.DEFAULT_IP.equals( Objects.firstNonNull( Strings.emptyToNull( getPublicAddress( ) ), VmNetworkConfig.DEFAULT_IP ) ) ?
getVpcId( ) == null ? getDisplayPrivateAddress( ) : "" :
getPublicAddress( );
}
@Nonnull
public String getDisplayPrivateDnsName( ) {
return VmStateSet.TORNDOWN.apply( this ) ?
"" :
dns() ?
getPrivateDnsName( ) :
getDisplayPrivateAddress( );
}
@Nonnull
public String getDisplayPrivateAddress( ) {
return VmStateSet.TORNDOWN.apply( this ) ?
"" :
VmNetworkConfig.DEFAULT_IP.equals( Objects.firstNonNull( Strings.emptyToNull( getPrivateAddress( ) ), VmNetworkConfig.DEFAULT_IP ) ) ?
VmNetworkConfig.DEFAULT_IP :
getPrivateAddress( );
}
private static boolean dns( ) {
return StackConfiguration.USE_INSTANCE_DNS && !ComponentIds.lookup( Dns.class ).runLimitedServices( );
}
@TypeMapper
public enum Transform implements Function<VmInstance, RunningInstancesItemType> {
INSTANCE;
/**
* @see Supplier#get()
*/
@Override
public RunningInstancesItemType apply( final VmInstance input ) {
if ( !Entities.isPersistent( input ) ) {
throw new TransientEntityException( input.toString( ) );
} else {
try {
final RunningInstancesItemType runningInstance = new RunningInstancesItemType( );
runningInstance.setAmiLaunchIndex( Integer.toString( input.getLaunchRecord( ).getLaunchIndex( ) ) );
final VmState displayState = input.getDisplayState();
runningInstance.setStateCode( Integer.toString( displayState.getCode() ) );
runningInstance.setStateName( displayState.getName() );
runningInstance.setPlatform( input.getPlatform( ) );
runningInstance.setInstanceId( input.getVmId( ).getInstanceId( ) );
//ASAP:FIXME:GRZE: restore.
runningInstance.setProductCodes( new ArrayList<String>( ) );
runningInstance.setImageId( input.getImageId() );
runningInstance.setKernel( input.getKernelId() );
runningInstance.setRamdisk( input.getRamdiskId() );
runningInstance.setPlatform( Strings.emptyToNull( input.getDisplayPlatform() ) );
runningInstance.setDnsName( input.getDisplayPublicDnsName() );
runningInstance.setIpAddress( Strings.emptyToNull( input.getDisplayPublicAddress() ) );
runningInstance.setPrivateDnsName( input.getDisplayPrivateDnsName() );
runningInstance.setPrivateIpAddress( Strings.emptyToNull( input.getDisplayPrivateAddress() ) );
if (input.getBootRecord() == null || input.getBootRecord().getArchitecture() == null) {
LOG.debug("WARNING: No architecture set for instance " + input.getInstanceId() + ", defaulting to x86_64");
runningInstance.setArchitecture( "x86_64" );
} else {
runningInstance.setArchitecture( input.getBootRecord().getArchitecture().toString() );
}
runningInstance.setReason( input.runtimeState.getDisplayReason( ) );
if ( input.getBootRecord( ).getSshKeyPair( ) != null ) {
runningInstance.setKeyName( input.getBootRecord( ).getSshKeyPair( ).getName( ) );
if ( ( runningInstance.getKeyName( ) != null ) && ( runningInstance.getKeyName( ).isEmpty( ) ) )
runningInstance.setKeyName( null );
} else runningInstance.setKeyName( "" );
runningInstance.setInstanceType( input.getVmType( ).getName( ) );
runningInstance.setPlacement( input.getPlacement( ).getPartitionName( ) );
runningInstance.setLaunchTime( input.getLaunchRecord( ).getLaunchTime( ) );
runningInstance.setClientToken( input.getClientToken() );
runningInstance.setVpcId( input.getVpcId() );
runningInstance.setSubnetId( input.getSubnetId( ) );
if ( !Strings.isNullOrEmpty( input.getIamInstanceProfileId( ) ) ) {
runningInstance.setIamInstanceProfile( new IamInstanceProfile(
input.getIamInstanceProfileArn( ),
input.getIamInstanceProfileId( )
) );
} else if ( !Strings.isNullOrEmpty( input.getIamInstanceProfileArn( ) ) &&
input.getIamInstanceProfileArn().startsWith("arn:") ) {
final String rawName = input.getIamInstanceProfileArn();
final int nameIndex = input.getIamInstanceProfileArn().lastIndexOf('/');
final String name = input.getIamInstanceProfileArn().substring(nameIndex + 1, rawName.length());
try {
BaseInstanceProfile instanceProfile = Accounts.lookupInstanceProfileByName( input.getOwnerAccountNumber( ), name);
final String profileArn = Accounts.getInstanceProfileArn(instanceProfile);
IamInstanceProfile iamInstanceProfile = new IamInstanceProfile();
iamInstanceProfile.setArn(profileArn);
iamInstanceProfile.setId(instanceProfile.getInstanceProfileId());
runningInstance.setIamInstanceProfile(iamInstanceProfile);
} catch (NoSuchElementException nsee ) {
LOG.debug("profile arn : " + name, nsee);
}
} else if ( !Strings.isNullOrEmpty( input.getIamInstanceProfileArn( ) ) &&
!input.getIamInstanceProfileArn().startsWith("arn:") ) {
try {
final BaseInstanceProfile instanceProfile = Accounts.lookupInstanceProfileByName(input.getOwnerAccountNumber(), input.getIamInstanceProfileArn());
final String profileArn = Accounts.getInstanceProfileArn(instanceProfile);
IamInstanceProfile iamInstanceProfile = new IamInstanceProfile();
iamInstanceProfile.setArn(profileArn);
iamInstanceProfile.setId(instanceProfile.getInstanceProfileId());
runningInstance.setIamInstanceProfile(iamInstanceProfile);
} catch (NoSuchElementException nsee ) {
LOG.debug("profile name : " + input.getIamInstanceProfileArn(),nsee);
}
}
if (input.getMonitoring()) {
runningInstance.setMonitoring("enabled");
} else {
runningInstance.setMonitoring("disabled");
}
runningInstance.getGroupSet( ).addAll( Collections2.transform(
input.getNetworkGroupIds( ),
TypeMappers.lookup( NetworkGroupId.class, GroupItemType.class ) ) );
Collections.sort( runningInstance.getGroupSet( ) );
runningInstance.setVirtualizationType( input.getVirtualizationType( ) );
if ( input.isBlockStorage( ) ) {
runningInstance.setRootDeviceType( ROOT_DEVICE_TYPE_EBS );
}
if ( input.getBootRecord( ).hasPersistentVolumes( ) ) {
for ( final VmVolumeAttachment attachedVol : input.getBootRecord( ).getPersistentVolumes( ) ) {
runningInstance.getBlockDevices( ).add( new InstanceBlockDeviceMapping( attachedVol.getDevice( ), attachedVol.getVolumeId( ),
attachedVol.getStatus( ),
attachedVol.getAttachTime( ),
attachedVol.getDeleteOnTerminate( ) ) );
if( attachedVol.getIsRootDevice() ) {
runningInstance.setRootDeviceName(attachedVol.getDevice());
}
}
}
for ( final VmVolumeAttachment attachedVol : input.getTransientVolumeState( ).getAttachments( ) ) {
runningInstance.getBlockDevices( ).add( new InstanceBlockDeviceMapping( attachedVol.getDevice( ), attachedVol.getVolumeId( ),
attachedVol.getStatus( ),
attachedVol.getAttachTime( ),
attachedVol.getDeleteOnTerminate( ) ) );
}
for ( final NetworkInterface networkInterface : input.getNetworkInterfaces( ) ) {
if ( runningInstance.getNetworkInterfaceSet( ) == null ) {
runningInstance.setNetworkInterfaceSet( new InstanceNetworkInterfaceSetType( ) );
}
if ( networkInterface.getAttachment( ).getDeviceIndex() == 0 ) {
// set properties for instance
runningInstance.setSourceDestCheck( networkInterface.getSourceDestCheck( ) );
}
runningInstance.getNetworkInterfaceSet( ).getItem( ).add( new InstanceNetworkInterfaceSetItemType(
networkInterface.getDisplayName( ),
networkInterface.getSubnet( ).getDisplayName( ),
networkInterface.getVpc( ).getDisplayName( ),
networkInterface.getDescription( ),
networkInterface.getOwnerAccountNumber( ),
String.valueOf( networkInterface.getState( ) ),
networkInterface.getMacAddress( ),
networkInterface.getPrivateIpAddress( ),
networkInterface.getPrivateDnsName( ),
networkInterface.getSourceDestCheck( ),
new GroupSetType( Collections2.transform(
networkInterface.getNetworkGroups( ),
TypeMappers.lookup( NetworkGroup.class, GroupItemType.class ) ) ),
new InstanceNetworkInterfaceAttachmentType(
networkInterface.getAttachment( ).getAttachmentId( ),
networkInterface.getAttachment( ).getDeviceIndex(),
String.valueOf( networkInterface.getAttachment( ).getStatus( ) ),
networkInterface.getAttachment( ).getAttachTime( ),
networkInterface.getAttachment( ).getDeleteOnTerminate( )
),
networkInterface.isAssociated( ) ? new InstanceNetworkInterfaceAssociationType(
networkInterface.getAssociation( ).getPublicIp( ),
networkInterface.getAssociation( ).getPublicDnsName( ),
networkInterface.getAssociation( ).getDisplayIpOwnerId( )
) : null,
new InstancePrivateIpAddressesSetType( Lists.newArrayList(
new InstancePrivateIpAddressesSetItemType(
networkInterface.getPrivateIpAddress( ),
networkInterface.getPrivateDnsName( ),
true,
networkInterface.isAssociated( ) ? new InstanceNetworkInterfaceAssociationType(
networkInterface.getAssociation( ).getPublicIp( ),
networkInterface.getAssociation( ).getPublicDnsName( ),
networkInterface.getAssociation( ).getDisplayIpOwnerId( )
) : null
)
) )
) );
}
return runningInstance;
} catch ( final NoSuchElementException ex ) {
throw ex;
} catch ( final Exception ex ) {
throw new NoSuchElementException( "Failed to lookup vm instance: " + input );
}
}
}
}
@TypeMapper
public enum ReservationTransform implements Function<VmInstance, ReservationInfoType> {
INSTANCE;
@Override
public ReservationInfoType apply( final VmInstance instance ) {
return new ReservationInfoType(
instance.getReservationId( ),
instance.getOwner( ).getAccountNumber( ),
Collections2.transform( instance.getNetworkGroupIds(), TypeMappers.lookup( NetworkGroupId.class, GroupItemType.class ) ) );
}
}
@TypeMapper
public enum NetworkGroupIdTransform implements Function<NetworkGroup,NetworkGroupId> {
INSTANCE;
@Override
public NetworkGroupId apply( final NetworkGroup networkGroup ) {
return new NetworkGroupId(
networkGroup.getGroupId(),
networkGroup.getName()
);
}
}
@TypeMapper
public enum NetworkGroupIdToGroupItemTypeTransform implements Function<NetworkGroupId,GroupItemType> {
INSTANCE;
@Override
public GroupItemType apply( final NetworkGroupId networkGroupId ) {
return new GroupItemType(
networkGroupId.getGroupId( ),
networkGroupId.getGroupName()
);
}
}
@TypeMapper
public enum NetworkGroupToGroupItemTypeTransform implements Function<NetworkGroup,GroupItemType> {
INSTANCE;
@Override
public GroupItemType apply( final NetworkGroup networkGroupId ) {
return new GroupItemType(
networkGroupId.getGroupId( ),
networkGroupId.getName()
);
}
}
public boolean isBlockStorage( ) {
return this.bootRecord.isBlockStorage( );
}
public boolean isEbsOptimized( ) {
return false;
}
public String getInstanceType( ) {
return getVmType( ).getName();
}
@Override
public void setNaturalId( final String naturalId ) {
super.setNaturalId( naturalId );
}
public VmVolumeState getTransientVolumeState( ) {
if ( this.transientVolumeState == null ) {
this.transientVolumeState = new VmVolumeState( this );
}
return this.transientVolumeState;
}
@Override
public String toString( ) {
final StringBuilder builder2 = new StringBuilder( );
builder2.append( "VmInstance:" );
if ( this.networkConfig != null ) builder2.append( "networkConfig=" ).append( this.getNetworkConfig( ) ).append( ":" );
if ( this.vmId != null ) builder2.append( "vmId=" ).append( this.vmId ).append( ":" );
if ( this.bootRecord != null ) builder2.append( "bootRecord=" ).append( this.bootRecord ).append( ":" );
if ( this.usageStats != null ) builder2.append( "usageStats=" ).append( this.usageStats ).append( ":" );
if ( this.launchRecord != null ) builder2.append( "launchRecord=" ).append( this.launchRecord ).append( ":" );
if ( this.runtimeState != null ) builder2.append( "runtimeState=" ).append( this.runtimeState ).append( ":" );
if ( this.transientVolumeState != null ) builder2.append( "transientVolumeState=" ).append( this.transientVolumeState ).append( ":" );
if ( this.placement != null ) builder2.append( "placement=" ).append( this.placement ).append( ":" );
if ( this.privateNetwork != null ) builder2.append( "privateNetwork=" ).append( this.privateNetwork ).append( ":" );
if ( Entities.isReadable( this.networkGroups ) ) builder2.append( "networkGroups=" ).append( this.networkGroups ).append( ":" );
return builder2.toString( );
}
private VmNetworkConfig getNetworkConfig( ) {
if ( this.networkConfig == null ) {
this.networkConfig = new VmNetworkConfig( this );
}
return this.networkConfig;
}
private void setNetworkGroups( final Set<NetworkGroup> networkGroups ) {
this.networkGroups = networkGroups;
}
/**
*
*/
void setNetworkConfig( final VmNetworkConfig networkConfig ) {
this.networkConfig = networkConfig;
}
public Date getExpiration( ) {
return this.expiration;
}
public Integer getLaunchIndex( ) {
return this.getLaunchRecord( ).getLaunchIndex( );
}
@Nullable
public String getClientToken() {
return this.getVmId().getClientToken();
}
/**
* For instances created prior to 3.4. this is the ARN or the profile name.
*/
@Nullable
public String getIamInstanceProfileArn() {
return getBootRecord( ).getIamInstanceProfileArn( );
}
@Nullable
public String getIamInstanceProfileId() {
return getBootRecord( ).getIamInstanceProfileId();
}
@Nullable
public String getIamRoleArn() {
return getBootRecord( ).getIamRoleArn();
}
public SshKeyPair getKeyPair( ) {
return this.getBootRecord( ).getSshKeyPair( );
}
public String getVirtualizationType( ) {
return this.getBootRecord( ).getDisplayVirtualizationType( ).toString( );
}
@Override
public int hashCode( ) {
final int prime = 31;
int result = super.hashCode( );
result = prime * result + ( ( this.vmId == null )
? 0
: this.vmId.hashCode( ) );
return result;
}
@Override
public boolean equals( final Object obj ) {
if ( this == obj ) {
return true;
}
if ( !super.equals( obj ) ) {
return false;
}
if ( this.getClass( ) != obj.getClass( ) ) {
return false;
}
final VmInstance other = ( VmInstance ) obj;
if ( this.vmId == null ) {
if ( other.vmId != null ) {
return false;
}
} else if ( !this.vmId.equals( other.vmId ) ) {
return false;
}
return true;
}
/**
*
*/
public static VmInstance create( ) {
return new VmInstance( );
}
public static VmInstance exampleWithPublicIp( String ip ) {
VmInstance vmExample = VmInstance.create( );
vmExample.setNetworkConfig( VmNetworkConfig.exampleWithPublicIp( ip ) );
return vmExample;
}
public static VmInstance exampleWithPrivateIp( String ip ) {
VmInstance vmExample = VmInstance.create( );
vmExample.setNetworkConfig( VmNetworkConfig.exampleWithPrivateIp( ip ) );
return vmExample;
}
public static VmInstance exampleResource( final String instanceId,
final OwnerFullName owner,
final String availabilityZone,
final String instanceProfileArn,
final String instanceType,
final boolean isBlockStorage ) {
return new VmInstance( owner, instanceId ) {
@Override public String getIamInstanceProfileArn( ) { return instanceProfileArn; }
@Override public String getInstanceType( ) { return instanceType; }
@Override public String getPartition( ) { return availabilityZone; }
@Override public boolean isBlockStorage( ) { return isBlockStorage; }
};
}
public static Function<VmInstance,String> clientToken( ) {
return StringPropertyFunctions.CLIENT_TOKEN;
}
private void setBootRecord( VmBootRecord bootRecord ) {
this.bootRecord = bootRecord;
}
@TypeMapper
public enum StatusTransform implements Function<VmInstance, InstanceStatusItemType> {
INSTANCE;
@Override
public InstanceStatusItemType apply( final VmInstance instance ) {
final InstanceStatusItemType instanceStatusItemType = new InstanceStatusItemType();
final VmState displayState = instance.getDisplayState();
instanceStatusItemType.setInstanceId( instance.getInstanceId() );
instanceStatusItemType.setAvailabilityZone( instance.getPlacement().getPartitionName() );
instanceStatusItemType.setEventsSet( buildEventSet( instance ) );
final InstanceStateType state = new InstanceStateType();
state.setCode( displayState.getCode() );
state.setName( displayState.getName() );
instanceStatusItemType.setInstanceState( state );
instanceStatusItemType.setInstanceStatus( buildStatus( Optional.of( Pair.pair(
VmRuntimeState.InstanceStatus.Ok,
Pair.pair( VmRuntimeState.ReachabilityStatus.Passed, Optional.<Date>absent( ) )
) ) ) );
instanceStatusItemType.setSystemStatus( buildStatus( instance ) );
return instanceStatusItemType;
}
public static Optional<InstanceStatusEventType> getEventInfo( final VmInstance instance ) {
Optional<InstanceStatusEventType> eventInfo = Optional.absent( );
if ( VmState.RUNNING.apply( instance ) ) {
final VmRuntimeState vmRuntimeState = instance.getRuntimeState( );
final Date unreachableTimestamp = vmRuntimeState.getUnreachableTimestamp( );
if ( Boolean.TRUE.equals( vmRuntimeState.getZombie( ) ) && unreachableTimestamp != null ) {
final InstanceStatusEventType event = new InstanceStatusEventType( );
event.setCode( "instance-retirement" );
event.setDescription( "Instance recovered with degraded functionality" );
event.setNotAfter( new Date( unreachableTimestamp.getTime( ) + TimeUnit.DAYS.toMillis( 365 ) ) );
event.setNotBefore( unreachableTimestamp );
eventInfo = Optional.of( event );
}
}
return eventInfo;
}
private InstanceStatusEventsSetType buildEventSet( final VmInstance instance ) {
InstanceStatusEventsSetType eventSet = null;
final Optional<InstanceStatusEventType> eventInfo = getEventInfo( instance );
if ( eventInfo.isPresent( ) ) {
eventSet = new InstanceStatusEventsSetType( );
eventSet.getItem( ).add( eventInfo.get( ) );
}
return eventSet;
}
private InstanceStatusType buildStatus( final VmInstance instance ) {
if ( VmState.RUNNING.apply( instance ) ) {
final VmRuntimeState vmRuntimeState = instance.getRuntimeState( );
final VmRuntimeState.InstanceStatus instanceStatus = Objects.firstNonNull(
vmRuntimeState.getInstanceStatus( ),
VmRuntimeState.InstanceStatus.Ok );
final VmRuntimeState.ReachabilityStatus reachabilityStatus = Objects.firstNonNull(
vmRuntimeState.getReachabilityStatus(),
VmRuntimeState.ReachabilityStatus.Passed );
final Date unreachabilityTimestamp = reachabilityStatus != VmRuntimeState.ReachabilityStatus.Passed ?
vmRuntimeState.getUnreachableTimestamp( ) :
null;
return buildStatus( Optional.of( Pair.pair( instanceStatus, Pair.ropair( reachabilityStatus, unreachabilityTimestamp ) ) ) );
} else {
return buildStatus( Optional.<Pair<VmRuntimeState.InstanceStatus,Pair<VmRuntimeState.ReachabilityStatus,Optional<Date>>>>absent( ) );
}
}
private InstanceStatusType buildStatus( final Optional<Pair<VmRuntimeState.InstanceStatus,Pair<VmRuntimeState.ReachabilityStatus,Optional<Date>>>> status ) {
final InstanceStatusType instanceStatusType = new InstanceStatusType( );
if ( status.isPresent( ) ) {
final VmRuntimeState.InstanceStatus instanceStatus = status.get( ).getLeft( );
final VmRuntimeState.ReachabilityStatus reachabilityStatus = status.get( ).getRight( ).getLeft( );
final Optional<Date> unreachableTimestamp = status.get( ).getRight( ).getRight( );
final InstanceStatusDetailsSetItemType statusDetailsItem = new InstanceStatusDetailsSetItemType( );
statusDetailsItem.setName( "reachability" );
statusDetailsItem.setStatus( reachabilityStatus.toString( ) );
statusDetailsItem.setImpairedSince( unreachableTimestamp.orNull( ) );
final InstanceStatusDetailsSetType statusDetails = new InstanceStatusDetailsSetType();
statusDetails.getItem().add( statusDetailsItem );
instanceStatusType.setStatus( instanceStatus.toString( ) );
instanceStatusType.setDetails( statusDetails );
} else {
instanceStatusType.setStatus( "not-applicable" );
}
return instanceStatusType;
}
}
public Boolean getMonitoring() {
return this.getBootRecord().isMonitoring( );
}
@PrePersist
@PreUpdate
private void updateGroups( ) {
networkGroupIds.clear( );
CollectionUtils.fluent( networkGroups )
.transform( TypeMappers.lookup( NetworkGroup.class, NetworkGroupId.class ) )
.copyInto( networkGroupIds );
}
@EntityUpgrade( entities = { VmInstance.class }, since = Version.v3_3_0, value = Eucalyptus.class )
public enum VmInstanceUpgrade_3_3_0 implements Predicate<Class> {
INSTANCE;
private static Logger LOG = Logger.getLogger( VmInstance.VmInstanceUpgrade_3_3_0.class );
@Override
public boolean apply( Class arg0 ) {
EntityTransaction db = Entities.get( VmInstance.class );
try {
List<VmInstance> instances = Entities.query( new VmInstance( ) );
for ( VmInstance vm : instances ) {
if( vm.getBootRecord().getMachine() instanceof BlockStorageImageInfo ) {
LOG.info( "Upgrading bfebs VmInstance: " + vm.toString() );
if( vm.getBootRecord().getEphemeralStorage().isEmpty() ) {
LOG.info("Adding ephemeral disk at " + Images.DEFAULT_EPHEMERAL_DEVICE);
vm.getBootRecord( ).getEphemeralStorage( ).add( new VmEphemeralAttachment( vm, "ephemeral0", Images.DEFAULT_EPHEMERAL_DEVICE ) );
}
// Pre 3.3 code allowed only one persistent volume i.e. the root volume. Check before upgrading
if ( vm.getBootRecord().getPersistentVolumes().size() == 1 ) {
VmVolumeAttachment attachment = vm.getBootRecord().getPersistentVolumes().iterator().next();
LOG.info("Found the only VmVolumeAttachment: " + attachment.toString());
LOG.info("Setting root device flag to true");
attachment.setIsRootDevice(Boolean.TRUE);
LOG.info("Changing the device name to " + Images.DEFAULT_ROOT_DEVICE);
attachment.setDevice( Images.DEFAULT_ROOT_DEVICE);
} else { // This should not be the case updating to 3.3
// If the instance has more or less than one persistent volume, iterate through them and update the one with device "/dev/sda1"
for ( VmVolumeAttachment attachment : vm.getBootRecord().getPersistentVolumes() ) {
LOG.info("Found VmVolumeAttachment: " + attachment.toString());
if ( attachment.getDevice().equalsIgnoreCase(Images.DEFAULT_PARTITIONED_ROOT_DEVICE) ) {
LOG.info("Setting root device flag to true");
attachment.setIsRootDevice(Boolean.TRUE);
LOG.info("Changing the device name from " + Images.DEFAULT_PARTITIONED_ROOT_DEVICE + " to " + Images.DEFAULT_ROOT_DEVICE);
attachment.setDevice(Images.DEFAULT_ROOT_DEVICE);
}
}
}
}
Entities.persist( vm );
}
db.commit( );
return true;
} catch ( Exception ex ) {
LOG.error("Error upgrading VmInstance: ", ex);
db.rollback();
throw Exceptions.toUndeclared( ex );
}
}
}
@PreUpgrade( value = Compute.class, since = Version.v5_0_0 )
public static class VmInstance500PreUpgrade implements Callable<Boolean> {
private static final Logger logger = Logger.getLogger( VmInstance500PreUpgrade.class );
@Override
public Boolean call( ) throws Exception {
Sql sql = null;
try {
logger.info( "Updating instance unique names" );
sql = Upgrades.DatabaseFilters.NEWVERSION.getConnection( "eucalyptus_cloud" );
sql.execute(
"update metadata_instances set metadata_unique_name=substr(metadata_unique_name,14,10) " +
"where length(metadata_unique_name) = 23" );
return true;
} catch ( Exception ex ) {
logger.error( "Error updating instance unique names (check for duplicates)", ex );
return true;
} finally {
if ( sql != null ) {
sql.close( );
}
}
}
}
}