5252import org .apache .cloudstack .jobs .JobInfo ;
5353import org .apache .cloudstack .storage .datastore .db .PrimaryDataStoreDao ;
5454import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
55+ import org .apache .commons .collections .CollectionUtils ;
5556import org .apache .commons .lang3 .StringUtils ;
5657import org .joda .time .DateTime ;
5758import org .springframework .stereotype .Component ;
8687import com .cloud .vm .VMInstanceVO ;
8788import com .cloud .vm .VirtualMachine ;
8889import com .cloud .vm .VirtualMachine .State ;
90+ import com .cloud .vm .VirtualMachineManager ;
8991import com .cloud .vm .VmDetailConstants ;
9092import com .cloud .vm .VmWork ;
9193import com .cloud .vm .VmWorkConstants ;
@@ -136,6 +138,9 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
136138 @ Inject
137139 AsyncJobManager asyncJobManager ;
138140
141+ @ Inject
142+ VirtualMachineManager virtualMachineManager ;
143+
139144 VmWorkJobHandlerProxy jobHandlerProxy = new VmWorkJobHandlerProxy (this );
140145
141146 private void verifyKVMBackupExportServiceSupported (Long zoneId ) {
@@ -145,24 +150,44 @@ private void verifyKVMBackupExportServiceSupported(Long zoneId) {
145150 }
146151 }
147152
153+ protected void validateVmVolumesForBackup (VMInstanceVO vm ) {
154+ List <VolumeVO > volumes = volumeDao .findByInstanceAndNotStates (vm .getId (), Volume .State .Ready );
155+ List <String > nonReadyVolumeIds = volumes
156+ .stream ()
157+ .map (VolumeVO ::getUuid )
158+ .collect (Collectors .toList ());
159+ if (CollectionUtils .isNotEmpty (nonReadyVolumeIds )) {
160+ throw new CloudRuntimeException (String .format ("Volumes [%s] of Instance: %s are not in Ready state" ,
161+ StringUtils .join (nonReadyVolumeIds , "," ), vm .getUuid ()));
162+ }
163+ }
164+
148165 @ Override
149166 public Backup createBackup (StartBackupCmd cmd ) {
150167 Long vmId = cmd .getVmId ();
151168
152169 VMInstanceVO vm = vmInstanceDao .findById (vmId );
153170 if (vm == null ) {
154- throw new CloudRuntimeException ("VM not found: " + vmId );
171+ throw new CloudRuntimeException ("Instance not found: " + vmId );
155172 }
156173
157174 verifyKVMBackupExportServiceSupported (vm .getDataCenterId ());
158175
159176 if (vm .getState () != State .Running && vm .getState () != State .Stopped ) {
160- throw new CloudRuntimeException ("VM must be running or stopped to start backup " );
177+ throw new CloudRuntimeException ("Instance must be running or stopped to start Backup " );
161178 }
162179
163180 Backup existingBackup = backupDao .findByVmId (vmId );
164181 if (existingBackup != null && existingBackup .getStatus () == Backup .Status .BackingUp ) {
165- throw new CloudRuntimeException ("Backup already in progress for VM: " + vmId );
182+ throw new CloudRuntimeException ("Backup already in progress for Instance: " + vm .getUuid ());
183+ }
184+
185+ validateVmVolumesForBackup (vm );
186+
187+ Pair <Long , Long > clusterAndHostId = virtualMachineManager .findClusterAndHostIdForVm (vm , false );
188+ Long hostId = clusterAndHostId .second ();
189+ if (hostId == null ) {
190+ throw new CloudRuntimeException ("Host cannot be determined for Instance: " + vm .getUuid ());
166191 }
167192
168193 BackupVO backup = new BackupVO ();
@@ -190,8 +215,6 @@ public Backup createBackup(StartBackupCmd cmd) {
190215 backup .setToCheckpointId (toCheckpointId );
191216 backup .setFromCheckpointId (fromCheckpointId );
192217 backup .setType ("FULL" );
193-
194- Long hostId = vm .getHostId () != null ? vm .getHostId () : vm .getLastHostId ();
195218 backup .setHostId (hostId );
196219
197220 return backupDao .persist (backup );
@@ -231,15 +254,20 @@ public Backup startBackup(StartBackupCmd cmd) {
231254 Long vmId = cmd .getVmId ();
232255 VMInstanceVO vm = vmInstanceDao .findById (vmId );
233256 if (vm == null ) {
234- throw new CloudRuntimeException ("VM not found: " + vmId );
257+ removeFailedBackup (backup );
258+ throw new CloudRuntimeException ("Instance not found for Backup: " + backup .getUuid ());
235259 }
236260 List <VolumeVO > volumes = volumeDao .findByInstance (vmId );
237261 Map <String , String > diskPathUuidMap = new HashMap <>();
238262 for (Volume vol : volumes ) {
263+ if (vol .getPoolId () == null ) {
264+ removeFailedBackup (backup );
265+ throw new CloudRuntimeException ("Storage Pool cannot be determined for Volume: " + vol .getUuid ());
266+ }
239267 String volumePath = getVolumePathForFileBasedBackend (vol );
240268 diskPathUuidMap .put (volumePath , vol .getUuid ());
241269 }
242- long hostId = backup .getHostId ();
270+ Long hostId = backup .getHostId ();
243271
244272 VMInstanceDetailVO lastCheckpointId = vmInstanceDetailsDao .findDetail (vmId , VmDetailConstants .LAST_CHECKPOINT_ID );
245273 if (lastCheckpointId != null ) {
@@ -249,6 +277,10 @@ public Backup startBackup(StartBackupCmd cmd) {
249277 logger .warn ("Failed to delete last checkpoint {} for VM {}, proceeding with backup start" , lastCheckpointId .getValue (), vmId , e );
250278 }
251279 }
280+ if (hostId == null ) {
281+ removeFailedBackup (backup );
282+ throw new CloudRuntimeException ("Host cannot be found for Backup: " + backup .getUuid ());
283+ }
252284
253285 Host host = hostDao .findById (hostId );
254286 Map <String , String > vmDetails = vmInstanceDetailsDao .listDetailsKeyPairs (vmId );
@@ -276,7 +308,7 @@ public Backup startBackup(StartBackupCmd cmd) {
276308 if (!answer .getResult ()) {
277309 removeFailedBackup (backup );
278310 logger .error ("Failed to start {} due to: {}" , backup , answer .getDetails ());
279- throw new CloudRuntimeException ("Failed to start backup : " + answer .getDetails ());
311+ throw new CloudRuntimeException ("Failed to start Backup : " + answer .getDetails ());
280312 }
281313
282314 // Update backup with checkpoint creation time
0 commit comments