mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	NAS BnR: Create Instance from Backup issues (#11754)
* add createCrossZoneInstnaceEnabled to BackupOfferingResponse * show use IP Address from Backup button when orignal instance is expunged * Fix NPE in takeBackup if the vm template is deleted. * Add since to Cross zone instance creation in BackupOfferingResponse.java Co-authored-by: Suresh Kumar Anaparti <sureshkumar.anaparti@gmail.com> * Store and show Guest os type in the backup metadata * show warning in create instance from backup form if guest os type is different * show warning in create instance from backup form if guest os type is different * backupvmexpunged -> isbackupvmexpunged * review comments * fix npe * improve err msg * err msg --------- Co-authored-by: Suresh Kumar Anaparti <sureshkumar.anaparti@gmail.com>
This commit is contained in:
		
							parent
							
								
									c0a4392b05
								
							
						
					
					
						commit
						046014b4c5
					
				| @ -64,6 +64,7 @@ public class ApiConstants { | |||||||
|     public static final String BACKUP_STORAGE_LIMIT = "backupstoragelimit"; |     public static final String BACKUP_STORAGE_LIMIT = "backupstoragelimit"; | ||||||
|     public static final String BACKUP_STORAGE_TOTAL = "backupstoragetotal"; |     public static final String BACKUP_STORAGE_TOTAL = "backupstoragetotal"; | ||||||
|     public static final String BACKUP_VM_OFFERING_REMOVED = "vmbackupofferingremoved"; |     public static final String BACKUP_VM_OFFERING_REMOVED = "vmbackupofferingremoved"; | ||||||
|  |     public static final String IS_BACKUP_VM_EXPUNGED = "isbackupvmexpunged"; | ||||||
|     public static final String BACKUP_TOTAL = "backuptotal"; |     public static final String BACKUP_TOTAL = "backuptotal"; | ||||||
|     public static final String BASE64_IMAGE = "base64image"; |     public static final String BASE64_IMAGE = "base64image"; | ||||||
|     public static final String BGP_PEERS = "bgppeers"; |     public static final String BGP_PEERS = "bgppeers"; | ||||||
|  | |||||||
| @ -61,6 +61,10 @@ public class BackupOfferingResponse extends BaseResponse { | |||||||
|     @Param(description = "zone name") |     @Param(description = "zone name") | ||||||
|     private String zoneName; |     private String zoneName; | ||||||
| 
 | 
 | ||||||
|  |     @SerializedName(ApiConstants.CROSS_ZONE_INSTANCE_CREATION) | ||||||
|  |     @Param(description = "the backups with this offering can be used to create Instances on all Zones", since = "4.22.0") | ||||||
|  |     private Boolean crossZoneInstanceCreation; | ||||||
|  | 
 | ||||||
|     @SerializedName(ApiConstants.CREATED) |     @SerializedName(ApiConstants.CREATED) | ||||||
|     @Param(description = "the date this backup offering was created") |     @Param(description = "the date this backup offering was created") | ||||||
|     private Date created; |     private Date created; | ||||||
| @ -97,6 +101,10 @@ public class BackupOfferingResponse extends BaseResponse { | |||||||
|         this.zoneName = zoneName; |         this.zoneName = zoneName; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public void setCrossZoneInstanceCreation(Boolean crossZoneInstanceCreation) { | ||||||
|  |         this.crossZoneInstanceCreation = crossZoneInstanceCreation; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public void setCreated(Date created) { |     public void setCreated(Date created) { | ||||||
|         this.created = created; |         this.created = created; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -123,6 +123,10 @@ public class BackupResponse extends BaseResponse { | |||||||
|     @Param(description = "The backup offering corresponding to this backup was removed from the VM", since = "4.21.0") |     @Param(description = "The backup offering corresponding to this backup was removed from the VM", since = "4.21.0") | ||||||
|     private Boolean vmOfferingRemoved; |     private Boolean vmOfferingRemoved; | ||||||
| 
 | 
 | ||||||
|  |     @SerializedName(ApiConstants.IS_BACKUP_VM_EXPUNGED) | ||||||
|  |     @Param(description = "Indicates whether the VM from which the backup was taken is expunged or not", since = "4.22.0") | ||||||
|  |     private Boolean isVmExpunged; | ||||||
|  | 
 | ||||||
|     public String getId() { |     public String getId() { | ||||||
|         return id; |         return id; | ||||||
|     } |     } | ||||||
| @ -306,4 +310,8 @@ public class BackupResponse extends BaseResponse { | |||||||
|     public void setVmOfferingRemoved(Boolean vmOfferingRemoved) { |     public void setVmOfferingRemoved(Boolean vmOfferingRemoved) { | ||||||
|         this.vmOfferingRemoved = vmOfferingRemoved; |         this.vmOfferingRemoved = vmOfferingRemoved; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public void setVmExpunged(Boolean isVmExpunged) { | ||||||
|  |         this.isVmExpunged = isVmExpunged; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ import org.apache.cloudstack.backup.BackupOfferingVO; | |||||||
| import com.cloud.utils.db.GenericDao; | import com.cloud.utils.db.GenericDao; | ||||||
| 
 | 
 | ||||||
| public interface BackupOfferingDao extends GenericDao<BackupOfferingVO, Long> { | public interface BackupOfferingDao extends GenericDao<BackupOfferingVO, Long> { | ||||||
|     BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy); |     BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy, Boolean crossZoneInstanceCreation); | ||||||
|     BackupOffering findByExternalId(String externalId, Long zoneId); |     BackupOffering findByExternalId(String externalId, Long zoneId); | ||||||
|     BackupOffering findByName(String name, Long zoneId); |     BackupOffering findByName(String name, Long zoneId); | ||||||
| } | } | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ public class BackupOfferingDaoImpl extends GenericDaoBase<BackupOfferingVO, Long | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering) { |     public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering, Boolean crossZoneInstanceCreation) { | ||||||
|         DataCenterVO zone = dataCenterDao.findById(offering.getZoneId()); |         DataCenterVO zone = dataCenterDao.findById(offering.getZoneId()); | ||||||
| 
 | 
 | ||||||
|         BackupOfferingResponse response = new BackupOfferingResponse(); |         BackupOfferingResponse response = new BackupOfferingResponse(); | ||||||
| @ -64,6 +64,9 @@ public class BackupOfferingDaoImpl extends GenericDaoBase<BackupOfferingVO, Long | |||||||
|             response.setZoneId(zone.getUuid()); |             response.setZoneId(zone.getUuid()); | ||||||
|             response.setZoneName(zone.getName()); |             response.setZoneName(zone.getName()); | ||||||
|         } |         } | ||||||
|  |         if (crossZoneInstanceCreation) { | ||||||
|  |             response.setCrossZoneInstanceCreation(true); | ||||||
|  |         } | ||||||
|         response.setCreated(offering.getCreated()); |         response.setCreated(offering.getCreated()); | ||||||
|         response.setObjectName("backupoffering"); |         response.setObjectName("backupoffering"); | ||||||
|         return response; |         return response; | ||||||
|  | |||||||
| @ -75,9 +75,11 @@ import org.apache.cloudstack.api.response.VolumeResponse; | |||||||
| import org.apache.cloudstack.api.response.VpcOfferingResponse; | import org.apache.cloudstack.api.response.VpcOfferingResponse; | ||||||
| import org.apache.cloudstack.api.response.ZoneResponse; | import org.apache.cloudstack.api.response.ZoneResponse; | ||||||
| import org.apache.cloudstack.backup.BackupOffering; | import org.apache.cloudstack.backup.BackupOffering; | ||||||
|  | import org.apache.cloudstack.backup.BackupRepository; | ||||||
| import org.apache.cloudstack.backup.BackupSchedule; | import org.apache.cloudstack.backup.BackupSchedule; | ||||||
| import org.apache.cloudstack.backup.dao.BackupDao; | import org.apache.cloudstack.backup.dao.BackupDao; | ||||||
| import org.apache.cloudstack.backup.dao.BackupOfferingDao; | import org.apache.cloudstack.backup.dao.BackupOfferingDao; | ||||||
|  | import org.apache.cloudstack.backup.dao.BackupRepositoryDao; | ||||||
| import org.apache.cloudstack.backup.dao.BackupScheduleDao; | import org.apache.cloudstack.backup.dao.BackupScheduleDao; | ||||||
| import org.apache.cloudstack.context.CallContext; | import org.apache.cloudstack.context.CallContext; | ||||||
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | ||||||
| @ -493,6 +495,7 @@ public class ApiDBUtils { | |||||||
|     static BackupDao s_backupDao; |     static BackupDao s_backupDao; | ||||||
|     static BackupScheduleDao s_backupScheduleDao; |     static BackupScheduleDao s_backupScheduleDao; | ||||||
|     static BackupOfferingDao s_backupOfferingDao; |     static BackupOfferingDao s_backupOfferingDao; | ||||||
|  |     static BackupRepositoryDao s_backupRepositoryDao; | ||||||
|     static NicDao s_nicDao; |     static NicDao s_nicDao; | ||||||
|     static ResourceManagerUtil s_resourceManagerUtil; |     static ResourceManagerUtil s_resourceManagerUtil; | ||||||
|     static SnapshotPolicyDetailsDao s_snapshotPolicyDetailsDao; |     static SnapshotPolicyDetailsDao s_snapshotPolicyDetailsDao; | ||||||
| @ -751,6 +754,8 @@ public class ApiDBUtils { | |||||||
|     @Inject |     @Inject | ||||||
|     private BackupOfferingDao backupOfferingDao; |     private BackupOfferingDao backupOfferingDao; | ||||||
|     @Inject |     @Inject | ||||||
|  |     private BackupRepositoryDao backupRepositoryDao; | ||||||
|  |     @Inject | ||||||
|     private BackupScheduleDao backupScheduleDao; |     private BackupScheduleDao backupScheduleDao; | ||||||
|     @Inject |     @Inject | ||||||
|     private NicDao nicDao; |     private NicDao nicDao; | ||||||
| @ -899,6 +904,7 @@ public class ApiDBUtils { | |||||||
|         s_backupDao = backupDao; |         s_backupDao = backupDao; | ||||||
|         s_backupScheduleDao = backupScheduleDao; |         s_backupScheduleDao = backupScheduleDao; | ||||||
|         s_backupOfferingDao = backupOfferingDao; |         s_backupOfferingDao = backupOfferingDao; | ||||||
|  |         s_backupRepositoryDao = backupRepositoryDao; | ||||||
|         s_resourceIconDao = resourceIconDao; |         s_resourceIconDao = resourceIconDao; | ||||||
|         s_resourceManagerUtil = resourceManagerUtil; |         s_resourceManagerUtil = resourceManagerUtil; | ||||||
|         s_objectStoreDao = objectStoreDao; |         s_objectStoreDao = objectStoreDao; | ||||||
| @ -2297,8 +2303,10 @@ public class ApiDBUtils { | |||||||
|         return s_backupScheduleDao.newBackupScheduleResponse(schedule); |         return s_backupScheduleDao.newBackupScheduleResponse(schedule); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy) { |     public static BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering) { | ||||||
|         return s_backupOfferingDao.newBackupOfferingResponse(policy); |         BackupRepository repository = s_backupRepositoryDao.findByUuid(offering.getExternalId()); | ||||||
|  |         Boolean crossZoneInstanceCreationEnabled = repository != null ? Boolean.TRUE.equals(repository.crossZoneInstanceCreationEnabled()) : false; | ||||||
|  |         return s_backupOfferingDao.newBackupOfferingResponse(offering, crossZoneInstanceCreationEnabled); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) { |     public static NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) { | ||||||
|  | |||||||
| @ -5040,8 +5040,8 @@ public class ApiResponseHelper implements ResponseGenerator { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public BackupOfferingResponse createBackupOfferingResponse(BackupOffering policy) { |     public BackupOfferingResponse createBackupOfferingResponse(BackupOffering offering) { | ||||||
|         return ApiDBUtils.newBackupOfferingResponse(policy); |         return ApiDBUtils.newBackupOfferingResponse(offering); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public ManagementServerResponse createManagementResponse(ManagementServerHost mgmt) { |     public ManagementServerResponse createManagementResponse(ManagementServerHost mgmt) { | ||||||
|  | |||||||
| @ -9606,11 +9606,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir | |||||||
|         } else { |         } else { | ||||||
|             String serviceOfferingUuid = backup.getDetail(ApiConstants.SERVICE_OFFERING_ID); |             String serviceOfferingUuid = backup.getDetail(ApiConstants.SERVICE_OFFERING_ID); | ||||||
|             if (serviceOfferingUuid == null) { |             if (serviceOfferingUuid == null) { | ||||||
|                 throw new CloudRuntimeException("Backup doesn't contain service offering uuid. Please specify a valid service offering id while creating the instance"); |                 throw new CloudRuntimeException("Backup doesn't contain a Service Offering UUID. Please specify a valid Service Offering while creating the Instance"); | ||||||
|             } |             } | ||||||
|             serviceOffering = serviceOfferingDao.findByUuid(serviceOfferingUuid); |             serviceOffering = serviceOfferingDao.findByUuid(serviceOfferingUuid); | ||||||
|             if (serviceOffering == null) { |             if (serviceOffering == null) { | ||||||
|                 throw new CloudRuntimeException("Unable to find service offering with the uuid stored in backup. Please specify a valid service offering id while creating instance"); |                 throw new CloudRuntimeException("Unable to find Service Offering with the UUID stored in the Backup. Please specify a valid Service Offering while creating the Instance"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         verifyServiceOffering(cmd, serviceOffering); |         verifyServiceOffering(cmd, serviceOffering); | ||||||
| @ -9625,11 +9625,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir | |||||||
|         } else { |         } else { | ||||||
|             String templateUuid = backup.getDetail(ApiConstants.TEMPLATE_ID); |             String templateUuid = backup.getDetail(ApiConstants.TEMPLATE_ID); | ||||||
|             if (templateUuid == null) { |             if (templateUuid == null) { | ||||||
|                 throw new CloudRuntimeException("Backup doesn't contain Template uuid. Please specify a valid Template/ISO while creating the instance"); |                 throw new CloudRuntimeException("Backup doesn't contain a Template UUID. Please specify a valid Template/ISO while creating the Instance"); | ||||||
|             } |             } | ||||||
|             template = _templateDao.findByUuid(templateUuid); |             template = _templateDao.findByUuid(templateUuid); | ||||||
|             if (template == null) { |             if (template == null) { | ||||||
|                 throw new CloudRuntimeException("Unable to find template associated with the backup. Please specify a valid Template/ISO while creating instance"); |                 throw new CloudRuntimeException("Unable to find Template with the UUID stored in the Backup. Please specify a valid Template/ISO while creating the Instance"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         verifyTemplate(cmd, template, serviceOffering.getId()); |         verifyTemplate(cmd, template, serviceOffering.getId()); | ||||||
|  | |||||||
| @ -122,12 +122,14 @@ import com.cloud.projects.Project; | |||||||
| import com.cloud.serializer.GsonHelper; | import com.cloud.serializer.GsonHelper; | ||||||
| import com.cloud.service.dao.ServiceOfferingDao; | import com.cloud.service.dao.ServiceOfferingDao; | ||||||
| import com.cloud.storage.DiskOfferingVO; | import com.cloud.storage.DiskOfferingVO; | ||||||
|  | import com.cloud.storage.GuestOSVO; | ||||||
| import com.cloud.storage.ScopeType; | import com.cloud.storage.ScopeType; | ||||||
| import com.cloud.storage.Storage; | import com.cloud.storage.Storage; | ||||||
| import com.cloud.storage.Volume; | import com.cloud.storage.Volume; | ||||||
| import com.cloud.storage.VolumeApiService; | import com.cloud.storage.VolumeApiService; | ||||||
| import com.cloud.storage.VolumeVO; | import com.cloud.storage.VolumeVO; | ||||||
| import com.cloud.storage.dao.DiskOfferingDao; | import com.cloud.storage.dao.DiskOfferingDao; | ||||||
|  | import com.cloud.storage.dao.GuestOSDao; | ||||||
| import com.cloud.storage.dao.VMTemplateDao; | import com.cloud.storage.dao.VMTemplateDao; | ||||||
| import com.cloud.storage.dao.VolumeDao; | import com.cloud.storage.dao.VolumeDao; | ||||||
| import com.cloud.template.VirtualMachineTemplate; | import com.cloud.template.VirtualMachineTemplate; | ||||||
| @ -232,6 +234,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
|     private ResourceLimitService resourceLimitMgr; |     private ResourceLimitService resourceLimitMgr; | ||||||
|     @Inject |     @Inject | ||||||
|     private AlertManager alertManager; |     private AlertManager alertManager; | ||||||
|  |     @Inject | ||||||
|  |     private GuestOSDao _guestOSDao; | ||||||
| 
 | 
 | ||||||
|     private AsyncJobDispatcher asyncJobDispatcher; |     private AsyncJobDispatcher asyncJobDispatcher; | ||||||
|     private Timer backupTimer; |     private Timer backupTimer; | ||||||
| @ -379,7 +383,15 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
|         ServiceOffering serviceOffering = serviceOfferingDao.findById(vm.getServiceOfferingId()); |         ServiceOffering serviceOffering = serviceOfferingDao.findById(vm.getServiceOfferingId()); | ||||||
|         details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOffering.getUuid()); |         details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOffering.getUuid()); | ||||||
|         VirtualMachineTemplate template = vmTemplateDao.findById(vm.getTemplateId()); |         VirtualMachineTemplate template = vmTemplateDao.findById(vm.getTemplateId()); | ||||||
|         details.put(ApiConstants.TEMPLATE_ID, template.getUuid()); |         if (template != null) { | ||||||
|  |             long guestOSId = template.getGuestOSId(); | ||||||
|  |             details.put(ApiConstants.TEMPLATE_ID, template.getUuid()); | ||||||
|  |             GuestOSVO guestOS = _guestOSDao.findById(guestOSId); | ||||||
|  |             if (guestOS != null) { | ||||||
|  |                 details.put(ApiConstants.OS_TYPE_ID, guestOS.getUuid()); | ||||||
|  |                 details.put(ApiConstants.OS_NAME, guestOS.getDisplayName()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         List<VMInstanceDetailVO> vmDetails = vmInstanceDetailsDao.listDetails(vm.getId()); |         List<VMInstanceDetailVO> vmDetails = vmInstanceDetailsDao.listDetails(vm.getId()); | ||||||
|         HashMap<String, String> settings = new HashMap<>(); |         HashMap<String, String> settings = new HashMap<>(); | ||||||
| @ -2143,7 +2155,6 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
|         if (details.containsKey(ApiConstants.TEMPLATE_ID)) { |         if (details.containsKey(ApiConstants.TEMPLATE_ID)) { | ||||||
|             VirtualMachineTemplate template = vmTemplateDao.findByUuid(details.get(ApiConstants.TEMPLATE_ID)); |             VirtualMachineTemplate template = vmTemplateDao.findByUuid(details.get(ApiConstants.TEMPLATE_ID)); | ||||||
|             if (template != null) { |             if (template != null) { | ||||||
|                 details.put(ApiConstants.TEMPLATE_ID, template.getUuid()); |  | ||||||
|                 details.put(ApiConstants.TEMPLATE_NAME, template.getName()); |                 details.put(ApiConstants.TEMPLATE_NAME, template.getName()); | ||||||
|                 details.put(ApiConstants.IS_ISO, String.valueOf(template.getFormat().equals(Storage.ImageFormat.ISO))); |                 details.put(ApiConstants.IS_ISO, String.valueOf(template.getFormat().equals(Storage.ImageFormat.ISO))); | ||||||
|             } |             } | ||||||
| @ -2151,7 +2162,6 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
|         if (details.containsKey(ApiConstants.SERVICE_OFFERING_ID)) { |         if (details.containsKey(ApiConstants.SERVICE_OFFERING_ID)) { | ||||||
|             ServiceOffering serviceOffering = serviceOfferingDao.findByUuid(details.get(ApiConstants.SERVICE_OFFERING_ID)); |             ServiceOffering serviceOffering = serviceOfferingDao.findByUuid(details.get(ApiConstants.SERVICE_OFFERING_ID)); | ||||||
|             if (serviceOffering != null) { |             if (serviceOffering != null) { | ||||||
|                 details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOffering.getUuid()); |  | ||||||
|                 details.put(ApiConstants.SERVICE_OFFERING_NAME, serviceOffering.getName()); |                 details.put(ApiConstants.SERVICE_OFFERING_NAME, serviceOffering.getName()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -2186,10 +2196,15 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
|         response.setId(backup.getUuid()); |         response.setId(backup.getUuid()); | ||||||
|         response.setName(backup.getName()); |         response.setName(backup.getName()); | ||||||
|         response.setDescription(backup.getDescription()); |         response.setDescription(backup.getDescription()); | ||||||
|         response.setVmName(vm.getHostName()); |         if (vm != null) { | ||||||
|         response.setVmId(vm.getUuid()); |             response.setVmName(vm.getHostName()); | ||||||
|         if (vm.getBackupOfferingId() == null || vm.getBackupOfferingId() != backup.getBackupOfferingId()) { |             response.setVmId(vm.getUuid()); | ||||||
|             response.setVmOfferingRemoved(true); |             if (vm.getBackupOfferingId() == null || vm.getBackupOfferingId() != backup.getBackupOfferingId()) { | ||||||
|  |                 response.setVmOfferingRemoved(true); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (vm == null || VirtualMachine.State.Expunging.equals(vm.getState())) { | ||||||
|  |             response.setVmExpunged(true); | ||||||
|         } |         } | ||||||
|         response.setExternalId(backup.getExternalId()); |         response.setExternalId(backup.getExternalId()); | ||||||
|         response.setType(backup.getType()); |         response.setType(backup.getType()); | ||||||
| @ -2205,9 +2220,11 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         // ACS 4.20: For backups taken prior this release the backup.backed_volumes column would be empty hence use vm_instance.backup_volumes |         // ACS 4.20: For backups taken prior this release the backup.backed_volumes column would be empty hence use vm_instance.backup_volumes | ||||||
|         String backedUpVolumes; |         String backedUpVolumes = ""; | ||||||
|         if (Objects.isNull(backup.getBackedUpVolumes())) { |         if (Objects.isNull(backup.getBackedUpVolumes())) { | ||||||
|             backedUpVolumes = new Gson().toJson(vm.getBackupVolumeList().toArray(), Backup.VolumeInfo[].class); |             if (vm != null) { | ||||||
|  |                 backedUpVolumes = new Gson().toJson(vm.getBackupVolumeList().toArray(), Backup.VolumeInfo[].class); | ||||||
|  |             } | ||||||
|         } else { |         } else { | ||||||
|             backedUpVolumes = new Gson().toJson(backup.getBackedUpVolumes().toArray(), Backup.VolumeInfo[].class); |             backedUpVolumes = new Gson().toJson(backup.getBackedUpVolumes().toArray(), Backup.VolumeInfo[].class); | ||||||
|         } |         } | ||||||
| @ -2223,7 +2240,9 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { | |||||||
| 
 | 
 | ||||||
|         if (Boolean.TRUE.equals(listVmDetails)) { |         if (Boolean.TRUE.equals(listVmDetails)) { | ||||||
|             Map<String, String> vmDetails = new HashMap<>(); |             Map<String, String> vmDetails = new HashMap<>(); | ||||||
|             vmDetails.put(ApiConstants.HYPERVISOR, vm.getHypervisorType().toString()); |             if (vm != null) { | ||||||
|  |                 vmDetails.put(ApiConstants.HYPERVISOR, vm.getHypervisorType().toString()); | ||||||
|  |             } | ||||||
|             Map<String, String> details = getDetailsFromBackupDetails(backup.getId()); |             Map<String, String> details = getDetailsFromBackupDetails(backup.getId()); | ||||||
|             vmDetails.putAll(details); |             vmDetails.putAll(details); | ||||||
|             response.setVmDetails(vmDetails); |             response.setVmDetails(vmDetails); | ||||||
|  | |||||||
| @ -49,6 +49,7 @@ import com.cloud.storage.Volume; | |||||||
| import com.cloud.storage.VolumeApiService; | import com.cloud.storage.VolumeApiService; | ||||||
| import com.cloud.storage.VolumeVO; | import com.cloud.storage.VolumeVO; | ||||||
| import com.cloud.storage.dao.DiskOfferingDao; | import com.cloud.storage.dao.DiskOfferingDao; | ||||||
|  | import com.cloud.storage.dao.GuestOSDao; | ||||||
| import com.cloud.storage.dao.VMTemplateDao; | import com.cloud.storage.dao.VMTemplateDao; | ||||||
| import com.cloud.storage.dao.VolumeDao; | import com.cloud.storage.dao.VolumeDao; | ||||||
| import com.cloud.user.Account; | import com.cloud.user.Account; | ||||||
| @ -237,6 +238,9 @@ public class BackupManagerTest { | |||||||
|     @Mock |     @Mock | ||||||
|     DomainDao domainDao; |     DomainDao domainDao; | ||||||
| 
 | 
 | ||||||
|  |     @Mock | ||||||
|  |     private GuestOSDao _guestOSDao; | ||||||
|  | 
 | ||||||
|     private Gson gson; |     private Gson gson; | ||||||
| 
 | 
 | ||||||
|     private String[] hostPossibleValues = {"127.0.0.1", "hostname"}; |     private String[] hostPossibleValues = {"127.0.0.1", "hostname"}; | ||||||
| @ -1572,14 +1576,12 @@ public class BackupManagerTest { | |||||||
| 
 | 
 | ||||||
|         VMTemplateVO template = mock(VMTemplateVO.class); |         VMTemplateVO template = mock(VMTemplateVO.class); | ||||||
|         when(template.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); |         when(template.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); | ||||||
|         when(template.getUuid()).thenReturn(templateUuid); |  | ||||||
|         when(template.getName()).thenReturn("template1"); |         when(template.getName()).thenReturn("template1"); | ||||||
|         when(vmTemplateDao.findByUuid(templateUuid)).thenReturn(template); |         when(vmTemplateDao.findByUuid(templateUuid)).thenReturn(template); | ||||||
|         Map<String, String> details = new HashMap<>(); |         Map<String, String> details = new HashMap<>(); | ||||||
|         details.put(ApiConstants.TEMPLATE_ID, templateUuid); |         details.put(ApiConstants.TEMPLATE_ID, templateUuid); | ||||||
| 
 | 
 | ||||||
|         ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class); |         ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class); | ||||||
|         when(serviceOffering.getUuid()).thenReturn(serviceOfferingUuid); |  | ||||||
|         when(serviceOffering.getName()).thenReturn("service-offering1"); |         when(serviceOffering.getName()).thenReturn("service-offering1"); | ||||||
|         when(serviceOfferingDao.findByUuid(serviceOfferingUuid)).thenReturn(serviceOffering); |         when(serviceOfferingDao.findByUuid(serviceOfferingUuid)).thenReturn(serviceOffering); | ||||||
|         details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOfferingUuid); |         details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOfferingUuid); | ||||||
|  | |||||||
| @ -2887,6 +2887,8 @@ | |||||||
| "message.action.create.snapshot.from.vmsnapshot": "Please confirm that you want to create Snapshot from Instance Snapshot", | "message.action.create.snapshot.from.vmsnapshot": "Please confirm that you want to create Snapshot from Instance Snapshot", | ||||||
| "message.action.create.instance.from.backup": "Please confirm that you want to create a new Instance from the given Backup.<br>Click on configure to edit the parameters for the new Instance before creation.", | "message.action.create.instance.from.backup": "Please confirm that you want to create a new Instance from the given Backup.<br>Click on configure to edit the parameters for the new Instance before creation.", | ||||||
| "message.create.instance.from.backup.different.zone": "Creating Instance from Backup on a different Zone. Please ensure that the backup repository is accessible in the selected Zone.", | "message.create.instance.from.backup.different.zone": "Creating Instance from Backup on a different Zone. Please ensure that the backup repository is accessible in the selected Zone.", | ||||||
|  | "message.template.ostype.different.from.backup": "Selected Template has a different OS type than the Backup. Please proceed with caution.", | ||||||
|  | "message.iso.ostype.different.from.backup": "Selected ISO has a different OS type than the Backup. Please proceed with caution.", | ||||||
| "message.action.delete.asnrange": "Please confirm the AS range that you want to delete", | "message.action.delete.asnrange": "Please confirm the AS range that you want to delete", | ||||||
| "message.action.delete.autoscale.vmgroup": "Please confirm that you want to delete this autoscaling group.", | "message.action.delete.autoscale.vmgroup": "Please confirm that you want to delete this autoscaling group.", | ||||||
| "message.action.delete.backup.offering": "Please confirm that you want to delete this backup offering?", | "message.action.delete.backup.offering": "Please confirm that you want to delete this backup offering?", | ||||||
|  | |||||||
| @ -42,6 +42,11 @@ | |||||||
|               {{ getTemplateDisplayName() }} |               {{ getTemplateDisplayName() }} | ||||||
|             </router-link> |             </router-link> | ||||||
|           </div> |           </div> | ||||||
|  |           <div v-else-if="item === 'ostypeid'"> | ||||||
|  |             <router-link :to="{ path: '/guestos' + '/' + backupMetadata[item] }"> | ||||||
|  |               {{ backupMetadata.osname }} | ||||||
|  |             </router-link> | ||||||
|  |           </div> | ||||||
|           <div v-else-if="item === 'serviceofferingid'"> |           <div v-else-if="item === 'serviceofferingid'"> | ||||||
|             <router-link :to="{ path: '/computeoffering/' + backupMetadata[item] }"> |             <router-link :to="{ path: '/computeoffering/' + backupMetadata[item] }"> | ||||||
|               {{ getServiceOfferingDisplayName() }} |               {{ getServiceOfferingDisplayName() }} | ||||||
| @ -84,15 +89,14 @@ export default { | |||||||
|       if (!this.backupMetadata || Object.keys(this.backupMetadata).length === 0) { |       if (!this.backupMetadata || Object.keys(this.backupMetadata).length === 0) { | ||||||
|         return [] |         return [] | ||||||
|       } |       } | ||||||
|       const fieldOrder = [] |       const fieldOrder = [ | ||||||
|       fieldOrder.push('templateid') |         'templateid', | ||||||
|       if (this.backupMetadata.isiso === 'true') { |         'ostypeid', | ||||||
|         fieldOrder.push('hypervisor') |         'hypervisor', | ||||||
|       } |         'serviceofferingid', | ||||||
|       fieldOrder.push('serviceofferingid') |         'nics', | ||||||
|       fieldOrder.push('nics') |         'vmsettings' | ||||||
|       fieldOrder.push('vmsettings') |       ] | ||||||
| 
 |  | ||||||
|       return fieldOrder.filter(field => this.backupMetadata[field] !== undefined) |       return fieldOrder.filter(field => this.backupMetadata[field] !== undefined) | ||||||
|     }, |     }, | ||||||
|     getNicEntities () { |     getNicEntities () { | ||||||
|  | |||||||
| @ -168,6 +168,23 @@ | |||||||
|                       :tabList="tabList" |                       :tabList="tabList" | ||||||
|                       :activeTabKey="tabKey" |                       :activeTabKey="tabKey" | ||||||
|                       @tabChange="key => onTabChange(key, 'tabKey')"> |                       @tabChange="key => onTabChange(key, 'tabKey')"> | ||||||
|  |                       <a-alert | ||||||
|  |                         v-if="showOsTypeWarning && selectedTemplateIso" | ||||||
|  |                         style="margin-bottom: 10px"> | ||||||
|  |                         <template #message> | ||||||
|  |                           <div> | ||||||
|  |                             {{ selectedTemplateIso.message }}<br> | ||||||
|  |                             {{ selectedTemplateIso.label }} : | ||||||
|  |                             <router-link :to="{ path: '/guestos/' + selectedTemplateIso.item.ostypeid }"> | ||||||
|  |                               {{ selectedTemplateIso.item.ostypename }} | ||||||
|  |                             </router-link><br> | ||||||
|  |                             {{ $t('label.backup') }} : | ||||||
|  |                             <router-link :to="{ path: '/guestos/' + dataPreFill.ostypeid }"> | ||||||
|  |                               {{ dataPreFill.ostypename }} | ||||||
|  |                             </router-link> | ||||||
|  |                           </div> | ||||||
|  |                         </template> | ||||||
|  |                       </a-alert> | ||||||
|                       <div v-if="tabKey === 'templateid'"> |                       <div v-if="tabKey === 'templateid'"> | ||||||
|                         {{ $t('message.template.desc') }} |                         {{ $t('message.template.desc') }} | ||||||
|                         <div v-if="isZoneSelectedMultiArch" style="width: 100%; margin-top: 5px"> |                         <div v-if="isZoneSelectedMultiArch" style="width: 100%; margin-top: 5px"> | ||||||
| @ -933,6 +950,7 @@ export default { | |||||||
|       dataPreFill: {}, |       dataPreFill: {}, | ||||||
|       showDetails: false, |       showDetails: false, | ||||||
|       showRootDiskSizeChanger: false, |       showRootDiskSizeChanger: false, | ||||||
|  |       showOsTypeWarning: false, | ||||||
|       showOverrideDiskOfferingOption: false, |       showOverrideDiskOfferingOption: false, | ||||||
|       securitygroupids: [], |       securitygroupids: [], | ||||||
|       rootDiskSizeFixed: 0, |       rootDiskSizeFixed: 0, | ||||||
| @ -978,6 +996,15 @@ export default { | |||||||
|     isNormalUserOrProject () { |     isNormalUserOrProject () { | ||||||
|       return ['User'].includes(this.$store.getters.userInfo.roletype) || store.getters.project.id |       return ['User'].includes(this.$store.getters.userInfo.roletype) || store.getters.project.id | ||||||
|     }, |     }, | ||||||
|  |     selectedTemplateIso () { | ||||||
|  |       if (this.tabKey === 'templateid' && this.template?.ostypeid) { | ||||||
|  |         return { label: this.$t('label.template'), item: this.template, message: this.$t('message.template.ostype.different.from.backup') } | ||||||
|  |       } | ||||||
|  |       if (this.tabKey === 'isoid' && this.iso?.ostypeid) { | ||||||
|  |         return { label: this.$t('label.iso'), item: this.iso, message: this.$t('message.iso.ostype.different.from.backup') } | ||||||
|  |       } | ||||||
|  |       return null | ||||||
|  |     }, | ||||||
|     diskSize () { |     diskSize () { | ||||||
|       const customRootDiskSize = _.get(this.instanceConfig, 'rootdisksize', null) |       const customRootDiskSize = _.get(this.instanceConfig, 'rootdisksize', null) | ||||||
|       const customDataDiskSize = _.get(this.instanceConfig, 'size', null) |       const customDataDiskSize = _.get(this.instanceConfig, 'size', null) | ||||||
| @ -1687,6 +1714,7 @@ export default { | |||||||
|           this.form.iothreadsenabled = template.details && Object.prototype.hasOwnProperty.call(template.details, 'iothreads') |           this.form.iothreadsenabled = template.details && Object.prototype.hasOwnProperty.call(template.details, 'iothreads') | ||||||
|           this.form.iodriverpolicy = template.details?.['io.policy'] |           this.form.iodriverpolicy = template.details?.['io.policy'] | ||||||
|           this.form.keyboard = template.details?.keyboard |           this.form.keyboard = template.details?.keyboard | ||||||
|  |           this.showOsTypeWarning = this.dataPreFill.ostypeid && template.ostypeid !== this.dataPreFill.ostypeid | ||||||
|           if (template.details['vmware-to-kvm-mac-addresses']) { |           if (template.details['vmware-to-kvm-mac-addresses']) { | ||||||
|             this.dataPreFill.macAddressArray = JSON.parse(template.details['vmware-to-kvm-mac-addresses']) |             this.dataPreFill.macAddressArray = JSON.parse(template.details['vmware-to-kvm-mac-addresses']) | ||||||
|           } |           } | ||||||
| @ -1700,6 +1728,13 @@ export default { | |||||||
|         this.tabKey = 'isoid' |         this.tabKey = 'isoid' | ||||||
|         this.form.isoid = value |         this.form.isoid = value | ||||||
|         this.form.templateid = null |         this.form.templateid = null | ||||||
|  |         for (const key in this.options.isos) { | ||||||
|  |           var iso = _.find(_.get(this.options.isos[key], 'iso', []), (option) => option.id === value) | ||||||
|  |           if (iso) { | ||||||
|  |             this.showOsTypeWarning = this.dataPreFill.ostypeid && iso.ostypeid !== this.dataPreFill.ostypeid | ||||||
|  |             break | ||||||
|  |           } | ||||||
|  |         } | ||||||
|       } else if (['cpuspeed', 'cpunumber', 'memory'].includes(name)) { |       } else if (['cpuspeed', 'cpunumber', 'memory'].includes(name)) { | ||||||
|         this.vm[name] = value |         this.vm[name] = value | ||||||
|         this.form[name] = value |         this.form[name] = value | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ | |||||||
|         <a-form-item :label="$t('label.name.optional')" name="name"> |         <a-form-item :label="$t('label.name.optional')" name="name"> | ||||||
|           <a-input v-model:value="form.name" /> |           <a-input v-model:value="form.name" /> | ||||||
|         </a-form-item> |         </a-form-item> | ||||||
|         <a-form-item v-if="!resource.virtualmachineid" name="preserveIpAddresses" style="margin-top: 8px"> |         <a-form-item v-if="resource.isbackupvmexpunged" name="preserveIpAddresses" style="margin-top: 8px"> | ||||||
|           <a-switch v-model:checked="form.preserveIpAddresses" /> |           <a-switch v-model:checked="form.preserveIpAddresses" /> | ||||||
|           <template #label> |           <template #label> | ||||||
|             <tooltip-label :title="$t('label.use.backup.ip.address')" :tooltip="$t('label.use.backup.ip.address.tooltip')"/> |             <tooltip-label :title="$t('label.use.backup.ip.address')" :tooltip="$t('label.use.backup.ip.address.tooltip')"/> | ||||||
| @ -91,16 +91,16 @@ export default { | |||||||
|       required: true |       required: true | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   created () { |   async created () { | ||||||
|     this.fetchServiceOffering() |     await Promise.all[( | ||||||
|     this.fetchBackupOffering().then(() => { |       this.fetchServiceOffering(), | ||||||
|       this.fetchBackupRepository() |       this.fetchBackupOffering() | ||||||
|       this.loading = false |     )] | ||||||
|     }) |     this.loading = false | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     fetchServiceOffering () { |     fetchServiceOffering () { | ||||||
|       getAPI('listServiceOfferings', { |       return getAPI('listServiceOfferings', { | ||||||
|         zoneid: this.resource.zoneid, |         zoneid: this.resource.zoneid, | ||||||
|         id: this.resource.vmdetails.serviceofferingid, |         id: this.resource.vmdetails.serviceofferingid, | ||||||
|         listall: true |         listall: true | ||||||
| @ -118,28 +118,19 @@ export default { | |||||||
|         this.backupOffering = backupOfferings[0] |         this.backupOffering = backupOfferings[0] | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|     fetchBackupRepository () { |  | ||||||
|       if (this.backupOffering.provider !== 'nas') { |  | ||||||
|         return |  | ||||||
|       } |  | ||||||
|       getAPI('listBackupRepositories', { |  | ||||||
|         id: this.backupOffering.externalid |  | ||||||
|       }).then(response => { |  | ||||||
|         const backupRepositories = response.listbackuprepositoriesresponse.backuprepository || [] |  | ||||||
|         this.backupRepository = backupRepositories[0] |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     populatePreFillData () { |     populatePreFillData () { | ||||||
|       this.vmdetails = this.resource.vmdetails |       this.vmdetails = this.resource.vmdetails | ||||||
|       this.dataPreFill.zoneid = this.resource.zoneid |       this.dataPreFill.zoneid = this.resource.zoneid | ||||||
|       this.dataPreFill.crosszoneinstancecreation = this.backupRepository?.crosszoneinstancecreation || this.backupOffering.provider === 'dummy' |       this.dataPreFill.crosszoneinstancecreation = this.backupOffering?.crosszoneinstancecreation || this.backupOffering.provider === 'dummy' | ||||||
|       this.dataPreFill.isIso = (this.vmdetails.isiso === 'true') |       this.dataPreFill.isIso = (this.vmdetails.isiso === 'true') | ||||||
|  |       this.dataPreFill.ostypeid = this.resource.vmdetails.ostypeid | ||||||
|  |       this.dataPreFill.ostypename = this.resource.vmdetails.osname | ||||||
|       this.dataPreFill.backupid = this.resource.id |       this.dataPreFill.backupid = this.resource.id | ||||||
|       this.dataPreFill.computeofferingid = this.vmdetails.serviceofferingid |       this.dataPreFill.computeofferingid = this.vmdetails.serviceofferingid | ||||||
|       this.dataPreFill.templateid = this.vmdetails.templateid |       this.dataPreFill.templateid = this.vmdetails.templateid | ||||||
|       this.dataPreFill.allowtemplateisoselection = true |       this.dataPreFill.allowtemplateisoselection = true | ||||||
|       this.dataPreFill.isoid = this.vmdetails.templateid |       this.dataPreFill.isoid = this.vmdetails.templateid | ||||||
|       this.dataPreFill.allowIpAddressesFetch = !this.resource.virtualmachineid |       this.dataPreFill.allowIpAddressesFetch = this.resource.isbackupvmexpunged | ||||||
|       if (this.vmdetails.nics) { |       if (this.vmdetails.nics) { | ||||||
|         const nics = JSON.parse(this.vmdetails.nics) |         const nics = JSON.parse(this.vmdetails.nics) | ||||||
|         this.dataPreFill.networkids = nics.map(nic => nic.networkid) |         this.dataPreFill.networkids = nics.map(nic => nic.networkid) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user