/**
* Copyright (C) 2009-2015 Dell, Inc.
* See annotations for authorship information
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.dasein.cloud.compute;
import org.dasein.cloud.*;
import org.dasein.cloud.network.Networkable;
import org.dasein.cloud.network.RawAddress;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.Callable;
/**
* <p>
* A virtual machine running within a cloud. This class contains the current state at the time
* of any cloud API call for the target VM.
* </p>
*
* @author George Reese @ enstratius (http://www.enstratius.com)
* @version 2013.04 added access to shell key IDs
*/
public class VirtualMachine implements Networkable, Taggable {
private String affinityGroupId;
private Architecture architecture;
private boolean clonable;
private long creationTimestamp;
private VmState currentState;
private Map<String, String> tags;
private String[] labels;
private String description;
private boolean imagable;
private long lastBootTimestamp;
private long lastPauseTimestamp;
private String name;
private boolean pausable;
private boolean persistent;
private Platform platform;
private String privateDnsAddress;
private RawAddress[] privateIpAddresses;
private String productId;
private String providerAssignedIpAddressId;
private String providerDataCenterId;
private String providerKernelImageId;
private String providerMachineImageId;
private String providerOwnerId;
private String providerRamdiskImageId;
private String providerRegionId;
private String[] providerShellKeyIds;
private String providerSubnetId;
private String providerVirtualMachineId;
private String[] providerNetworkInterfaceIds;
private String providerVlanId;
private String providerKeypairId;
private String[] providerFirewallIds;
private String[] providerVolumeIds;
private String publicDnsAddress;
private RawAddress[] publicIpAddresses;
private boolean rebootable;
private String rootPassword;
private String rootUser;
private String stateReasonMessage;
private long terminationTimestamp;
private Volume[] volumes;
private boolean ioOptimized;
private boolean ipForwardingAllowed;
private String providerRoleId;
private VmStatus providerHostStatus;
private VmStatus providerVmStatus;
private String virtualMachineGroup;
private VisibleScope visibleScope;
private VirtualMachineLifecycle lifecycle;
private String spotRequestId; // TODO - add filtering by, add setter/getter
private String resourcePoolId;
private String clientRequestToken;
public VirtualMachine() {
}
public boolean equals( Object ob ) {
if( ob == null ) {
return false;
}
if( ob == this ) {
return true;
}
if( !getClass().getName().equals(ob.getClass().getName()) ) {
return false;
}
VirtualMachine other = ( VirtualMachine ) ob;
if( !getProviderRegionId().equals(other.getProviderRegionId()) ) {
return false;
}
return getProviderVirtualMachineId().equals(other.getProviderVirtualMachineId());
}
public void addTag( Tag t ) {
addTag(t.getKey(), t.getValue());
}
public void addTag( String key, String value ) {
getTags().put(key, value);
}
private transient volatile Callable<String> passwordCallback = null;
public void setPasswordCallback( Callable<String> callback ) {
this.passwordCallback = callback;
}
public void setRootPassword( String rootPassword ) {
this.rootPassword = rootPassword;
}
public String getRootPassword() {
String pw;
synchronized ( this ) {
pw = rootPassword;
}
if( pw != null ) {
return pw;
}
if( passwordCallback != null ) {
pw = fetchPassword();
}
return pw;
}
public String getRootPassword( long timeoutInMilliseconds ) throws InterruptedException {
long timeout = System.currentTimeMillis() + timeoutInMilliseconds;
String pw = getRootPassword();
boolean hasCallback;
synchronized ( this ) {
hasCallback = ( passwordCallback != null );
}
if( hasCallback ) {
while( pw == null ) {
if( timeout <= System.currentTimeMillis() ) {
throw new InterruptedException("System timed out waiting for a password to become available.");
}
try {
Thread.sleep(15000L);
} catch( InterruptedException ignore ) {
}
pw = getRootPassword();
}
}
return pw;
}
public String fetchPassword() {
String pw;
synchronized ( this ) {
pw = rootPassword;
}
if( pw != null ) {
return pw;
}
if( passwordCallback == null ) {
return null;
}
try {
pw = passwordCallback.call();
if( pw != null ) {
synchronized ( this ) {
rootPassword = pw;
}
}
return rootPassword;
} catch( Exception e ) {
return null;
}
}
public String toString() {
return name + " [" + providerVirtualMachineId + "]";
}
public String getAffinityGroupId(){
return affinityGroupId;
}
public void setAffinityGroupId(String affinityGroupId){
this.affinityGroupId = affinityGroupId;
}
public Architecture getArchitecture() {
return architecture;
}
public void setArchitecture( Architecture architecture ) {
this.architecture = architecture;
}
public boolean isClonable() {
return clonable;
}
public void setClonable( boolean clonable ) {
this.clonable = clonable;
}
public long getCreationTimestamp() {
return creationTimestamp;
}
public void setCreationTimestamp( long creationTimestamp ) {
this.creationTimestamp = creationTimestamp;
}
public VmState getCurrentState() {
return currentState;
}
public void setCurrentState( VmState currentState ) {
this.currentState = currentState;
}
public String getDescription() {
return description;
}
public void setDescription( String description ) {
this.description = description;
}
public boolean isImagable() {
return imagable;
}
public void setImagable( boolean imagable ) {
this.imagable = imagable;
}
public long getLastBootTimestamp() {
return lastBootTimestamp;
}
public void setLastBootTimestamp( long lastBootTimestamp ) {
this.lastBootTimestamp = lastBootTimestamp;
}
public long getLastPauseTimestamp() {
return lastPauseTimestamp;
}
public void setLastPauseTimestamp( long lastPauseTimestamp ) {
this.lastPauseTimestamp = lastPauseTimestamp;
}
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
public boolean isPausable() {
return pausable;
}
public void setPausable( boolean pausable ) {
this.pausable = pausable;
}
public boolean isPersistent() {
return persistent;
}
public void setPersistent( boolean persistent ) {
this.persistent = persistent;
}
public Platform getPlatform() {
return platform;
}
public void setPlatform( Platform platform ) {
this.platform = platform;
}
public String getPrivateDnsAddress() {
return privateDnsAddress;
}
public void setPrivateDnsAddress( String privateDnsAddress ) {
this.privateDnsAddress = privateDnsAddress;
}
public @Nonnull RawAddress[] getPrivateAddresses() {
return ( privateIpAddresses == null ? new RawAddress[0] : privateIpAddresses );
}
/**
* @return a list of private IP address strings
* @deprecated Use {@link #getPrivateAddresses()}
*/
@Deprecated
public String[] getPrivateIpAddresses() {
String[] addrs = new String[privateIpAddresses == null ? 0 : privateIpAddresses.length];
if( privateIpAddresses != null ) {
int i = 0;
for( RawAddress addr : privateIpAddresses ) {
addrs[i++] = addr.getIpAddress();
}
}
return addrs;
}
public void setPrivateAddresses( @Nonnull RawAddress... addresses ) {
privateIpAddresses = addresses;
}
/**
* @deprecated Use {@link #setPrivateAddresses(RawAddress...)}
*/
@Deprecated
public void setPrivateIpAddresses( String[] privateIpAddresses ) {
this.privateIpAddresses = new RawAddress[privateIpAddresses == null ? 0 : privateIpAddresses.length];
if( privateIpAddresses != null ) {
for( int i = 0; i < this.privateIpAddresses.length; i++ ) {
this.privateIpAddresses[i] = new RawAddress(privateIpAddresses[i]);
}
}
}
public String getProviderAssignedIpAddressId() {
return providerAssignedIpAddressId;
}
public void setProviderAssignedIpAddressId( String providerAssignedIpAddressId ) {
this.providerAssignedIpAddressId = providerAssignedIpAddressId;
}
public String getProviderDataCenterId() {
return providerDataCenterId;
}
public void setProviderDataCenterId( String providerDataCenterId ) {
this.providerDataCenterId = providerDataCenterId;
}
public String getProviderMachineImageId() {
return providerMachineImageId;
}
public void setProviderMachineImageId( String providerMachineImageId ) {
this.providerMachineImageId = providerMachineImageId;
}
public String getProviderOwnerId() {
return providerOwnerId;
}
public void setProviderOwnerId( String providerOwnerId ) {
this.providerOwnerId = providerOwnerId;
}
public String getProviderRegionId() {
return providerRegionId;
}
public void setProviderRegionId( String providerRegionId ) {
this.providerRegionId = providerRegionId;
}
public String getProviderVirtualMachineId() {
return providerVirtualMachineId;
}
public void setProviderVirtualMachineId( String providerVirtualMachineId ) {
this.providerVirtualMachineId = providerVirtualMachineId;
}
public String getPublicDnsAddress() {
return publicDnsAddress;
}
public void setPublicDnsAddress( String publicDnsAddress ) {
this.publicDnsAddress = publicDnsAddress;
}
public @Nonnull RawAddress[] getPublicAddresses() {
return ( publicIpAddresses == null ? new RawAddress[0] : publicIpAddresses );
}
/**
* @deprecated Use {@link #getPublicAddresses()}
*/
@Deprecated
public String[] getPublicIpAddresses() {
if( publicIpAddresses == null || publicIpAddresses.length < 0 ) {
if( publicDnsAddress == null ) {
return new String[0];
}
String ip = resolve(publicDnsAddress);
if( ip != null ) {
publicIpAddresses = new RawAddress[]{new RawAddress(ip)};
}
else {
return new String[0];
}
}
String[] addrs = new String[publicIpAddresses.length];
if( publicIpAddresses != null ) {
for( int i = 0; i < addrs.length; i++ ) {
addrs[i] = publicIpAddresses[i].getIpAddress();
}
}
return addrs;
}
/**
* Creates an informal association under a group name for the launched VM with other virtual machines in
* the system. The underlying cloud may interpret this in any number of ways.
*
* @return the virtual machine group association
*/
public @Nullable String getVirtualMachineGroup() {
return virtualMachineGroup;
}
private String resolve( String dnsName ) {
if( dnsName != null && dnsName.length() > 0 ) {
InetAddress[] addresses;
try {
addresses = InetAddress.getAllByName(dnsName);
} catch( UnknownHostException e ) {
addresses = null;
}
if( addresses != null && addresses.length > 0 ) {
dnsName = addresses[0].getHostAddress();
}
else {
dnsName = dnsName.split("\\.")[0];
dnsName = dnsName.replaceAll("-", "\\.");
dnsName = dnsName.substring(4);
}
}
return dnsName;
}
public void setPublicAddresses( @Nonnull RawAddress... addresses ) {
publicIpAddresses = addresses;
}
/**
* @deprecated Use {@link #setPublicAddresses(RawAddress...)}
*/
@Deprecated
public void setPublicIpAddresses( String[] publicIpAddresses ) {
this.publicIpAddresses = new RawAddress[publicIpAddresses == null ? 0 : publicIpAddresses.length];
if( publicIpAddresses != null ) {
for( int i = 0; i < this.publicIpAddresses.length; i++ ) {
this.publicIpAddresses[i] = new RawAddress(publicIpAddresses[i]);
}
}
}
public boolean isRebootable() {
return rebootable;
}
public void setRebootable( boolean rebootable ) {
this.rebootable = rebootable;
}
public String getRootUser() {
return rootUser;
}
public void setRootUser( String rootUser ) {
this.rootUser = rootUser;
}
public String getStateReasonMessage() {
return stateReasonMessage;
}
public void setStateReasonMessage( String stateReasonMessage ) {
this.stateReasonMessage = stateReasonMessage;
}
public long getTerminationTimestamp() {
return terminationTimestamp;
}
public void setTerminationTimestamp( long terminationTimestamp ) {
this.terminationTimestamp = terminationTimestamp;
}
public Callable<String> getPasswordCallback() {
return passwordCallback;
}
public void setProductId( String productId ) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
public void setLabels( String[] labels ) {
this.labels = labels;
}
public String[] getLabels() {
return ( labels == null ? new String[0] : labels );
}
public Object getTag( String tag ) {
return getTags().get(tag);
}
public synchronized @Nonnull Map<String, String> getTags() {
if( tags == null ) {
tags = new HashMap<String, String>();
}
return tags;
}
public void setTag( @Nonnull String key, @Nonnull String value ) {
if( tags == null ) {
tags = new HashMap<String, String>();
}
tags.put(key, value);
}
public synchronized void setTags( Map<String, String> properties ) {
getTags().clear();
getTags().putAll(properties);
}
public void setProviderSubnetId( String providerSubnetId ) {
this.providerSubnetId = providerSubnetId;
}
public String getProviderSubnetId() {
return providerSubnetId;
}
public void setProviderVlanId( String providerVlanId ) {
this.providerVlanId = providerVlanId;
}
public String getProviderVlanId() {
return providerVlanId;
}
public String getProviderKeypairId() {
return providerKeypairId;
}
public void setProviderKeypairId( String providerKeypairId ) {
this.providerKeypairId = providerKeypairId;
}
public String[] getProviderFirewallIds() {
return ( providerFirewallIds == null ? new String[0] : providerFirewallIds );
}
public void setProviderFirewallIds( String[] providerFirewallIds ) {
this.providerFirewallIds = providerFirewallIds;
}
public String[] getProviderNetworkInterfaceIds() {
return ( providerNetworkInterfaceIds == null ? new String[0] : providerNetworkInterfaceIds );
}
public void setProviderNetworkInterfaceIds( String[] providerNetworkInterfaceIds ) {
this.providerNetworkInterfaceIds = providerNetworkInterfaceIds;
}
public @Nullable String getProviderKernelImageId() {
return providerKernelImageId;
}
public void setProviderKernelImageId( @Nullable String providerKernelImageId ) {
this.providerKernelImageId = providerKernelImageId;
}
public @Nullable String getProviderRamdiskImageId() {
return providerRamdiskImageId;
}
public void setProviderRamdiskImageId( @Nullable String providerRamdiskImageId ) {
this.providerRamdiskImageId = providerRamdiskImageId;
}
public void setProviderShellKeyIds( @Nonnull String... keyIds ) {
this.providerShellKeyIds = keyIds;
}
public @Nonnull String[] getProviderShellKeyIds() {
return ( providerShellKeyIds == null ? new String[0] : providerShellKeyIds );
}
public @Nonnull String[] getProviderVolumeIds( @Nonnull CloudProvider provider ) throws CloudException, InternalException {
if( providerVolumeIds == null ) {
ComputeServices services = provider.getComputeServices();
if( services == null ) {
throw new OperationNotSupportedException("No compute services are defined");
}
VolumeSupport support = services.getVolumeSupport();
if( support == null ) {
providerVolumeIds = new String[0];
}
else {
TreeSet<String> ids = new TreeSet<String>();
for( Volume v : support.listVolumes(VolumeFilterOptions.getInstance().attachedTo(providerVirtualMachineId)) ) {
ids.add(v.getProviderVolumeId());
}
providerVolumeIds = ids.toArray(new String[ids.size()]);
}
}
return providerVolumeIds;
}
public void setProviderVolumeIds( @Nonnull String... ids ) {
providerVolumeIds = ids;
}
public @Nullable Volume[] getVolumes() {
return volumes;
}
public void setVolumes( @Nullable Volume[] volumes ) {
this.volumes = volumes;
}
public boolean isIoOptimized() {
return ioOptimized;
}
public void setIoOptimized( boolean ioOptimized ) {
this.ioOptimized = ioOptimized;
}
public boolean isIpForwardingAllowed() {
return ipForwardingAllowed;
}
public void setIpForwardingAllowed( boolean ipForwardingAllowed ) {
this.ipForwardingAllowed = ipForwardingAllowed;
}
public String getProviderRoleId() {
return providerRoleId;
}
public void setProviderRoleId( String roleId ) {
this.providerRoleId = roleId;
}
public VmStatus getProviderVmStatus() {
return providerVmStatus;
}
public void setProviderVmStatus( VmStatus vmStatus ) {
this.providerVmStatus = vmStatus;
}
public VmStatus getProviderHostStatus() {
return providerHostStatus;
}
public void setProviderHostStatus( VmStatus vmStatus ) {
this.providerHostStatus = vmStatus;
}
public void setVisibleScope( VisibleScope visibleScope ) {
this.visibleScope = visibleScope;
}
public VisibleScope getVisibleScope() {
return this.visibleScope;
}
public VirtualMachineLifecycle getLifecycle() {
if( lifecycle == null ) {
lifecycle = VirtualMachineLifecycle.NORMAL;
}
return lifecycle;
}
public void setLifecycle( VirtualMachineLifecycle lifecycle ) {
this.lifecycle = lifecycle;
}
public String getSpotRequestId() {
return spotRequestId;
}
public void setSpotRequestId( String spotRequestId ) {
this.spotRequestId = spotRequestId;
}
public String getResourcePoolId() {
return resourcePoolId;
}
public void setResourcePoolId(String resourcePoolId) {
this.resourcePoolId = resourcePoolId;
}
public String getClientRequestToken() {return clientRequestToken;}
public void setClientRequestToken(String clientRequestToken) {this.clientRequestToken = clientRequestToken;}
}