Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,11 @@ protected void logAndThrow(final Level logLevel, final String message, final Exc
logTransitStateAndThrow(logLevel, message, null, null, ex);
}

protected String getAutoscalerEnableCommand(Long minSize, Long maxSize) {
return String.format("sudo /opt/bin/autoscale-kube-cluster -i %s -e -M %d -m %d",
kubernetesCluster.getUuid(), maxSize, minSize);
}

protected File getManagementServerSshPublicKeyFile() {
boolean devel = Boolean.parseBoolean(configurationDao.getValue("developer"));
String keyFile = String.format("%s/.ssh/id_rsa", System.getProperty("user.home"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -930,8 +930,7 @@ protected boolean autoscaleCluster(boolean enable, Long minSize, Long maxSize) {

try {
if (enable) {
String command = String.format("sudo /opt/bin/autoscale-kube-cluster -i %s -e -M %d -m %d",
kubernetesCluster.getUuid(), maxSize, minSize);
String command = getAutoscalerEnableCommand(minSize, maxSize);
Pair<Boolean, String> result = SshHelper.sshExecute(publicIpAddress, sshPort, getControlNodeLoginUser(),
pkFile, null, command, 10000, 10000, 60000);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,32 @@ private void upgradeKubernetesClusterNodes() {
}
}

/**
* The autoscaler on a binaries ISO matches the ISO's Kubernetes version, and the upgrade has
* copied the new ISO's autoscaler manifest to the control node. Once the nodes in this upgrade
* have imported the new ISO's images, redeploy the autoscaler from it with the cluster's
* settings. A failure leaves the previous autoscaler running, so it doesn't fail the upgrade.
*/
protected void updateAutoscaler() {
if (!kubernetesCluster.getAutoscalingEnabled()) {
return;
}
if (kubernetesCluster.getMinSize() == null || kubernetesCluster.getMaxSize() == null) {
logger.warn("Not updating the autoscaler of Kubernetes cluster {}: its minimum or maximum size is not set", kubernetesCluster);
return;
}
String command = getAutoscalerEnableCommand(kubernetesCluster.getMinSize(), kubernetesCluster.getMaxSize());
try {
Pair<Boolean, String> result = SshHelper.sshExecute(publicIpAddress, sshPort, getControlNodeLoginUser(),
sshKeyFile, null, command, 10000, 10000, 60000);
if (!result.first()) {
logger.warn("Unable to update the autoscaler of Kubernetes cluster {}: {}", kubernetesCluster, result.second());
}
} catch (Exception e) {
logger.warn("Unable to update the autoscaler of Kubernetes cluster {}", kubernetesCluster, e);
}
}

public boolean upgradeCluster() throws CloudRuntimeException {
init();
if (logger.isInfoEnabled()) {
Expand Down Expand Up @@ -184,6 +210,8 @@ public boolean upgradeCluster() throws CloudRuntimeException {
if (!updated) {
stateTransitTo(kubernetesCluster.getId(), KubernetesCluster.Event.OperationFailed);
} else {
// While the cluster is still Upgrading, so autoscaling can't be changed meanwhile
updateAutoscaler();
stateTransitTo(kubernetesCluster.getId(), KubernetesCluster.Event.OperationSucceeded);
}
return updated;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@
import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
import com.cloud.kubernetes.version.KubernetesSupportedVersion;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair;
import com.cloud.utils.ssh.SshHelper;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

Expand Down Expand Up @@ -80,4 +84,68 @@ public void testFilterOutManualUpgradeNodesFromClusterUpgrade() {
Assert.assertTrue(ids.contains(controlNodeId) && ids.contains(workerNode1Id));
Assert.assertFalse(ids.contains(workerNode2Id));
}

private MockedStatic<SshHelper> mockAutoscalerSsh(KubernetesClusterUpgradeWorker spyWorker, Pair<Boolean, String> result) {
Mockito.doReturn("cloud").when(spyWorker).getControlNodeLoginUser();
MockedStatic<SshHelper> sshHelper = Mockito.mockStatic(SshHelper.class);
sshHelper.when(() -> SshHelper.sshExecute(ArgumentMatchers.any(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyString(),
ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.anyString(), ArgumentMatchers.anyInt(),
ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(result);
return sshHelper;
}

@Test
public void testUpdateAutoscalerSkippedWhenAutoscalingDisabled() {
Mockito.when(kubernetesCluster.getAutoscalingEnabled()).thenReturn(false);
try (MockedStatic<SshHelper> sshHelper = Mockito.mockStatic(SshHelper.class)) {
worker.updateAutoscaler();
sshHelper.verifyNoInteractions();
}
}

@Test
public void testUpdateAutoscalerSkippedWithoutMinMaxSize() {
Mockito.when(kubernetesCluster.getAutoscalingEnabled()).thenReturn(true);
Mockito.when(kubernetesCluster.getMinSize()).thenReturn(null);
try (MockedStatic<SshHelper> sshHelper = Mockito.mockStatic(SshHelper.class)) {
worker.updateAutoscaler();
sshHelper.verifyNoInteractions();
}
}

@Test
public void testUpdateAutoscalerRedeploysWithClusterSettings() {
Mockito.when(kubernetesCluster.getAutoscalingEnabled()).thenReturn(true);
Mockito.when(kubernetesCluster.getUuid()).thenReturn("cluster-uuid");
Mockito.when(kubernetesCluster.getMinSize()).thenReturn(1L);
Mockito.when(kubernetesCluster.getMaxSize()).thenReturn(5L);
KubernetesClusterUpgradeWorker spyWorker = Mockito.spy(worker);
try (MockedStatic<SshHelper> sshHelper = mockAutoscalerSsh(spyWorker, new Pair<>(true, ""))) {
spyWorker.updateAutoscaler();
sshHelper.verify(() -> SshHelper.sshExecute(ArgumentMatchers.any(), ArgumentMatchers.anyInt(), ArgumentMatchers.eq("cloud"),
ArgumentMatchers.any(), ArgumentMatchers.any(),
ArgumentMatchers.eq("sudo /opt/bin/autoscale-kube-cluster -i cluster-uuid -e -M 5 -m 1"),
ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()));
}
}

@Test
public void testUpdateAutoscalerDoesNotThrowOnFailure() {
Mockito.when(kubernetesCluster.getAutoscalingEnabled()).thenReturn(true);
Mockito.when(kubernetesCluster.getUuid()).thenReturn("cluster-uuid");
Mockito.when(kubernetesCluster.getMinSize()).thenReturn(1L);
Mockito.when(kubernetesCluster.getMaxSize()).thenReturn(5L);
KubernetesClusterUpgradeWorker spyWorker = Mockito.spy(worker);
try (MockedStatic<SshHelper> sshHelper = mockAutoscalerSsh(spyWorker, new Pair<>(false, "autoscale-kube-cluster: not found"))) {
spyWorker.updateAutoscaler();
sshHelper.when(() -> SshHelper.sshExecute(ArgumentMatchers.any(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyString(),
ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.anyString(), ArgumentMatchers.anyInt(),
ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenThrow(new RuntimeException("ssh failed"));
spyWorker.updateAutoscaler();
sshHelper.verify(() -> SshHelper.sshExecute(ArgumentMatchers.any(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyString(),
ArgumentMatchers.any(), ArgumentMatchers.any(),
ArgumentMatchers.eq("sudo /opt/bin/autoscale-kube-cluster -i cluster-uuid -e -M 5 -m 1"),
ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()), Mockito.times(2));
}
}
}
Loading
Loading