You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2023/07/03 07:30:39 UTC
[cloudstack] branch 4.18 updated: engine-orchestration: fix volume size resource count mismatch (#7666)
This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch 4.18
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.18 by this push:
new 31dbdd0f5c0 engine-orchestration: fix volume size resource count mismatch (#7666)
31dbdd0f5c0 is described below
commit 31dbdd0f5c0a0eb33e71fa7e7bef0b8b74f408b3
Author: Abhishek Kumar <ab...@gmail.com>
AuthorDate: Mon Jul 3 13:00:32 2023 +0530
engine-orchestration: fix volume size resource count mismatch (#7666)
Fixes case of account/domain having negative storage count when there is a volume size difference while deploying volumes on certain stroages. In case of Powerflex volume size results in a multiple of 8. If user deploys a volume of 12GB it will result in 16GB in size. But currently CloudStack will not update resource count after deployment.
Signed-off-by: Abhishek Kumar <ab...@gmail.com>
---
.../engine/orchestration/VolumeOrchestrator.java | 23 ++++-
.../orchestration/VolumeOrchestratorTest.java | 103 +++++++++++++++++++++
2 files changed, 124 insertions(+), 2 deletions(-)
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 49c822d25ad..2aa997e13aa 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@@ -83,6 +84,7 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.Nullable;
@@ -1656,6 +1658,23 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
return tasks;
}
+ protected void checkAndUpdateVolumeAccountResourceCount(VolumeVO originalEntry, VolumeVO updateEntry) {
+ if (Objects.equals(originalEntry.getSize(), updateEntry.getSize())) {
+ return;
+ }
+ s_logger.debug(String.format("Size mismatch found for %s after creation, old size: %d, new size: %d. Updating resource count", updateEntry, originalEntry.getSize(), updateEntry.getSize()));
+ if (ObjectUtils.anyNull(originalEntry.getSize(), updateEntry.getSize())) {
+ _resourceLimitMgr.recalculateResourceCount(updateEntry.getAccountId(), updateEntry.getDomainId(),
+ ResourceType.primary_storage.getOrdinal());
+ return;
+ }
+ if (updateEntry.getSize() > originalEntry.getSize()) {
+ _resourceLimitMgr.incrementResourceCount(updateEntry.getAccountId(), ResourceType.primary_storage, updateEntry.isDisplayVolume(), updateEntry.getSize() - originalEntry.getSize());
+ } else {
+ _resourceLimitMgr.decrementResourceCount(updateEntry.getAccountId(), ResourceType.primary_storage, updateEntry.isDisplayVolume(), originalEntry.getSize() - updateEntry.getSize());
+ }
+ }
+
private Pair<VolumeVO, DataStore> recreateVolume(VolumeVO vol, VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, StorageAccessException {
String volToString = getReflectOnlySelectedFields(vol);
@@ -1793,8 +1812,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
throw new StorageUnavailableException(msg, destPool.getId());
}
}
-
- return new Pair<VolumeVO, DataStore>(newVol, destPool);
+ checkAndUpdateVolumeAccountResourceCount(vol, newVol);
+ return new Pair<>(newVol, destPool);
}
private VolumeVO setPassphraseForVolumeEncryption(VolumeVO volume) {
diff --git a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java
new file mode 100644
index 00000000000..b2f4c436ca3
--- /dev/null
+++ b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.engine.orchestration;
+
+import java.util.ArrayList;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+import com.cloud.configuration.Resource;
+import com.cloud.storage.VolumeVO;
+import com.cloud.user.ResourceLimitService;
+
+@RunWith(MockitoJUnitRunner.class)
+public class VolumeOrchestratorTest {
+
+ @Mock
+ protected ResourceLimitService resourceLimitMgr;
+
+ @Spy
+ @InjectMocks
+ private VolumeOrchestrator volumeOrchestrator = new VolumeOrchestrator();
+
+ private static final Long DEFAULT_ACCOUNT_PS_RESOURCE_COUNT = 100L;
+ private Long accountPSResourceCount;
+
+ @Before
+ public void setUp() throws Exception {
+ accountPSResourceCount = DEFAULT_ACCOUNT_PS_RESOURCE_COUNT;
+ Mockito.when(resourceLimitMgr.recalculateResourceCount(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyInt())).thenReturn(new ArrayList<>());
+ Mockito.doAnswer((Answer<Void>) invocation -> {
+ Resource.ResourceType type = (Resource.ResourceType)invocation.getArguments()[1];
+ Long increment = (Long)invocation.getArguments()[3];
+ if (Resource.ResourceType.primary_storage.equals(type)) {
+ accountPSResourceCount += increment;
+ }
+ return null;
+ }).when(resourceLimitMgr).incrementResourceCount(Mockito.anyLong(), Mockito.any(Resource.ResourceType.class), Mockito.anyBoolean(), Mockito.anyLong());
+ Mockito.doAnswer((Answer<Void>) invocation -> {
+ Resource.ResourceType type = (Resource.ResourceType)invocation.getArguments()[1];
+ Long decrement = (Long)invocation.getArguments()[3];
+ if (Resource.ResourceType.primary_storage.equals(type)) {
+ accountPSResourceCount -= decrement;
+ }
+ return null;
+ }).when(resourceLimitMgr).decrementResourceCount(Mockito.anyLong(), Mockito.any(Resource.ResourceType.class), Mockito.anyBoolean(), Mockito.anyLong());
+ }
+
+ private void runCheckAndUpdateVolumeAccountResourceCountTest(Long originalSize, Long newSize) {
+ VolumeVO v1 = Mockito.mock(VolumeVO.class);
+ Mockito.when(v1.getSize()).thenReturn(originalSize);
+ VolumeVO v2 = Mockito.mock(VolumeVO.class);
+ Mockito.when(v2.getSize()).thenReturn(newSize);
+ volumeOrchestrator.checkAndUpdateVolumeAccountResourceCount(v1, v2);
+ Long expected = ObjectUtils.anyNull(originalSize, newSize) ?
+ DEFAULT_ACCOUNT_PS_RESOURCE_COUNT : DEFAULT_ACCOUNT_PS_RESOURCE_COUNT + (newSize - originalSize);
+ Assert.assertEquals(expected, accountPSResourceCount);
+ }
+
+ @Test
+ public void testCheckAndUpdateVolumeAccountResourceCountSameSize() {
+ runCheckAndUpdateVolumeAccountResourceCountTest(10L, 10L);
+ }
+
+ @Test
+ public void testCheckAndUpdateVolumeAccountResourceCountEitherSizeNull() {
+ runCheckAndUpdateVolumeAccountResourceCountTest(null, 10L);
+ runCheckAndUpdateVolumeAccountResourceCountTest(10L, null);
+ }
+
+ @Test
+ public void testCheckAndUpdateVolumeAccountResourceCountMoreSize() {
+ runCheckAndUpdateVolumeAccountResourceCountTest(10L, 20L);
+ }
+
+ @Test
+ public void testCheckAndUpdateVolumeAccountResourceCountLessSize() {
+ runCheckAndUpdateVolumeAccountResourceCountTest(20L, 10L);
+ }
+}