Skip to content

Commit 1c1dad9

Browse files
committed
Merge remote-tracking branch 'apache/4.20'
2 parents eab37ec + 35a7438 commit 1c1dad9

File tree

38 files changed

+1412
-404
lines changed

38 files changed

+1412
-404
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteBackupScheduleCmd.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.cloudstack.api.BaseCmd;
2727
import org.apache.cloudstack.api.Parameter;
2828
import org.apache.cloudstack.api.ServerApiException;
29+
import org.apache.cloudstack.api.response.BackupScheduleResponse;
2930
import org.apache.cloudstack.api.response.SuccessResponse;
3031
import org.apache.cloudstack.api.response.UserVmResponse;
3132
import org.apache.cloudstack.backup.BackupManager;
@@ -54,10 +55,16 @@ public class DeleteBackupScheduleCmd extends BaseCmd {
5455
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
5556
type = CommandType.UUID,
5657
entityType = UserVmResponse.class,
57-
required = true,
5858
description = "ID of the VM")
5959
private Long vmId;
6060

61+
@Parameter(name = ApiConstants.ID,
62+
type = CommandType.UUID,
63+
entityType = BackupScheduleResponse.class,
64+
description = "ID of the schedule",
65+
since = "4.20.1")
66+
private Long id;
67+
6168
/////////////////////////////////////////////////////
6269
/////////////////// Accessors ///////////////////////
6370
/////////////////////////////////////////////////////
@@ -66,14 +73,17 @@ public Long getVmId() {
6673
return vmId;
6774
}
6875

76+
public Long getId() { return id; }
77+
78+
6979
/////////////////////////////////////////////////////
7080
/////////////// API Implementation///////////////////
7181
/////////////////////////////////////////////////////
7282

7383
@Override
7484
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
7585
try {
76-
boolean result = backupManager.deleteBackupSchedule(getVmId());
86+
boolean result = backupManager.deleteBackupSchedule(this);
7787
if (result) {
7888
SuccessResponse response = new SuccessResponse(getCommandName());
7989
response.setResponseName(getCommandName());

api/src/main/java/org/apache/cloudstack/api/response/BackupRepositoryResponse.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ public class BackupRepositoryResponse extends BaseResponse {
5757
@Param(description = "backup type")
5858
private String type;
5959

60-
@SerializedName(ApiConstants.MOUNT_OPTIONS)
61-
@Param(description = "mount options for the backup repository")
62-
private String mountOptions;
63-
6460
@SerializedName(ApiConstants.CAPACITY_BYTES)
6561
@Param(description = "capacity of the backup repository")
6662
private Long capacityBytes;
@@ -112,14 +108,6 @@ public void setAddress(String address) {
112108
this.address = address;
113109
}
114110

115-
public String getMountOptions() {
116-
return mountOptions;
117-
}
118-
119-
public void setMountOptions(String mountOptions) {
120-
this.mountOptions = mountOptions;
121-
}
122-
123111
public String getProviderName() {
124112
return providerName;
125113
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
2424
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
2525
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
26+
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
2627
import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd;
2728
import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd;
2829
import org.apache.cloudstack.framework.config.ConfigKey;
@@ -192,10 +193,10 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
192193

193194
/**
194195
* Deletes VM backup schedule for a VM
195-
* @param vmId
196+
* @param cmd
196197
* @return
197198
*/
198-
boolean deleteBackupSchedule(Long vmId);
199+
boolean deleteBackupSchedule(DeleteBackupScheduleCmd cmd);
199200

200201
/**
201202
* Creates backup of a VM

engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,7 @@ private void processHostHealthCheckResult(Boolean hostHealthCheckResult, long ho
14731473
}
14741474
if (!BooleanUtils.toBoolean(EnableKVMAutoEnableDisable.valueIn(host.getClusterId()))) {
14751475
logger.debug("{} is disabled for the cluster {}, cannot process the health check result " +
1476-
"received for the host {}", EnableKVMAutoEnableDisable.key(), host.getClusterId(), host);
1476+
"received for {}", EnableKVMAutoEnableDisable.key(), host.getClusterId(), host);
14771477
return;
14781478
}
14791479

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6071,6 +6071,9 @@ protected boolean isDiskOfferingSuitableForVm(VMInstanceVO vm, VirtualMachinePro
60716071
@Override
60726072
public Map<Long, Boolean> getDiskOfferingSuitabilityForVm(long vmId, List<Long> diskOfferingIds) {
60736073
VMInstanceVO vm = _vmDao.findById(vmId);
6074+
if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.DEPLOY_VM) != null) {
6075+
return new HashMap<>();
6076+
}
60746077
VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
60756078
Pair<Long, Long> clusterAndHost = findClusterAndHostIdForVm(vm, false);
60766079
Long clusterId = clusterAndHost.first();

packaging/el8/cloud.spec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ Requires: iproute
114114
Requires: ipset
115115
Requires: perl
116116
Requires: rsync
117+
Requires: cifs-utils
117118
Requires: (python3-libvirt or python3-libvirt-python)
118119
Requires: (qemu-img or qemu-tools)
119120
Requires: qemu-kvm

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
219219
restoreCommand.setBackupPath(backup.getExternalId());
220220
restoreCommand.setBackupRepoType(backupRepository.getType());
221221
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
222+
restoreCommand.setMountOptions(backupRepository.getMountOptions());
222223
restoreCommand.setVmName(vm.getName());
223224
restoreCommand.setVolumePaths(getVolumePaths(volumes));
224225
restoreCommand.setVmExists(vm.getRemoved() == null);
@@ -287,6 +288,7 @@ public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeU
287288
restoreCommand.setVmName(vmNameAndState.first());
288289
restoreCommand.setVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
289290
restoreCommand.setDiskType(volume.getVolumeType().name().toLowerCase(Locale.ROOT));
291+
restoreCommand.setMountOptions(backupRepository.getMountOptions());
290292
restoreCommand.setVmExists(null);
291293
restoreCommand.setVmState(vmNameAndState.second());
292294
restoreCommand.setRestoreVolumeUUID(volumeUuid);
@@ -372,8 +374,12 @@ public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<Vir
372374
Long vmBackupSize = 0L;
373375
Long vmBackupProtectedSize = 0L;
374376
for (final Backup backup: backupDao.listByVmId(null, vm.getId())) {
375-
vmBackupSize += backup.getSize();
376-
vmBackupProtectedSize += backup.getProtectedSize();
377+
if (Objects.nonNull(backup.getSize())) {
378+
vmBackupSize += backup.getSize();
379+
}
380+
if (Objects.nonNull(backup.getProtectedSize())) {
381+
vmBackupProtectedSize += backup.getProtectedSize();
382+
}
377383
}
378384
Backup.Metric vmBackupMetric = new Backup.Metric(vmBackupSize,vmBackupProtectedSize);
379385
LOG.debug("Metrics for VM {} is [backup size: {}, data size: {}].", vm, vmBackupMetric.getBackupSize(), vmBackupMetric.getDataSize());

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java

Lines changed: 118 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,34 @@
2727
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
2828
import com.cloud.resource.CommandWrapper;
2929
import com.cloud.resource.ResourceWrapper;
30+
import com.cloud.utils.Pair;
3031
import com.cloud.utils.net.NetUtils;
3132
import com.cloud.utils.script.Script;
3233

3334
@ResourceWrapper(handles = GetVmIpAddressCommand.class)
3435
public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper<GetVmIpAddressCommand, Answer, LibvirtComputingResource> {
3536

3637

38+
static String virsh_path = null;
39+
static String virt_win_reg_path = null;
40+
static String grep_path = null;
41+
static String awk_path = null;
42+
static String sed_path = null;
43+
static String virt_ls_path = null;
44+
static String virt_cat_path = null;
45+
static String tail_path = null;
46+
47+
static void init() {
48+
virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
49+
virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
50+
virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
51+
tail_path = Script.getExecutableAbsolutePath("tail");
52+
grep_path = Script.getExecutableAbsolutePath("grep");
53+
awk_path = Script.getExecutableAbsolutePath("awk");
54+
sed_path = Script.getExecutableAbsolutePath("sed");
55+
virsh_path = Script.getExecutableAbsolutePath("virsh");
56+
}
57+
3758
@Override
3859
public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputingResource libvirtComputingResource) {
3960
String ip = null;
@@ -42,65 +63,113 @@ public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputin
4263
if (!NetUtils.verifyDomainNameLabel(vmName, true)) {
4364
return new Answer(command, result, ip);
4465
}
66+
4567
String sanitizedVmName = sanitizeBashCommandArgument(vmName);
4668
String networkCidr = command.getVmNetworkCidr();
69+
70+
ip = ipFromDomIf(sanitizedVmName, networkCidr);
71+
72+
if (ip == null) {
73+
if(!command.isWindows()) {
74+
ip = ipFromDhcpLeaseFile(sanitizedVmName, networkCidr);
75+
} else {
76+
ip = ipFromWindowsRegistry(sanitizedVmName, networkCidr);
77+
}
78+
}
79+
80+
if(ip != null){
81+
result = true;
82+
logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
83+
} else {
84+
logger.warn("GetVmIp: "+ vmName + " IP not found.");
85+
}
86+
87+
return new Answer(command, result, ip);
88+
}
89+
90+
private String ipFromDomIf(String sanitizedVmName, String networkCidr) {
91+
String ip = null;
4792
List<String[]> commands = new ArrayList<>();
48-
final String virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
49-
final String virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
50-
final String virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
51-
final String tail_path = Script.getExecutableAbsolutePath("tail");
52-
final String grep_path = Script.getExecutableAbsolutePath("grep");
53-
final String awk_path = Script.getExecutableAbsolutePath("awk");
54-
final String sed_path = Script.getExecutableAbsolutePath("sed");
55-
if(!command.isWindows()) {
56-
//List all dhcp lease files inside guestVm
57-
commands.add(new String[]{virt_ls_path, sanitizedVmName, "/var/lib/dhclient/"});
58-
commands.add(new String[]{grep_path, ".*\\*.leases"});
59-
String leasesList = Script.executePipedCommands(commands, 0).second();
60-
if(leasesList != null) {
61-
String[] leasesFiles = leasesList.split("\n");
62-
for(String leaseFile : leasesFiles){
63-
//Read from each dhclient lease file inside guest Vm using virt-cat libguestfs utility
64-
commands = new ArrayList<>();
65-
commands.add(new String[]{virt_cat_path, sanitizedVmName, "/var/lib/dhclient/" + leaseFile});
66-
commands.add(new String[]{tail_path, "-16"});
67-
commands.add(new String[]{grep_path, "fixed-address"});
68-
commands.add(new String[]{awk_path, "{print $2}"});
69-
commands.add(new String[]{sed_path, "-e", "s/;//"});
70-
String ipAddr = Script.executePipedCommands(commands, 0).second();
71-
// Check if the IP belongs to the network
72-
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
73-
ip = ipAddr;
74-
break;
93+
commands.add(new String[]{virsh_path, "domifaddr", sanitizedVmName, "--source", "agent"});
94+
Pair<Integer,String> response = executePipedCommands(commands, 0);
95+
if (response != null) {
96+
String output = response.second();
97+
String[] lines = output.split("\n");
98+
for (String line : lines) {
99+
if (line.contains("ipv4")) {
100+
String[] parts = line.split(" ");
101+
String[] ipParts = parts[parts.length-1].split("/");
102+
if (ipParts.length > 1) {
103+
if (NetUtils.isIpWithInCidrRange(ipParts[0], networkCidr)) {
104+
ip = ipParts[0];
105+
break;
106+
}
75107
}
76-
logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
77108
}
78109
}
79110
} else {
80-
// For windows, read from guest Vm registry using virt-win-reg libguestfs ulitiy. Registry Path: HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Tcpip\Parameters\Interfaces\<service>\DhcpIPAddress
81-
commands = new ArrayList<>();
82-
commands.add(new String[]{virt_win_reg_path, "--unsafe-printable-strings", sanitizedVmName, "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
83-
commands.add(new String[]{grep_path, "DhcpIPAddress"});
84-
commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
85-
commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", "s/\"$//"});
86-
String ipList = Script.executePipedCommands(commands, 0).second();
87-
if(ipList != null) {
88-
logger.debug("GetVmIp: "+ vmName + "Ips: "+ipList);
89-
String[] ips = ipList.split("\n");
90-
for (String ipAddr : ips){
91-
// Check if the IP belongs to the network
92-
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
93-
ip = ipAddr;
94-
break;
95-
}
96-
logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
111+
logger.error("ipFromDomIf: Command execution failed for VM: " + sanitizedVmName);
112+
}
113+
return ip;
114+
}
115+
116+
private String ipFromDhcpLeaseFile(String sanitizedVmName, String networkCidr) {
117+
String ip = null;
118+
List<String[]> commands = new ArrayList<>();
119+
commands.add(new String[]{virt_ls_path, sanitizedVmName, "/var/lib/dhclient/"});
120+
commands.add(new String[]{grep_path, ".*\\*.leases"});
121+
Pair<Integer,String> response = executePipedCommands(commands, 0);
122+
123+
if(response != null && response.second() != null) {
124+
String leasesList = response.second();
125+
String[] leasesFiles = leasesList.split("\n");
126+
for(String leaseFile : leasesFiles){
127+
commands = new ArrayList<>();
128+
commands.add(new String[]{virt_cat_path, sanitizedVmName, "/var/lib/dhclient/" + leaseFile});
129+
commands.add(new String[]{tail_path, "-16"});
130+
commands.add(new String[]{grep_path, "fixed-address"});
131+
commands.add(new String[]{awk_path, "{print $2}"});
132+
commands.add(new String[]{sed_path, "-e", "s/;//"});
133+
String ipAddr = executePipedCommands(commands, 0).second();
134+
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
135+
ip = ipAddr;
136+
break;
97137
}
138+
logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
98139
}
140+
} else {
141+
logger.error("ipFromDhcpLeaseFile: Command execution failed for VM: " + sanitizedVmName);
99142
}
100-
if(ip != null){
101-
result = true;
102-
logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
143+
return ip;
144+
}
145+
146+
private String ipFromWindowsRegistry(String sanitizedVmName, String networkCidr) {
147+
String ip = null;
148+
List<String[]> commands = new ArrayList<>();
149+
commands.add(new String[]{virt_win_reg_path, "--unsafe-printable-strings", sanitizedVmName, "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
150+
commands.add(new String[]{grep_path, "DhcpIPAddress"});
151+
commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
152+
commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", "s/\"$//"});
153+
Pair<Integer,String> pair = executePipedCommands(commands, 0);
154+
if(pair != null && pair.second() != null) {
155+
String ipList = pair.second();
156+
ipList = ipList.replaceAll("\"", "");
157+
logger.debug("GetVmIp: "+ sanitizedVmName + "Ips: "+ipList);
158+
String[] ips = ipList.split("\n");
159+
for (String ipAddr : ips){
160+
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
161+
ip = ipAddr;
162+
break;
163+
}
164+
logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
165+
}
166+
} else {
167+
logger.error("ipFromWindowsRegistry: Command execution failed for VM: " + sanitizedVmName);
103168
}
104-
return new Answer(command, result, ip);
169+
return ip;
170+
}
171+
172+
static Pair<Integer, String> executePipedCommands(List<String[]> commands, long timeout) {
173+
return Script.executePipedCommands(commands, timeout);
105174
}
106175
}

0 commit comments

Comments
 (0)