Skip to content

Commit 4bacb50

Browse files
committed
Save and restore Instance settings to/from backup
1 parent 8ba1436 commit 4bacb50

File tree

9 files changed

+82
-24
lines changed

9 files changed

+82
-24
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ public class ApiConstants {
607607
public static final String VM_DETAILS = "vmdetails";
608608
public static final String VM_LIMIT = "vmlimit";
609609
public static final String VM_TOTAL = "vmtotal";
610+
public static final String VM_SETTINGS = "vmsettings";
610611
public static final String VM_TYPE = "vmtype";
611612
public static final String VNET = "vnet";
612613
public static final String IS_VOLATILE = "isvolatile";

api/src/main/java/org/apache/cloudstack/backup/BackupManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
262262

263263
void checkDiskOfferingSizeAgainstBackup(List<DiskOfferingInfo> dataDiskOfferingsInfo, Backup backup);
264264

265-
Map<String, String> getVmDetailsForBackup(VirtualMachine vm);
265+
Map<String, String> getBackupDetailsFromVM(VirtualMachine vm);
266266

267267
String createVolumeInfoFromVolumes(List<Volume> vmVolumes);
268268

plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public Pair<Boolean, Backup> takeBackup(VirtualMachine vm, Boolean quiesceVM) {
172172
backup.setName(backupManager.getBackupNameFromVM(vm));
173173
List<Volume> volumes = new ArrayList<>(volumeDao.findByInstance(vm.getId()));
174174
backup.setBackedUpVolumes(backupManager.createVolumeInfoFromVolumes(volumes));
175-
Map<String, String> details = backupManager.getVmDetailsForBackup(vm);
175+
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
176176
backup.setDetails(details);
177177

178178
backup = backupDao.persist(backup);

plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ private BackupVO createBackupObject(VirtualMachine vm, String backupPath) {
240240
backup.setDomainId(vm.getDomainId());
241241
backup.setZoneId(vm.getDataCenterId());
242242
backup.setName(backupManager.getBackupNameFromVM(vm));
243-
Map<String, String> details = backupManager.getVmDetailsForBackup(vm);
243+
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
244244
backup.setDetails(details);
245245

246246
return backupDao.persist(backup);

plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ public Pair<Boolean, Backup> takeBackup(VirtualMachine vm, Boolean quiesceVM) {
521521
if (backup != null) {
522522
List<Volume> volumes = new ArrayList<>(volumeDao.findByInstance(vm.getId()));
523523
backup.setBackedUpVolumes(backupManager.createVolumeInfoFromVolumes(volumes));
524-
Map<String, String> details = backupManager.getVmDetailsForBackup(vm);
524+
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
525525
backup.setDetails(details);
526526
backupDao.persist(backup);
527527
return new Pair<>(true, backup);

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.io.IOException;
2626
import java.io.StringReader;
2727
import java.io.UnsupportedEncodingException;
28+
import java.lang.reflect.Type;
2829
import java.net.URLDecoder;
2930
import java.text.SimpleDateFormat;
3031
import java.time.LocalDateTime;
@@ -400,6 +401,8 @@
400401
import com.cloud.vm.snapshot.VMSnapshotManager;
401402
import com.cloud.vm.snapshot.VMSnapshotVO;
402403
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
404+
import com.google.gson.Gson;
405+
import com.google.gson.reflect.TypeToken;
403406

404407
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
405408
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -9411,7 +9414,6 @@ private void checkRootDiskSizeAgainstBackup(Long instanceVolumeSize,DiskOffering
94119414

94129415
@Override
94139416
public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws InsufficientCapacityException, ResourceAllocationException, ResourceUnavailableException {
9414-
//Verify that all objects exist before passing them to the service
94159417
Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId());
94169418
Long zoneId = cmd.getZoneId();
94179419
DataCenter zone = _dcDao.findById(zoneId);
@@ -9453,19 +9455,21 @@ public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws Insufficien
94539455
}
94549456
verifyServiceOffering(cmd, serviceOffering);
94559457

9456-
Long templateId;
94579458
VirtualMachineTemplate template;
94589459
if (cmd.getTemplateId() != null) {
9459-
templateId = cmd.getTemplateId();
9460+
Long templateId = cmd.getTemplateId();
94609461
template = _templateDao.findById(templateId);
94619462
if (template == null) {
94629463
throw new InvalidParameterValueException("Unable to use template " + templateId);
94639464
}
94649465
} else {
9465-
templateId = backupVm.getTemplateId();
9466-
template = _templateDao.findById(templateId);
9466+
String templateUuid = backup.getDetail(ApiConstants.TEMPLATE_ID);
9467+
if (templateUuid == null) {
9468+
throw new CloudRuntimeException("Backup doesn't contain Template uuid. Please specify a valid Template/ISO while creating the instance");
9469+
}
9470+
template = _templateDao.findByUuid(templateUuid);
94679471
if (template == null) {
9468-
throw new CloudRuntimeException("Unable to find template associated with the backup. Please specify a valid template while creating instance");
9472+
throw new CloudRuntimeException("Unable to find template associated with the backup. Please specify a valid Template/ISO while creating instance");
94699473
}
94709474
}
94719475
verifyTemplate(cmd, template, serviceOffering.getId());
@@ -9534,7 +9538,23 @@ public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws Insufficien
95349538
ipToNetworkMap = backupManager.getIpToNetworkMapFromBackup(backup, cmd.getPreserveIp(), networkIds);
95359539
}
95369540

9537-
return createVirtualMachine(cmd, zone, owner, serviceOffering, template, hypervisorType, diskOfferingId, size, overrideDiskOfferingId, dataDiskOfferingsInfo, networkIds, ipToNetworkMap, null, null);
9541+
UserVm vm = createVirtualMachine(cmd, zone, owner, serviceOffering, template, hypervisorType, diskOfferingId, size, overrideDiskOfferingId, dataDiskOfferingsInfo, networkIds, ipToNetworkMap, null, null);
9542+
9543+
String vmSettingsFromBackup = backup.getDetail(ApiConstants.VM_SETTINGS);
9544+
if (vm != null && vmSettingsFromBackup != null) {
9545+
UserVmVO vmVO = _vmDao.findById(vm.getId());
9546+
Map<String, String> details = userVmDetailsDao.listDetailsKeyPairs(vm.getId());
9547+
vmVO.setDetails(details);
9548+
9549+
Type type = new TypeToken<Map<String, String>>(){}.getType();
9550+
Map<String, String> vmDetailsFromBackup = new Gson().fromJson(vmSettingsFromBackup, type);
9551+
for (Map.Entry<String, String> entry : vmDetailsFromBackup.entrySet()) {
9552+
vmVO.setDetail(entry.getKey(), entry.getValue());
9553+
}
9554+
_vmDao.saveDetails(vmVO);
9555+
}
9556+
9557+
return vm;
95389558
}
95399559

95409560
@Override

server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.backup;
1818

19+
import java.lang.reflect.Type;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collections;
@@ -53,9 +54,11 @@
5354
import com.cloud.storage.DiskOfferingVO;
5455
import com.cloud.storage.VolumeApiService;
5556
import com.cloud.storage.dao.VMTemplateDao;
57+
import com.cloud.template.VirtualMachineTemplate;
5658
import com.cloud.user.DomainManager;
5759
import com.cloud.user.ResourceLimitService;
5860
import com.cloud.utils.fsm.NoTransitionException;
61+
import com.cloud.vm.UserVmDetailVO;
5962
import com.cloud.vm.VirtualMachineManager;
6063
import javax.inject.Inject;
6164
import javax.naming.ConfigurationException;
@@ -149,8 +152,10 @@
149152
import com.cloud.vm.VMInstanceVO;
150153
import com.cloud.vm.VirtualMachine;
151154
import com.cloud.vm.dao.UserVmDao;
155+
import com.cloud.vm.dao.UserVmDetailsDao;
152156
import com.cloud.vm.dao.VMInstanceDao;
153157
import com.google.gson.Gson;
158+
import com.google.gson.reflect.TypeToken;
154159

155160
public class BackupManagerImpl extends ManagerBase implements BackupManager {
156161

@@ -191,6 +196,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
191196
@Inject
192197
private UserVmJoinDao userVmJoinDao;
193198
@Inject
199+
private UserVmDetailsDao userVmDetailsDao;
200+
@Inject
194201
private NetworkDao networkDao;
195202
@Inject
196203
private NetworkService networkService;
@@ -324,12 +331,24 @@ public boolean deleteBackupOffering(final Long offeringId) {
324331
}
325332

326333
@Override
327-
public Map<String, String> getVmDetailsForBackup(VirtualMachine vm) {
334+
public Map<String, String> getBackupDetailsFromVM(VirtualMachine vm) {
328335
HashMap<String, String> details = new HashMap<>();
329-
ServiceOffering serviceOffering = serviceOfferingDao.findById(vm.getServiceOfferingId());
336+
337+
ServiceOffering serviceOffering = serviceOfferingDao.findById(vm.getServiceOfferingId());
330338
details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOffering.getUuid());
331-
List<UserVmJoinVO> userVmJoinVOs = userVmJoinDao.searchByIds(vm.getId());
339+
VirtualMachineTemplate template = vmTemplateDao.findById(vm.getTemplateId());
340+
details.put(ApiConstants.TEMPLATE_ID, template.getUuid());
332341

342+
List<UserVmDetailVO> vmDetails = userVmDetailsDao.listDetails(vm.getId());
343+
HashMap<String, String> settings = new HashMap<>();
344+
for (UserVmDetailVO detail : vmDetails) {
345+
settings.put(detail.getName(), detail.getValue());
346+
}
347+
if (!settings.isEmpty()) {
348+
details.put(ApiConstants.VM_SETTINGS, new Gson().toJson(settings));
349+
}
350+
351+
List<UserVmJoinVO> userVmJoinVOs = userVmJoinDao.searchByIds(vm.getId());
333352
if (userVmJoinVOs != null && !userVmJoinVOs.isEmpty()) {
334353
List<Map<String, String>> nics = new ArrayList<>();
335354
Set<String> seen = new HashSet<>();
@@ -1102,7 +1121,8 @@ public Map<Long, Network.IpAddresses> getIpToNetworkMapFromBackup(Backup backup,
11021121
"Please specify at least one valid network while creating instance");
11031122
}
11041123

1105-
List<Map<String, String>> nics = new Gson().fromJson(nicsJson, List.class);
1124+
Type type = new TypeToken<List<Map<String, String>>>(){}.getType();
1125+
List<Map<String, String>> nics = new Gson().fromJson(nicsJson, type);
11061126

11071127
for (Map<String, String> nic : nics) {
11081128
String networkUuid = nic.get(ApiConstants.NETWORK_ID);

server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ public void testBackupSyncTask() {
804804
}
805805

806806
@Test
807-
public void testGetVmDetailsForBackup() {
807+
public void testGetBackupDetailsFromVM() {
808808
Long vmId = 1L;
809809
VirtualMachine vm = mock(VirtualMachine.class);
810810
when(vm.getServiceOfferingId()).thenReturn(1L);
@@ -819,7 +819,7 @@ public void testGetVmDetailsForBackup() {
819819
List<UserVmJoinVO> userVmJoinVOs = Collections.singletonList(userVmJoinVO);
820820
when(userVmJoinDao.searchByIds(vmId)).thenReturn(userVmJoinVOs);
821821

822-
Map<String, String> details = backupManager.getVmDetailsForBackup(vm);
822+
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
823823

824824
assertEquals("service-offering-uuid", details.get(ApiConstants.SERVICE_OFFERING_ID));
825825
assertEquals("mocked-network-uuid", details.get(ApiConstants.NETWORK_IDS));

ui/src/components/view/BackupMetadata.vue

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
<div style="width: 100%">
88
<strong>{{ getFieldLabel(item) }}</strong>
99
<br/>
10-
<div v-if="item === 'nics'">
11-
<div v-for="(nic, idx) in getNicEntities()" :key="idx">
12-
<router-link :to="{ path: '/guestnetwork/' + nic.networkid }">
13-
{{ nic.networkname || nic.networkid }}
14-
</router-link>
10+
<div v-if="item === 'nics'">
11+
<div v-for="(nic, idx) in getNicEntities()" :key="idx">
12+
<router-link :to="{ path: '/guestnetwork/' + nic.networkid }">
13+
{{ nic.networkname || nic.networkid }}
14+
</router-link>
1515
<br/>
1616
IP Address: {{ nic.ipaddress }}
1717
<span v-if="nic.ip6address && nic.ip6address !== 'null'"> | IPv6: {{ nic.ip6address }}</span>
@@ -30,6 +30,14 @@
3030
{{ getServiceOfferingDisplayName() }}
3131
</router-link>
3232
</div>
33+
<div v-else-if="item === 'vmsettings'">
34+
<div v-for="(value, key, index) in getVmSettings()" :key="key">
35+
{{ key }}
36+
<br/>
37+
{{ value }}
38+
<div v-if="index < Object.keys(getVmSettings()).length - 1" style="margin: 6px 0; border-bottom: 1px dashed #d9d9d9;"></div>
39+
</div>
40+
</div>
3341
<div v-else>{{ backupMetadata[item] }}</div>
3442
</div>
3543
</a-list-item>
@@ -66,20 +74,23 @@ export default {
6674
}
6775
fieldOrder.push('serviceofferingid')
6876
fieldOrder.push('nics')
77+
fieldOrder.push('vmsettings')
6978
7079
return fieldOrder.filter(field => this.backupMetadata[field] !== undefined)
7180
},
7281
getNicEntities () {
7382
if (this.backupMetadata.nics) {
74-
const nics = JSON.parse(this.backupMetadata.nics)
75-
return nics
83+
return JSON.parse(this.backupMetadata.nics)
7684
}
7785
return []
7886
},
7987
getFieldLabel (field) {
8088
if (field === 'templateid') {
8189
return this.backupMetadata.isiso === 'true' ? this.$t('label.iso') : this.$t('label.template')
8290
}
91+
if (field === 'vmsettings') {
92+
return this.$t('label.settings')
93+
}
8394
return this.$t('label.' + String(field).toLowerCase())
8495
},
8596
getTemplateDisplayName () {
@@ -93,6 +104,12 @@ export default {
93104
return this.backupMetadata.serviceofferingname
94105
}
95106
return this.backupMetadata.serviceofferingid
107+
},
108+
getVmSettings () {
109+
if (this.backupMetadata.vmsettings) {
110+
return JSON.parse(this.backupMetadata.vmsettings)
111+
}
112+
return {}
96113
}
97114
}
98115
}

0 commit comments

Comments
 (0)