Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

merged in testing

  • Loading branch information...
commit 74cdc972fd6e33b5b5b11c87dd47b398f881d2fe 2 parents 0a61100 + 37c42c2
@dmitrii dmitrii authored
Showing with 2,077 additions and 469 deletions.
  1. +45 −0 clc/eucadmin/eucadmin/describeinstances.py
  2. +56 −22 clc/eucadmin/eucadmin/describenodes.py
  3. +15 −1 clc/modules/cluster-manager/src/main/java/com/eucalyptus/blockstorage/VolumeManager.java
  4. +32 −22 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cloud/run/AdmissionControl.java
  5. +1 −1  clc/modules/cluster-manager/src/main/java/com/eucalyptus/cloud/run/ClusterAllocator.java
  6. +217 −66 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cluster/Cluster.java
  7. +12 −6 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cluster/ClusterEndpoint.java
  8. +2 −8 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cluster/callback/ResourceStateCallback.java
  9. +36 −47 clc/modules/cluster-manager/src/main/java/com/eucalyptus/{cluster/Nodes.java → node/NodeController.java}
  10. +150 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/node/NodeControllerConfiguration.java
  11. +166 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/node/NodeControllerConfigurationBuilder.java
  12. +88 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/node/NodeControllerConfigurationMessages.groovy
  13. +222 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/node/Nodes.java
  14. +1 −1  clc/modules/cluster-manager/src/main/java/com/eucalyptus/tags/TagManager.java
  15. +122 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/MigrationState.java
  16. +145 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/MigrationTags.java
  17. +7 −1 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmControl.java
  18. +11 −0 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmInstance.java
  19. +3 −0  clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmInstances.java
  20. +118 −49 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmMigrationTask.java
  21. +125 −89 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmRuntimeState.java
  22. +0 −4 clc/modules/configuration/src/main/java/com/eucalyptus/config/ClusterConfigurationMessages.groovy
  23. +0 −6 clc/modules/configuration/src/main/java/com/eucalyptus/config/ConfigurationManager.java
  24. +1 −1  clc/modules/msgs/src/main/java/com/eucalyptus/component/ServiceState.java
  25. +3 −3 clc/modules/msgs/src/main/java/com/eucalyptus/component/Topology.java
  26. +0 −36 clc/modules/msgs/src/main/java/com/eucalyptus/component/id/ClusterController.java
  27. +2 −1  clc/modules/msgs/src/main/java/com/eucalyptus/context/Contexts.java
  28. +3 −1 clc/modules/msgs/src/main/java/edu/ucsb/eucalyptus/cloud/Extra.groovy
  29. +121 −24 cluster/handlers-state.c
  30. +2 −2 cluster/handlers-state.h
  31. +38 −18 cluster/handlers.c
  32. +1 −0  cluster/handlers.h
  33. +23 −6 cluster/server-marshal-state.c
  34. +18 −0 cluster/server-marshal.c
  35. +6 −1 node/client-marshal-adb.c
  36. +99 −42 node/handlers.c
  37. +4 −0 node/handlers.h
  38. +50 −7 node/handlers_default.c
  39. +1 −0  node/server-marshal.c
  40. +120 −1 node/xml.c
  41. +3 −0  node/xml.h
  42. +4 −2 util/data.c
  43. +2 −1  util/data.h
  44. +1 −0  util/eucalyptus.h
  45. +1 −0  wsdl/eucalyptus_nc.wsdl
View
45 clc/eucadmin/eucadmin/describeinstances.py
@@ -0,0 +1,45 @@
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2013 Eucalyptus Systems, Inc.
+# 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.
+
+import eucadmin
+
+
+class DescribeInstances(eucadmin.EucadminRequest):
+ ServiceClass = eucadmin.EucAdmin
+ ServicePath = '/services/Eucalyptus'
+
+ def __init__(self, **args):
+ eucadmin.EucadminRequest.__init__(self, **args)
+ self.list_markers = ['reservationSet', 'instancesSet', 'tagSet']
+ self.item_markers = ['item']
+ self.get_connection().APIVersion = '2012-07-20' # cheap hack
+
+ def main(self, **args):
+ return self.send(**args)
View
78 clc/eucadmin/eucadmin/describenodes.py
@@ -1,4 +1,4 @@
-# Copyright 2011-2012 Eucalyptus Systems, Inc.
+# Copyright 2013 Eucalyptus Systems, Inc.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
@@ -23,27 +23,61 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import eucadmin.describerequest
+import eucadmin
+from eucadmin.describeinstances import DescribeInstances
+from eucadmin.describeservices import DescribeServices
-class DescribeNodes(eucadmin.describerequest.DescribeRequest):
- ServiceName = 'Node'
- Description = 'List Node controllers.'
- def __init__(self, **kwargs):
- eucadmin.describerequest.DescribeRequest.__init__(self, **kwargs)
- self.list_markers.append('euca:instances')
+class DescribeNodes(eucadmin.EucadminRequest):
+ Description = 'List node controllers and their instances'
+ ServiceClass = eucadmin.EucAdmin
- def cli_formatter(self, data):
- nodes = getattr(data, 'euca:registered')
- for node in nodes:
- instances = node.get('euca:instances')
- if isinstance(instances, list):
- instance_ids = [instance.get('euca:entry') for instance in
- node.get('euca:instances', [])]
- else:
- # If boto's XML parsing bug hasn't been fixed then instances
- # will be a dict with only one or zero instances per node.
- instance_ids = []
- fmt = ['NODE', node.get('euca:name'), node.get('euca:clusterName')]
- fmt.extend(instance_ids)
- print '\t'.join(map(str, fmt))
+ def main(self, **args):
+ obj = DescribeServices(debug=self.args.get('debug'))
+ services = obj.main(all=True, filter_type='node', **args)
+ service_statuses = services['euca:DescribeServicesResponseType'] \
+ ['euca:serviceStatuses']
+ nodes = {}
+ for service in service_statuses:
+ sid = service['euca:serviceId']
+ hostname = sid.get('euca:hostName')
+ nodes[sid['euca:name']] = {'partition': sid['euca:partition'],
+ 'name': sid['euca:name'],
+ 'hostname': hostname,
+ 'state': service['euca:localState'],
+ 'details': service['euca:details'],
+ 'instances': {}}
+
+ obj = DescribeInstances(debug=self.args.get('debug'))
+ inst_response = obj.main(**args)
+ reservations = inst_response['DescribeInstancesResponse'] \
+ ['reservationSet']
+ for reservation in reservations:
+ for instance in reservation.get('instancesSet', []):
+ i_info = {}
+ for tag in instance.get('tagSet', []):
+ if tag['key'] == 'euca:node' and tag['value'] in nodes:
+ node = nodes[tag['value']]
+ node['instances'][instance['instanceId']] = i_info
+ elif tag['key'] == 'euca:node:migration:destination':
+ i_info['migration_dest'] = tag['value']
+ # 'euca:node:migration-source'
+ return nodes
+
+ def cli_formatter(self, nodes):
+ for node_name, node in nodes.iteritems():
+ print '\t'.join(('NODE', node['partition'],
+ node['hostname'] or '', node_name,
+ node['state'],
+ ', '.join('%s=%s' % (key, val) for key, val in
+ node.get('details', {}).iteritems())))
+ for inst_id, instance in node['instances'].iteritems():
+ if 'migration_dest' in instance:
+ print '\t'.join(('INSTANCE', inst_id, 'MIGRATING-TO',
+ instance['migration_dest']))
+ else:
+ print '\t'.join(('INSTANCE', inst_id))
+
+ def main_cli(self):
+ eucadmin.print_version_if_necessary()
+ self.do_cli()
View
16 clc/modules/cluster-manager/src/main/java/com/eucalyptus/blockstorage/VolumeManager.java
@@ -75,7 +75,6 @@
import com.eucalyptus.cloud.CloudMetadatas;
import com.eucalyptus.cluster.Cluster;
import com.eucalyptus.cluster.Clusters;
-import com.eucalyptus.cluster.Nodes;
import com.eucalyptus.cluster.callback.VolumeAttachCallback;
import com.eucalyptus.cluster.callback.VolumeDetachCallback;
import com.eucalyptus.component.Partition;
@@ -89,6 +88,7 @@
import com.eucalyptus.entities.Entities;
import com.eucalyptus.entities.TransactionException;
import com.eucalyptus.entities.Transactions;
+import com.eucalyptus.node.Nodes;
import com.eucalyptus.records.EventClass;
import com.eucalyptus.records.EventRecord;
import com.eucalyptus.records.EventType;
@@ -105,6 +105,7 @@
import com.eucalyptus.util.async.AsyncRequests;
import com.eucalyptus.vm.VmInstance;
import com.eucalyptus.vm.VmInstance.VmState;
+import com.eucalyptus.vm.MigrationState;
import com.eucalyptus.vm.VmInstances;
import com.eucalyptus.vm.VmVolumeAttachment;
import com.google.common.base.Function;
@@ -366,6 +367,13 @@ public AttachVolumeResponseType AttachVolume( AttachVolumeType request ) throws
LOG.debug( ex, ex );
throw new EucalyptusCloudException( ex.getMessage( ), ex );
}
+ if ( MigrationState.isMigrating( vm ) ) {
+ throw Exceptions.toUndeclared( "Cannot attach a volume to an instance which is currently migrating: "
+ + vm.getInstanceId( )
+ + " "
+ + vm.getMigrationTask( ) );
+ }
+
AccountFullName ownerFullName = ctx.getUserFullName( ).asAccountFullName( );
Volume volume = Volumes.lookup( ownerFullName, volumeId );
if ( !RestrictedTypes.filterPrivileged( ).apply( volume ) ) {
@@ -447,6 +455,12 @@ public DetachVolumeResponseType detach( DetachVolumeType request ) throws Eucaly
} catch ( NoSuchElementException ex ) {
/** no such attachment **/
}
+ if ( MigrationState.isMigrating( vm ) ) {
+ throw Exceptions.toUndeclared( "Cannot detach a volume from an instance which is currently migrating: "
+ + vm.getInstanceId( )
+ + " "
+ + vm.getMigrationTask( ) );
+ }
if ( volume == null ) {
throw new EucalyptusCloudException( "Volume is not attached: " + request.getVolumeId( ) );
}
View
54 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cloud/run/AdmissionControl.java
@@ -67,6 +67,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import javax.persistence.EntityTransaction;
import org.apache.log4j.Logger;
import com.eucalyptus.address.Addresses;
@@ -85,6 +86,7 @@
import com.eucalyptus.component.id.Storage;
import com.eucalyptus.context.Context;
import com.eucalyptus.context.Contexts;
+import com.eucalyptus.context.ServiceStateException;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.entities.TransientEntityException;
import com.eucalyptus.images.BlockStorageImageInfo;
@@ -216,31 +218,39 @@ public void fail( Allocation allocInfo, Throwable t ) {}
* It shouldn't be handled directly here, but instead be handled in {@link ResourceState#requestResourceAllocation().
*
*/
- final ResourceState state = cluster.getNodeState( );
- final List<ResourceToken> tokens = state.requestResourceAllocation( allocInfo, tryAmount, maxAmount );
- final Iterator<ResourceToken> tokenIterator = tokens.iterator( );
- try {
- final Supplier<ResourceToken> allocator = new Supplier<ResourceToken>( ) {
- @Override
- public ResourceToken get( ) {
- final ResourceToken ret = tokenIterator.next( );
- allocInfo.getAllocationTokens( ).add( ret );
- return ret;
- }
- };
+ if ( cluster.getGateLock( ).tryLock( 30, TimeUnit.SECONDS ) ) {
+ try {
+ final ResourceState state = cluster.getNodeState( );
+ final List<ResourceToken> tokens = state.requestResourceAllocation( allocInfo, tryAmount, maxAmount );
+ final Iterator<ResourceToken> tokenIterator = tokens.iterator( );
+ try {
+ final Supplier<ResourceToken> allocator = new Supplier<ResourceToken>( ) {
+ @Override
+ public ResourceToken get( ) {
+ final ResourceToken ret = tokenIterator.next( );
+ allocInfo.getAllocationTokens( ).add( ret );
+ return ret;
+ }
+ };
- RestrictedTypes.allocateUnitlessResources( tokens.size( ), allocator );
- } finally {
- // release any tokens that were not allocated
- Iterators.all( tokenIterator, new Predicate<ResourceToken>() {
- @Override
- public boolean apply(final ResourceToken resourceToken) {
- state.releaseToken( resourceToken );
- return true;
+ RestrictedTypes.allocateUnitlessResources( tokens.size( ), allocator );
+ } finally {
+ // release any tokens that were not allocated
+ Iterators.all( tokenIterator, new Predicate<ResourceToken>() {
+ @Override
+ public boolean apply(final ResourceToken resourceToken) {
+ state.releaseToken( resourceToken );
+ return true;
+ }
+ } );
}
- } );
+ return allocInfo.getAllocationTokens( );
+ } finally {
+ cluster.getGateLock( ).unlock( );
+ }
+ } else {
+ throw new ServiceStateException( "Failed to allocate resources in the zone " + cluster.getPartition( ) + ", it is currently locked for maintenance." );
}
- return allocInfo.getAllocationTokens( );
}
@Override
View
2  clc/modules/cluster-manager/src/main/java/com/eucalyptus/cloud/run/ClusterAllocator.java
@@ -77,7 +77,6 @@
import com.eucalyptus.cloud.util.NotEnoughResourcesException;
import com.eucalyptus.cluster.Cluster;
import com.eucalyptus.cluster.Clusters;
-import com.eucalyptus.cluster.Nodes;
import com.eucalyptus.cluster.callback.StartNetworkCallback;
import com.eucalyptus.cluster.callback.VmRunCallback;
import com.eucalyptus.component.Partitions;
@@ -92,6 +91,7 @@
import com.eucalyptus.network.ExtantNetwork;
import com.eucalyptus.network.NetworkGroup;
import com.eucalyptus.network.NetworkGroups;
+import com.eucalyptus.node.Nodes;
import com.eucalyptus.records.EventRecord;
import com.eucalyptus.records.EventType;
import com.eucalyptus.records.Logs;
View
283 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cluster/Cluster.java
@@ -69,7 +69,6 @@
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
@@ -85,14 +84,14 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.Nullable;
import org.apache.log4j.Logger;
import com.eucalyptus.auth.principal.Principals;
import com.eucalyptus.bootstrap.Bootstrap;
import com.eucalyptus.bootstrap.Hosts;
import com.eucalyptus.cloud.CloudMetadata.AvailabilityZoneMetadata;
+import com.eucalyptus.cloud.CloudMetadatas;
import com.eucalyptus.cluster.ResourceState.VmTypeAvailability;
import com.eucalyptus.cluster.callback.ClusterCertsCallback;
import com.eucalyptus.cluster.callback.LogDataCallback;
@@ -113,6 +112,8 @@
import com.eucalyptus.component.ServiceUris;
import com.eucalyptus.component.id.ClusterController;
import com.eucalyptus.component.id.ClusterController.GatherLogService;
+import com.eucalyptus.context.Contexts;
+import com.eucalyptus.context.ServiceStateException;
import com.eucalyptus.crypto.util.B64;
import com.eucalyptus.crypto.util.PEMFiles;
import com.eucalyptus.empyrean.DescribeServicesResponseType;
@@ -123,18 +124,21 @@
import com.eucalyptus.empyrean.ServiceStatusType;
import com.eucalyptus.empyrean.ServiceTransitionType;
import com.eucalyptus.empyrean.StartServiceType;
+import com.eucalyptus.entities.Entities;
import com.eucalyptus.event.ClockTick;
import com.eucalyptus.event.Event;
import com.eucalyptus.event.EventListener;
import com.eucalyptus.event.Hertz;
import com.eucalyptus.event.ListenerRegistry;
import com.eucalyptus.event.Listeners;
+import com.eucalyptus.node.Nodes;
import com.eucalyptus.records.EventRecord;
import com.eucalyptus.records.EventType;
import com.eucalyptus.records.Logs;
import com.eucalyptus.system.Threads;
import com.eucalyptus.util.Callback;
import com.eucalyptus.util.Classes;
+import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.util.FullName;
import com.eucalyptus.util.HasFullName;
@@ -150,17 +154,22 @@
import com.eucalyptus.util.async.SubjectRemoteCallbackFactory;
import com.eucalyptus.util.fsm.AbstractTransitionAction;
import com.eucalyptus.util.fsm.Automata;
+import com.eucalyptus.util.fsm.ExistingTransitionException;
import com.eucalyptus.util.fsm.HasStateMachine;
import com.eucalyptus.util.fsm.StateMachine;
import com.eucalyptus.util.fsm.StateMachineBuilder;
import com.eucalyptus.util.fsm.TransitionAction;
import com.eucalyptus.util.fsm.Transitions;
+import com.eucalyptus.vm.MigrationState;
+import com.eucalyptus.vm.VmInstance;
import com.eucalyptus.vm.VmInstances;
import com.eucalyptus.vmtypes.VmType;
import com.eucalyptus.vmtypes.VmTypes;
import com.eucalyptus.ws.WebServicesException;
import com.google.common.base.Function;
+import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.Iterables;
@@ -171,7 +180,6 @@
import edu.ucsb.eucalyptus.msgs.MigrateInstancesType;
import edu.ucsb.eucalyptus.msgs.NodeCertInfo;
import edu.ucsb.eucalyptus.msgs.NodeLogInfo;
-import edu.ucsb.eucalyptus.msgs.NodeType;
public class Cluster implements AvailabilityZoneMetadata, HasFullName<Cluster>, EventListener, HasStateMachine<Cluster, Cluster.State, Cluster.Transition> {
private static Logger LOG = Logger.getLogger( Cluster.class );
@@ -856,50 +864,6 @@ public NodeInfo getNode( final String serviceTag ) {
}
}
- public void updateNodeInfo( final ArrayList<String> serviceTags ) {
- NodeInfo ret = null;
-
- for ( final String serviceTag : this.nodeMap.keySet( ) ) {
- if ( !serviceTags.contains( serviceTag ) ) {
- this.nodeMap.remove( serviceTag );
- }
- }
-
- for ( final String serviceTag : serviceTags ) {
- if ( ( ret = this.nodeMap.putIfAbsent( serviceTag, new NodeInfo( serviceTag ) ) ) != null ) {
- ret.touch( );
- ret.setServiceTag( serviceTag );
- ret.setIqn( "No IQN reported" );
- }
- }
- }
-
- public void updateNodeInfo( final List<NodeType> nodeTags ) {
- NodeInfo ret = null;
- boolean hasServiceTag = false;
-
- for ( final String serviceTag : this.nodeMap.keySet( ) ) {
- for ( final NodeType node : nodeTags ) {
- if ( node.getServiceTag( ).equals( serviceTag ) ) {
- hasServiceTag = true;
- }
- }
- if( !hasServiceTag ) {
- this.nodeMap.remove( serviceTag );
- } else {
- hasServiceTag = false;
- }
- }
-
- for ( final NodeType node : nodeTags ) {
- if ( ( ret = this.nodeMap.putIfAbsent( node.getServiceTag( ), new NodeInfo( node ) ) ) != null ) {
- ret.touch( );
- ret.setServiceTag( node.getServiceTag( ) );
- ret.setIqn( node.getIqn( ) );
- }
- }
- }
-
@Override
public int compareTo( final Cluster that ) {
return this.getName( ).compareTo( that.getName( ) );
@@ -1106,6 +1070,13 @@ public String toString( ) {
}
private final AtomicBoolean logUpdate = new AtomicBoolean( false );
+ private final Predicate<VmInstance> filterPartition = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ return input.getPartition( ).equals( Cluster.this.getPartition( ) ) && MigrationState.isMigrating( input );
+ }
+ };
public NodeLogInfo getLastLog( ) {
if ( this.logUpdate.compareAndSet( false, true ) ) {
@@ -1392,42 +1363,222 @@ public OwnerFullName getOwner( ) {
* GRZE:WARNING: this is a temporary method to expose the forwarding map of NC info
* @return
*/
- Map<String,NodeInfo> getNodeHostMap( ) {
+ public Map<String,NodeInfo> getNodeHostMap( ) {
return this.nodeHostAddrMap;
}
+
+ public Lock getGateLock( ) {
+ return this.gateLock;
+ }
/**
* <ol>
* <li> Mark this cluster as gated.
* <li> Update node and resource information; describe resources.
- * <li> Find all VMs with volume attachments and authorize every node's IQN.
+ * <li> Find all VMs and update their migration state and volumes
* <li> Send the MigrateInstances operation.
* <li> Update node and resource information; describe resources.
* <li> Unmark this cluster as gated.
* </ol>
* @param sourceHost
+ * @param destHostsWhiteList -- the destination host list is a white list when true and a black list when false
+ * @param destHosts -- list of hosts which are either a white list or black list based on {@code destHostsWhiteList}
+ * @throws EucalyptusCloudException
* @throws Exception
*/
- public void migrateInstances( final String sourceHost ) throws Exception {
- this.gateLock.lock( );
- try {
- //TODO:GRZE: gate cluster
- //TODO:GRZE: describe resources
- //TODO:GRZE: authorize all NCs for volume attachments on VMs running on sourceHost
- AsyncRequests.sendSync( this.getConfiguration( ), new MigrateInstancesType( ) {
- {
- this.setSourceHost( sourceHost );
+ public void migrateInstances( final String sourceHost, final Boolean destHostsWhiteList, final List<String> destHosts ) throws Exception {
+ //#1 Mark this cluster as gated.
+ if ( this.gateLock.tryLock( 30, TimeUnit.SECONDS ) ) {
+ try {
+ //#2 Only one migration per cluster for now
+ List<VmInstance> currentMigrations = this.lookupCurrentMigrations( );
+ if ( !currentMigrations.isEmpty( ) ) {
+ throw Exceptions.toUndeclared( "Cannot start a new migration because the following are already ongoing: "
+ + Joiner.on( ", " ).join( Iterables.transform( currentMigrations, CloudMetadatas.toDisplayName( ) ) ) );
}
- } );
- //TODO:GRZE: describe resources
- //TODO:GRZE: ungate cluster
- } finally {
- this.gateLock .unlock( );
+ //#3 Update node and resource information
+ this.retryCheck( );
+ //#4 Find all VMs and update their migration state and volumes
+ this.prepareInstanceEvacuations( sourceHost );
+ //#5 Send the MigrateInstances operation.
+ try {
+ AsyncRequests.sendSync( this.getConfiguration( ), new MigrateInstancesType( ) {
+ {
+ this.setCorrelationId( Contexts.lookup( ).getCorrelationId( ) );
+ this.setSourceHost( sourceHost );
+ this.setAllowHosts( destHostsWhiteList );
+ this.getDestinationHosts( ).addAll( destHosts );
+ }
+ } );
+ } catch ( Exception ex ) {
+ //#5 On error go back and abort the migration status for every instance
+ this.rollbackInstanceEvacuations( sourceHost );
+ throw ex;
+ }
+ //#6 Update node and resource information; describe resources.
+ this.retryCheck( );
+ } catch ( Exception ex ) {
+ LOG.error( ex );
+ throw ex;
+ } finally {
+ //#6 Unmark this cluster as gated.
+ this.gateLock.unlock( );
+ }
+ } else {
+ throw new ServiceStateException( "Failed to request migration in the zone " + this.getPartition( ) + ", it is currently locked for maintenance." );
}
}
- protected Lock getGateLock( ) {
- return this.gateLock;
+ /**
+ * <ol>
+ * <li> Mark this cluster as gated.
+ * <li> Update node and resource information; describe resources.
+ * <li> Find the VM and its volume attachments and authorize every node's IQN.
+ * <li> Send the MigrateInstances operation.
+ * <li> Update node and resource information; describe resources.
+ * <li> Unmark this cluster as gated.
+ * </ol>
+ * @param sourceHost
+ * @param destHostsWhiteList -- the destination host list is a white list when true and a black list when false
+ * @param destHosts -- list of hosts which are either a white list or black list based on {@code destHostsWhiteList}
+ * @throws EucalyptusCloudException
+ * @throws Exception
+ */
+ public void migrateInstance( final String instanceId, final Boolean destHostsWhiteList, final List<String> destHosts ) throws Exception {
+ //#1 Mark this cluster as gated.
+ if ( this.gateLock.tryLock( 30, TimeUnit.SECONDS ) ) {
+ try {
+ //#2 Only one migration per cluster for now
+ List<VmInstance> currentMigrations = this.lookupCurrentMigrations( );
+ if ( !currentMigrations.isEmpty( ) ) {
+ throw Exceptions.toUndeclared( "Cannot start a new migration because the following are already ongoing: "
+ + Joiner.on( ", " ).join( Iterables.transform( currentMigrations, CloudMetadatas.toDisplayName( ) ) ) );
+ }
+ //#3 Update node and resource information
+ this.retryCheck( );
+ //#4 Find all VMs and update their migration state and volumes
+ this.prepareInstanceMigrations( instanceId );
+ //#5 Send the MigrateInstances operation.
+ try {
+ AsyncRequests.sendSync( this.getConfiguration( ), new MigrateInstancesType( ) {
+ {
+ this.setCorrelationId( Contexts.lookup( ).getCorrelationId( ) );
+ this.setInstanceId( instanceId );
+ this.setAllowHosts( destHostsWhiteList );
+ this.getDestinationHosts( ).addAll( destHosts );
+ }
+ } );
+ } catch ( Exception ex ) {
+ //#5 On error go back and abort the migration status for every instance
+ this.rollbackInstanceMigrations( instanceId );
+ throw ex;
+ }
+ //#6 Update node and resource information; describe resources.
+ this.retryCheck( );
+ } catch ( Exception ex ) {
+ LOG.error( ex );
+ throw ex;
+ } finally {
+ //#6 Unmark this cluster as gated.
+ this.gateLock.unlock( );
+ }
+ } else {
+ throw new ServiceStateException( "Failed to request migration in the zone " + this.getPartition( ) + ", it is currently locked for maintenance." );
+ }
+ }
+
+ private void rollbackInstanceEvacuations( final String sourceHost ) {
+ Predicate<VmInstance> filterHost = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ String vmHost = URI.create( input.getServiceTag( ) ).getHost( );
+ return Strings.nullToEmpty( vmHost ).equals( sourceHost );
+ }
+ };
+ Predicate<VmInstance> rollbackMigration = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ input.abortMigration( );
+ return true;
+ }
+ };
+ Predicate<VmInstance> filterAndAbort = Predicates.and( this.filterPartition, rollbackMigration );
+ Predicate<VmInstance> rollbackMigrationTx = Entities.asTransaction( VmInstance.class, filterAndAbort );
+ VmInstances.list( rollbackMigrationTx );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ private void prepareInstanceEvacuations( final String sourceHost ) {
+ Predicate<VmInstance> filterHost = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ String vmHost = URI.create( input.getServiceTag( ) ).getHost( );
+ return Strings.nullToEmpty( vmHost ).equals( sourceHost );
+ }
+ };
+ Predicate<VmInstance> startMigration = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ input.startMigration( );
+ return true;
+ }
+ };
+ Predicate<VmInstance> filterAndAbort = Predicates.and( this.filterPartition, startMigration );
+ Predicate<VmInstance> startMigrationTx = Entities.asTransaction( VmInstance.class, filterAndAbort );
+ VmInstances.list( startMigrationTx );
+ }
+
+ private void rollbackInstanceMigrations( final String instanceId ) {
+ Predicate<VmInstance> rollbackMigration = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ input.abortMigration( );
+ return true;
+ }
+ };
+ Predicate<VmInstance> rollbackMigrationTx = Entities.asTransaction( VmInstance.class, rollbackMigration );
+ rollbackMigrationTx.apply( VmInstances.lookup( instanceId ) );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ private void prepareInstanceMigrations( final String instanceId ) {
+ Predicate<VmInstance> startMigration = new Predicate<VmInstance>( ) {
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ input.startMigration( );
+ return true;
+ }
+ };
+ Predicate<VmInstance> startMigrationTx = Entities.asTransaction( VmInstance.class, startMigration );
+ startMigrationTx.apply( VmInstances.lookup( instanceId ) );
+ }
+
+ private List<VmInstance> lookupCurrentMigrations( ) throws Exception {
+ return VmInstances.list( this.filterPartition );
+ }
+
+ private void retryCheck( ) throws Exception {
+ Exception lastEx = null;
+ for ( int i = 0; i < 5; i++ ) {
+ try {
+ this.check( );
+ return;
+ } catch ( Exception ex ) {
+ LOG.debug( "Retrying after failed attempt to refresh cluster state in check(): " + ex.getMessage( ) );
+ lastEx = ex;
+ TimeUnit.SECONDS.sleep( 2 );
+ }
+ }
+ throw new ServiceStateException( "Failed to request migration in the zone "
+ + this.getPartition( )
+ + " because updating resources returned an error: "
+ + ( lastEx != null ? lastEx.getMessage( ) : "unknown error" ) );
}
}
View
18 clc/modules/cluster-manager/src/main/java/com/eucalyptus/cluster/ClusterEndpoint.java
@@ -85,6 +85,7 @@
import com.eucalyptus.component.id.Eucalyptus;
import com.eucalyptus.component.id.Walrus;
import com.eucalyptus.context.Contexts;
+import com.eucalyptus.node.Nodes;
import com.eucalyptus.tags.Filter;
import com.eucalyptus.tags.FilterSupport;
import com.eucalyptus.tags.Filters;
@@ -95,6 +96,7 @@
import com.google.common.base.Function;
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.ImmutableList;
import com.google.common.collect.Iterables;
@@ -135,18 +137,22 @@ public void start( ) throws MuleException {
Clusters.getInstance( );
}
- public MigrateInstancesResponseType migrateInstances( final MigrateInstancesType request ) {
+ public MigrateInstancesResponseType migrateInstances( final MigrateInstancesType request ) throws EucalyptusCloudException {
MigrateInstancesResponseType reply = request.getReply( );
for ( ServiceConfiguration c : Topology.enabledServices( ClusterController.class ) ) {
try {
- Nodes.lookupNodeInfo( c, request.getSourceHost( ) );
Cluster cluster = Clusters.lookup( c );
- cluster.migrateInstances( request.getSourceHost( ) );
+ if ( !Strings.isNullOrEmpty( request.getSourceHost( ) ) ) {
+ cluster.migrateInstances( request.getSourceHost( ), request.getAllowHosts( ), request.getDestinationHosts( ) );
+ } else if ( !Strings.isNullOrEmpty( request.getInstanceId( ) ) ) {
+ cluster.migrateInstance( request.getInstanceId( ), request.getAllowHosts( ), request.getDestinationHosts( ) );
+ } else {
+ throw new IllegalArgumentException( "Either the sourceHost or instanceId must be provided" );
+ }
return reply.markWinning( );
- } catch ( NoSuchElementException ex1 ) {
- //noop
} catch ( Exception ex ) {
- LOG.error( ex, ex );
+ LOG.error( ex );
+ throw new EucalyptusCloudException( ex.getMessage( ), ex );
}
}
return reply.markFailed( );
View
10 .../cluster-manager/src/main/java/com/eucalyptus/cluster/callback/ResourceStateCallback.java
@@ -64,6 +64,7 @@
import org.apache.log4j.Logger;
import com.eucalyptus.cluster.Cluster;
+import com.eucalyptus.node.Nodes;
import com.eucalyptus.util.async.FailedRequestException;
import com.eucalyptus.vmtypes.VmType;
import com.eucalyptus.vmtypes.VmTypes;
@@ -97,15 +98,8 @@ public ResourceStateCallback( ) {
public void fire( DescribeResourcesResponseType reply ) {
this.getSubject( ).getNodeState( ).update( reply.getResources( ) );
LOG.debug( "Adding node service tags: " + reply.getServiceTags( ) );
- /**
- * TODO:GRZE: if not present emulate {@link ClusterController.NodeController} using {@link Component#setup()}
- * TODO:GRZE: emulate update of emulate {@link ClusterController.NodeController} state
- * TODO:GRZE: {@link Component#destroy()} for the NodeControllers which are not reported by the CC.
- */
if( !reply.getNodes( ).isEmpty( ) ) {
- this.getSubject( ).updateNodeInfo( reply.getNodes( ) );
- } else {
- this.getSubject( ).updateNodeInfo( reply.getServiceTags( ) );
+ Nodes.updateNodeInfo( this.getSubject( ).getConfiguration( ), reply.getNodes( ) );
}
}
View
83 ...in/java/com/eucalyptus/cluster/Nodes.java → ...a/com/eucalyptus/node/NodeController.java
@@ -60,59 +60,48 @@
* NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS.
************************************************************************/
-package com.eucalyptus.cluster;
+package com.eucalyptus.node;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import com.eucalyptus.component.ServiceConfiguration;
-import com.eucalyptus.component.Topology;
+import com.eucalyptus.component.ComponentId;
+import com.eucalyptus.component.ServiceUris;
+import com.eucalyptus.component.ComponentId.FaultLogPrefix;
+import com.eucalyptus.component.ComponentId.InternalService;
+import com.eucalyptus.component.ComponentId.Partition;
import com.eucalyptus.component.id.ClusterController;
-import com.eucalyptus.vm.VmInstance;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import edu.ucsb.eucalyptus.cloud.NodeInfo;
+import com.eucalyptus.util.Internets;
-public class Nodes {
+@Partition( value = { ClusterController.class }, manyToOne = true )
+@InternalService
+@FaultLogPrefix( "cloud" ) // nc stub, but within clc
+public class NodeController extends ComponentId {
- /**
- * GRZE:TODO: should return the node's service configuration
- * @param ccConfig
- * @param ncHostOrTag
- * @return
- */
- public static NodeInfo lookupNodeInfo( ServiceConfiguration ccConfig, String ncHostOrTag ) {
- Map<String, NodeInfo> map = Clusters.lookup( ccConfig ).getNodeHostMap( );
- if ( map.containsKey( ncHostOrTag ) ) {
- return map.get( ncHostOrTag );
- } else {
- throw new NoSuchElementException( "Failed to lookup node using " + ncHostOrTag + ". Available nodes are: " + Joiner.on("\n").join( map.keySet( ) ) );
- }
+ public NodeController( ) {
+ super( "node" );
}
- public static List<String> lookupIqns( ServiceConfiguration ccConfig ) {
- Cluster cluster = Clusters.lookup( ccConfig );
- Set<String> ret = Sets.newHashSet( );
- for ( NodeInfo node : cluster.getNodeMap( ).values( ) ) {
- if ( node.getIqn( ) != null ) {
- ret.add( node.getIqn( ) );
- }
- }
- return Lists.newArrayList( ret );
+ @Override
+ public Integer getPort( ) {
+ return 8775;
}
- public static List<String> lookupIqn( VmInstance vm ) {
- ServiceConfiguration ccConfig = Topology.lookup( ClusterController.class, vm.lookupPartition( ) );
- Cluster cluster = Clusters.lookup( ccConfig );
- NodeInfo node = cluster.getNode( vm.getServiceTag( ) );
- if ( node == null ) {
- throw new NoSuchElementException( "Failed to look up node information for " + vm.getInstanceId( ) + " with service tag " + vm.getServiceTag( ) );
- } else if ( node.getIqn( ) == null ) {
- throw new NoSuchElementException( "Error looking up iqn for node " + vm.getServiceTag( ) + " (" + vm.getInstanceId( ) + "): node does not have an iqn." );
- } else {
- return Lists.newArrayList( node.getIqn( ) );
- }
+ @Override
+ public String getLocalEndpointName( ) {
+ return ServiceUris.remote( this, Internets.localHostInetAddress( ), this.getPort( ) ).toASCIIString( );
}
-}
+
+ @Override
+ public String getServicePath( final String... pathParts ) {
+ return "/axis2/services/EucalyptusNC";
+ }
+
+ @Override
+ public String getInternalServicePath( final String... pathParts ) {
+ return this.getServicePath( pathParts );
+ }
+
+ @Override
+ public boolean isRegisterable( ) {
+ return false;
+ }
+
+}
View
150 ...odules/cluster-manager/src/main/java/com/eucalyptus/node/NodeControllerConfiguration.java
@@ -0,0 +1,150 @@
+/*************************************************************************
+ * Copyright 2009-2012 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.node;
+
+import java.io.Serializable;
+import javax.persistence.PersistenceContext;
+import javax.persistence.PostLoad;
+import javax.persistence.Transient;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.Entity;
+import com.eucalyptus.bootstrap.BootstrapArgs;
+import com.eucalyptus.component.ComponentId.ComponentPart;
+import com.eucalyptus.config.ComponentConfiguration;
+import com.eucalyptus.configurable.ConfigurableClass;
+import com.eucalyptus.configurable.ConfigurableIdentifier;
+
+/**
+ * @todo doc
+ * @author chris grzegorczyk <grze@eucalyptus.com>
+ */
+@Entity
+@javax.persistence.Entity
+@PersistenceContext( name = "eucalyptus_config" )
+@Cache( usage = CacheConcurrencyStrategy.TRANSACTIONAL )
+@ComponentPart( NodeController.class )
+@ConfigurableClass( root = "node",
+ alias = "basic",
+ description = "Node Controller Configuration.",
+ singleton = false,
+ deferred = true )
+public class NodeControllerConfiguration extends ComponentConfiguration implements Serializable {
+ @Transient
+ private static String DEFAULT_SERVICE_PATH = "/axis2/services/EucalyptusNC";
+ @Transient
+ private static Integer DEFAULT_SERVICE_PORT = 8775;
+
+ @Transient
+ @ConfigurableIdentifier
+ private String propertyPrefix;
+
+ public NodeControllerConfiguration( ) {
+ super( );
+ }
+
+ public NodeControllerConfiguration( String partition, String hostName ) {
+ super( partition, hostName, hostName, DEFAULT_SERVICE_PORT, DEFAULT_SERVICE_PATH );
+ }
+
+ @PostLoad
+ private void initOnLoad( ) {//GRZE:HACK:HACK: needed to mark field as @ConfigurableIdentifier
+ if ( this.propertyPrefix == null ) {
+ this.propertyPrefix = this.getPartition( ).replace( ".", "" ) + "." + this.getName( );
+ }
+ }
+
+ @Override
+ public Boolean isVmLocal( ) {
+ return false;
+ }
+
+ @Override
+ public Boolean isHostLocal( ) {
+ return BootstrapArgs.isCloudController( );
+ }
+
+ /**
+ * Immutable for now.
+ */
+ @Override
+ public Integer getPort( ) {
+ return DEFAULT_SERVICE_PORT;
+ }
+
+ /**
+ * Immutable for now.
+ */
+ @Override
+ public String getServicePath( ) {
+ return DEFAULT_SERVICE_PATH;
+ }
+
+ public String getPropertyPrefix( ) {
+ return this.getPartition( );
+ }
+
+ public void setPropertyPrefix( String propertyPrefix ) {
+ this.setPartition( propertyPrefix );
+ }
+}
View
166 ...cluster-manager/src/main/java/com/eucalyptus/node/NodeControllerConfigurationBuilder.java
@@ -0,0 +1,166 @@
+/*************************************************************************
+ * Copyright 2009-2012 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.node;
+
+import com.eucalyptus.bootstrap.Handles;
+import com.eucalyptus.component.ComponentId;
+import com.eucalyptus.component.ComponentId.ComponentPart;
+import com.eucalyptus.component.ComponentIds;
+import com.eucalyptus.component.Partitions;
+import com.eucalyptus.component.ServiceBuilder;
+import com.eucalyptus.component.ServiceConfiguration;
+import com.eucalyptus.component.ServiceConfigurations;
+import com.eucalyptus.component.ServiceRegistrationException;
+import com.eucalyptus.component.Topology;
+import com.eucalyptus.component.id.ClusterController;
+import com.eucalyptus.empyrean.DescribeServicesType;
+import com.eucalyptus.empyrean.DisableServiceType;
+import com.eucalyptus.empyrean.EnableServiceType;
+import com.eucalyptus.empyrean.ServiceId;
+import com.eucalyptus.empyrean.ServiceTransitionType;
+import com.eucalyptus.util.Exceptions;
+import com.eucalyptus.util.async.AsyncRequests;
+import edu.ucsb.eucalyptus.msgs.BaseMessage;
+
+/**
+ * @todo doc
+ * @author chris grzegorczyk <grze@eucalyptus.com>
+ */
+@ComponentPart( NodeController.class )
+@Handles( { RegisterNodeControllerType.class,
+ DeregisterNodeControllerType.class,
+ DescribeNodeControllersType.class,
+ ModifyNodeControllerAttributeType.class } )
+public class NodeControllerConfigurationBuilder implements ServiceBuilder<NodeControllerConfiguration> {
+
+ @Override
+ public ComponentId getComponentId( ) {
+ return ComponentIds.lookup( NodeController.class );
+ }
+
+ @Override
+ public Boolean checkAdd( String partition, String name, String host, Integer port ) throws ServiceRegistrationException {
+ throw new ServiceRegistrationException( "Node Controllers must currently be registered " +
+ "on the Cluster Controllers for the partition." +
+ "Apologies. Please see the documentation." );
+ }
+
+ /**
+ * Here we do nothing for now.
+ */
+ @Override
+ public void fireLoad( ServiceConfiguration parent ) throws ServiceRegistrationException {}
+
+ /**
+ * Here we do nothing for now.
+ */
+ @Override
+ public void fireStart( ServiceConfiguration config ) throws ServiceRegistrationException {
+// sendNodeServiceRequest( config, new StartServiceType( ) );
+ }
+
+ /**
+ * Here we do nothing for now.
+ */
+ @Override
+ public void fireStop( ServiceConfiguration config ) throws ServiceRegistrationException {
+// sendNodeServiceRequest( config, new StopServiceType( ) );
+ }
+
+ @Override
+ public void fireEnable( ServiceConfiguration config ) throws ServiceRegistrationException {
+ sendNodeServiceRequest( config, new EnableServiceType( ) );
+ }
+
+ @Override
+ public void fireDisable( ServiceConfiguration config ) throws ServiceRegistrationException {
+ sendNodeServiceRequest( config, new DisableServiceType( ) );
+ }
+
+ @Override
+ public void fireCheck( ServiceConfiguration config ) throws ServiceRegistrationException {
+ sendNodeServiceRequest( config, new DescribeServicesType( ) );
+ }
+
+ @Override
+ public NodeControllerConfiguration newInstance( String partition, String name, String host, Integer port ) {
+ return new NodeControllerConfiguration( partition, host );
+ }
+
+ @Override
+ public NodeControllerConfiguration newInstance( ) {
+ return new NodeControllerConfiguration( );
+ }
+
+ private static <T extends BaseMessage> T sendNodeServiceRequest( ServiceConfiguration config, ServiceTransitionType msg ) throws RuntimeException {
+ ServiceConfiguration ccConfig = Topology.lookup( ClusterController.class, Partitions.lookupByName( config.getPartition( ) ) );
+ ServiceId serviceId = ServiceConfigurations.ServiceConfigurationToServiceId.INSTANCE.apply( config );
+ msg.getServices().add( serviceId );
+ try {
+ return AsyncRequests.sendSync( ccConfig, msg );
+ } catch ( Exception ex ) {
+ throw Exceptions.toUndeclared( ex );
+ }
+ }
+
+}
View
88 ...ster-manager/src/main/java/com/eucalyptus/node/NodeControllerConfigurationMessages.groovy
@@ -0,0 +1,88 @@
+/*************************************************************************
+ * Copyright 2009-2012 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.node
+
+import java.util.ArrayList;
+import com.eucalyptus.config.ConfigurationMessage;
+import com.eucalyptus.config.DeregisterComponentResponseType;
+import com.eucalyptus.config.DeregisterComponentType;
+import com.eucalyptus.config.DescribeComponentsResponseType;
+import com.eucalyptus.config.DescribeComponentsType;
+import com.eucalyptus.config.ModifyComponentAttributeResponseType;
+import com.eucalyptus.config.ModifyComponentAttributeType;
+import com.eucalyptus.config.NodeComponentInfoType;
+import com.eucalyptus.config.RegisterComponentResponseType;
+import com.eucalyptus.config.RegisterComponentType;
+
+public class RegisterNodeControllerType extends RegisterComponentType {}
+public class RegisterNodeControllerResponseType extends RegisterComponentResponseType {}
+public class DeregisterNodeControllerType extends DeregisterComponentType {}
+public class DeregisterNodeControllerResponseType extends DeregisterComponentResponseType {}
+public class ModifyNodeControllerAttributeType extends ModifyComponentAttributeType{}
+public class ModifyNodeControllerAttributeResponseType extends ModifyComponentAttributeResponseType {}
+public class DescribeNodeControllersType extends DescribeComponentsType {}
+public class DescribeNodeControllersResponseType extends DescribeComponentsResponseType {}
+public class DescribeNodesType extends ConfigurationMessage {}
+public class DescribeNodesResponseType extends ConfigurationMessage {
+ ArrayList<NodeComponentInfoType> registered = new ArrayList<NodeComponentInfoType>();
+}
View
222 clc/modules/cluster-manager/src/main/java/com/eucalyptus/node/Nodes.java
@@ -0,0 +1,222 @@
+/*************************************************************************
+ * Copyright 2009-2012 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.node;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nullable;
+import org.apache.log4j.Logger;
+import com.eucalyptus.cluster.Cluster;
+import com.eucalyptus.cluster.Clusters;
+import com.eucalyptus.component.Component;
+import com.eucalyptus.component.ComponentIds;
+import com.eucalyptus.component.Components;
+import com.eucalyptus.component.ServiceBuilder;
+import com.eucalyptus.component.ServiceBuilders;
+import com.eucalyptus.component.ServiceConfiguration;
+import com.eucalyptus.component.ServiceConfigurations;
+import com.eucalyptus.component.Topology;
+import com.eucalyptus.component.id.ClusterController;
+import com.eucalyptus.util.Exceptions;
+import com.eucalyptus.vm.VmInstance;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import edu.ucsb.eucalyptus.cloud.NodeInfo;
+import edu.ucsb.eucalyptus.msgs.NodeType;
+
+public class Nodes {
+ private static Logger LOG = Logger.getLogger( Nodes.class );
+ public static Long REFRESH_TIMEOUT = TimeUnit.MINUTES.toMillis( 10 );
+ private static Function<String, NodeInfo> lookupNodeInfo( final ServiceConfiguration ccConfig ) {
+ return new Function<String, NodeInfo>( ) {
+
+ @Override
+ public NodeInfo apply( @Nullable String ncHostOrTag ) {
+ Map<String, NodeInfo> map = Clusters.lookup( ccConfig ).getNodeHostMap( );
+ if ( map.containsKey( ncHostOrTag ) ) {
+ return map.get( ncHostOrTag );
+ } else {
+ throw new NoSuchElementException( "Failed to lookup node using " + ncHostOrTag + ". Available nodes are: " + Joiner.on( "\n" ).join( map.keySet( ) ) );
+ }
+ }
+ };
+
+ }
+
+ private static Function<NodeInfo, ServiceConfiguration> transformNodeInfo( final ServiceConfiguration ccConfig ) {
+ return new Function<NodeInfo, ServiceConfiguration>( ) {
+
+ @Override
+ public ServiceConfiguration apply( @Nullable NodeInfo input ) {
+ NodeController compId = ComponentIds.lookup( NodeController.class );
+ Component comp = Components.lookup( compId );
+ try {
+ return comp.lookup( input.getName( ) );
+ } catch ( final NoSuchElementException ex1 ) {
+ URI nodeUri = URI.create( input.getServiceTag( ) );
+ final ServiceBuilder<? extends ServiceConfiguration> builder = ServiceBuilders.lookup( comp.getComponentId( ) );
+ ServiceConfiguration config = builder.newInstance( ccConfig.getPartition( ), input.getName( ), nodeUri.getHost( ), nodeUri.getPort( ) );
+ comp.setup( config );
+ return config;
+ }
+ }
+ };
+ }
+
+ private static Function<String, ServiceConfiguration> lookupNodeServiceConfiguration( ServiceConfiguration ccConfig ) {
+ return Functions.compose( transformNodeInfo( ccConfig ), lookupNodeInfo( ccConfig ) );
+ }
+
+ public static void updateNodeInfo( ServiceConfiguration ccConfig, List<NodeType> nodes ) {
+ ConcurrentNavigableMap<String, NodeInfo> clusterNodeMap = Clusters.lookup( ccConfig ).getNodeMap( );
+ /** prepare key sets for comparison **/
+ Set<String> knownTags = Sets.newHashSet( clusterNodeMap.keySet( ) );
+ Set<String> reportedTags = Sets.newHashSet( );
+ for ( final NodeType node : nodes ) {
+ reportedTags.add( node.getServiceTag( ) );
+ }
+ /** compute intersections and differences **/
+ Set<String> unreportedTags = Sets.difference( knownTags, reportedTags );
+ Set<String> newTags = Sets.difference( reportedTags, knownTags );
+ Set<String> stillKnownTags = Sets.intersection( knownTags, reportedTags );
+ /** maybe remove unreported nodes **/
+ for ( String unreportedTag : unreportedTags ) {
+ NodeInfo unreportedNode = clusterNodeMap.get( unreportedTag );
+ if ( unreportedNode != null && ( System.currentTimeMillis( ) - unreportedNode.getLastSeen( ).getTime( ) ) > Nodes.REFRESH_TIMEOUT ) {
+ clusterNodeMap.remove( unreportedTag );
+ //TODO:GRZE: this is where unreported node service configurations need to be updated!
+ }
+ }
+ /** add new nodes or updated existing node infos **/
+ for ( final NodeType node : nodes ) {
+ String serviceTag = node.getServiceTag( );
+ if ( newTags.contains( serviceTag ) ) {
+ clusterNodeMap.putIfAbsent( serviceTag, new NodeInfo( ccConfig.getPartition( ), node ) );
+ NodeInfo nodeInfo = clusterNodeMap.get( serviceTag );
+ nodeInfo.touch( );
+ Nodes.updateServiceConfiguration( ccConfig, nodeInfo );
+ } else if ( stillKnownTags.contains( serviceTag ) ) {
+ NodeInfo nodeInfo = clusterNodeMap.get( serviceTag );
+ nodeInfo.touch( );
+ nodeInfo.setIqn( serviceTag );
+ Nodes.updateServiceConfiguration( ccConfig, nodeInfo );
+ }
+ }
+ /**
+ * TODO:GRZE: if not present emulate {@link ClusterController.NodeController} using
+ * {@link Component#setup()} TODO:GRZE: emulate update of emulate
+ * {@link ClusterController.NodeController} state
+ * TODO:GRZE: {@link Component#destroy()} for the NodeControllers which are not reported by the
+ * CC.
+ */
+
+ }
+
+ public static ServiceConfiguration lookup( ServiceConfiguration ccConfig, String hostOrTag ) throws NoSuchElementException {
+ return Nodes.lookupNodeServiceConfiguration( ccConfig ).apply( hostOrTag );
+ }
+
+ private static void updateServiceConfiguration( ServiceConfiguration ccConfig, NodeInfo nodeInfo ) throws NoSuchElementException {
+ //GRZE:TODO:MAINTMODE: this is a hack in order to inject ephemeral configs for the NCs
+ ServiceConfiguration ncConfig = Nodes.lookup( ccConfig, nodeInfo.getName( ) );
+
+ Component component = Components.lookup( NodeController.class );
+ if ( !component.hasService( ncConfig ) ) {
+ component.setup( ncConfig );
+ Topology.disable( ncConfig );
+ }
+ }
+
+ public static List<String> lookupIqns( ServiceConfiguration ccConfig ) {
+ Cluster cluster = Clusters.lookup( ccConfig );
+ Set<String> ret = Sets.newHashSet( );
+ for ( NodeInfo node : cluster.getNodeMap( ).values( ) ) {
+ if ( node.getIqn( ) != null ) {
+ ret.add( node.getIqn( ) );
+ }
+ }
+ return Lists.newArrayList( ret );
+ }
+
+ public static List<String> lookupIqn( VmInstance vm ) {
+ ServiceConfiguration ccConfig = Topology.lookup( ClusterController.class, vm.lookupPartition( ) );
+ Cluster cluster = Clusters.lookup( ccConfig );
+ NodeInfo node = cluster.getNode( vm.getServiceTag( ) );
+ if ( node == null ) {
+ throw new NoSuchElementException( "Failed to look up node information for " + vm.getInstanceId( ) + " with service tag " + vm.getServiceTag( ) );
+ } else if ( node.getIqn( ) == null ) {
+ throw new NoSuchElementException( "Error looking up iqn for node " + vm.getServiceTag( ) + " (" + vm.getInstanceId( ) + "): node does not have an iqn." );
+ } else {
+ return Lists.newArrayList( node.getIqn( ) );
+ }
+ }
+}
View
2  clc/modules/cluster-manager/src/main/java/com/eucalyptus/tags/TagManager.java
@@ -171,7 +171,7 @@ public boolean apply( final Void v ) {
Tags.delete( example, TagSupport.fromResource( resource ).exampleCriterion( example ), Collections.<String,String>emptyMap() );
}
} catch ( NoSuchMetadataException e ) {
- log.debug( e, e );
+ log.trace( e );
} catch ( MetadataException e ) {
throw Exceptions.toUndeclared(e);
}
View
122 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/MigrationState.java
@@ -0,0 +1,122 @@
+/*************************************************************************
+ * Copyright 2009-2012 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.vm;
+
+import javax.annotation.Nullable;
+import org.apache.log4j.Logger;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+
+/**
+ * @todo doc
+ * @author chris grzegorczyk <grze@eucalyptus.com>
+ */
+public enum MigrationState {
+ none {
+ @Override
+ public boolean isMigrating( ) {
+ return false;
+ }
+ },
+ pending,
+ preparing,
+ ready,
+ migrating,
+ cleaning;
+ private static Logger LOG = Logger.getLogger( MigrationState.class );
+
+ public static boolean isMigrating( VmInstance vm ) {
+ return VmInstanceFilter.INSTANCE.apply( vm );
+ }
+
+ public enum VmInstanceFilter implements Predicate<VmInstance> {
+ INSTANCE;
+
+ /**
+ * @see com.google.common.base.Predicate#apply(java.lang.Object)
+ */
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ return input.getRuntimeState( ).getMigrationTask( ).getState( ).isMigrating( );
+ }
+
+ }
+
+ public boolean isMigrating( ) {
+ return true;
+ }
+
+ public static MigrationState defaultValueOf( String state ) {
+ if ( !Strings.isNullOrEmpty( state ) ) {
+ try {
+ return MigrationState.valueOf( state );
+ } catch ( IllegalArgumentException ex ) {
+ LOG.debug( ex );
+ return none;
+ }
+ } else {
+ return none;
+ }
+ }
+
+}
View
145 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/MigrationTags.java
@@ -0,0 +1,145 @@
+/*************************************************************************
+ * Copyright 2009-2012 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.vm;
+
+import javax.annotation.Nullable;
+import org.apache.log4j.Logger;
+import com.eucalyptus.component.Topology;
+import com.eucalyptus.component.id.Eucalyptus;
+import com.eucalyptus.util.async.AsyncRequests;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import edu.ucsb.eucalyptus.msgs.CreateTagsType;
+import edu.ucsb.eucalyptus.msgs.DeleteResourceTag;
+import edu.ucsb.eucalyptus.msgs.DeleteTagsType;
+import edu.ucsb.eucalyptus.msgs.ResourceTag;
+import edu.ucsb.eucalyptus.msgs.ResourceTagMessage;
+
+enum MigrationTags implements Predicate<VmInstance> {
+ STATE,
+ SOURCE,
+ DESTINATION;
+ private static Logger LOG = Logger.getLogger( MigrationTags.class );
+
+ public String toString( ) {
+ return "euca:node:migration:" + this.name( ).toLowerCase( );
+ }
+
+ public static void deleteFor( final VmInstance vm ) {
+ final DeleteTagsType deleteTags = new DeleteTagsType( );
+ deleteTags.getTagSet( ).add( MigrationTags.STATE.deleteTag( ) );
+ deleteTags.getTagSet( ).add( MigrationTags.SOURCE.deleteTag( ) );
+ deleteTags.getTagSet( ).add( MigrationTags.DESTINATION.deleteTag( ) );
+ deleteTags.getResourcesSet( ).add( vm.getInstanceId( ) );
+ deleteTags.setEffectiveUserId( vm.getOwnerUserId( ) );//GRZE:TODO: update impersonation impl later.
+ dispatch( deleteTags );
+ }
+
+ private static void dispatch( final ResourceTagMessage tagMessage ) {
+ try {
+ AsyncRequests.dispatch( Topology.lookup( Eucalyptus.class ), tagMessage );
+ } catch ( Exception ex ) {
+ LOG.trace( ex );
+ }
+ }
+
+ public static void createFor( final VmInstance vm ) {
+ final VmMigrationTask migrationTask = vm.getRuntimeState( ).getMigrationTask( );
+ final CreateTagsType createTags = new CreateTagsType( );
+ createTags.getTagSet( ).add( MigrationTags.STATE.getTag( migrationTask.getState( ).name( ) ) );
+ if ( !Strings.isNullOrEmpty( migrationTask.getSourceHost( ) ) ) {
+ createTags.getTagSet( ).add( MigrationTags.SOURCE.getTag( migrationTask.getSourceHost( ) ) );
+ }
+ if ( !Strings.isNullOrEmpty( migrationTask.getDestinationHost( ) ) ) {
+ createTags.getTagSet( ).add( MigrationTags.DESTINATION.getTag( migrationTask.getDestinationHost( ) ) );
+ }
+ createTags.getResourcesSet( ).add( vm.getInstanceId( ) );
+ createTags.setEffectiveUserId( vm.getOwnerUserId( ) );//GRZE:TODO: update impersonation impl later.
+ dispatch( createTags );
+ }
+
+ ResourceTag getTag( String value ) {
+ return new ResourceTag( this.toString( ), value );
+ }
+
+ private DeleteResourceTag deleteTag( ) {
+ DeleteResourceTag rsrcTag = new DeleteResourceTag( );
+ rsrcTag.setKey( this.toString( ) );
+ return rsrcTag;
+ }
+
+ @Override
+ public boolean apply( @Nullable VmInstance input ) {
+ VmMigrationTask task = input.getRuntimeState( ).getMigrationTask( );
+ if ( MigrationState.none.equals( task.getState( ) ) ) {
+ MigrationTags.deleteFor( input );
+ } else {
+ MigrationTags.createFor( input );
+ }
+ return true;
+ }
+
+ public static void update( VmInstance input ) {
+ SOURCE.apply( input );
+ }
+}
View
8 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmControl.java
@@ -342,6 +342,12 @@ public TerminateInstancesItemType apply( final String instanceId ) {
TerminateInstancesItemType result = null;
try {
VmInstance vm = RestrictedTypes.doPrivileged( instanceId, VmInstance.class );
+ if ( MigrationState.isMigrating( vm ) ) {
+ throw Exceptions.toUndeclared( "Cannot terminate an instance which is currently migrating: "
+ + vm.getInstanceId( )
+ + " "
+ + vm.getMigrationTask( ) );
+ }
oldCode = vm.getState( ).getCode( );
oldState = vm.getState( ).getName( );
if ( VmState.STOPPED.apply( vm ) ) {
@@ -574,7 +580,7 @@ public boolean apply( final String instanceId ) {
try {
final VmInstance v = VmInstances.lookup( instanceId );
if ( RestrictedTypes.filterPrivileged( ).apply( v ) ) {
- if ( v.getBootRecord( ).getMachine( ) instanceof BlockStorageImageInfo ) {
+ if ( !MigrationState.isMigrating( v ) && v.getBootRecord( ).getMachine( ) instanceof BlockStorageImageInfo ) {
final int oldCode = v.getState( ).getCode( ), newCode = VmState.STOPPING.getCode( );
final String oldState = v.getState( ).getName( ), newState = VmState.STOPPING.getName( );
TerminateInstancesItemType termInfo = new TerminateInstancesItemType( v.getInstanceId( ), oldCode, oldState, newCode, newState );
View
11 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmInstance.java
@@ -2108,4 +2108,15 @@ public void setDeleteOnTerminate( boolean deleteOnterminate ) {
this.bootRecord.setDeleteOnTerminate( deleteOnterminate );
}
+ public void startMigration( ) {
+ this.runtimeState.startMigration( );
+ }
+
+ public void abortMigration( ) {
+ this.runtimeState.abortMigration( );
+ }
+
+ public VmMigrationTask getMigrationTask( ) {
+ return this.runtimeState.getMigrationTask( );
+ }
}
View
3  clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmInstances.java
@@ -255,6 +255,9 @@ protected boolean inState( final VmState state ) {
@ConfigurableField( description = "Maximum amount of time (in seconds) that the network topology service takes to propagate state changes.",
initial = "" + 60 * 60 * 1000 )
public static Long NETWORK_METADATA_REFRESH_TIME = 15l;
+ @ConfigurableField( description = "Maximum amount of time (in seconds) that migration state will take to propagate state changes (e.g., to tags).",
+ initial = "" + 60 )
+ public static Long MIGRATION_REFRESH_TIME = 60l;
@ConfigurableField( description = "Prefix to use for instance MAC addresses.",
initial = "d0:0d" )
public static String MAC_PREFIX = "d0:0d";
View
167 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmMigrationTask.java
@@ -62,12 +62,18 @@
package com.eucalyptus.vm;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import org.apache.log4j.Logger;
import org.hibernate.annotations.Parent;
-import com.google.common.base.Function;
+import com.google.common.base.Strings;
/**
* @todo doc
@@ -75,92 +81,155 @@
*/
@Embeddable
public class VmMigrationTask {
- public enum MigrationState {
- none( "none" );
- private String mappedState;
-
- MigrationState( final String mappedState ) {
- this.mappedState = mappedState;
- }
-
- public String getMappedState( ) {
- return this.mappedState;
- }
-
- public static Function<String, MigrationState> mapper = new Function<String, MigrationState>( ) {
-
- @Override
- public MigrationState apply( final String input ) {
- if ( input != null ) {
- for ( final MigrationState s : MigrationState.values( ) ) {
- if ( ( s.getMappedState( ) != null ) && s.getMappedState( ).equals( input ) ) {
- return s;
- }
- }
- }
- return none;
- }
- };
+ @Override
+ public String toString( ) {
+ StringBuilder builder = new StringBuilder( );
+ if ( this.state != null ) builder.append( this.state );
+ if ( this.sourceHost != null && this.destinationHost != null ) builder.append( " " ).append( this.sourceHost ).append( "->" ).append( this.destinationHost );
+ return builder.toString( );
}
+
+ @Transient
+ private static Logger LOG = Logger.getLogger( VmMigrationTask.class );
@Parent
private VmInstance vmInstance;
+
+ /**
+ * Most recently reported migration state.
+ *
+ * @see {@link MigrationState}
+ */
@Enumerated( EnumType.STRING )
@Column( name = "metadata_vm_migration_state" )
private MigrationState state;
+
+ /**
+ * Source host for the migration as it is registered.
+ */
+ @Enumerated( EnumType.STRING )
@Column( name = "metadata_vm_migration_source_host" )
private String sourceHost;
+
+ /**
+ * Destination host for the migration as it is registered.
+ */
@Column( name = "metadata_vm_migration_dest_host" )
private String destinationHost;
+ /**
+ * The purpose of this timestamp is to serve as a periodic trigger for state propagation; viz. to
+ * tags (unlike the AbstractPersistent timestamps). In
+ * {@code #updateMigrationTask(String, String, String)} this timer is used to determine when a
+ * false-positive indicate that state needs to be refreshed.
+ *
+ * @see {@link #updateMigrationTask(String, String, String)}
+ */
+ @Temporal( TemporalType.TIMESTAMP )
+ @Column( name = "metadata_vm_migration_state_timer" )
+ private Date refreshTimer;
+
private VmMigrationTask( ) {}
- private VmMigrationTask( VmInstance vmInstance, String state, String sourceHost, String destinationHost ) {
+ private VmMigrationTask( VmInstance vmInstance, MigrationState state, String sourceHost, String destinationHost ) {
this.vmInstance = vmInstance;
- this.state = MigrationState.mapper.apply( state );
- this.sourceHost = sourceHost;
- this.destinationHost = destinationHost;
+ this.state = state;
+ this.sourceHost = Strings.nullToEmpty( sourceHost );
+ this.destinationHost = Strings.nullToEmpty( destinationHost );
+ this.refreshTimer = new Date( );
+ }
+
+ private VmMigrationTask( VmInstance vmInstance, String state, String sourceHost, String destinationHost ) {
+ this( vmInstance, MigrationState.defaultValueOf( state ), sourceHost, destinationHost );
+ }
+
+ public static VmMigrationTask create( VmInstance vmInstance ) {
+ return new VmMigrationTask( vmInstance, MigrationState.none, null, null );
}
public static VmMigrationTask create( VmInstance vmInstance, String state, String sourceHost, String destinationHost ) {
return new VmMigrationTask( vmInstance, state, sourceHost, destinationHost );
}
+
+ /**
+ * Verify and update the local state, src and dest hosts.
+ *
+ * @param state
+ * @param sourceHost
+ * @param destinationHost
+ */
+ boolean updateMigrationTask( String state, String sourceHost, String destinationHost ) {
+ MigrationState migrationState = MigrationState.defaultValueOf( state );
+ /**
+ * GRZE:TODO: this entire notion of refresh timer can be (and should be!) made orthogonal to the
+ * domain type. Indeed, the idea that an external operation wants to have a timer associated
+ * with a resource, in this case periodic tag propagation, is decidedly external state and this
+ * should GTFO.
+ */
+ boolean timerExpired = ( System.currentTimeMillis( ) - this.getRefreshTimer( ).getTime( ) ) > TimeUnit.SECONDS.toMillis( VmInstances.MIGRATION_REFRESH_TIME );
+ if ( !timerExpired && MigrationState.pending.equals( this.getState( ) ) && migrationState.ordinal( ) < MigrationState.preparing.ordinal( ) ) {
+ return false;
+ } else {
+ boolean updated = !this.getState( ).equals( migrationState ) || !this.getSourceHost( ).equals( sourceHost ) || !this.getDestinationHost( ).equals( destinationHost );
+ this.setState( migrationState );
+ this.setSourceHost( sourceHost );
+ this.setDestinationHost( destinationHost );
+ if ( MigrationState.none.equals( this.getState( ) ) ) {
+ this.setRefreshTimer( null );
+ return updated || timerExpired;
+ } else if ( timerExpired ) {
+ this.updateRefreshTimer( );
+ return true;
+ } else {
+ return updated;
+ }
+ }
+ }
+
+ protected Date getRefreshTimer( ) {
+ return this.refreshTimer == null ? this.refreshTimer = new Date( ) : this.refreshTimer;
+ }
+
+ protected void setRefreshTimer( Date refreshTimer ) {
+ this.refreshTimer = refreshTimer;
+ }
- void updateMigrationState( String state, String sourceHost, String destinationHost ) {
- this.state = MigrationState.mapper.apply( state );
- this.sourceHost = sourceHost;
- this.destinationHost = destinationHost;
+ private void updateRefreshTimer( ) {
+ this.setRefreshTimer( new Date( ) );
}
protected VmInstance getVmInstance( ) {
return this.vmInstance;
}
-
+
protected void setVmInstance( VmInstance vmInstance ) {
this.vmInstance = vmInstance;
}
-
- protected MigrationState getState( ) {
+
+ public MigrationState getState( ) {
return this.state;
}
-
+
protected void setState( MigrationState state ) {
- this.state = state;
+ if ( !this.equals( state ) ) {
+ this.updateRefreshTimer( );
+ this.state = state;
+ }
}
-
- protected String getSourceHost( ) {
+
+ public String getSourceHost( ) {
return this.sourceHost;
}
-
+
protected void setSourceHost( String sourceHost ) {
- this.sourceHost = sourceHost;
+ this.sourceHost = Strings.nullToEmpty( sourceHost );
}
-
- protected String getDestinationHost( ) {
+
+ public String getDestinationHost( ) {
return this.destinationHost;
}
-
+
protected void setDestinationHost( String destinationHost ) {
- this.destinationHost = destinationHost;
+ this.destinationHost = Strings.nullToEmpty( destinationHost );
}
-}
+}
View
214 clc/modules/cluster-manager/src/main/java/com/eucalyptus/vm/VmRuntimeState.java
@@ -62,6 +62,7 @@
package com.eucalyptus.vm;
+import java.net.URI;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.Callable;
@@ -84,12 +85,12 @@
import org.hibernate.annotations.Type;
import com.eucalyptus.cluster.Cluster;
import com.eucalyptus.cluster.Clusters;
-import com.eucalyptus.cluster.Nodes;
import com.eucalyptus.component.ServiceConfiguration;
import com.eucalyptus.component.Topology;
import com.eucalyptus.component.id.ClusterController;
import com.eucalyptus.component.id.Eucalyptus;
import com.eucalyptus.component.id.Storage;
+import com.eucalyptus.node.Nodes;
import com.eucalyptus.records.EventRecord;
import com.eucalyptus.records.EventType;
import com.eucalyptus.records.Logs;
@@ -103,44 +104,51 @@
import com.eucalyptus.vm.VmInstance.VmState;
import com.eucalyptus.vm.VmInstance.VmStateSet;
import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import edu.ucsb.eucalyptus.msgs.AttachStorageVolumeResponseType;
import edu.ucsb.eucalyptus.msgs.AttachStorageVolumeType;
import edu.ucsb.eucalyptus.msgs.AttachVolumeType;
+import edu.ucsb.eucalyptus.msgs.CreateTagsType;
+import edu.ucsb.eucalyptus.msgs.ResourceTag;
@Embeddable
public class VmRuntimeState {
+ /**
+ *
+ */
+ private static final String VM_NC_HOST_TAG = "euca:node";
@Transient
- private static String SEND_USER_TERMINATE = "SIGTERM";
+ private static String SEND_USER_TERMINATE = "SIGTERM";
@Transient
- private static String SEND_USER_STOP = "SIGSTOP";
+ private static String SEND_USER_STOP = "SIGSTOP";
@Transient
- private static Logger LOG = Logger.getLogger( VmRuntimeState.class );
+ private static Logger LOG = Logger.getLogger( VmRuntimeState.class );
@Parent
- private VmInstance vmInstance;
+ private VmInstance vmInstance;
@Embedded
- private VmBundleTask bundleTask;
+ private VmBundleTask bundleTask;
@Embedded
- private VmCreateImageTask createImageTask;
+ private VmCreateImageTask createImageTask;
@Column( name = "metadata_vm_service_tag" )
- private String serviceTag;
+ private String serviceTag;
@Enumerated( EnumType.STRING )
@Column( name = "metadata_vm_reason" )
- private Reason reason;
+ private Reason reason;
@ElementCollection
@CollectionTable( name = "metadata_instances_state_reasons" )
@Cache( usage = CacheConcurrencyStrategy.TRANSACTIONAL )
- private Set<String> reasonDetails = Sets.newHashSet( );
+ private Set<String> reasonDetails = Sets.newHashSet( );
@Transient
- private StringBuffer consoleOutput