Skip to content

Commit 8705c00

Browse files
committed
Fix: API Thread held forever during force deleting across MS
1 parent 4708121 commit 8705c00

File tree

6 files changed

+81
-5
lines changed

6 files changed

+81
-5
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
public class PropagateResourceEventCommand extends Command {
2525
long hostId;
2626
ResourceState.Event event;
27+
boolean forced;
28+
boolean forceDeleteStorage;
2729

2830
protected PropagateResourceEventCommand() {
2931

@@ -34,6 +36,13 @@ public PropagateResourceEventCommand(long hostId, ResourceState.Event event) {
3436
this.event = event;
3537
}
3638

39+
public PropagateResourceEventCommand(long hostId, ResourceState.Event event, boolean forced, boolean forceDeleteStorage) {
40+
this.hostId = hostId;
41+
this.event = event;
42+
this.forced = forced;
43+
this.forceDeleteStorage = forceDeleteStorage;
44+
}
45+
3746
public long getHostId() {
3847
return hostId;
3948
}
@@ -42,6 +51,14 @@ public ResourceState.Event getEvent() {
4251
return event;
4352
}
4453

54+
public boolean isForced() {
55+
return forced;
56+
}
57+
58+
public boolean isForceDeleteStorage() {
59+
return forceDeleteStorage;
60+
}
61+
4562
@Override
4663
public boolean executeInSequence() {
4764
// TODO Auto-generated method stub

engine/components-api/src/main/java/com/cloud/resource/ResourceManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ public interface ResourceManager extends ResourceService, Configurable {
122122

123123
public boolean executeUserRequest(long hostId, ResourceState.Event event) throws AgentUnavailableException;
124124

125+
boolean executeUserRequest(long hostId, ResourceState.Event event, boolean isForced, boolean isForceDeleteStorage) throws AgentUnavailableException;
126+
125127
boolean resourceStateTransitTo(Host host, Event event, long msId) throws NoTransitionException;
126128

127129
boolean umanageHost(long hostId);

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,11 +1307,20 @@ public String dispatch(final ClusterServicePdu pdu) {
13071307

13081308
boolean result;
13091309
try {
1310-
result = _resourceMgr.executeUserRequest(cmd.getHostId(), cmd.getEvent());
1310+
result = _resourceMgr.executeUserRequest(cmd.getHostId(), cmd.getEvent(), cmd.isForced(), cmd.isForceDeleteStorage());
13111311
logger.debug("Result is {}", result);
13121312
} catch (final AgentUnavailableException ex) {
13131313
logger.warn("Agent is unavailable", ex);
13141314
return null;
1315+
} catch (final RuntimeException ex) {
1316+
s_logger.error(String.format("Failed to execute propagated event %s for host %d", cmd.getEvent().name(), cmd.getHostId()), ex);
1317+
final Answer[] answers = new Answer[1];
1318+
String details = ex.getMessage();
1319+
if (details == null || details.isEmpty()) {
1320+
details = ex.toString();
1321+
}
1322+
answers[0] = new Answer(cmd, false, details);
1323+
return _gson.toJson(answers);
13151324
}
13161325

13171326
final Answer[] answers = new Answer[1];

server/src/main/java/com/cloud/resource/ResourceManagerImpl.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,7 @@ protected boolean canDeleteHost(HostVO host) {
11691169
@Override
11701170
public boolean deleteHost(final long hostId, final boolean isForced, final boolean isForceDeleteStorage) {
11711171
try {
1172-
final Boolean result = propagateResourceEvent(hostId, ResourceState.Event.DeleteHost);
1172+
final Boolean result = propagateResourceEvent(hostId, ResourceState.Event.DeleteHost, isForced, isForceDeleteStorage);
11731173
if (result != null) {
11741174
return result;
11751175
}
@@ -3902,13 +3902,18 @@ public boolean cancelMaintenance(final long hostId) {
39023902
}
39033903

39043904
@Override
3905-
public boolean executeUserRequest(final long hostId, final ResourceState.Event event) {
3905+
public boolean executeUserRequest(final long hostId, final ResourceState.Event event) throws AgentUnavailableException {
3906+
return executeUserRequest(hostId, event, false, false);
3907+
}
3908+
3909+
@Override
3910+
public boolean executeUserRequest(final long hostId, final ResourceState.Event event, final boolean isForced, final boolean isForceDeleteStorage) throws AgentUnavailableException {
39063911
if (event == ResourceState.Event.AdminAskMaintenance) {
39073912
return doMaintain(hostId);
39083913
} else if (event == ResourceState.Event.AdminCancelMaintenance) {
39093914
return doCancelMaintenance(hostId);
39103915
} else if (event == ResourceState.Event.DeleteHost) {
3911-
return doDeleteHost(hostId, false, false);
3916+
return doDeleteHost(hostId, isForced, isForceDeleteStorage);
39123917
} else if (event == ResourceState.Event.Unmanaged) {
39133918
return doUmanageHost(hostId);
39143919
} else if (event == ResourceState.Event.UpdatePassword) {
@@ -4028,14 +4033,18 @@ public String getPeerName(final long agentHostId) {
40284033
}
40294034

40304035
public Boolean propagateResourceEvent(final long agentId, final ResourceState.Event event) throws AgentUnavailableException {
4036+
return propagateResourceEvent(agentId, event, false, false);
4037+
}
4038+
4039+
public Boolean propagateResourceEvent(final long agentId, final ResourceState.Event event, final boolean isForced, final boolean isForceDeleteStorage) throws AgentUnavailableException {
40314040
final String msPeer = getPeerName(agentId);
40324041
if (msPeer == null) {
40334042
return null;
40344043
}
40354044

40364045
logger.debug("Propagating resource request event:" + event.toString() + " to agent:" + agentId);
40374046
final Command[] cmds = new Command[1];
4038-
cmds[0] = new PropagateResourceEventCommand(agentId, event);
4047+
cmds[0] = new PropagateResourceEventCommand(agentId, event, isForced, isForceDeleteStorage);
40394048

40404049
final String AnsStr = _clusterMgr.execute(msPeer, agentId, _gson.toJson(cmds), true);
40414050
if (AnsStr == null) {
@@ -4048,6 +4057,13 @@ public Boolean propagateResourceEvent(final long agentId, final ResourceState.Ev
40484057
logger.debug("Result for agent change is " + answers[0].getResult());
40494058
}
40504059

4060+
if (!answers[0].getResult()) {
4061+
final String details = answers[0].getDetails();
4062+
if (details != null && !details.isEmpty()) {
4063+
throw new CloudRuntimeException(String.format("Failed to propagate resource event %s for host %d on peer %s: %s", event, agentId, msPeer, details));
4064+
}
4065+
}
4066+
40514067
return answers[0].getResult();
40524068
}
40534069

server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ public boolean executeUserRequest(final long hostId, final Event event) throws A
318318
return false;
319319
}
320320

321+
@Override
322+
public boolean executeUserRequest(long hostId, Event event, boolean isForced, boolean isForceDeleteStorage) throws AgentUnavailableException {
323+
return false;
324+
}
325+
321326
/* (non-Javadoc)
322327
* @see com.cloud.resource.ResourceManager#resourceStateTransitTo(com.cloud.host.Host, com.cloud.resource.ResourceState.Event, long)
323328
*/

server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,4 +1184,31 @@ public void testUpdateHostStorageAccessGroups() {
11841184
Mockito.verify(host).setStorageAccessGroups("group1,group2");
11851185
Mockito.verify(hostDao).update(hostId, host);
11861186
}
1187+
1188+
@Test
1189+
public void executeUserRequestDeleteHostPassesForcedFlags() throws Exception {
1190+
Mockito.doReturn(true).when(resourceManager).doDeleteHost(anyLong(), anyBoolean(), anyBoolean());
1191+
1192+
resourceManager.executeUserRequest(hostId, ResourceState.Event.DeleteHost, true, true);
1193+
1194+
Mockito.verify(resourceManager).doDeleteHost(hostId, true, true);
1195+
}
1196+
1197+
@Test
1198+
public void executeUserRequestDeleteHostPassesNonForcedFlags() throws Exception {
1199+
Mockito.doReturn(true).when(resourceManager).doDeleteHost(anyLong(), anyBoolean(), anyBoolean());
1200+
1201+
resourceManager.executeUserRequest(hostId, ResourceState.Event.DeleteHost, false, false);
1202+
1203+
Mockito.verify(resourceManager).doDeleteHost(hostId, false, false);
1204+
}
1205+
1206+
@Test
1207+
public void executeUserRequestDefaultOverloadPassesFalseForDeleteHost() throws Exception {
1208+
Mockito.doReturn(true).when(resourceManager).doDeleteHost(anyLong(), anyBoolean(), anyBoolean());
1209+
1210+
resourceManager.executeUserRequest(hostId, ResourceState.Event.DeleteHost);
1211+
1212+
Mockito.verify(resourceManager).doDeleteHost(hostId, false, false);
1213+
}
11871214
}

0 commit comments

Comments
 (0)