Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e97cff3

Browse files
committedJun 10, 2025
Management Server - Prepare for Maintenance and Cancel Maintenance improvements:
- Added new setting 'management.server.maintenance.ignore.maintenance.hosts' to ignore hosts in maintenance states while preparing management server for maintenance. This skips agent transfer and agents count check for hosts in maintenance. - Rebalance indirect agents after cancel maintenance, using rebalance parameter in cancelMaintenance API - Force maintenance after maintenance window timeout, using forced parameter in prepareForMaintenance API. - Propagate 'indirect.agent.lb.check.interval' setting change to the host agents.
1 parent f496ed6 commit e97cff3

File tree

25 files changed

+308
-94
lines changed

25 files changed

+308
-94
lines changed
 

‎agent/src/main/java/com/cloud/agent/Agent.java‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ private Answer setupAgentCertificate(final SetupCertificateCommand cmd) {
928928
return new SetupCertificateAnswer(true);
929929
}
930930

931-
private void processManagementServerList(final List<String> msList, final List<String> avoidMsList, final String lbAlgorithm, final Long lbCheckInterval) {
931+
private void processManagementServerList(final List<String> msList, final List<String> avoidMsList, final String lbAlgorithm, final Long lbCheckInterval, final boolean triggerHostLB) {
932932
if (CollectionUtils.isNotEmpty(msList) && StringUtils.isNotEmpty(lbAlgorithm)) {
933933
try {
934934
final String newMSHosts = String.format("%s%s%s", com.cloud.utils.StringUtils.toCSVList(msList), IAgentShell.hostLbAlgorithmSeparator, lbAlgorithm);
@@ -941,6 +941,12 @@ private void processManagementServerList(final List<String> msList, final List<S
941941
}
942942
}
943943
shell.setAvoidHosts(avoidMsList);
944+
if (triggerHostLB) {
945+
logger.info("Triggering preferred host task");
946+
hostLbCheckExecutor = Executors.newSingleThreadScheduledExecutor((new NamedThreadFactory("HostLB-Executor")));
947+
ScheduledExecutorService hostLbExecutor = Executors.newScheduledThreadPool(1);
948+
hostLbExecutor.schedule(new PreferredHostCheckerTask(), 0, TimeUnit.MILLISECONDS);
949+
}
944950
if ("shuffle".equals(lbAlgorithm)) {
945951
scheduleHostLBCheckerTask(0);
946952
} else {
@@ -949,14 +955,14 @@ private void processManagementServerList(final List<String> msList, final List<S
949955
}
950956

951957
private Answer setupManagementServerList(final SetupMSListCommand cmd) {
952-
processManagementServerList(cmd.getMsList(), cmd.getAvoidMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval());
958+
processManagementServerList(cmd.getMsList(), cmd.getAvoidMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval(), cmd.getTriggerHostLb());
953959
return new SetupMSListAnswer(true);
954960
}
955961

956962
private Answer migrateAgentToOtherMS(final MigrateAgentConnectionCommand cmd) {
957963
try {
958964
if (CollectionUtils.isNotEmpty(cmd.getMsList())) {
959-
processManagementServerList(cmd.getMsList(), cmd.getAvoidMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval());
965+
processManagementServerList(cmd.getMsList(), cmd.getAvoidMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval(), false);
960966
}
961967
Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("MigrateAgentConnection-Job")).schedule(() -> {
962968
migrateAgentConnection(cmd.getAvoidMsList());
@@ -1046,7 +1052,7 @@ public void processReadyCommand(final Command cmd) {
10461052
}
10471053

10481054
verifyAgentArch(ready.getArch());
1049-
processManagementServerList(ready.getMsHostList(), ready.getAvoidMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval());
1055+
processManagementServerList(ready.getMsHostList(), ready.getAvoidMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval(), false);
10501056

10511057
logger.info("Ready command is processed for agent [id: {}, uuid: {}, name: {}]", getId(), getUuid(), getName());
10521058
}

‎api/src/main/java/com/cloud/exception/OperationTimedoutException.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class OperationTimedoutException extends CloudException {
4040
boolean _isActive;
4141

4242
public OperationTimedoutException(Command[] cmds, long agentId, long seqId, int time, boolean isActive) {
43-
super("Commands " + seqId + " to Host " + agentId + " timed out after " + time);
43+
super("Commands " + seqId + " to Host " + agentId + " timed out after " + time + " secs");
4444
_agentId = agentId;
4545
_seqId = seqId;
4646
_time = time;

‎api/src/main/java/com/cloud/resource/ResourceState.java‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public static Event toEvent(String e) {
7676
}
7777
}
7878

79+
public static List<ResourceState> s_maintenanceStates = List.of(ResourceState.Maintenance,
80+
ResourceState.ErrorInMaintenance, ResourceState.PrepareForMaintenance,
81+
ResourceState.ErrorInPrepareForMaintenance);
82+
7983
public ResourceState getNextState(Event a) {
8084
return s_fsm.getNextState(this, a);
8185
}
@@ -98,8 +102,7 @@ public static String[] toString(ResourceState... states) {
98102
}
99103

100104
public static boolean isMaintenanceState(ResourceState state) {
101-
return Arrays.asList(ResourceState.Maintenance, ResourceState.ErrorInMaintenance,
102-
ResourceState.PrepareForMaintenance, ResourceState.ErrorInPrepareForMaintenance).contains(state);
105+
return s_maintenanceStates.contains(state);
103106
}
104107

105108
public static boolean canAttemptMaintenance(ResourceState state) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ public class ApiConstants {
427427
public static final String PUBLIC_END_PORT = "publicendport";
428428
public static final String PUBLIC_ZONE = "publiczone";
429429
public static final String PURGE_RESOURCES = "purgeresources";
430+
public static final String REBALANCE = "rebalance";
430431
public static final String RECEIVED_BYTES = "receivedbytes";
431432
public static final String RECONNECT = "reconnect";
432433
public static final String RECOVER = "recover";

‎core/src/main/java/org/apache/cloudstack/agent/lb/SetupMSListCommand.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ public class SetupMSListCommand extends Command {
2929
private List<String> avoidMsList;
3030
private String lbAlgorithm;
3131
private Long lbCheckInterval;
32+
private Boolean triggerHostLb;
3233

33-
public SetupMSListCommand(final List<String> msList, final List<String> avoidMsList, final String lbAlgorithm, final Long lbCheckInterval) {
34+
public SetupMSListCommand(final List<String> msList, final List<String> avoidMsList, final String lbAlgorithm, final Long lbCheckInterval, final Boolean triggerHostLb) {
3435
super();
3536
this.msList = msList;
3637
this.avoidMsList = avoidMsList;
3738
this.lbAlgorithm = lbAlgorithm;
3839
this.lbCheckInterval = lbCheckInterval;
40+
this.triggerHostLb = triggerHostLb;
3941
}
4042

4143
public List<String> getMsList() {
@@ -54,9 +56,12 @@ public Long getLbCheckInterval() {
5456
return lbCheckInterval;
5557
}
5658

59+
public boolean getTriggerHostLb() {
60+
return triggerHostLb;
61+
}
62+
5763
@Override
5864
public boolean executeInSequence() {
5965
return false;
6066
}
61-
6267
}

‎engine/components-api/src/main/java/com/cloud/agent/AgentManager.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,5 @@ enum TapAgentsAction {
171171

172172
void propagateChangeToAgents(Map<String, String> params);
173173

174-
boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs);
174+
boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs, boolean excludeHostsInMaintenance);
175175
}

‎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
@@ -2193,7 +2193,7 @@ public void propagateChangeToAgents(Map<String, String> params) {
21932193
}
21942194

21952195
@Override
2196-
public boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs) {
2196+
public boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs, boolean excludeHostsInMaintenance) {
21972197
return true;
21982198
}
21992199

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import javax.net.ssl.SSLContext;
4343
import javax.net.ssl.SSLEngine;
4444

45+
import com.cloud.resource.ResourceState;
4546
import org.apache.cloudstack.ca.CAManager;
4647
import org.apache.cloudstack.framework.config.ConfigDepot;
4748
import org.apache.cloudstack.framework.config.ConfigKey;
@@ -431,10 +432,10 @@ public boolean routeToPeer(final String peer, final byte[] bytes) {
431432
ch = connectToPeer(peer, ch);
432433
if (ch == null) {
433434
try {
434-
logD(bytes, "Unable to route to peer: " + Request.parse(bytes));
435+
logD(bytes, "Unable to establish connection to route to peer: " + Request.parse(bytes));
435436
} catch (ClassNotFoundException | UnsupportedVersionException e) {
436437
// Request.parse thrown exception when we try to log it, log as much as we can
437-
logD(bytes, "Unable to route to peer, and Request.parse further caught exception" + e.getMessage());
438+
logD(bytes, "Unable to establish connection to route to peer, and Request.parse further caught exception" + e.getMessage());
438439
}
439440
return false;
440441
}
@@ -643,7 +644,6 @@ protected void doTask(final Task task) throws TaskExecutionException {
643644
final Link link = task.getLink();
644645

645646
if (Request.fromServer(data)) {
646-
647647
final AgentAttache agent = findAttache(hostId);
648648

649649
if (Request.isControl(data)) {
@@ -691,7 +691,6 @@ protected void doTask(final Task task) throws TaskExecutionException {
691691
cancel(Long.toString(Request.getManagementServerId(data)), hostId, Request.getSequence(data), e.getMessage());
692692
}
693693
} else {
694-
695694
final long mgmtId = Request.getManagementServerId(data);
696695
if (mgmtId != -1 && mgmtId != _nodeId) {
697696
routeToPeer(Long.toString(mgmtId), data);
@@ -1352,7 +1351,7 @@ private String handleShutdownManagementServerHostCommand(BaseShutdownManagementS
13521351
if (cmd instanceof PrepareForMaintenanceManagementServerHostCommand) {
13531352
logger.debug("Received PrepareForMaintenanceManagementServerHostCommand - preparing for maintenance");
13541353
try {
1355-
managementServerMaintenanceManager.prepareForMaintenance(((PrepareForMaintenanceManagementServerHostCommand) cmd).getLbAlgorithm());
1354+
managementServerMaintenanceManager.prepareForMaintenance(((PrepareForMaintenanceManagementServerHostCommand) cmd).getLbAlgorithm(), ((PrepareForMaintenanceManagementServerHostCommand) cmd).isForced());
13561355
return "Successfully prepared for maintenance";
13571356
} catch(CloudRuntimeException e) {
13581357
return e.getMessage();
@@ -1399,14 +1398,14 @@ private String handleShutdownManagementServerHostCommand(BaseShutdownManagementS
13991398
}
14001399

14011400
@Override
1402-
public boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs) {
1401+
public boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs, boolean excludeHostsInMaintenance) {
14031402
if (timeoutDurationInMs <= 0) {
14041403
logger.debug("Not transferring direct agents from management server node {} (id: {}) to other nodes, invalid timeout duration", fromMsId, fromMsUuid);
14051404
return false;
14061405
}
14071406

14081407
long transferStartTimeInMs = System.currentTimeMillis();
1409-
if (CollectionUtils.isEmpty(getDirectAgentHosts(fromMsId))) {
1408+
if (CollectionUtils.isEmpty(getDirectAgentHosts(fromMsId, excludeHostsInMaintenance))) {
14101409
logger.info("No direct agent hosts available on management server node {} (id: {}), to transfer", fromMsId, fromMsUuid);
14111410
return true;
14121411
}
@@ -1421,7 +1420,7 @@ public boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long
14211420
int agentTransferFailedCount = 0;
14221421
List<DataCenterVO> dataCenterList = dcDao.listAll();
14231422
for (DataCenterVO dc : dataCenterList) {
1424-
List<HostVO> directAgentHostsInDc = getDirectAgentHostsInDc(fromMsId, dc.getId());
1423+
List<HostVO> directAgentHostsInDc = getDirectAgentHostsInDc(fromMsId, dc.getId(), excludeHostsInMaintenance);
14251424
if (CollectionUtils.isEmpty(directAgentHostsInDc)) {
14261425
continue;
14271426
}
@@ -1455,9 +1454,9 @@ public boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long
14551454
return (agentTransferFailedCount == 0);
14561455
}
14571456

1458-
private List<HostVO> getDirectAgentHosts(long msId) {
1457+
private List<HostVO> getDirectAgentHosts(long msId, boolean excludeHostsInMaintenance) {
14591458
List<HostVO> directAgentHosts = new ArrayList<>();
1460-
List<HostVO> hosts = _hostDao.listHostsByMs(msId);
1459+
List<HostVO> hosts = _hostDao.listHostsByMsResourceState(msId, null);
14611460
for (HostVO host : hosts) {
14621461
AgentAttache agent = findAttache(host.getId());
14631462
if (agent instanceof DirectAgentAttache) {
@@ -1468,9 +1467,11 @@ private List<HostVO> getDirectAgentHosts(long msId) {
14681467
return directAgentHosts;
14691468
}
14701469

1471-
private List<HostVO> getDirectAgentHostsInDc(long msId, long dcId) {
1470+
private List<HostVO> getDirectAgentHostsInDc(long msId, long dcId, boolean excludeHostsInMaintenance) {
14721471
List<HostVO> directAgentHosts = new ArrayList<>();
1473-
List<HostVO> hosts = _hostDao.listHostsByMsAndDc(msId, dcId);
1472+
// To exclude maintenance states use values from ResourceState as source of truth
1473+
List<ResourceState> statesToExclude = excludeHostsInMaintenance ? ResourceState.s_maintenanceStates : List.of();
1474+
List<HostVO> hosts = _hostDao.listHostsByMsDcResourceState(msId, dcId, statesToExclude);
14741475
for (HostVO host : hosts) {
14751476
AgentAttache agent = findAttache(host.getId());
14761477
if (agent instanceof DirectAgentAttache) {
@@ -1506,6 +1507,10 @@ public void onManagementServerPreparingForMaintenance() {
15061507
public void onManagementServerCancelPreparingForMaintenance() {
15071508
logger.debug("Management server cancel preparing for maintenance");
15081509
super.onManagementServerPreparingForMaintenance();
1510+
1511+
// needed for the case when Management Server in Preparing For Maintenance but didn't go to Maintenance state
1512+
// (where this variable will be reset)
1513+
_agentLbHappened = false;
15091514
}
15101515

15111516
@Override

‎engine/schema/src/main/java/com/cloud/host/dao/HostDao.java‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,24 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
177177

178178
List<HostVO> listHostsByMsAndDc(long msId, long dcId);
179179

180+
List<HostVO> listHostsByMsDcResourceState(long msId, long dcId, List<ResourceState> excludedResourceStates);
181+
180182
List<HostVO> listHostsByMs(long msId);
181183

184+
List<HostVO> listHostsByMsResourceState(long msId, List<ResourceState> excludedResourceStates);
185+
182186
/**
183-
* Retrieves the number of hosts/agents this {@see ManagementServer} has responsibility over.
184-
* @param msId the id of the {@see ManagementServer}
185-
* @return the number of hosts/agents this {@see ManagementServer} has responsibility over
187+
* Count Hosts by given Management Server, Host and Hypervisor Types,
188+
* and exclude Hosts with given Resource States.
189+
*
190+
* @param msId Management Server Id
191+
* @param excludedResourceStates Resource States to be excluded
192+
* @param hostTypes Host Types
193+
* @param hypervisorTypes Hypervisor Types
194+
* @return Hosts count
186195
*/
187-
int countByMs(long msId);
196+
int countHostsByMsResourceStateTypeAndHypervisorType(long msId, List<ResourceState> excludedResourceStates,
197+
List<Type> hostTypes, List<HypervisorType> hypervisorTypes);
188198

189199
/**
190200
* Retrieves the host ids/agents this {@see ManagementServer} has responsibility over.

‎engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java‎

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import com.cloud.utils.db.GenericSearchBuilder;
7373
import com.cloud.utils.db.JoinBuilder;
7474
import com.cloud.utils.db.JoinBuilder.JoinType;
75+
import com.cloud.utils.db.QueryBuilder;
7576
import com.cloud.utils.db.SearchBuilder;
7677
import com.cloud.utils.db.SearchCriteria;
7778
import com.cloud.utils.db.SearchCriteria.Func;
@@ -1600,6 +1601,17 @@ public List<HostVO> listHostsByMsAndDc(long msId, long dcId) {
16001601
return listBy(sc);
16011602
}
16021603

1604+
@Override
1605+
public List<HostVO> listHostsByMsDcResourceState(long msId, long dcId, List<ResourceState> excludedResourceStates) {
1606+
QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
1607+
sc.and(sc.entity().getManagementServerId(), Op.EQ, msId);
1608+
sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
1609+
if (CollectionUtils.isNotEmpty(excludedResourceStates)) {
1610+
sc.and(sc.entity().getResourceState(), Op.NIN, excludedResourceStates.toArray());
1611+
}
1612+
return listBy(sc.create());
1613+
}
1614+
16031615
@Override
16041616
public List<HostVO> listHostsByMs(long msId) {
16051617
SearchCriteria<HostVO> sc = ResponsibleMsSearch.create();
@@ -1608,10 +1620,32 @@ public List<HostVO> listHostsByMs(long msId) {
16081620
}
16091621

16101622
@Override
1611-
public int countByMs(long msId) {
1612-
SearchCriteria<HostVO> sc = ResponsibleMsSearch.create();
1613-
sc.setParameters("managementServerId", msId);
1614-
return getCount(sc);
1623+
public List<HostVO> listHostsByMsResourceState(long msId, List<ResourceState> excludedResourceStates) {
1624+
QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
1625+
sc.and(sc.entity().getManagementServerId(), Op.EQ, msId);
1626+
if (CollectionUtils.isNotEmpty(excludedResourceStates)) {
1627+
sc.and(sc.entity().getResourceState(), Op.NIN, excludedResourceStates.toArray());
1628+
}
1629+
return listBy(sc.create());
1630+
}
1631+
1632+
@Override
1633+
public int countHostsByMsResourceStateTypeAndHypervisorType(long msId,
1634+
List<ResourceState> excludedResourceStates,
1635+
List<Type> hostTypes,
1636+
List<HypervisorType> hypervisorTypes) {
1637+
QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
1638+
sc.and(sc.entity().getManagementServerId(), Op.EQ, msId);
1639+
if (CollectionUtils.isNotEmpty(excludedResourceStates)) {
1640+
sc.and(sc.entity().getResourceState(), Op.NIN, excludedResourceStates.toArray());
1641+
}
1642+
if (CollectionUtils.isNotEmpty(hostTypes)) {
1643+
sc.and(sc.entity().getType(), Op.IN, hostTypes.toArray());
1644+
}
1645+
if (CollectionUtils.isNotEmpty(hypervisorTypes)) {
1646+
sc.and(sc.entity().getHypervisorType(), Op.IN, hypervisorTypes.toArray());
1647+
}
1648+
return getCount(sc.create());
16151649
}
16161650

16171651
@Override

‎framework/agent-lb/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLB.java‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ public interface IndirectAgentLB {
7070
*/
7171
Long getLBPreferredHostCheckInterval(Long clusterId);
7272

73-
void propagateMSListToAgents();
73+
void propagateMSListToAgents(boolean triggerHostLB);
7474

75-
boolean haveAgentBasedHosts(long msId);
75+
void propagateMSListToAgentsInCluster(Long clusterId);
7676

77-
boolean migrateAgents(String fromMsUuid, long fromMsId, String lbAlgorithm, long timeoutDurationInMs);
77+
boolean haveAgentBasedHosts(long msId, boolean excludeHostsInMaintenance);
78+
79+
boolean migrateAgents(String fromMsUuid, long fromMsId, String lbAlgorithm, long timeoutDurationInMs, boolean excludeHostsInMaintenance);
7880
}

‎plugins/maintenance/src/main/java/org/apache/cloudstack/api/command/CancelMaintenanceCmd.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
package org.apache.cloudstack.api.command;
1919

2020
import org.apache.cloudstack.api.APICommand;
21+
import org.apache.cloudstack.api.ApiConstants;
2122
import org.apache.cloudstack.api.BaseCmd;
2223

2324
import com.cloud.user.Account;
2425

26+
import org.apache.cloudstack.api.Parameter;
2527
import org.apache.cloudstack.api.response.ManagementServerMaintenanceResponse;
2628
import org.apache.cloudstack.acl.RoleType;
29+
import org.apache.commons.lang3.BooleanUtils;
2730

2831
@APICommand(name = CancelMaintenanceCmd.APINAME,
2932
description = "Cancels maintenance of the management server",
@@ -36,6 +39,13 @@ public class CancelMaintenanceCmd extends BaseMSMaintenanceActionCmd {
3639

3740
public static final String APINAME = "cancelMaintenance";
3841

42+
@Parameter(name = ApiConstants.REBALANCE, type = CommandType.BOOLEAN, description = "Rebalance agents (applicable for indirect agents) after cancelling maintenance, default is true")
43+
private Boolean rebalance;
44+
45+
public boolean getRebalance() {
46+
return BooleanUtils.toBooleanDefaultIfNull(rebalance, true);
47+
}
48+
3949
@Override
4050
public String getCommandName() {
4151
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;

‎plugins/maintenance/src/main/java/org/apache/cloudstack/api/command/PrepareForMaintenanceCmd.java‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import org.apache.cloudstack.api.response.ManagementServerMaintenanceResponse;
2828
import org.apache.cloudstack.acl.RoleType;
29+
import org.apache.commons.lang3.BooleanUtils;
2930

3031
@APICommand(name = PrepareForMaintenanceCmd.APINAME,
3132
description = "Prepares management server for maintenance by preventing new jobs from being accepted after completion of active jobs and migrating the agents",
@@ -40,6 +41,9 @@ public class PrepareForMaintenanceCmd extends BaseMSMaintenanceActionCmd {
4041
" when this is not set, already configured algorithm from setting 'indirect.agent.lb.algorithm' is considered")
4142
private String algorithm;
4243

44+
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, description = "Force management server to maintenance after the maintenance window timeout, default is false")
45+
private Boolean forced;
46+
4347
public String getAlgorithm() {
4448
return algorithm;
4549
}
@@ -48,6 +52,10 @@ public void setAlgorithm(String algorithm) {
4852
this.algorithm = algorithm;
4953
}
5054

55+
public boolean isForced() {
56+
return BooleanUtils.toBooleanDefaultIfNull(forced, false);
57+
}
58+
5159
@Override
5260
public String getCommandName() {
5361
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;

‎plugins/maintenance/src/main/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManager.java‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ public interface ManagementServerMaintenanceManager {
4040
ConfigKey.Scope.Global,
4141
null);
4242

43+
ConfigKey<Boolean> ManagementServerMaintenanceIgnoreMaintenanceHosts = new ConfigKey<>(Boolean.class,
44+
"management.server.maintenance.ignore.maintenance.hosts",
45+
"Advanced",
46+
String.valueOf(Boolean.FALSE),
47+
"Host in Maintenance state can sometimes block Management Server to go to Maintenance; this setting skips Host(s) in Maintenance state during Management Server Maintenance, default: false.",
48+
true,
49+
ConfigKey.Scope.Global,
50+
null);
51+
4352
void registerListener(ManagementServerMaintenanceListener listener);
4453

4554
void unregisterListener(ManagementServerMaintenanceListener listener);
@@ -83,7 +92,7 @@ public interface ManagementServerMaintenanceManager {
8392
String getLbAlgorithm();
8493

8594
// Prepares the current management server for maintenance by migrating the agents and not accepting any more async jobs
86-
void prepareForMaintenance(String lbAlorithm);
95+
void prepareForMaintenance(String lbAlorithm, boolean forced);
8796

8897
// Cancels maintenance of the current management server
8998
void cancelMaintenance();

‎plugins/maintenance/src/main/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImpl.java‎

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626

2727
import javax.inject.Inject;
2828

29+
import com.cloud.resource.ResourceState;
2930
import org.apache.cloudstack.agent.lb.IndirectAgentLB;
31+
import org.apache.cloudstack.agent.lb.IndirectAgentLBServiceImpl;
3032
import org.apache.cloudstack.api.command.CancelMaintenanceCmd;
3133
import org.apache.cloudstack.api.command.CancelShutdownCmd;
3234
import org.apache.cloudstack.api.command.PrepareForMaintenanceCmd;
@@ -251,7 +253,7 @@ private void prepareForShutdown(boolean postTrigger) {
251253

252254
this.preparingForShutdown = true;
253255
jobManager.disableAsyncJobs();
254-
waitForPendingJobs();
256+
waitForPendingJobs(false);
255257
}
256258

257259
@Override
@@ -273,7 +275,7 @@ public void cancelShutdown() {
273275
}
274276

275277
@Override
276-
public void prepareForMaintenance(String lbAlorithm) {
278+
public void prepareForMaintenance(String lbAlorithm, boolean forced) {
277279
if (this.preparingForShutdown) {
278280
throw new CloudRuntimeException("Shutdown has already been triggered, cancel shutdown and try again");
279281
}
@@ -286,7 +288,7 @@ public void prepareForMaintenance(String lbAlorithm) {
286288
this.lbAlgorithm = lbAlorithm;
287289
jobManager.disableAsyncJobs();
288290
onPreparingForMaintenance();
289-
waitForPendingJobs();
291+
waitForPendingJobs(forced);
290292
}
291293

292294
@Override
@@ -310,12 +312,13 @@ public void cancelMaintenance() {
310312
}
311313
}
312314

313-
private void waitForPendingJobs() {
315+
private void waitForPendingJobs(boolean forceMaintenance) {
314316
cancelWaitForPendingJobs();
315317
pendingJobsCheckTask = Executors.newScheduledThreadPool(1, new NamedThreadFactory("PendingJobsCheck"));
316318
long pendingJobsCheckDelayInSecs = 1L; // 1 sec
317319
long pendingJobsCheckPeriodInSecs = 3L; // every 3 secs, check more frequently for pending jobs
318-
pendingJobsCheckTask.scheduleAtFixedRate(new CheckPendingJobsTask(this), pendingJobsCheckDelayInSecs, pendingJobsCheckPeriodInSecs, TimeUnit.SECONDS);
320+
boolean ignoreMaintenanceHosts = ManagementServerMaintenanceIgnoreMaintenanceHosts.value();
321+
pendingJobsCheckTask.scheduleAtFixedRate(new CheckPendingJobsTask(this, ignoreMaintenanceHosts, forceMaintenance), pendingJobsCheckDelayInSecs, pendingJobsCheckPeriodInSecs, TimeUnit.SECONDS);
319322
}
320323

321324
@Override
@@ -426,7 +429,8 @@ public ManagementServerMaintenanceResponse prepareForMaintenance(PrepareForMaint
426429

427430
checkAnyMsInPreparingStates("prepare for maintenance");
428431

429-
if (indirectAgentLB.haveAgentBasedHosts(msHost.getMsid())) {
432+
boolean ignoreMaintenanceHosts = ManagementServerMaintenanceIgnoreMaintenanceHosts.value();
433+
if (indirectAgentLB.haveAgentBasedHosts(msHost.getMsid(), ignoreMaintenanceHosts)) {
430434
List<String> indirectAgentMsList = indirectAgentLB.getManagementServerList();
431435
indirectAgentMsList.remove(msHost.getServiceIP());
432436
List<String> nonUpMsList = msHostDao.listNonUpStateMsIPs();
@@ -437,7 +441,7 @@ public ManagementServerMaintenanceResponse prepareForMaintenance(PrepareForMaint
437441
}
438442

439443
final Command[] cmds = new Command[1];
440-
cmds[0] = new PrepareForMaintenanceManagementServerHostCommand(msHost.getMsid(), cmd.getAlgorithm());
444+
cmds[0] = new PrepareForMaintenanceManagementServerHostCommand(msHost.getMsid(), cmd.getAlgorithm(), cmd.isForced());
441445
executeCmd(msHost, cmds);
442446

443447
msHostDao.updateState(msHost.getId(), State.PreparingForMaintenance);
@@ -457,10 +461,15 @@ public ManagementServerMaintenanceResponse cancelMaintenance(CancelMaintenanceCm
457461
}
458462

459463
final Command[] cmds = new Command[1];
460-
cmds[0] = new CancelMaintenanceManagementServerHostCommand(msHost.getMsid());
464+
cmds[0] = new CancelMaintenanceManagementServerHostCommand(msHost.getMsid(), cmd.getRebalance());
461465
executeCmd(msHost, cmds);
462466

463467
msHostDao.updateState(msHost.getId(), State.Up);
468+
469+
if (cmd.getRebalance()) {
470+
logger.info("Propagate MS list and rebalance indirect agents");
471+
indirectAgentLB.propagateMSListToAgents(true);
472+
}
464473
return prepareMaintenanceResponse(cmd.getManagementServerId());
465474
}
466475

@@ -546,17 +555,21 @@ public String getConfigComponentName() {
546555
@Override
547556
public ConfigKey<?>[] getConfigKeys() {
548557
return new ConfigKey<?>[]{
549-
ManagementServerMaintenanceTimeoutInMins
558+
ManagementServerMaintenanceTimeoutInMins, ManagementServerMaintenanceIgnoreMaintenanceHosts
550559
};
551560
}
552561

553562
private final class CheckPendingJobsTask extends ManagedContextRunnable {
554563

555564
private ManagementServerMaintenanceManager managementServerMaintenanceManager;
565+
private boolean ignoreMaintenanceHosts = false;
556566
private boolean agentsTransferTriggered = false;
567+
private boolean forceMaintenance = false;
557568

558-
public CheckPendingJobsTask(ManagementServerMaintenanceManager managementServerMaintenanceManager) {
569+
public CheckPendingJobsTask(ManagementServerMaintenanceManager managementServerMaintenanceManager, boolean ignoreMaintenanceHosts, boolean forceMaintenance) {
559570
this.managementServerMaintenanceManager = managementServerMaintenanceManager;
571+
this.ignoreMaintenanceHosts = ignoreMaintenanceHosts;
572+
this.forceMaintenance = forceMaintenance;
560573
}
561574

562575
@Override
@@ -570,14 +583,25 @@ protected void runInContext() {
570583
}
571584

572585
if (managementServerMaintenanceManager.isPreparingForMaintenance() && isMaintenanceWindowExpired()) {
586+
if (forceMaintenance) {
587+
logger.debug("Maintenance window timeout, MS is forced to Maintenance Mode");
588+
ManagementServerHostVO msHost = msHostDao.findByMsid(ManagementServerNode.getManagementServerId());
589+
msHostDao.updateState(msHost.getId(), State.Maintenance);
590+
managementServerMaintenanceManager.onMaintenance();
591+
managementServerMaintenanceManager.cancelWaitForPendingJobs();
592+
return;
593+
}
594+
573595
logger.debug("Maintenance window timeout, terminating the pending jobs check timer task");
574596
managementServerMaintenanceManager.cancelPreparingForMaintenance(null);
575597
managementServerMaintenanceManager.cancelWaitForPendingJobs();
576598
return;
577599
}
578600

579601
long totalPendingJobs = managementServerMaintenanceManager.countPendingJobs(ManagementServerNode.getManagementServerId());
580-
int totalAgents = hostDao.countByMs(ManagementServerNode.getManagementServerId());
602+
603+
long totalAgents = totalAgentsInMs();
604+
581605
String msg = String.format("Checking for triggered maintenance or shutdown... shutdownTriggered [%b] AllowAsyncJobs [%b] PendingJobCount [%d] AgentsCount [%d]",
582606
managementServerMaintenanceManager.isShutdownTriggered(), managementServerMaintenanceManager.isAsyncJobsEnabled(), totalPendingJobs, totalAgents);
583607
logger.debug(msg);
@@ -609,15 +633,15 @@ protected void runInContext() {
609633

610634
agentsTransferTriggered = true;
611635
logger.info(String.format("Preparing for maintenance - migrating agents from management server node %d (id: %s)", ManagementServerNode.getManagementServerId(), msHost.getUuid()));
612-
boolean agentsMigrated = indirectAgentLB.migrateAgents(msHost.getUuid(), ManagementServerNode.getManagementServerId(), managementServerMaintenanceManager.getLbAlgorithm(), remainingMaintenanceWindowInMs());
636+
boolean agentsMigrated = indirectAgentLB.migrateAgents(msHost.getUuid(), ManagementServerNode.getManagementServerId(), managementServerMaintenanceManager.getLbAlgorithm(), remainingMaintenanceWindowInMs(), ignoreMaintenanceHosts);
613637
if (!agentsMigrated) {
614638
logger.warn(String.format("Unable to prepare for maintenance, cannot migrate indirect agents on this management server node %d (id: %s)", ManagementServerNode.getManagementServerId(), msHost.getUuid()));
615639
managementServerMaintenanceManager.cancelPreparingForMaintenance(msHost);
616640
managementServerMaintenanceManager.cancelWaitForPendingJobs();
617641
return;
618642
}
619643

620-
if(!agentMgr.transferDirectAgentsFromMS(msHost.getUuid(), ManagementServerNode.getManagementServerId(), remainingMaintenanceWindowInMs())) {
644+
if(!agentMgr.transferDirectAgentsFromMS(msHost.getUuid(), ManagementServerNode.getManagementServerId(), remainingMaintenanceWindowInMs(), ignoreMaintenanceHosts)) {
621645
logger.warn(String.format("Unable to prepare for maintenance, cannot transfer direct agents on this management server node %d (id: %s)", ManagementServerNode.getManagementServerId(), msHost.getUuid()));
622646
managementServerMaintenanceManager.cancelPreparingForMaintenance(msHost);
623647
managementServerMaintenanceManager.cancelWaitForPendingJobs();
@@ -648,5 +672,14 @@ private long remainingMaintenanceWindowInMs() {
648672
long remainingMaintenanceWindowTimeInMs = (ManagementServerMaintenanceTimeoutInMins.value().longValue() * 60 * 1000) - maintenanceElapsedTimeInMs;
649673
return (remainingMaintenanceWindowTimeInMs > 0) ? remainingMaintenanceWindowTimeInMs : 0;
650674
}
675+
676+
private long totalAgentsInMs() {
677+
/* Any Host in Maintenance state could block moving Management Server to Maintenance state, exclude those Hosts from total agents count
678+
* To exclude maintenance states use values from ResourceState as source of truth
679+
*/
680+
List<ResourceState> statesToExclude = ignoreMaintenanceHosts ? ResourceState.s_maintenanceStates : List.of();
681+
return hostDao.countHostsByMsResourceStateTypeAndHypervisorType(ManagementServerNode.getManagementServerId(), statesToExclude,
682+
IndirectAgentLBServiceImpl.agentValidHostTypes, null);
683+
}
651684
}
652685
}

‎plugins/maintenance/src/main/java/org/apache/cloudstack/maintenance/command/CancelMaintenanceManagementServerHostCommand.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,18 @@
1919
package org.apache.cloudstack.maintenance.command;
2020

2121
public class CancelMaintenanceManagementServerHostCommand extends BaseShutdownManagementServerHostCommand {
22+
boolean rebalance;
2223

2324
public CancelMaintenanceManagementServerHostCommand(long msId) {
2425
super(msId);
2526
}
27+
28+
public CancelMaintenanceManagementServerHostCommand(long msId, boolean rebalance) {
29+
super(msId);
30+
this.rebalance = rebalance;
31+
}
32+
33+
public boolean getRebalance() {
34+
return rebalance;
35+
}
2636
}

‎plugins/maintenance/src/main/java/org/apache/cloudstack/maintenance/command/PrepareForMaintenanceManagementServerHostCommand.java‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,23 @@
2020

2121
public class PrepareForMaintenanceManagementServerHostCommand extends BaseShutdownManagementServerHostCommand {
2222
String lbAlgorithm;
23+
boolean forced;
2324

2425
public PrepareForMaintenanceManagementServerHostCommand(long msId) {
2526
super(msId);
2627
}
2728

28-
public PrepareForMaintenanceManagementServerHostCommand(long msId, String lbAlgorithm) {
29+
public PrepareForMaintenanceManagementServerHostCommand(long msId, String lbAlgorithm, boolean forced) {
2930
super(msId);
3031
this.lbAlgorithm = lbAlgorithm;
32+
this.forced = forced;
3133
}
3234

3335
public String getLbAlgorithm() {
3436
return lbAlgorithm;
3537
}
38+
39+
public boolean isForced() {
40+
return forced;
41+
}
3642
}

‎plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,11 @@ public void triggerShutdownCmd() {
305305
@Test
306306
public void prepareForMaintenanceAndCancelFromMaintenanceState() {
307307
Mockito.doNothing().when(jobManagerMock).disableAsyncJobs();
308-
spy.prepareForMaintenance("static");
308+
spy.prepareForMaintenance("static", false);
309309
Mockito.verify(jobManagerMock).disableAsyncJobs();
310310

311311
Assert.assertThrows(CloudRuntimeException.class, () -> {
312-
spy.prepareForMaintenance("static");
312+
spy.prepareForMaintenance("static", false);
313313
});
314314

315315
ManagementServerHostVO msHost = mock(ManagementServerHostVO.class);
@@ -324,11 +324,11 @@ public void prepareForMaintenanceAndCancelFromMaintenanceState() {
324324
@Test
325325
public void prepareForMaintenanceAndCancelFromPreparingForMaintenanceState() {
326326
Mockito.doNothing().when(jobManagerMock).disableAsyncJobs();
327-
spy.prepareForMaintenance("static");
327+
spy.prepareForMaintenance("static", false);
328328
Mockito.verify(jobManagerMock).disableAsyncJobs();
329329

330330
Assert.assertThrows(CloudRuntimeException.class, () -> {
331-
spy.prepareForMaintenance("static");
331+
spy.prepareForMaintenance("static", false);
332332
});
333333

334334
ManagementServerHostVO msHost = mock(ManagementServerHostVO.class);
@@ -455,7 +455,7 @@ public void prepareForMaintenanceCmdNoIndirectMsHosts() {
455455
Mockito.when(msHostDao.listNonUpStateMsIPs()).thenReturn(new ArrayList<>());
456456
PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class);
457457
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
458-
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(true);
458+
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong(), anyBoolean())).thenReturn(true);
459459
Mockito.when(indirectAgentLBMock.getManagementServerList()).thenReturn(new ArrayList<>());
460460

461461
Assert.assertThrows(CloudRuntimeException.class, () -> {
@@ -476,7 +476,7 @@ public void prepareForMaintenanceCmdNullResponseFromClusterManager() {
476476
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1);
477477
PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class);
478478
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
479-
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(false);
479+
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong(), anyBoolean())).thenReturn(false);
480480
Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn(null);
481481

482482
Assert.assertThrows(CloudRuntimeException.class, () -> {
@@ -497,7 +497,7 @@ public void prepareForMaintenanceCmdFailedResponseFromClusterManager() {
497497
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1);
498498
PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class);
499499
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
500-
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(false);
500+
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong(), anyBoolean())).thenReturn(false);
501501
Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Failed");
502502

503503
Assert.assertThrows(CloudRuntimeException.class, () -> {
@@ -518,7 +518,7 @@ public void prepareForMaintenanceCmdSuccessResponseFromClusterManager() {
518518
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1);
519519
PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class);
520520
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
521-
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(false);
521+
Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong(), anyBoolean())).thenReturn(false);
522522
Mockito.when(hostDao.listByMs(anyLong())).thenReturn(new ArrayList<>());
523523
Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Success");
524524

‎server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import javax.naming.ConfigurationException;
5252

5353
import com.cloud.resource.ResourceManager;
54+
import com.cloud.utils.Ternary;
5455
import org.apache.cloudstack.acl.SecurityChecker;
5556
import org.apache.cloudstack.affinity.AffinityGroup;
5657
import org.apache.cloudstack.affinity.AffinityGroupService;
@@ -616,19 +617,28 @@ private void initMessageBusListener() {
616617
messageBus.subscribe(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, new MessageSubscriber() {
617618
@Override
618619
public void onPublishMessage(String serderAddress, String subject, Object args) {
619-
String globalSettingUpdated = (String) args;
620-
if (StringUtils.isEmpty(globalSettingUpdated)) {
620+
Ternary<String, ConfigKey.Scope, Long> settingUpdated = (Ternary<String, ConfigKey.Scope, Long>) args;
621+
String settingNameUpdated = settingUpdated.first();
622+
if (StringUtils.isEmpty(settingNameUpdated)) {
621623
return;
622624
}
623-
if (globalSettingUpdated.equals(ApiServiceConfiguration.ManagementServerAddresses.key()) ||
624-
globalSettingUpdated.equals(IndirectAgentLBServiceImpl.IndirectAgentLBAlgorithm.key())) {
625-
_indirectAgentLB.propagateMSListToAgents();
626-
} else if (globalSettingUpdated.equals(Config.RouterAggregationCommandEachTimeout.toString())
627-
|| globalSettingUpdated.equals(Config.MigrateWait.toString())) {
625+
if (settingNameUpdated.equals(ApiServiceConfiguration.ManagementServerAddresses.key()) ||
626+
settingNameUpdated.equals(IndirectAgentLBServiceImpl.IndirectAgentLBAlgorithm.key())) {
627+
_indirectAgentLB.propagateMSListToAgents(false);
628+
} else if (settingNameUpdated.equals(Config.RouterAggregationCommandEachTimeout.toString())
629+
|| settingNameUpdated.equals(Config.MigrateWait.toString())) {
628630
Map<String, String> params = new HashMap<String, String>();
629631
params.put(Config.RouterAggregationCommandEachTimeout.toString(), _configDao.getValue(Config.RouterAggregationCommandEachTimeout.toString()));
630632
params.put(Config.MigrateWait.toString(), _configDao.getValue(Config.MigrateWait.toString()));
631633
_agentManager.propagateChangeToAgents(params);
634+
} else if (settingNameUpdated.equals(IndirectAgentLBServiceImpl.IndirectAgentLBCheckInterval.key())) {
635+
ConfigKey.Scope scope = settingUpdated.second();
636+
if (scope == ConfigKey.Scope.Global) {
637+
_indirectAgentLB.propagateMSListToAgents(false);
638+
} else if (scope == ConfigKey.Scope.Cluster) {
639+
Long clusterId = settingUpdated.third();
640+
_indirectAgentLB.propagateMSListToAgentsInCluster(clusterId);
641+
}
632642
}
633643
}
634644
});
@@ -817,6 +827,7 @@ public String updateConfiguration(final long userId, final String name, final St
817827
CallContext.current().setEventDetails(String.format(" Name: %s, New Value: %s, Scope: %s", name, value, scope));
818828

819829
_configDepot.invalidateConfigCache(name, scopeVal, resourceId);
830+
messageBus.publish(_name, EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, PublishScope.GLOBAL, new Ternary<>(name, scopeVal, resourceId));
820831
return valueEncrypted ? DBEncryptionUtil.decrypt(value) : value;
821832
}
822833

@@ -911,7 +922,7 @@ public String updateConfiguration(final long userId, final String name, final St
911922
}
912923

913924
txn.commit();
914-
messageBus.publish(_name, EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, PublishScope.GLOBAL, name);
925+
messageBus.publish(_name, EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, PublishScope.GLOBAL, new Ternary<>(name, ConfigKey.Scope.Global, resourceId));
915926
return _configDao.getValue(name);
916927
}
917928

‎server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java‎

Lines changed: 78 additions & 26 deletions
Large diffs are not rendered by default.

‎server/src/test/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImplTest.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public void testExceptionOnEmptyHostSetting() throws NoSuchFieldException, Illeg
204204
public void testGetOrderedRunningHostIdsEmptyList() {
205205
doReturn(Collections.emptyList()).when(hostDao).findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(
206206
Mockito.eq(DC_1_ID), Mockito.eq(null), Mockito.eq(null), Mockito.anyList(), Mockito.anyList(), Mockito.anyList());
207-
Assert.assertTrue(agentMSLB.getOrderedHostIdList(DC_1_ID).isEmpty());
207+
Assert.assertTrue(agentMSLB.getOrderedHostIdList(DC_1_ID, false).isEmpty());
208208
}
209209

210210
@Test
@@ -213,6 +213,6 @@ public void testGetOrderedRunningHostIdsOrderList() {
213213
.findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(Mockito.eq(DC_1_ID), Mockito.eq(null), Mockito.eq(null),
214214
Mockito.anyList(), Mockito.anyList(), Mockito.anyList());
215215
Assert.assertEquals(Arrays.asList(host1.getId(), host2.getId(), host3.getId(), host4.getId()),
216-
agentMSLB.getOrderedHostIdList(DC_1_ID));
216+
agentMSLB.getOrderedHostIdList(DC_1_ID, false));
217217
}
218218
}

‎ui/public/locales/en.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,7 @@
18751875
"label.read.io": "Read (IO)",
18761876
"label.readonly": "Read-Only",
18771877
"label.reason": "Reason",
1878+
"label.rebalance": "Rebalance",
18781879
"label.reboot": "Reboot",
18791880
"label.recent.deliveries": "Recent deliveries",
18801881
"label.receivedbytes": "Bytes received",

‎ui/src/config/section/infra/managementServers.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export default {
7575
message: 'message.cancel.maintenance',
7676
dataView: true,
7777
popup: true,
78+
args: ['rebalance'],
7879
show: (record, store) => { return ['PreparingForMaintenance', 'Maintenance'].includes(record.state) },
7980
mapping: {
8081
managementserverid: {

‎ui/src/views/infra/Confirmation.vue‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545
</a-select-option>
4646
</a-select>
4747
</a-form-item>
48+
<a-form-item name="forced" ref="forced">
49+
<template #label>
50+
<tooltip-label :title="$t('label.forced')" :tooltip="prepareForMaintenanceApiParams.forced.description"/>
51+
</template>
52+
<a-switch v-model:checked="form.forced" />
53+
</a-form-item>
4854
<a-divider/>
4955
<a-alert type="error">
5056
<template #message>
@@ -135,6 +141,7 @@ export default {
135141
if (this.isPrepareForMaintenance && this.form.algorithm !== '') {
136142
params.algorithm = this.form.algorithm
137143
}
144+
params.forced = this.form.forced
138145
api(this.action.currentAction.api, params).then(() => {
139146
this.$message.success(this.$t(this.action.currentAction.label) + ' : ' + this.resource.name)
140147
this.closeAction()

‎utils/src/main/java/com/cloud/utils/nio/NioConnection.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ protected void read(final SelectionKey key) throws IOException {
323323
logger.trace("Reading from: {}", socketChannel.socket().toString());
324324
final byte[] data = link.read(socketChannel);
325325
if (data == null) {
326-
logger.trace("Packet is incomplete. Waiting for more.");
326+
logger.trace("Packet is incomplete. Waiting for more.");
327327
return;
328328
}
329329
final Task task = _factory.create(Task.Type.DATA, link, data);

0 commit comments

Comments
 (0)
Please sign in to comment.