127127import org .apache .cloudstack .veeam .api .dto .VnicProfile ;
128128import org .apache .commons .collections .CollectionUtils ;
129129import org .apache .commons .collections .MapUtils ;
130+ import org .apache .commons .lang3 .ObjectUtils ;
130131import org .apache .commons .lang3 .StringUtils ;
131132import org .jetbrains .annotations .NotNull ;
132133
192193import com .cloud .vm .NicVO ;
193194import com .cloud .vm .UserVmManager ;
194195import com .cloud .vm .UserVmVO ;
196+ import com .cloud .vm .VMInstanceDetailVO ;
195197import com .cloud .vm .VmDetailConstants ;
196198import com .cloud .vm .dao .NicDao ;
197199import com .cloud .vm .dao .UserVmDao ;
@@ -207,6 +209,7 @@ public class ServerAdapter extends ManagerBase {
207209 );
208210 private static final String VM_TA_KEY = "veeam_tag" ;
209211 private static final String WORKER_VM_GUEST_CPU_MODE = "host-passthrough" ;
212+ private static final String RESTORE_CONFIG = "restore.config" ;
210213
211214 @ Inject
212215 AccountService accountService ;
@@ -512,7 +515,7 @@ protected VMTemplateVO getTemplateForInstanceCreation(String templateUuid) {
512515 return template ;
513516 }
514517
515- protected Vm createInstance (com .cloud .dc .DataCenter zone , Long clusterId , Account owner , Long domainId ,
518+ protected Pair < Vm , UserVm > createInstance (com .cloud .dc .DataCenter zone , Long clusterId , Account owner , Long domainId ,
516519 String accountName , Long projectId , String name , String displayName , String serviceOfferingUuid ,
517520 int cpu , int memory , String templateUuid , String userdata , ApiConstants .BootType bootType ,
518521 ApiConstants .BootMode bootMode , String affinityGroupId , String userDataId , Map <String , String > details ) {
@@ -582,8 +585,10 @@ protected Vm createInstance(com.cloud.dc.DataCenter zone, Long clusterId, Accoun
582585 UserVm vm = userVmManager .createVirtualMachine (cmd );
583586 vm = userVmManager .finalizeCreateVirtualMachine (vm .getId ());
584587 UserVmJoinVO vo = userVmJoinDao .findById (vm .getId ());
585- return UserVmJoinVOToVmConverter .toVm (vo , this ::getHostById , this ::getDetailsByInstanceId ,
586- this ::listTagsByInstanceId , this ::listDiskAttachmentsByInstanceId , this ::listNicsByInstance , false );
588+ Vm vmObj = UserVmJoinVOToVmConverter .toVm (vo , this ::getHostById , this ::getDetailsByInstanceId ,
589+ this ::listTagsByInstanceId , this ::listDiskAttachmentsByInstanceId , this ::listNicsByInstance ,
590+ false );
591+ return new Pair <>(vmObj , vm );
587592 } catch (InsufficientCapacityException | ResourceUnavailableException | ResourceAllocationException | CloudRuntimeException e ) {
588593 throw new CloudRuntimeException ("Failed to create VM: " + e .getMessage (), e );
589594 }
@@ -618,6 +623,63 @@ protected static Map<String, String> getDetailsForInstanceCreation(String userda
618623 return details ;
619624 }
620625
626+ protected void saveInstanceRestoreConfig (Vm request , UserVm vm ) {
627+ if (StringUtils .isBlank (request .getAccountId ())) {
628+ return ;
629+ }
630+ if (accountService .getAccountByUuid (request .getAccountId ()) == null ) {
631+ return ;
632+ }
633+ String restoreConfig = OvfXmlUtil .getConfigMetadataXml (request , logger );
634+ if (StringUtils .isBlank (restoreConfig )) {
635+ return ;
636+ }
637+ vmInstanceDetailsDao .addDetail (vm .getId (), RESTORE_CONFIG , restoreConfig , false );
638+ }
639+
640+ protected void removeInstanceRestoreConfig (UserVm vm ) {
641+ vmInstanceDetailsDao .removeDetail (vm .getId (), RESTORE_CONFIG );
642+ }
643+
644+ protected Pair <String , String > getValidatedInstanceNicDetails (final UserVmVO vm , final NetworkVO network ) {
645+ if (ObjectUtils .anyNull (vm , network )) {
646+ return new Pair <>(null , null );
647+ }
648+ VMInstanceDetailVO detail = vmInstanceDetailsDao .findDetail (vm .getId (), RESTORE_CONFIG );
649+ if (detail == null || StringUtils .isBlank (detail .getValue ())) {
650+ return new Pair <>(null , null );
651+ }
652+ Pair <String , String > result = OvfXmlUtil .getVmNicDetailFromStoredConfig (detail .getValue (), network .getUuid (), logger );
653+ String mac = StringUtils .trimToNull (result .first ());
654+ String ip4Address = StringUtils .trimToNull (result .second ());
655+ NicVO nic = null ;
656+ if (mac != null ) {
657+ nic = nicDao .findByNetworkIdAndMacAddress (network .getId (), mac );
658+ if (nic != null ) {
659+ logger .warn ("MAC address {} specified in the restore config for {} is already in use by {}, ignoring it" ,
660+ mac , network , nic );
661+ mac = null ;
662+ if (!Objects .equals (ip4Address , nic .getIPv4Address ())) {
663+ nic = null ;
664+ }
665+ }
666+ }
667+ if (ip4Address != null ) {
668+ if (nic == null ) {
669+ nic = nicDao .findNonPlaceHolderByIp4AddressAndNetworkId (ip4Address , network .getId ());
670+ }
671+ if (nic != null ) {
672+ logger .warn ("IPv4 address {} specified in the restore config for {} is already in use by {}, ignoring it" ,
673+ ip4Address , network , nic );
674+ mac = null ;
675+ if (Objects .equals (ip4Address , nic .getIPv4Address ())) {
676+ ip4Address = null ;
677+ }
678+ }
679+ }
680+ return new Pair <>(mac , ip4Address );
681+ }
682+
621683 protected static long getProvisionedSizeInGb (String sizeStr ) {
622684 long provisionedSizeInGb ;
623685 try {
@@ -968,10 +1030,12 @@ public Vm createInstance(Vm request) {
9681030 if (request .getTemplate () != null && StringUtils .isNotEmpty (request .getTemplate ().getId ())) {
9691031 templateUuid = request .getTemplate ().getId ();
9701032 }
971- return createInstance (zone , clusterId , owner , ownerDetails .first (), ownerDetails .second (),
1033+ Pair < Vm , UserVm > result = createInstance (zone , clusterId , owner , ownerDetails .first (), ownerDetails .second (),
9721034 ownerDetails .third (), name , displayName , serviceOfferingUuid , cpu , memoryMB , templateUuid ,
9731035 userdata , bootOptions .first (), bootOptions .second (), request .getAffinityGroupId (),
9741036 request .getUserDataId (), request .getDetails ());
1037+ saveInstanceRestoreConfig (request , result .second ());
1038+ return result .first ();
9751039 }
9761040
9771041 @ ApiAccess (command = UpdateVMCmd .class )
@@ -1175,6 +1239,7 @@ public DiskAttachment attachInstanceDisk(final String vmUuid, final DiskAttachme
11751239 }
11761240 accountService .checkAccess (CallContext .current ().getCallingAccount (), SecurityChecker .AccessType .OperateEntry ,
11771241 false , vmVo );
1242+ removeInstanceRestoreConfig (vmVo );
11781243 if (vmVo .getAccountId () != volumeVO .getAccountId ()) {
11791244 if (VeeamControlService .InstanceRestoreAssignOwner .value ()) {
11801245 assignVolumeToAccount (volumeVO , vmVo .getAccountId ());
@@ -1296,10 +1361,13 @@ public Nic attachInstanceNic(final String vmUuid, final Nic request) {
12961361 accountCannotAccessNetwork (networkVO , vmVo .getAccountId ())) {
12971362 assignVmToAccount (vmVo , networkVO .getAccountId ());
12981363 }
1364+ Pair <String , String > nicDetails = getValidatedInstanceNicDetails (vmVo , networkVO );
12991365 AddNicToVMCmd cmd = new AddNicToVMCmd ();
13001366 ComponentContext .inject (cmd );
13011367 cmd .setVmId (vmVo .getId ());
13021368 cmd .setNetworkId (networkVO .getId ());
1369+ cmd .setMacAddress (nicDetails .first ());
1370+ cmd .setIpaddr (nicDetails .second ());
13031371 if (request .getMac () != null && StringUtils .isNotBlank (request .getMac ().getAddress ())) {
13041372 cmd .setMacAddress (request .getMac ().getAddress ());
13051373 }
0 commit comments