2929import org .apache .cloudstack .engine .subsystem .api .storage .TemplateDataFactory ;
3030import org .apache .cloudstack .engine .subsystem .api .storage .TemplateInfo ;
3131import org .apache .cloudstack .engine .subsystem .api .storage .VolumeInfo ;
32+ import org .apache .cloudstack .engine .subsystem .api .storage .ObjectInDataStoreStateMachine ;
33+ import org .apache .cloudstack .storage .command .CopyCommand ;
34+ import org .apache .cloudstack .storage .datastore .DataStoreManagerImpl ;
3235import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
36+ import org .apache .cloudstack .storage .to .TemplateObjectTO ;
37+ import org .apache .commons .lang .StringUtils ;
38+ import org .apache .log4j .Logger ;
3339
3440import com .cloud .agent .api .Answer ;
3541import com .cloud .agent .api .MigrateCommand ;
3642import com .cloud .agent .api .MigrateCommand .MigrateDiskInfo ;
3743import com .cloud .agent .api .storage .CreateAnswer ;
3844import com .cloud .agent .api .storage .CreateCommand ;
3945import com .cloud .agent .api .to .VirtualMachineTO ;
46+ import com .cloud .exception .AgentUnavailableException ;
47+ import com .cloud .exception .OperationTimedoutException ;
4048import com .cloud .host .Host ;
4149import com .cloud .hypervisor .Hypervisor .HypervisorType ;
4250import com .cloud .storage .DataStoreRole ;
4351import com .cloud .storage .DiskOfferingVO ;
4452import com .cloud .storage .Storage .StoragePoolType ;
53+ import com .cloud .storage .StorageManager ;
54+ import com .cloud .storage .StoragePool ;
55+ import com .cloud .storage .VMTemplateStoragePoolVO ;
56+ import com .cloud .storage .VMTemplateStorageResourceAssoc ;
4557import com .cloud .storage .VolumeVO ;
58+ import com .cloud .storage .dao .VMTemplatePoolDao ;
4659import com .cloud .utils .exception .CloudRuntimeException ;
4760import com .cloud .vm .DiskProfile ;
61+ import com .cloud .vm .VirtualMachineManager ;
4862
4963/**
5064 * Extends {@link StorageSystemDataMotionStrategy}, allowing KVM hosts to migrate VMs with the ROOT volume on a non managed local storage pool.
@@ -54,6 +68,14 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
5468
5569 @ Inject
5670 private TemplateDataFactory templateDataFactory ;
71+ @ Inject
72+ private VMTemplatePoolDao vmTemplatePoolDao ;
73+ @ Inject
74+ private DataStoreManagerImpl dataStoreManagerImpl ;
75+ @ Inject
76+ private VirtualMachineManager virtualMachineManager ;
77+
78+ private static final Logger LOGGER = Logger .getLogger (KvmNonManagedStorageDataMotionStrategy .class );
5779
5880 /**
5981 * Uses the canHandle from the Super class {@link StorageSystemDataMotionStrategy}. If the storage pool is of file and the internalCanHandle from {@link StorageSystemDataMotionStrategy} CANT_HANDLE, returns the StrategyPriority.HYPERVISOR strategy priority. otherwise returns CANT_HANDLE.
@@ -95,7 +117,7 @@ protected String generateDestPath(VirtualMachineTO vmTO, VolumeVO srcVolume, Hos
95117 String templateUuid = getTemplateUuid (destVolumeInfo .getTemplateId ());
96118 CreateCommand rootImageProvisioningCommand = new CreateCommand (diskProfile , templateUuid , destStoragePool , true );
97119
98- Answer rootImageProvisioningAnswer = _agentMgr .easySend (destHost .getId (), rootImageProvisioningCommand );
120+ Answer rootImageProvisioningAnswer = agentManager .easySend (destHost .getId (), rootImageProvisioningCommand );
99121
100122 if (rootImageProvisioningAnswer == null ) {
101123 throw new CloudRuntimeException (String .format ("Migration with storage of vm [%s] failed while provisioning root image" , vmTO .getName ()));
@@ -140,4 +162,77 @@ protected void setVolumePath(VolumeVO volume) {
140162 protected boolean shouldMigrateVolume (StoragePoolVO sourceStoragePool , Host destHost , StoragePoolVO destStoragePool ) {
141163 return sourceStoragePool .getPoolType () == StoragePoolType .Filesystem ;
142164 }
165+
166+ /**
167+ * If the template is not on the target primary storage then it copies the template.
168+ */
169+ @ Override
170+ protected void copyTemplateToTargetFilesystemStorageIfNeeded (VolumeInfo srcVolumeInfo , StoragePool srcStoragePool , DataStore destDataStore , StoragePool destStoragePool ,
171+ Host destHost ) {
172+ VMTemplateStoragePoolVO sourceVolumeTemplateStoragePoolVO = vmTemplatePoolDao .findByPoolTemplate (destStoragePool .getId (), srcVolumeInfo .getTemplateId ());
173+ if (sourceVolumeTemplateStoragePoolVO == null && destStoragePool .getPoolType () == StoragePoolType .Filesystem ) {
174+ DataStore sourceTemplateDataStore = dataStoreManagerImpl .getImageStore (srcVolumeInfo .getDataCenterId ());
175+ TemplateInfo sourceTemplateInfo = templateDataFactory .getTemplate (srcVolumeInfo .getTemplateId (), sourceTemplateDataStore );
176+ TemplateObjectTO sourceTemplate = new TemplateObjectTO (sourceTemplateInfo );
177+
178+ LOGGER .debug (String .format ("Could not find template [id=%s, name=%s] on the storage pool [id=%s]; copying the template to the target storage pool." ,
179+ srcVolumeInfo .getTemplateId (), sourceTemplateInfo .getName (), destDataStore .getId ()));
180+
181+ TemplateInfo destTemplateInfo = templateDataFactory .getTemplate (srcVolumeInfo .getTemplateId (), destDataStore );
182+ final TemplateObjectTO destTemplate = new TemplateObjectTO (destTemplateInfo );
183+ Answer copyCommandAnswer = sendCopyCommand (destHost , sourceTemplate , destTemplate , destDataStore );
184+
185+ if (copyCommandAnswer != null && copyCommandAnswer .getResult ()) {
186+ updateTemplateReferenceIfSuccessfulCopy (srcVolumeInfo , srcStoragePool , destTemplateInfo , destDataStore );
187+ }
188+ }
189+ }
190+
191+ /**
192+ * Update the template reference on table "template_spool_ref" (VMTemplateStoragePoolVO).
193+ */
194+ protected void updateTemplateReferenceIfSuccessfulCopy (VolumeInfo srcVolumeInfo , StoragePool srcStoragePool , TemplateInfo destTemplateInfo , DataStore destDataStore ) {
195+ VMTemplateStoragePoolVO srcVolumeTemplateStoragePoolVO = vmTemplatePoolDao .findByPoolTemplate (srcStoragePool .getId (), srcVolumeInfo .getTemplateId ());
196+ VMTemplateStoragePoolVO destVolumeTemplateStoragePoolVO = new VMTemplateStoragePoolVO (destDataStore .getId (), srcVolumeInfo .getTemplateId ());
197+ destVolumeTemplateStoragePoolVO .setDownloadPercent (100 );
198+ destVolumeTemplateStoragePoolVO .setDownloadState (VMTemplateStorageResourceAssoc .Status .DOWNLOADED );
199+ destVolumeTemplateStoragePoolVO .setState (ObjectInDataStoreStateMachine .State .Ready );
200+ destVolumeTemplateStoragePoolVO .setTemplateSize (srcVolumeTemplateStoragePoolVO .getTemplateSize ());
201+ destVolumeTemplateStoragePoolVO .setLocalDownloadPath (destTemplateInfo .getUuid ());
202+ destVolumeTemplateStoragePoolVO .setInstallPath (destTemplateInfo .getUuid ());
203+ vmTemplatePoolDao .persist (destVolumeTemplateStoragePoolVO );
204+ }
205+
206+ /**
207+ * Sends the CopyCommand to migrate the template to the dest host.
208+ */
209+ protected Answer sendCopyCommand (Host destHost , TemplateObjectTO sourceTemplate , TemplateObjectTO destTemplate , DataStore destDataStore ) {
210+ boolean executeInSequence = virtualMachineManager .getExecuteInSequence (HypervisorType .KVM );
211+ CopyCommand copyCommand = new CopyCommand (sourceTemplate , destTemplate , StorageManager .PRIMARY_STORAGE_DOWNLOAD_WAIT .value (), executeInSequence );
212+ try {
213+ Answer copyCommandAnswer = agentManager .send (destHost .getId (), copyCommand );
214+ logInCaseOfTemplateCopyFailure (copyCommandAnswer , sourceTemplate , destDataStore );
215+ return copyCommandAnswer ;
216+ } catch (AgentUnavailableException | OperationTimedoutException e ) {
217+ throw new CloudRuntimeException (generateFailToCopyTemplateMessage (sourceTemplate , destDataStore ), e );
218+ }
219+ }
220+
221+ private String generateFailToCopyTemplateMessage (TemplateObjectTO sourceTemplate , DataStore destDataStore ) {
222+ return String .format ("Failed to copy template [id=%s, name=%s] to the primary storage pool [id=%s]." , sourceTemplate .getId (),
223+ sourceTemplate .getName (), destDataStore .getId ());
224+ }
225+
226+ /**
227+ * Logs in debug mode the copy command failure if the CopyCommand Answer has result as false.
228+ */
229+ protected void logInCaseOfTemplateCopyFailure (Answer copyCommandAnswer , TemplateObjectTO sourceTemplate , DataStore destDataStore ) {
230+ if (copyCommandAnswer != null && !copyCommandAnswer .getResult ()) {
231+ String failureDetails = StringUtils .EMPTY ;
232+ if (copyCommandAnswer .getDetails () != null ) {
233+ failureDetails = " Details: " + copyCommandAnswer .getDetails ();
234+ }
235+ LOGGER .error (generateFailToCopyTemplateMessage (sourceTemplate , destDataStore ) + failureDetails );
236+ }
237+ }
143238}
0 commit comments