Skip to content

Commit a21f912

Browse files
committed
Merge branch '4.19' of https://github.com/apache/cloudstack into 4.20
2 parents 17e062a + e68abcd commit a21f912

File tree

22 files changed

+489
-84
lines changed

22 files changed

+489
-84
lines changed

core/src/main/java/com/cloud/agent/api/GetVmIpAddressCommand.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ public class GetVmIpAddressCommand extends Command {
2424
String vmName;
2525
String vmNetworkCidr;
2626
boolean windows = false;
27+
String macAddress;
2728

28-
public GetVmIpAddressCommand(String vmName, String vmNetworkCidr, boolean windows) {
29+
public GetVmIpAddressCommand(String vmName, String vmNetworkCidr, boolean windows, String macAddress) {
2930
this.vmName = vmName;
3031
this.windows = windows;
3132
this.vmNetworkCidr = vmNetworkCidr;
33+
this.macAddress = macAddress;
3234
}
3335

3436
@Override
@@ -47,4 +49,8 @@ public boolean isWindows(){
4749
public String getVmNetworkCidr() {
4850
return vmNetworkCidr;
4951
}
52+
53+
public String getMacAddress() {
54+
return macAddress;
55+
}
5056
}

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl
223223
protected final ConfigKey<Boolean> CheckTxnBeforeSending = new ConfigKey<Boolean>("Developer", Boolean.class, "check.txn.before.sending.agent.commands", "false",
224224
"This parameter allows developers to enable a check to see if a transaction wraps commands that are sent to the resource. This is not to be enabled on production systems.", true);
225225

226+
public static final List<Host.Type> HOST_DOWN_ALERT_UNSUPPORTED_HOST_TYPES = Arrays.asList(
227+
Host.Type.SecondaryStorage,
228+
Host.Type.ConsoleProxy
229+
);
230+
226231
@Override
227232
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
228233

@@ -986,9 +991,11 @@ protected boolean handleDisconnectWithInvestigation(final AgentAttache attache,
986991
if (determinedState == Status.Down) {
987992
final String message = String.format("Host %s is down. Starting HA on the VMs", host);
988993
logger.error(message);
989-
if (host.getType() != Host.Type.SecondaryStorage && host.getType() != Host.Type.ConsoleProxy) {
990-
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(),
991-
host.getPodId(), String.format("Host down, %s", host), message);
994+
if (Status.Down.equals(host.getStatus())) {
995+
logger.debug(String.format("Skipping sending alert for %s as it already in %s state",
996+
host, host.getStatus()));
997+
} else if (!HOST_DOWN_ALERT_UNSUPPORTED_HOST_TYPES.contains(host.getType())) {
998+
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Host down, " + host.getId(), message);
992999
}
9931000
event = Status.Event.HostDown;
9941001
} else if (determinedState == Status.Up) {

engine/schema/src/main/java/com/cloud/usage/dao/UsageNetworksDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ public interface UsageNetworksDao extends GenericDao<UsageNetworksVO, Long> {
2828
void remove(long networkId, Date removed);
2929

3030
List<UsageNetworksVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
31+
32+
List<UsageNetworksVO> listAll(long networkId);
3133
}

engine/schema/src/main/java/com/cloud/usage/dao/UsageNetworksDaoImpl.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919
import com.cloud.usage.UsageNetworksVO;
2020
import com.cloud.utils.DateUtil;
2121
import com.cloud.utils.db.GenericDaoBase;
22+
import com.cloud.utils.db.SearchBuilder;
2223
import com.cloud.utils.db.SearchCriteria;
2324
import com.cloud.utils.db.TransactionLegacy;
2425

2526
import org.springframework.stereotype.Component;
2627
import org.apache.logging.log4j.LogManager;
2728
import org.apache.logging.log4j.Logger;
2829

30+
import javax.annotation.PostConstruct;
2931
import java.sql.PreparedStatement;
3032
import java.sql.ResultSet;
3133
import java.util.ArrayList;
@@ -40,6 +42,14 @@ public class UsageNetworksDaoImpl extends GenericDaoBase<UsageNetworksVO, Long>
4042
" account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " +
4143
" OR ((created <= ?) AND (removed >= ?)))";
4244

45+
private SearchBuilder<UsageNetworksVO> usageNetworksSearch;
46+
47+
@PostConstruct
48+
public void init() {
49+
usageNetworksSearch = createSearchBuilder();
50+
usageNetworksSearch.and("networkId", usageNetworksSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
51+
usageNetworksSearch.done();
52+
}
4353

4454
@Override
4555
public void update(long networkId, long newNetworkOffering, String state) {
@@ -131,4 +141,11 @@ public List<UsageNetworksVO> getUsageRecords(Long accountId, Date startDate, Dat
131141

132142
return usageRecords;
133143
}
144+
145+
@Override
146+
public List<UsageNetworksVO> listAll(long networkId) {
147+
SearchCriteria<UsageNetworksVO> sc = usageNetworksSearch.create();
148+
sc.setParameters("networkId", networkId);
149+
return listBy(sc);
150+
}
134151
}

engine/schema/src/main/java/com/cloud/usage/dao/UsageVpcDao.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424

2525
public interface UsageVpcDao extends GenericDao<UsageVpcVO, Long> {
2626
void update(UsageVpcVO usage);
27+
2728
void remove(long vpcId, Date removed);
29+
2830
List<UsageVpcVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
31+
32+
List<UsageVpcVO> listAll(long vpcId);
2933
}

engine/schema/src/main/java/com/cloud/usage/dao/UsageVpcDaoImpl.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import com.cloud.usage.UsageVpcVO;
2020
import com.cloud.utils.DateUtil;
2121
import com.cloud.utils.db.GenericDaoBase;
22+
import com.cloud.utils.db.SearchBuilder;
2223
import com.cloud.utils.db.SearchCriteria;
2324
import com.cloud.utils.db.TransactionLegacy;
2425
import org.springframework.stereotype.Component;
2526

27+
import javax.annotation.PostConstruct;
2628
import java.sql.PreparedStatement;
2729
import java.sql.ResultSet;
2830
import java.util.ArrayList;
@@ -36,6 +38,15 @@ public class UsageVpcDaoImpl extends GenericDaoBase<UsageVpcVO, Long> implements
3638
" account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " +
3739
" OR ((created <= ?) AND (removed >= ?)))";
3840

41+
private SearchBuilder<UsageVpcVO> usageVpcSearch;
42+
43+
@PostConstruct
44+
public void init() {
45+
usageVpcSearch = createSearchBuilder();
46+
usageVpcSearch.and("vpcId", usageVpcSearch.entity().getVpcId(), SearchCriteria.Op.EQ);
47+
usageVpcSearch.done();
48+
}
49+
3950
@Override
4051
public void update(UsageVpcVO usage) {
4152
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
@@ -124,4 +135,11 @@ public List<UsageVpcVO> getUsageRecords(Long accountId, Date startDate, Date end
124135

125136
return usageRecords;
126137
}
138+
139+
@Override
140+
public List<UsageVpcVO> listAll(long vpcId) {
141+
SearchCriteria<UsageVpcVO> sc = usageVpcSearch.create();
142+
sc.setParameters("vpcId", vpcId);
143+
return listBy(sc);
144+
}
127145
}

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

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputin
6666

6767
String sanitizedVmName = sanitizeBashCommandArgument(vmName);
6868
String networkCidr = command.getVmNetworkCidr();
69+
String macAddress = command.getMacAddress();
6970

70-
ip = ipFromDomIf(sanitizedVmName, networkCidr);
71+
init();
7172

72-
if (ip == null) {
73+
ip = ipFromDomIf(sanitizedVmName, networkCidr, macAddress);
74+
75+
if (ip == null && networkCidr != null) {
7376
if(!command.isWindows()) {
7477
ip = ipFromDhcpLeaseFile(sanitizedVmName, networkCidr);
7578
} else {
@@ -87,32 +90,56 @@ public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputin
8790
return new Answer(command, result, ip);
8891
}
8992

90-
private String ipFromDomIf(String sanitizedVmName, String networkCidr) {
93+
private String ipFromDomIf(String sanitizedVmName, String networkCidr, String macAddress) {
9194
String ip = null;
9295
List<String[]> commands = new ArrayList<>();
9396
commands.add(new String[]{virsh_path, "domifaddr", sanitizedVmName, "--source", "agent"});
9497
Pair<Integer,String> response = executePipedCommands(commands, 0);
9598
if (response != null) {
9699
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-
}
107-
}
108-
}
100+
Pair<String, String> ipAddresses = getIpAddresses(output, macAddress);
101+
String ipv4 = ipAddresses.first();
102+
if (networkCidr == null || NetUtils.isIpWithInCidrRange(ipv4, networkCidr)) {
103+
ip = ipv4;
109104
}
110105
} else {
111106
logger.error("ipFromDomIf: Command execution failed for VM: " + sanitizedVmName);
112107
}
113108
return ip;
114109
}
115110

111+
private Pair<String, String> getIpAddresses(String output, String macAddress) {
112+
String ipv4 = null;
113+
String ipv6 = null;
114+
boolean found = false;
115+
String[] lines = output.split("\n");
116+
for (String line : lines) {
117+
String[] parts = line.replaceAll(" +", " ").trim().split(" ");
118+
if (parts.length < 4) {
119+
continue;
120+
}
121+
String device = parts[0];
122+
String mac = parts[1];
123+
if (found) {
124+
if (!device.equals("-") || !mac.equals("-")) {
125+
break;
126+
}
127+
} else if (!mac.equals(macAddress)) {
128+
continue;
129+
}
130+
found = true;
131+
String ipFamily = parts[2];
132+
String ipPart = parts[3].split("/")[0];
133+
if (ipFamily.equals("ipv4")) {
134+
ipv4 = ipPart;
135+
} else if (ipFamily.equals("ipv6")) {
136+
ipv6 = ipPart;
137+
}
138+
}
139+
s_logger.debug(String.format("Found ipv4: %s and ipv6: %s with mac address %s", ipv4, ipv6, macAddress));
140+
return new Pair<>(ipv4, ipv6);
141+
}
142+
116143
private String ipFromDhcpLeaseFile(String sanitizedVmName, String networkCidr) {
117144
String ip = null;
118145
List<String[]> commands = new ArrayList<>();

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public void testExecuteWithValidVmName() {
6666

6767
when(getVmIpAddressCommand.getVmName()).thenReturn("validVmName");
6868
when(getVmIpAddressCommand.getVmNetworkCidr()).thenReturn("192.168.0.0/24");
69+
when(getVmIpAddressCommand.getMacAddress()).thenReturn("02:0c:02:f9:00:80");
6970
when(getVmIpAddressCommand.isWindows()).thenReturn(false);
7071
when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, VIRSH_DOMIF_OUTPUT));
7172

@@ -88,6 +89,7 @@ public void testExecuteWithInvalidVmName() {
8889

8990
when(getVmIpAddressCommand.getVmName()).thenReturn("invalidVmName!");
9091
when(getVmIpAddressCommand.getVmNetworkCidr()).thenReturn("192.168.0.0/24");
92+
when(getVmIpAddressCommand.getMacAddress()).thenReturn("02:0c:02:f9:00:80");
9193
when(getVmIpAddressCommand.isWindows()).thenReturn(false);
9294
when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, VIRSH_DOMIF_OUTPUT));
9395

@@ -114,6 +116,7 @@ public void testExecuteWithWindowsVm() {
114116

115117
when(getVmIpAddressCommand.getVmName()).thenReturn("validVmName");
116118
when(getVmIpAddressCommand.getVmNetworkCidr()).thenReturn("192.168.0.0/24");
119+
when(getVmIpAddressCommand.getMacAddress()).thenReturn("02:0c:02:f9:00:80");
117120
when(getVmIpAddressCommand.isWindows()).thenReturn(true);
118121
when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, "192.168.0.10"));
119122

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/XenServerGuru.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
3535
import org.apache.commons.lang3.StringUtils;
3636

37+
import com.cloud.agent.api.CleanupVMCommand;
3738
import com.cloud.agent.api.Command;
3839
import com.cloud.agent.api.to.DataObjectType;
3940
import com.cloud.agent.api.to.DataStoreTO;
@@ -234,4 +235,12 @@ public String getConfigComponentName() {
234235
public ConfigKey<?>[] getConfigKeys() {
235236
return new ConfigKey<?>[] {MaxNumberOfVCPUSPerVM};
236237
}
238+
239+
@Override
240+
public List<Command> finalizeExpunge(VirtualMachine vm) {
241+
List<Command> commands = new ArrayList<>();
242+
final CleanupVMCommand cleanupVMCommand = new CleanupVMCommand(vm.getInstanceName(), true);
243+
commands.add(cleanupVMCommand);
244+
return commands;
245+
}
237246
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package com.cloud.hypervisor.xenserver.resource.wrapper.xenbase;
19+
20+
import java.util.Iterator;
21+
import java.util.Set;
22+
23+
import org.apache.log4j.Logger;
24+
25+
import com.cloud.agent.api.Answer;
26+
import com.cloud.agent.api.CleanupVMCommand;
27+
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
28+
import com.cloud.resource.CommandWrapper;
29+
import com.cloud.resource.ResourceWrapper;
30+
import com.xensource.xenapi.Connection;
31+
import com.xensource.xenapi.Types;
32+
import com.xensource.xenapi.VM;
33+
34+
@ResourceWrapper(handles = CleanupVMCommand.class)
35+
public class CitrixCleanupVMCommandWrapper extends CommandWrapper<CleanupVMCommand, Answer, CitrixResourceBase> {
36+
37+
private static final Logger s_logger = Logger.getLogger(CitrixCleanupVMCommandWrapper.class);
38+
39+
@Override
40+
public Answer execute(final CleanupVMCommand command, final CitrixResourceBase citrixResourceBase) {
41+
if (citrixResourceBase.isDestroyHaltedVms()) {
42+
s_logger.debug(String.format("Cleanup VM is not needed for host with version %s",
43+
citrixResourceBase.getHost().getProductVersion()));
44+
return new Answer(command);
45+
}
46+
final String vmName = command.getVmName();
47+
try {
48+
final Connection conn = citrixResourceBase.getConnection();
49+
final Set<VM> vms = VM.getByNameLabel(conn, vmName);
50+
if (vms.isEmpty()) {
51+
return new Answer(command, true, "VM does not exist");
52+
}
53+
// destroy vm which is in HALTED state on this host
54+
final Iterator<VM> iter = vms.iterator();
55+
while (iter.hasNext()) {
56+
final VM vm = iter.next();
57+
final VM.Record vmr = vm.getRecord(conn);
58+
if (!Types.VmPowerState.HALTED.equals(vmr.powerState)) {
59+
final String msg = String.format("VM %s is not in %s state", vmName, Types.VmPowerState.HALTED);
60+
s_logger.error(msg);
61+
return new Answer(command, false, msg);
62+
}
63+
if (citrixResourceBase.isRefNull(vmr.residentOn)) {
64+
continue;
65+
}
66+
if (vmr.residentOn.getUuid(conn).equals(citrixResourceBase.getHost().getUuid())) {
67+
continue;
68+
}
69+
iter.remove();
70+
}
71+
for (final VM vm : vms) {
72+
citrixResourceBase.destroyVm(vm, conn, true);
73+
}
74+
75+
} catch (final Exception e) {
76+
final String msg = String.format("Clean up VM %s fail due to %s", vmName, e);
77+
s_logger.error(msg, e);
78+
return new Answer(command, false, e.getMessage());
79+
}
80+
return new Answer(command);
81+
}
82+
}

0 commit comments

Comments
 (0)