Skip to content

Commit 1b43424

Browse files
committed
Merge branch '4.20' into fix-arm-watchdog
2 parents 7b7c37f + 96b757c commit 1b43424

File tree

15 files changed

+212
-27
lines changed

15 files changed

+212
-27
lines changed

client/conf/server.properties.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ session.timeout=30
3232
# Max allowed API request payload/content size in bytes
3333
request.content.size=1048576
3434

35+
# Max allowed API request form keys
36+
request.max.form.keys=5000
37+
3538
# Options to configure and enable HTTPS on the management server
3639
#
3740
# For the management server to pick up these configuration settings, the configured

client/src/main/java/org/apache/cloudstack/ServerDaemon.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ public class ServerDaemon implements Daemon {
8282
private static final String ACCESS_LOG = "access.log";
8383
private static final String REQUEST_CONTENT_SIZE_KEY = "request.content.size";
8484
private static final int DEFAULT_REQUEST_CONTENT_SIZE = 1048576;
85+
private static final String REQUEST_MAX_FORM_KEYS_KEY = "request.max.form.keys";
86+
private static final int DEFAULT_REQUEST_MAX_FORM_KEYS = 5000;
8587

8688
////////////////////////////////////////////////////////
8789
/////////////// Server Configuration ///////////////////
@@ -94,6 +96,7 @@ public class ServerDaemon implements Daemon {
9496
private int httpsPort = 8443;
9597
private int sessionTimeout = 30;
9698
private int maxFormContentSize = DEFAULT_REQUEST_CONTENT_SIZE;
99+
private int maxFormKeys = DEFAULT_REQUEST_MAX_FORM_KEYS;
97100
private boolean httpsEnable = false;
98101
private String accessLogFile = "access.log";
99102
private String bindInterface = null;
@@ -141,6 +144,7 @@ public void init(final DaemonContext context) {
141144
setAccessLogFile(properties.getProperty(ACCESS_LOG, "access.log"));
142145
setSessionTimeout(Integer.valueOf(properties.getProperty(SESSION_TIMEOUT, "30")));
143146
setMaxFormContentSize(Integer.valueOf(properties.getProperty(REQUEST_CONTENT_SIZE_KEY, String.valueOf(DEFAULT_REQUEST_CONTENT_SIZE))));
147+
setMaxFormKeys(Integer.valueOf(properties.getProperty(REQUEST_MAX_FORM_KEYS_KEY, String.valueOf(DEFAULT_REQUEST_MAX_FORM_KEYS))));
144148
} catch (final IOException e) {
145149
logger.warn("Failed to read configuration from server.properties file", e);
146150
} finally {
@@ -192,6 +196,7 @@ public void start() throws Exception {
192196
// Extra config options
193197
server.setStopAtShutdown(true);
194198
server.setAttribute(ContextHandler.MAX_FORM_CONTENT_SIZE_KEY, maxFormContentSize);
199+
server.setAttribute(ContextHandler.MAX_FORM_KEYS_KEY, maxFormKeys);
195200

196201
// HTTPS Connector
197202
createHttpsConnector(httpConfig);
@@ -264,6 +269,7 @@ private Pair<SessionHandler,HandlerCollection> createHandlers() {
264269
webApp.setContextPath(contextPath);
265270
webApp.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
266271
webApp.setMaxFormContentSize(maxFormContentSize);
272+
webApp.setMaxFormKeys(maxFormKeys);
267273

268274
// GZIP handler
269275
final GzipHandler gzipHandler = new GzipHandler();
@@ -366,4 +372,8 @@ public void setSessionTimeout(int sessionTimeout) {
366372
public void setMaxFormContentSize(int maxFormContentSize) {
367373
this.maxFormContentSize = maxFormContentSize;
368374
}
375+
376+
public void setMaxFormKeys(int maxFormKeys) {
377+
this.maxFormKeys = maxFormKeys;
378+
}
369379
}

engine/schema/src/main/java/org/apache/cloudstack/network/dao/NetworkPermissionDao.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public interface NetworkPermissionDao extends GenericDao<NetworkPermissionVO, Lo
4040
*/
4141
void removeAllPermissions(long networkId);
4242

43+
/**
44+
* Removes all network permissions associated with a given account.
45+
*
46+
* @param accountId The ID of the account from which all network permissions will be removed.
47+
*/
48+
void removeAccountPermissions(long accountId);
49+
4350
/**
4451
* Find a Network permission by networkId, accountName, and domainId
4552
*

engine/schema/src/main/java/org/apache/cloudstack/network/dao/NetworkPermissionDaoImpl.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class NetworkPermissionDaoImpl extends GenericDaoBase<NetworkPermissionVO
3333

3434
private SearchBuilder<NetworkPermissionVO> NetworkAndAccountSearch;
3535
private SearchBuilder<NetworkPermissionVO> NetworkIdSearch;
36+
private SearchBuilder<NetworkPermissionVO> accountSearch;
3637
private GenericSearchBuilder<NetworkPermissionVO, Long> FindNetworkIdsByAccount;
3738

3839
protected NetworkPermissionDaoImpl() {
@@ -45,6 +46,10 @@ protected NetworkPermissionDaoImpl() {
4546
NetworkIdSearch.and("networkId", NetworkIdSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
4647
NetworkIdSearch.done();
4748

49+
accountSearch = createSearchBuilder();
50+
accountSearch.and("accountId", accountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
51+
accountSearch.done();
52+
4853
FindNetworkIdsByAccount = createSearchBuilder(Long.class);
4954
FindNetworkIdsByAccount.select(null, SearchCriteria.Func.DISTINCT, FindNetworkIdsByAccount.entity().getNetworkId());
5055
FindNetworkIdsByAccount.and("account", FindNetworkIdsByAccount.entity().getAccountId(), SearchCriteria.Op.IN);
@@ -69,6 +74,16 @@ public void removeAllPermissions(long networkId) {
6974
expunge(sc);
7075
}
7176

77+
@Override
78+
public void removeAccountPermissions(long accountId) {
79+
SearchCriteria<NetworkPermissionVO> sc = accountSearch.create();
80+
sc.setParameters("accountId", accountId);
81+
int networkPermissionRemoved = expunge(sc);
82+
if (networkPermissionRemoved > 0) {
83+
logger.debug(String.format("Removed [%s] network permission(s) for the account with Id [%s]", networkPermissionRemoved, accountId));
84+
}
85+
}
86+
7287
@Override
7388
public NetworkPermissionVO findByNetworkAndAccount(long networkId, long accountId) {
7489
SearchCriteria<NetworkPermissionVO> sc = NetworkAndAccountSearch.create();

plugins/metrics/src/main/java/org/apache/cloudstack/api/ListSystemVMsUsageHistoryCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
@APICommand(name = "listSystemVmsUsageHistory", description = "Lists System VM stats", responseObject = VmMetricsStatsResponse.class,
2828
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.18.0",
29-
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin})
29+
authorized = {RoleType.Admin})
3030
public class ListSystemVMsUsageHistoryCmd extends BaseResourceUsageHistoryCmd {
3131

3232
/////////////////////////////////////////////////////

plugins/storage/volume/linstor/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2025-01-20]
9+
10+
### Fixed
11+
12+
- Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev
13+
814
## [2024-12-13]
915

1016
### Fixed

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LinstorBackupSnapshotCommandWrapper.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,17 @@ public final class LinstorBackupSnapshotCommandWrapper
4646
{
4747
protected static Logger LOGGER = LogManager.getLogger(LinstorBackupSnapshotCommandWrapper.class);
4848

49+
private static String zfsDatasetName(String zfsFullSnapshotUrl) {
50+
String zfsFullPath = zfsFullSnapshotUrl.substring(6);
51+
int atPos = zfsFullPath.indexOf('@');
52+
return atPos >= 0 ? zfsFullPath.substring(0, atPos) : zfsFullPath;
53+
}
54+
4955
private String zfsSnapdev(boolean hide, String zfsUrl) {
50-
Script script = new Script("/usr/bin/zfs", Duration.millis(5000));
56+
Script script = new Script("zfs", Duration.millis(5000));
5157
script.add("set");
5258
script.add("snapdev=" + (hide ? "hidden" : "visible"));
53-
script.add(zfsUrl.substring(6)); // cutting zfs://
59+
script.add(zfsDatasetName(zfsUrl)); // cutting zfs:// and @snapshotname
5460
return script.execute();
5561
}
5662

@@ -134,10 +140,10 @@ public CopyCmdAnswer execute(LinstorBackupSnapshotCommand cmd, LibvirtComputingR
134140
LOGGER.info("Src: " + srcPath + " | " + src.getName());
135141
if (srcPath.startsWith("zfs://")) {
136142
zfsHidden = true;
137-
if (zfsSnapdev(false, srcPath) != null) {
143+
if (zfsSnapdev(false, src.getPath()) != null) {
138144
return new CopyCmdAnswer("Unable to unhide zfs snapshot device.");
139145
}
140-
srcPath = "/dev/" + srcPath.substring(6);
146+
srcPath = "/dev/zvol/" + srcPath.substring(6);
141147
}
142148

143149
secondaryPool = storagePoolMgr.getStoragePoolByURI(dstDataStore.getUrl());

server/src/main/java/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,7 @@ private Pair<List<Long>, Integer> searchForUserVMIdsAndCount(ListVMsCmd cmd) {
14071407
if (networkId != null || vpcId != null) {
14081408
SearchBuilder<NicVO> nicSearch = nicDao.createSearchBuilder();
14091409
nicSearch.and("networkId", nicSearch.entity().getNetworkId(), Op.EQ);
1410+
nicSearch.and("removed", nicSearch.entity().getRemoved(), Op.NULL);
14101411
if (vpcId != null) {
14111412
SearchBuilder<NetworkVO> networkSearch = networkDao.createSearchBuilder();
14121413
networkSearch.and("vpcId", networkSearch.entity().getVpcId(), Op.EQ);

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1473,8 +1473,10 @@ private void migrateAwayVmWithVolumes(HostVO host, VMInstanceVO vm) {
14731473
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offeringVO, null, null);
14741474
plan.setMigrationPlan(true);
14751475
DeployDestination dest = null;
1476+
DeploymentPlanner.ExcludeList avoids = new DeploymentPlanner.ExcludeList();
1477+
avoids.addHost(host.getId());
14761478
try {
1477-
dest = deploymentManager.planDeployment(profile, plan, new DeploymentPlanner.ExcludeList(), null);
1479+
dest = deploymentManager.planDeployment(profile, plan, avoids, null);
14781480
} catch (InsufficientServerCapacityException e) {
14791481
throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM: %s.", vm), e);
14801482
}

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

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.apache.cloudstack.context.CallContext;
3838
import org.apache.cloudstack.framework.config.ConfigKey;
3939
import org.apache.commons.collections.CollectionUtils;
40+
import org.apache.commons.lang3.ObjectUtils;
4041

4142
import com.cloud.agent.AgentManager;
4243
import com.cloud.agent.api.Answer;
@@ -64,12 +65,16 @@
6465
import com.cloud.service.ServiceOfferingVO;
6566
import com.cloud.service.dao.ServiceOfferingDao;
6667
import com.cloud.utils.Pair;
68+
import com.cloud.utils.StringUtils;
6769
import com.cloud.utils.Ternary;
6870
import com.cloud.utils.component.ManagerBase;
6971
import com.cloud.utils.exception.CloudRuntimeException;
72+
import com.cloud.vm.UserVmDetailVO;
7073
import com.cloud.vm.VMInstanceVO;
7174
import com.cloud.vm.VirtualMachine.State;
7275
import com.cloud.vm.VirtualMachineProfileImpl;
76+
import com.cloud.vm.VmDetailConstants;
77+
import com.cloud.vm.dao.UserVmDetailsDao;
7378
import com.cloud.vm.dao.VMInstanceDao;
7479

7580
public class RollingMaintenanceManagerImpl extends ManagerBase implements RollingMaintenanceManager {
@@ -85,6 +90,8 @@ public class RollingMaintenanceManagerImpl extends ManagerBase implements Rollin
8590
@Inject
8691
private VMInstanceDao vmInstanceDao;
8792
@Inject
93+
protected UserVmDetailsDao userVmDetailsDao;
94+
@Inject
8895
private ServiceOfferingDao serviceOfferingDao;
8996
@Inject
9097
private ClusterDetailsDao clusterDetailsDao;
@@ -619,10 +626,19 @@ private Pair<Boolean, String> performCapacityChecksBeforeHostInMaintenance(Host
619626
int successfullyCheckedVmMigrations = 0;
620627
for (VMInstanceVO runningVM : vmsRunning) {
621628
boolean canMigrateVm = false;
629+
Ternary<Integer, Integer, Integer> cpuSpeedAndRamSize = getComputeResourcesCpuSpeedAndRamSize(runningVM);
630+
Integer cpu = cpuSpeedAndRamSize.first();
631+
Integer speed = cpuSpeedAndRamSize.second();
632+
Integer ramSize = cpuSpeedAndRamSize.third();
633+
if (ObjectUtils.anyNull(cpu, speed, ramSize)) {
634+
logger.warn("Cannot fetch compute resources for the VM {}, skipping it from the capacity check", runningVM);
635+
continue;
636+
}
637+
622638
ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(runningVM.getServiceOfferingId());
623639
for (Host hostInCluster : hostsInCluster) {
624640
if (!checkHostTags(hostTags, hostTagsDao.getHostTags(hostInCluster.getId()), serviceOffering.getHostTag())) {
625-
logger.debug(String.format("Host tags mismatch between %s and %s Skipping it from the capacity check", host, hostInCluster));
641+
logger.debug("Host tags mismatch between {} and {} Skipping it from the capacity check", host, hostInCluster);
626642
continue;
627643
}
628644
DeployDestination deployDestination = new DeployDestination(null, null, null, host);
@@ -632,13 +648,13 @@ private Pair<Boolean, String> performCapacityChecksBeforeHostInMaintenance(Host
632648
affinityChecks = affinityChecks && affinityProcessor.check(vmProfile, deployDestination);
633649
}
634650
if (!affinityChecks) {
635-
logger.debug(String.format("Affinity check failed between %s and %s Skipping it from the capacity check", host, hostInCluster));
651+
logger.debug("Affinity check failed between {} and {} Skipping it from the capacity check", host, hostInCluster);
636652
continue;
637653
}
638654
boolean maxGuestLimit = capacityManager.checkIfHostReachMaxGuestLimit(host);
639-
boolean hostHasCPUCapacity = capacityManager.checkIfHostHasCpuCapability(hostInCluster.getId(), serviceOffering.getCpu(), serviceOffering.getSpeed());
640-
int cpuRequested = serviceOffering.getCpu() * serviceOffering.getSpeed();
641-
long ramRequested = serviceOffering.getRamSize() * 1024L * 1024L;
655+
boolean hostHasCPUCapacity = capacityManager.checkIfHostHasCpuCapability(hostInCluster.getId(), cpu, speed);
656+
int cpuRequested = cpu * speed;
657+
long ramRequested = ramSize * 1024L * 1024L;
642658
ClusterDetailsVO clusterDetailsCpuOvercommit = clusterDetailsDao.findDetail(cluster.getId(), "cpuOvercommitRatio");
643659
ClusterDetailsVO clusterDetailsRamOvercommmt = clusterDetailsDao.findDetail(cluster.getId(), "memoryOvercommitRatio");
644660
Float cpuOvercommitRatio = Float.parseFloat(clusterDetailsCpuOvercommit.getValue());
@@ -664,11 +680,42 @@ private Pair<Boolean, String> performCapacityChecksBeforeHostInMaintenance(Host
664680
return new Pair<>(true, "OK");
665681
}
666682

683+
protected Ternary<Integer, Integer, Integer> getComputeResourcesCpuSpeedAndRamSize(VMInstanceVO runningVM) {
684+
ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(runningVM.getServiceOfferingId());
685+
Integer cpu = serviceOffering.getCpu();
686+
Integer speed = serviceOffering.getSpeed();
687+
Integer ramSize = serviceOffering.getRamSize();
688+
if (!serviceOffering.isDynamic()) {
689+
return new Ternary<>(cpu, speed, ramSize);
690+
}
691+
692+
List<UserVmDetailVO> vmDetails = userVmDetailsDao.listDetails(runningVM.getId());
693+
if (CollectionUtils.isEmpty(vmDetails)) {
694+
return new Ternary<>(cpu, speed, ramSize);
695+
}
696+
697+
for (UserVmDetailVO vmDetail : vmDetails) {
698+
if (StringUtils.isBlank(vmDetail.getName()) || StringUtils.isBlank(vmDetail.getValue())) {
699+
continue;
700+
}
701+
702+
if (cpu == null && VmDetailConstants.CPU_NUMBER.equals(vmDetail.getName())) {
703+
cpu = Integer.valueOf(vmDetail.getValue());
704+
} else if (speed == null && VmDetailConstants.CPU_SPEED.equals(vmDetail.getName())) {
705+
speed = Integer.valueOf(vmDetail.getValue());
706+
} else if (ramSize == null && VmDetailConstants.MEMORY.equals(vmDetail.getName())) {
707+
ramSize = Integer.valueOf(vmDetail.getValue());
708+
}
709+
}
710+
711+
return new Ternary<>(cpu, speed, ramSize);
712+
}
713+
667714
/**
668715
* Check hosts tags
669716
*/
670717
private boolean checkHostTags(List<HostTagVO> hostTags, List<HostTagVO> hostInClusterTags, String offeringTag) {
671-
if (CollectionUtils.isEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) {
718+
if ((CollectionUtils.isEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) || StringUtils.isBlank(offeringTag)) {
672719
return true;
673720
} else if ((CollectionUtils.isNotEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) ||
674721
(CollectionUtils.isEmpty(hostTags) && CollectionUtils.isNotEmpty(hostInClusterTags))) {

server/src/main/java/com/cloud/user/AccountManagerImpl.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import org.apache.cloudstack.framework.messagebus.PublishScope;
7777
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
7878
import org.apache.cloudstack.network.RoutedIpv4Manager;
79+
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
7980
import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
8081
import org.apache.cloudstack.resourcedetail.UserDetailVO;
8182
import org.apache.cloudstack.resourcedetail.dao.UserDetailsDao;
@@ -303,6 +304,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
303304
private SSHKeyPairDao _sshKeyPairDao;
304305
@Inject
305306
private UserDataDao userDataDao;
307+
@Inject
308+
private NetworkPermissionDao networkPermissionDao;
306309

307310
private List<QuerySelector> _querySelectors;
308311

@@ -898,6 +901,9 @@ protected boolean cleanupAccount(AccountVO account, long callerUserId, Account c
898901
// delete the account from project accounts
899902
_projectAccountDao.removeAccountFromProjects(accountId);
900903

904+
// Delete account's network permissions
905+
networkPermissionDao.removeAccountPermissions(accountId);
906+
901907
if (account.getType() != Account.Type.PROJECT) {
902908
// delete the account from group
903909
_messageBus.publish(_name, MESSAGE_REMOVE_ACCOUNT_EVENT, PublishScope.LOCAL, accountId);
@@ -1943,22 +1949,23 @@ public boolean deleteUserAccount(long accountId) {
19431949
return true;
19441950
}
19451951

1946-
// Account that manages project(s) can't be removed
1947-
List<Long> managedProjectIds = _projectAccountDao.listAdministratedProjectIds(accountId);
1948-
if (!managedProjectIds.isEmpty()) {
1949-
StringBuilder projectIds = new StringBuilder();
1950-
for (Long projectId : managedProjectIds) {
1951-
projectIds.append(projectId).append(", ");
1952-
}
1953-
1954-
throw new InvalidParameterValueException(String.format("The account %s with id %d manages project(s) with ids %s and can't be removed", account, accountId, projectIds));
1955-
}
1952+
checkIfAccountManagesProjects(accountId);
19561953

19571954
CallContext.current().putContextParameter(Account.class, account.getUuid());
19581955

19591956
return deleteAccount(account, callerUserId, caller);
19601957
}
19611958

1959+
protected void checkIfAccountManagesProjects(long accountId) {
1960+
List<Long> managedProjectIds = _projectAccountDao.listAdministratedProjectIds(accountId);
1961+
if (!CollectionUtils.isEmpty(managedProjectIds)) {
1962+
throw new InvalidParameterValueException(String.format(
1963+
"Unable to delete account [%s], because it manages the following project(s): %s. Please, remove the account from these projects or demote it to a regular project role first.",
1964+
accountId, managedProjectIds
1965+
));
1966+
}
1967+
}
1968+
19621969
protected boolean isDeleteNeeded(AccountVO account, long accountId, Account caller) {
19631970
if (account == null) {
19641971
logger.info(String.format("The account, identified by id %d, doesn't exist", accountId ));

0 commit comments

Comments
 (0)