Skip to content

Commit ecd60a4

Browse files
committed
Merge release branch 4.20 to main
* 4.20: Maintenance mode: Add host to deployment planner avoid list to fix local storage vm migration (#9892) Add project-user association normalization script to 4.20.1 upgrade (#10116) fix slider component for global settings of the range type (#10187) Clean up network permissions on account deletion (#10176)
2 parents 0ed6895 + a163831 commit ecd60a4

File tree

8 files changed

+71
-16
lines changed

8 files changed

+71
-16
lines changed

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

+7
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

+15
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();

engine/schema/src/main/resources/META-INF/db/schema-42000to42010-cleanup.sql

+3
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@
1818
--;
1919
-- Schema upgrade cleanup from 4.20.0.0 to 4.20.1.0
2020
--;
21+
22+
-- Delete `project_account` entries for users that were removed
23+
DELETE FROM `cloud`.`project_account` WHERE `user_id` IN (SELECT `id` FROM `cloud`.`user` WHERE `removed`);

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

+3-1
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/user/AccountManagerImpl.java

+17-10
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 ));

server/src/test/java/com/cloud/user/AccountManagerImplTest.java

+18
Original file line numberDiff line numberDiff line change
@@ -1338,4 +1338,22 @@ public void testValidateRoleAdminCannotEscalateAdminFromNonRootDomain() {
13381338
Mockito.when(roleService.findRole(2L)).thenReturn(callerRole);
13391339
accountManagerImpl.validateRoleChange(account, newRole, caller);
13401340
}
1341+
1342+
@Test
1343+
public void checkIfAccountManagesProjectsTestNotThrowExceptionWhenTheAccountIsNotAProjectAdministrator() {
1344+
long accountId = 1L;
1345+
List<Long> managedProjectIds = new ArrayList<>();
1346+
1347+
Mockito.when(_projectAccountDao.listAdministratedProjectIds(accountId)).thenReturn(managedProjectIds);
1348+
accountManagerImpl.checkIfAccountManagesProjects(accountId);
1349+
}
1350+
1351+
@Test(expected = InvalidParameterValueException.class)
1352+
public void checkIfAccountManagesProjectsTestThrowExceptionWhenTheAccountIsAProjectAdministrator() {
1353+
long accountId = 1L;
1354+
List<Long> managedProjectIds = List.of(1L);
1355+
1356+
Mockito.when(_projectAccountDao.listAdministratedProjectIds(accountId)).thenReturn(managedProjectIds);
1357+
accountManagerImpl.checkIfAccountManagesProjects(accountId);
1358+
}
13411359
}

server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java

+3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
6767
import org.apache.cloudstack.framework.messagebus.MessageBus;
6868
import org.apache.cloudstack.network.RoutedIpv4Manager;
69+
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
6970
import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
7071
import org.apache.cloudstack.resourcedetail.dao.UserDetailsDao;
7172
import org.junit.After;
@@ -196,6 +197,8 @@ public class AccountManagetImplTestBase {
196197
SSHKeyPairDao _sshKeyPairDao;
197198
@Mock
198199
UserDataDao userDataDao;
200+
@Mock
201+
NetworkPermissionDao networkPermissionDaoMock;
199202

200203
@Spy
201204
@InjectMocks

ui/src/views/setting/ConfigurationValue.vue

+5-5
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@
5555
/>
5656
</a-tooltip>
5757
</span>
58-
<span v-else-if="configrecord.type ==='Range'">
59-
<a-row>
60-
<a-col>
58+
<span v-else-if="configrecord.type ==='Range'" style="width: 75%;">
59+
<a-row type="flex">
60+
<a-col flex="auto">
6161
<a-tooltip :title="editableValue">
6262
<a-slider
6363
style="width: 13vw"
@@ -73,10 +73,10 @@
7373
/>
7474
</a-tooltip>
7575
</a-col>
76-
<a-col>
76+
<a-col flex="30px">
7777
<a-tooltip :title="editableValue">
7878
<a-input-number
79-
style="width: 5vw; margin-left: 10px; float: right"
79+
style="margin-left: 10px;"
8080
class="config-slider-text"
8181
:defaultValue="configrecord.value * 100"
8282
:min="0"

0 commit comments

Comments
 (0)