30
30
import javax .inject .Inject ;
31
31
import javax .naming .ConfigurationException ;
32
32
33
+ import com .cloud .vm .dao .UserVmDetailsDao ;
33
34
import org .apache .cloudstack .api .ApiConstants ;
34
35
import org .apache .cloudstack .api .command .admin .cluster .AddClusterCmd ;
35
36
import org .apache .cloudstack .api .command .admin .cluster .DeleteClusterCmd ;
53
54
import com .cloud .agent .AgentManager ;
54
55
import com .cloud .agent .api .Answer ;
55
56
import com .cloud .agent .api .Command ;
57
+ import com .cloud .agent .api .GetVncPortCommand ;
58
+ import com .cloud .agent .api .GetVncPortAnswer ;
56
59
import com .cloud .agent .api .GetGPUStatsAnswer ;
57
60
import com .cloud .agent .api .GetGPUStatsCommand ;
58
61
import com .cloud .agent .api .GetHostStatsAnswer ;
74
77
import com .cloud .capacity .dao .CapacityDao ;
75
78
import com .cloud .cluster .ClusterManager ;
76
79
import com .cloud .configuration .Config ;
80
+ import com .cloud .configuration .ConfigurationManager ;
77
81
import com .cloud .dc .ClusterDetailsDao ;
78
82
import com .cloud .dc .ClusterDetailsVO ;
79
83
import com .cloud .dc .ClusterVO ;
@@ -247,7 +251,11 @@ public void setDiscoverers(final List<? extends Discoverer> discoverers) {
247
251
@ Inject
248
252
private VMTemplateDao _templateDao ;
249
253
@ Inject
254
+ private ConfigurationManager _configMgr ;
255
+ @ Inject
250
256
private ClusterVSMMapDao _clusterVSMMapDao ;
257
+ @ Inject
258
+ private UserVmDetailsDao userVmDetailsDao ;
251
259
252
260
private final long _nodeId = ManagementServerNode .getManagementServerId ();
253
261
@@ -606,7 +614,7 @@ public List<? extends Host> discoverHosts(final AddSecondaryStorageCmd cmd) thro
606
614
607
615
private List <HostVO > discoverHostsFull (final Long dcId , final Long podId , Long clusterId , final String clusterName , String url , String username , String password ,
608
616
final String hypervisorType , final List <String > hostTags , final Map <String , String > params , final boolean deferAgentCreation ) throws IllegalArgumentException , DiscoveryException ,
609
- InvalidParameterValueException {
617
+ InvalidParameterValueException {
610
618
URI uri = null ;
611
619
612
620
// Check if the zone exists in the system
@@ -1282,6 +1290,68 @@ public Host maintain(final PrepareForMaintenanceCmd cmd) {
1282
1290
}
1283
1291
}
1284
1292
1293
+ /**
1294
+ * Add VNC details as user VM details for each VM in 'vms' (KVM hosts only)
1295
+ */
1296
+ protected void setKVMVncAccess (long hostId , List <VMInstanceVO > vms ) {
1297
+ for (VMInstanceVO vm : vms ) {
1298
+ GetVncPortAnswer vmVncPortAnswer = (GetVncPortAnswer ) _agentMgr .easySend (hostId , new GetVncPortCommand (vm .getId (), vm .getInstanceName ()));
1299
+ if (vmVncPortAnswer != null ) {
1300
+ userVmDetailsDao .addDetail (vm .getId (), "kvm.vnc.address" , vmVncPortAnswer .getAddress (), true );
1301
+ userVmDetailsDao .addDetail (vm .getId (), "kvm.vnc.port" , String .valueOf (vmVncPortAnswer .getPort ()), true );
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ /**
1307
+ * Configure VNC access for host VMs which have failed migrating to another host while trying to enter Maintenance mode
1308
+ */
1309
+ protected void configureVncAccessForKVMHostFailedMigrations (HostVO host , List <VMInstanceVO > failedMigrations ) {
1310
+ if (host .getHypervisorType ().equals (HypervisorType .KVM )) {
1311
+ _agentMgr .pullAgentOutMaintenance (host .getId ());
1312
+ setKVMVncAccess (host .getId (), failedMigrations );
1313
+ _agentMgr .pullAgentToMaintenance (host .getId ());
1314
+ }
1315
+ }
1316
+
1317
+ /**
1318
+ * Set host into ErrorInMaintenance state, as errors occurred during VM migrations. Do the following:
1319
+ * - Cancel scheduled migrations for those which have already failed
1320
+ * - Configure VNC access for VMs (KVM hosts only)
1321
+ */
1322
+ protected boolean setHostIntoErrorInMaintenance (HostVO host , List <VMInstanceVO > failedMigrations ) throws NoTransitionException {
1323
+ s_logger .debug ("Unable to migrate " + failedMigrations .size () + " VM(s) from host " + host .getUuid ());
1324
+ _haMgr .cancelScheduledMigrations (host );
1325
+ configureVncAccessForKVMHostFailedMigrations (host , failedMigrations );
1326
+ resourceStateTransitTo (host , ResourceState .Event .UnableToMigrate , _nodeId );
1327
+ return false ;
1328
+ }
1329
+
1330
+ /**
1331
+ * Safely transit host into Maintenance mode
1332
+ */
1333
+ protected boolean setHostIntoMaintenance (HostVO host ) throws NoTransitionException {
1334
+ s_logger .debug ("Host " + host .getUuid () + " entering in Maintenance" );
1335
+ resourceStateTransitTo (host , ResourceState .Event .InternalEnterMaintenance , _nodeId );
1336
+ ActionEventUtils .onCompletedActionEvent (CallContext .current ().getCallingUserId (), CallContext .current ().getCallingAccountId (),
1337
+ EventVO .LEVEL_INFO , EventTypes .EVENT_MAINTENANCE_PREPARE ,
1338
+ "completed maintenance for host " + host .getId (), 0 );
1339
+ return true ;
1340
+ }
1341
+
1342
+ /**
1343
+ * Return true if host goes into Maintenance mode, only when:
1344
+ * - No Running, Migrating or Failed migrations (host_id = last_host_id) for the host
1345
+ */
1346
+ protected boolean isHostInMaintenance (HostVO host , List <VMInstanceVO > runningVms , List <VMInstanceVO > migratingVms , List <VMInstanceVO > failedMigrations ) throws NoTransitionException {
1347
+ if (CollectionUtils .isEmpty (runningVms ) && CollectionUtils .isEmpty (migratingVms )) {
1348
+ return CollectionUtils .isEmpty (failedMigrations ) ?
1349
+ setHostIntoMaintenance (host ) :
1350
+ setHostIntoErrorInMaintenance (host , failedMigrations );
1351
+ }
1352
+ return false ;
1353
+ }
1354
+
1285
1355
@ Override
1286
1356
public boolean checkAndMaintain (final long hostId ) {
1287
1357
boolean hostInMaintenance = false ;
@@ -1291,11 +1361,9 @@ public boolean checkAndMaintain(final long hostId) {
1291
1361
if (host .getType () != Host .Type .Storage ) {
1292
1362
final List <VMInstanceVO > vos = _vmDao .listByHostId (hostId );
1293
1363
final List <VMInstanceVO > vosMigrating = _vmDao .listVmsMigratingFromHost (hostId );
1294
- if (vos .isEmpty () && vosMigrating .isEmpty ()) {
1295
- resourceStateTransitTo (host , ResourceState .Event .InternalEnterMaintenance , _nodeId );
1296
- hostInMaintenance = true ;
1297
- ActionEventUtils .onCompletedActionEvent (CallContext .current ().getCallingUserId (), CallContext .current ().getCallingAccountId (), EventVO .LEVEL_INFO , EventTypes .EVENT_MAINTENANCE_PREPARE , "completed maintenance for host " + hostId , 0 );
1298
- }
1364
+ final List <VMInstanceVO > failedVmMigrations = _vmDao .listNonMigratingVmsByHostEqualsLastHost (hostId );
1365
+
1366
+ hostInMaintenance = isHostInMaintenance (host , vos , vosMigrating , failedVmMigrations );
1299
1367
}
1300
1368
} catch (final NoTransitionException e ) {
1301
1369
s_logger .debug ("Cannot transmit host " + host .getId () + "to Maintenance state" , e );
0 commit comments