Add node version details to every node of k8s cluster - as we now support manual upgrade

* Add node version details to every node of k8s cluster - as we now support manual upgrade

* update column name

* CKS: Exclude etcd nodes when calculating port numbers

* update param name

* update param
This commit is contained in:
Pearl Dsilva 2024-05-28 11:50:50 -04:00 committed by nvazquez
parent 5a11451ce3
commit 97aa35a705
No known key found for this signature in database
GPG Key ID: 656E1BCC8CB54F84
11 changed files with 47 additions and 10 deletions

View File

@ -322,6 +322,7 @@ public class ApiConstants {
public static final String NIC_PACKED_VIRTQUEUES_ENABLED = "nicpackedvirtqueuesenabled";
public static final String NEW_START_IP = "newstartip";
public static final String NEW_END_IP = "newendip";
public static final String KUBERNETES_NODE_VERSION = "kubernetesnodeversion";
public static final String NUM_RETRIES = "numretries";
public static final String OFFER_HA = "offerha";
public static final String OS_DISTRIBUTION = "osdistribution";

View File

@ -34,6 +34,11 @@ public class KubernetesUserVmResponse extends UserVmResponse {
@Param(description = "If the VM is an etcd node")
private boolean isEtcdNode;
@SerializedName(ApiConstants.KUBERNETES_NODE_VERSION)
@Param(description = "Kubernetes version of the node")
private String nodeVersion;
public void setExternalNode(boolean externalNode) {
isExternalNode = externalNode;
}
@ -41,4 +46,6 @@ public class KubernetesUserVmResponse extends UserVmResponse {
public void setEtcdNode(boolean etcdNode) {
isEtcdNode = etcdNode;
}
public void setNodeVersion(String nodeVersion) { this.nodeVersion = nodeVersion;}
}

View File

@ -338,6 +338,7 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster','etcd_template_i
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster_vm_map','etcd_node', 'tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT "indicates if the VM is an etcd node"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster_vm_map','external_node', 'tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT "indicates if the node was imported into the Kubernetes cluster"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster_vm_map','manual_upgrade', 'tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT "indicates if the node is marked for manual upgrade and excluded from the Kubernetes cluster upgrade operation"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster_vm_map','kubernetes_node_version', 'varchar(40) COMMENT "version of k8s the cluster node is on"');
ALTER TABLE `cloud`.`kubernetes_cluster` ADD CONSTRAINT `fk_cluster__control_service_offering_id` FOREIGN KEY `fk_cluster__control_service_offering_id`(`control_service_offering_id`) REFERENCES `service_offering`(`id`) ON DELETE CASCADE;
ALTER TABLE `cloud`.`kubernetes_cluster` ADD CONSTRAINT `fk_cluster__worker_service_offering_id` FOREIGN KEY `fk_cluster__worker_service_offering_id`(`worker_service_offering_id`) REFERENCES `service_offering`(`id`) ON DELETE CASCADE;

View File

@ -756,6 +756,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
}
kubernetesUserVmResponse.setExternalNode(vmMapVO.isExternalNode());
kubernetesUserVmResponse.setEtcdNode(vmMapVO.isEtcdNode());
kubernetesUserVmResponse.setNodeVersion(vmMapVO.getNodeVersion());
vmResponses.add(kubernetesUserVmResponse);
}
}

View File

@ -51,6 +51,9 @@ public class KubernetesClusterVmMapVO implements KubernetesClusterVmMap {
@Column(name = "manual_upgrade")
boolean manualUpgrade;
@Column(name = "kubernetes_node_version")
String nodeVersion;
public KubernetesClusterVmMapVO() {
}
@ -116,4 +119,12 @@ public class KubernetesClusterVmMapVO implements KubernetesClusterVmMap {
public void setManualUpgrade(boolean manualUpgrade) {
this.manualUpgrade = manualUpgrade;
}
public String getNodeVersion() {
return nodeVersion;
}
public void setNodeVersion(String nodeVersion) {
this.nodeVersion = nodeVersion;
}
}

View File

@ -363,6 +363,7 @@ public class KubernetesClusterActionWorker {
protected KubernetesClusterVmMapVO addKubernetesClusterVm(final long kubernetesClusterId, final long vmId,
boolean isControlNode, boolean isExternalNode,
boolean isEtcdNode, boolean markForManualUpgrade) {
KubernetesSupportedVersion kubernetesVersion = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
return Transaction.execute(new TransactionCallback<KubernetesClusterVmMapVO>() {
@Override
public KubernetesClusterVmMapVO doInTransaction(TransactionStatus status) {
@ -370,6 +371,7 @@ public class KubernetesClusterActionWorker {
newClusterVmMap.setExternalNode(isExternalNode);
newClusterVmMap.setManualUpgrade(markForManualUpgrade);
newClusterVmMap.setEtcdNode(isEtcdNode);
newClusterVmMap.setNodeVersion(kubernetesVersion.getSemanticVersion());
kubernetesClusterVmMapDao.persist(newClusterVmMap);
return newClusterVmMap;
}

View File

@ -147,7 +147,7 @@ public class KubernetesClusterUpgradeWorker extends KubernetesClusterActionWorke
logTransitStateDetachIsoAndThrow(Level.ERROR, String.format("Failed to upgrade Kubernetes cluster : %s, unable to get control Kubernetes node on VM : %s in ready state", kubernetesCluster.getName(), vm.getDisplayName()), kubernetesCluster, clusterVMs, KubernetesCluster.Event.OperationFailed, null);
}
}
if (!KubernetesClusterUtil.clusterNodeVersionMatches(upgradeVersion.getSemanticVersion(), publicIpAddress, sshPort, getControlNodeLoginUser(), getManagementServerSshPublicKeyFile(), hostName, upgradeTimeoutTime, 15000)) {
if (!KubernetesClusterUtil.clusterNodeVersionMatches(upgradeVersion.getSemanticVersion(), publicIpAddress, sshPort, getControlNodeLoginUser(), getManagementServerSshPublicKeyFile(), hostName, upgradeTimeoutTime, 15000, vm.getId(), kubernetesClusterVmMapDao)) {
logTransitStateDetachIsoAndThrow(Level.ERROR, String.format("Failed to upgrade Kubernetes cluster : %s, unable to get Kubernetes node on VM : %s upgraded to version %s", kubernetesCluster.getName(), vm.getDisplayName(), upgradeVersion.getSemanticVersion()), kubernetesCluster, clusterVMs, KubernetesCluster.Event.OperationFailed, null);
}
if (logger.isInfoEnabled()) {

View File

@ -31,6 +31,8 @@ import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import com.cloud.kubernetes.cluster.KubernetesClusterVmMapVO;
import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
import org.apache.cloudstack.utils.security.SSLUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
@ -333,7 +335,7 @@ public class KubernetesClusterUtil {
final String ipAddress, final int port,
final String user, final File sshKeyFile,
final String hostName,
final long timeoutTime, final long waitDuration) {
final long timeoutTime, final long waitDuration, final long vmId, KubernetesClusterVmMapDao vmMapDao) {
int retry = 10;
while (System.currentTimeMillis() < timeoutTime && retry-- > 0) {
if (LOGGER.isDebugEnabled()) {
@ -345,7 +347,10 @@ public class KubernetesClusterUtil {
user, sshKeyFile, null,
String.format(CLUSTER_NODE_VERSION_COMMAND, hostName.toLowerCase()),
10000, 10000, 20000);
if (clusterNodeVersionMatches(result, version)) {
Pair<Boolean, String> clusterVersionMatchesAndValue = clusterNodeVersionMatches(result, version);
if (Boolean.TRUE.equals(clusterVersionMatchesAndValue.first())) {
KubernetesClusterVmMapVO vmMapVO = vmMapDao.findById(vmId);
vmMapVO.setNodeVersion(clusterVersionMatchesAndValue.second());
return true;
}
} catch (Exception e) {
@ -362,11 +367,11 @@ public class KubernetesClusterUtil {
return false;
}
protected static boolean clusterNodeVersionMatches(final Pair<Boolean, String> result, final String version) {
protected static Pair<Boolean, String> clusterNodeVersionMatches(final Pair<Boolean, String> result, final String version) {
if (result == null || Boolean.FALSE.equals(result.first()) || StringUtils.isBlank(result.second())) {
return false;
return new Pair<>(false, null);
}
String response = result.second();
return response.contains(String.format("v%s", version));
return new Pair<>(response.contains(String.format("v%s", version)), response);
}
}

View File

@ -27,14 +27,14 @@ public class KubernetesClusterUtilTest {
private void executeThrowAndTestVersionMatch() {
Pair<Boolean, String> resultPair = null;
boolean result = KubernetesClusterUtil.clusterNodeVersionMatches(resultPair, "1.24.0");
Assert.assertFalse(result);
Pair<Boolean, String> result = KubernetesClusterUtil.clusterNodeVersionMatches(resultPair, "1.24.0");
Assert.assertFalse(result.first());
}
private void executeAndTestVersionMatch(boolean status, String response, boolean expectedResult) {
Pair<Boolean, String> resultPair = new Pair<>(status, response);
boolean result = KubernetesClusterUtil.clusterNodeVersionMatches(resultPair, "1.24.0");
Assert.assertEquals(expectedResult, result);
Pair<Boolean, String> result = KubernetesClusterUtil.clusterNodeVersionMatches(resultPair, "1.24.0");
Assert.assertEquals(expectedResult, result.first());
}
@Test

View File

@ -1458,6 +1458,7 @@
"label.no.items": "No available Items",
"label.no.matching.offering": "No matching offering found",
"label.no.matching.network": "No matching Networks found",
"label.node.version": "Node version",
"label.noderootdisksize": "Node root disk size (in GB)",
"label.nodiskcache": "No disk cache",
"label.none": "None",

View File

@ -117,6 +117,9 @@
<span v-if="record.isexternalnode || (!record.isexternalnode && !record.isetcdnode)"> {{ cksSshStartingPort + index }} </span>
<span v-else> {{ parseInt(etcdSshPort) + parseInt(getEtcdIndex(record.name)) }} </span>
</template>
<template v-if="column.key === 'kubernetesnodeversion'">
<span> {{ text ? text : '' }} </span>
</template>
<template v-if="column.key === 'actions'">
<a-tooltip placement="bottom" >
<template #title>
@ -239,6 +242,11 @@ export default {
title: this.$t('label.ssh.port'),
dataIndex: 'port'
},
{
key: 'kubernetesnodeversion',
title: this.$t('label.node.version'),
dataIndex: 'kubernetesnodeversion'
},
{
title: this.$t('label.zonename'),
dataIndex: 'zonename'