Skip to content

Commit 8ab7d5c

Browse files
committed
[CKS] Add pre-check for node types offerings before scaling CKS cluster
1 parent 5b7c3b4 commit 8ab7d5c

File tree

2 files changed

+156
-1
lines changed

2 files changed

+156
-1
lines changed

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterScaleWorker.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,8 @@ public boolean scaleCluster() throws CloudRuntimeException {
542542
}
543543
}
544544

545+
checkScalingKubernetesClusterOfferingsPerNodeType(serviceOfferingNodeTypeMap, kubernetesCluster);
546+
545547
final boolean autoscalingChanged = isAutoscalingChanged();
546548
ServiceOffering defaultServiceOffering = serviceOfferingNodeTypeMap.getOrDefault(DEFAULT.name(), null);
547549

@@ -587,6 +589,38 @@ public boolean scaleCluster() throws CloudRuntimeException {
587589
return true;
588590
}
589591

592+
protected void compareExistingToScalingServiceOfferingForNodeType(Long existingOfferingId, Long scalingOfferingId,
593+
KubernetesClusterNodeType nodeType) {
594+
if (existingOfferingId.equals(scalingOfferingId)) {
595+
String err = String.format("Cannot scale the nodes of type %s as the provided offering %s " +
596+
"is the same as the existing offering", nodeType.name(), scalingOfferingId);
597+
logger.error(err);
598+
throw new CloudRuntimeException(err);
599+
}
600+
}
601+
602+
protected void checkScalingKubernetesClusterOfferingsPerNodeType(Map<String, ServiceOffering> scalingNodeTypeMap,
603+
KubernetesCluster kubernetesCluster) {
604+
for (KubernetesClusterNodeType nodeType : Arrays.asList(WORKER, CONTROL, ETCD)) {
605+
Long existingNodeTypeOfferingId = getKubernetesClusterNodeTypeOfferingId(kubernetesCluster, nodeType);
606+
if (existingNodeTypeOfferingId == null) {
607+
existingNodeTypeOfferingId = kubernetesCluster.getServiceOfferingId();
608+
}
609+
if (ETCD == nodeType && (kubernetesCluster.getEtcdNodeCount() == null || kubernetesCluster.getEtcdNodeCount() == 0)) {
610+
continue;
611+
}
612+
String scalingMapKey = scalingNodeTypeMap.containsKey(nodeType.name()) ? nodeType.name() : DEFAULT.name();
613+
ServiceOffering scalingServiceOffering = scalingNodeTypeMap.get(scalingMapKey);
614+
if (scalingServiceOffering == null) {
615+
String err = String.format("Cannot find a service offering to scale the nodes of type %s", nodeType.name());
616+
logger.error(err);
617+
throw new CloudRuntimeException(err);
618+
}
619+
compareExistingToScalingServiceOfferingForNodeType(existingNodeTypeOfferingId,
620+
scalingServiceOffering.getId(), nodeType);
621+
}
622+
}
623+
590624
private Long getKubernetesClusterNodeTypeOfferingId(KubernetesCluster kubernetesCluster, KubernetesClusterNodeType nodeType) {
591625
if (nodeType == WORKER) {
592626
return kubernetesCluster.getWorkerNodeServiceOfferingId();
@@ -595,7 +629,7 @@ private Long getKubernetesClusterNodeTypeOfferingId(KubernetesCluster kubernetes
595629
} else if (nodeType == CONTROL) {
596630
return kubernetesCluster.getControlNodeServiceOfferingId();
597631
}
598-
return null;
632+
return kubernetesCluster.getServiceOfferingId();
599633
}
600634

601635
protected boolean isServiceOfferingScalingNeededForNodeType(KubernetesClusterNodeType nodeType,

plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterScaleWorkerTest.java

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.cloud.service.ServiceOfferingVO;
2525
import com.cloud.service.dao.ServiceOfferingDao;
2626
import com.cloud.utils.Pair;
27+
import com.cloud.utils.exception.CloudRuntimeException;
2728
import com.cloud.vm.UserVmVO;
2829
import com.cloud.vm.dao.UserVmDao;
2930
import org.junit.Assert;
@@ -34,10 +35,14 @@
3435
import org.mockito.Mockito;
3536
import org.mockito.junit.MockitoJUnitRunner;
3637

38+
import java.util.HashMap;
3739
import java.util.List;
40+
import java.util.Map;
3841

3942
import static com.cloud.kubernetes.cluster.KubernetesServiceHelper.KubernetesClusterNodeType.DEFAULT;
4043
import static com.cloud.kubernetes.cluster.KubernetesServiceHelper.KubernetesClusterNodeType.CONTROL;
44+
import static com.cloud.kubernetes.cluster.KubernetesServiceHelper.KubernetesClusterNodeType.ETCD;
45+
import static com.cloud.kubernetes.cluster.KubernetesServiceHelper.KubernetesClusterNodeType.WORKER;
4146

4247
@RunWith(MockitoJUnitRunner.class)
4348
public class KubernetesClusterScaleWorkerTest {
@@ -125,4 +130,120 @@ public void testCalculateNewClusterCountAndCapacityNodeTypeScaleControlOffering(
125130
Assert.assertEquals(expectedCores, newClusterCapacity.first().longValue());
126131
Assert.assertEquals(expectedMemory, newClusterCapacity.second().longValue());
127132
}
133+
134+
private KubernetesCluster createExistingKubernetesClusterForTesting(Long defaultOfferingId, Long workerOfferingId,
135+
Long controlOfferingId) {
136+
KubernetesCluster kubernetesClusterMock = Mockito.mock(KubernetesCluster.class);
137+
Mockito.when(kubernetesClusterMock.getServiceOfferingId()).thenReturn(defaultOfferingId);
138+
Mockito.when(kubernetesClusterMock.getWorkerNodeServiceOfferingId()).thenReturn(workerOfferingId);
139+
Mockito.when(kubernetesClusterMock.getControlNodeServiceOfferingId()).thenReturn(controlOfferingId);
140+
return kubernetesClusterMock;
141+
}
142+
143+
private ServiceOffering createServiceOfferingForTesting(Long offeringId) {
144+
ServiceOffering cksOffering = Mockito.mock(ServiceOffering.class);
145+
Mockito.when(cksOffering.getId()).thenReturn(offeringId);
146+
return cksOffering;
147+
}
148+
149+
@Test
150+
public void testCheckScalingKubernetesClusterOfferingsPerNodeTypeToNewDefaultOffering() {
151+
Long cksOfferingId = 20L;
152+
153+
ServiceOffering newCksOffering = createServiceOfferingForTesting(21L);
154+
155+
KubernetesCluster kubernetesClusterMock = createExistingKubernetesClusterForTesting(cksOfferingId,
156+
null, null);
157+
158+
Map<String, ServiceOffering> scalingMap = new HashMap<>();
159+
scalingMap.put(DEFAULT.name(), newCksOffering);
160+
161+
worker.checkScalingKubernetesClusterOfferingsPerNodeType(scalingMap, kubernetesClusterMock);
162+
}
163+
164+
@Test(expected = CloudRuntimeException.class)
165+
public void testCheckScalingKubernetesClusterOfferingsPerNodeTypeToSameDefaultOffering() {
166+
Long cksOfferingId = 20L;
167+
ServiceOffering cksOffering = createServiceOfferingForTesting(cksOfferingId);
168+
169+
KubernetesCluster kubernetesClusterMock = createExistingKubernetesClusterForTesting(cksOfferingId,
170+
null, null);
171+
172+
Map<String, ServiceOffering> scalingMap = new HashMap<>();
173+
scalingMap.put(DEFAULT.name(), cksOffering);
174+
175+
worker.checkScalingKubernetesClusterOfferingsPerNodeType(scalingMap, kubernetesClusterMock);
176+
}
177+
178+
@Test
179+
public void testCheckScalingKubernetesClusterOfferingsPerNodeTypeWorkerAndControlNodes() {
180+
Long cksOfferingId = 20L;
181+
Long workerOfferingId = 21L;
182+
Long controlOfferingId = 22L;
183+
ServiceOffering scalingWorkerOffering = createServiceOfferingForTesting(30L);
184+
ServiceOffering scalingControlOffering = createServiceOfferingForTesting(31L);
185+
186+
KubernetesCluster kubernetesClusterMock = createExistingKubernetesClusterForTesting(cksOfferingId,
187+
workerOfferingId, controlOfferingId);
188+
189+
Map<String, ServiceOffering> scalingMap = new HashMap<>();
190+
scalingMap.put(WORKER.name(), scalingWorkerOffering);
191+
scalingMap.put(CONTROL.name(), scalingControlOffering);
192+
193+
worker.checkScalingKubernetesClusterOfferingsPerNodeType(scalingMap, kubernetesClusterMock);
194+
}
195+
196+
@Test(expected = CloudRuntimeException.class)
197+
public void testCheckScalingKubernetesClusterOfferingsPerNodeTypeWorkerAndControlNodesUseSameOffering() {
198+
Long cksOfferingId = 20L;
199+
Long workerOfferingId = 21L;
200+
Long controlOfferingId = 22L;
201+
ServiceOffering scalingWorkerOffering = createServiceOfferingForTesting(30L);
202+
ServiceOffering controlOffering = createServiceOfferingForTesting(controlOfferingId);
203+
204+
KubernetesCluster kubernetesClusterMock = createExistingKubernetesClusterForTesting(cksOfferingId,
205+
workerOfferingId, controlOfferingId);
206+
207+
Map<String, ServiceOffering> scalingMap = new HashMap<>();
208+
scalingMap.put(WORKER.name(), scalingWorkerOffering);
209+
scalingMap.put(CONTROL.name(), controlOffering);
210+
211+
worker.checkScalingKubernetesClusterOfferingsPerNodeType(scalingMap, kubernetesClusterMock);
212+
}
213+
214+
@Test
215+
public void testCheckScalingKubernetesClusterOfferingsPerNodeTypeWorkerAndControlNodesByDefaultOffering() {
216+
Long cksOfferingId = 20L;
217+
Long workerOfferingId = 21L;
218+
Long controlOfferingId = 22L;
219+
ServiceOffering scalingOffering = createServiceOfferingForTesting(30L);
220+
221+
KubernetesCluster kubernetesClusterMock = createExistingKubernetesClusterForTesting(cksOfferingId,
222+
workerOfferingId, controlOfferingId);
223+
224+
Map<String, ServiceOffering> scalingMap = new HashMap<>();
225+
scalingMap.put(DEFAULT.name(), scalingOffering);
226+
227+
worker.checkScalingKubernetesClusterOfferingsPerNodeType(scalingMap, kubernetesClusterMock);
228+
}
229+
230+
@Test
231+
public void testCheckScalingKubernetesClusterOfferingsPerNodeTypeWorkerEtcdAndControlNodes() {
232+
Long cksOfferingId = 20L;
233+
Long workerOfferingId = 21L;
234+
Long controlOfferingId = 22L;
235+
Long etcdOfferingId = 23L;
236+
ServiceOffering scalingOffering = createServiceOfferingForTesting(30L);
237+
238+
KubernetesCluster kubernetesClusterMock = createExistingKubernetesClusterForTesting(cksOfferingId,
239+
workerOfferingId, controlOfferingId);
240+
Mockito.when(kubernetesClusterMock.getEtcdNodeServiceOfferingId()).thenReturn(etcdOfferingId);
241+
242+
Map<String, ServiceOffering> scalingMap = new HashMap<>();
243+
scalingMap.put(WORKER.name(), scalingOffering);
244+
scalingMap.put(CONTROL.name(), scalingOffering);
245+
scalingMap.put(ETCD.name(), scalingOffering);
246+
247+
worker.checkScalingKubernetesClusterOfferingsPerNodeType(scalingMap, kubernetesClusterMock);
248+
}
128249
}

0 commit comments

Comments
 (0)