Skip to content

Commit cef6250

Browse files
validate naming of k8s clusters
1 parent 55c8138 commit cef6250

File tree

5 files changed

+85
-16
lines changed

5 files changed

+85
-16
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,10 @@ public class ApiConstants {
11071107

11081108
public static final String NFS_MOUNT_OPTIONS = "nfsmountopts";
11091109

1110+
public static final String PARAMETER_DESCRIPTION_KUBERNETES_CLUSTER_NAME = "Kubernetes cluster's name. It must: " +
1111+
"contain at most 43 characters; contain only lowercase alphanumeric characters or '-'; " +
1112+
"start with a letter; end with an alphanumeric character.";
1113+
11101114
/**
11111115
* This enum specifies IO Drivers, each option controls specific policies on I/O.
11121116
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).

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

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -746,9 +746,7 @@ private void validateManagedKubernetesClusterCreateParameters(final CreateKubern
746746
final Long nodeRootDiskSize = cmd.getNodeRootDiskSize();
747747
final String externalLoadBalancerIpAddress = cmd.getExternalLoadBalancerIpAddress();
748748

749-
if (name == null || name.isEmpty()) {
750-
throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name: " + name);
751-
}
749+
validateKubernetesClusterName(name);
752750

753751
if (controlNodeCount < 1) {
754752
throw new InvalidParameterValueException("Invalid cluster control nodes count: " + controlNodeCount);
@@ -838,6 +836,34 @@ private void validateManagedKubernetesClusterCreateParameters(final CreateKubern
838836
}
839837
}
840838

839+
/**
840+
* Checks whether Kubernetes cluster name complies with the Kubernetes naming convention; throws an {@link InvalidParameterValueException} otherwise.
841+
* @see <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/names/"> Kubernetes documentation </a>
842+
*
843+
* @param name Kubernetes cluster name to be validated.
844+
* @throws InvalidParameterValueException When Kubernetes cluster name does not comply with Kubernetes naming convention.
845+
*/
846+
protected void validateKubernetesClusterName(String name) {
847+
String baseErrorString = "Unable to create Kubernetes cluster. Reason: ";
848+
if (!name.equals(name.toLowerCase())) {
849+
String errorString = String.format("%s cluster name [%s] needs to be entirely in lowercase.", baseErrorString, name);
850+
LOGGER.debug(errorString);
851+
throw new InvalidParameterValueException(errorString);
852+
}
853+
if (name.length() > 43) {
854+
String reason = "CloudStack appends the VM type and an 11-character hash to the cluster name to generate VM names, which must not exceed 63 characters. Please ensure the cluster name is 43 characters or fewer.";
855+
String errorString = String.format("%s cluster name [%s] needs to contain at most 43 characters. %s", baseErrorString, name, reason);
856+
LOGGER.debug(errorString);
857+
throw new InvalidParameterValueException(errorString);
858+
}
859+
String pattern = "[a-z]($|[a-z\\d-]*[a-z\\d]$)";
860+
if (!name.matches(pattern)) {
861+
String errorString = String.format("%s cluster name [%s] needs to start with a letter and end with an alphanumeric character, and can contain only '-' aside from alphanumeric characters.", baseErrorString, name);
862+
LOGGER.debug(errorString);
863+
throw new InvalidParameterValueException(errorString);
864+
}
865+
}
866+
841867
private Network getKubernetesClusterNetworkIfMissing(final String clusterName, final DataCenter zone, final Account owner, final int controlNodesCount,
842868
final int nodesCount, final String externalLoadBalancerIpAddress, final Long networkId) throws CloudRuntimeException {
843869
Network network = null;

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

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -773,18 +773,7 @@ protected void setupKubernetesClusterVpcTierRules(IpAddress publicIp, Network ne
773773
}
774774

775775
protected String getKubernetesClusterNodeNamePrefix() {
776-
String prefix = kubernetesCluster.getName();
777-
if (!NetUtils.verifyDomainNameLabel(prefix, true)) {
778-
prefix = prefix.replaceAll("[^a-zA-Z0-9-]", "");
779-
if (prefix.length() == 0) {
780-
prefix = kubernetesCluster.getUuid();
781-
}
782-
prefix = "k8s-" + prefix;
783-
}
784-
if (prefix.length() > 40) {
785-
prefix = prefix.substring(0, 40);
786-
}
787-
return prefix;
776+
return kubernetesCluster.getName();
788777
}
789778

790779
protected KubernetesClusterVO updateKubernetesClusterEntry(final Long cores, final Long memory, final Long size,

plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
6767
//////////////// API parameters /////////////////////
6868
/////////////////////////////////////////////////////
6969

70-
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name for the Kubernetes cluster")
70+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = ApiConstants.PARAMETER_DESCRIPTION_KUBERNETES_CLUSTER_NAME)
7171
private String name;
7272

7373
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "description for the Kubernetes cluster")

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,54 @@ public void removeVmsFromCluster() {
292292
Mockito.when(kubernetesClusterDao.findById(Mockito.anyLong())).thenReturn(cluster);
293293
Assert.assertTrue(kubernetesClusterManager.removeVmsFromCluster(cmd).size() > 0);
294294
}
295+
296+
@Test(expected = InvalidParameterValueException.class)
297+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameContainsUpperCaseLetters() {
298+
kubernetesClusterManager.validateKubernetesClusterName("clusterName");
299+
}
300+
301+
@Test(expected = InvalidParameterValueException.class)
302+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameExceedsMaxAllowedLength() {
303+
kubernetesClusterManager.validateKubernetesClusterName("c".repeat(44));
304+
}
305+
306+
@Test(expected = InvalidParameterValueException.class)
307+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameStartsWithDigit() {
308+
kubernetesClusterManager.validateKubernetesClusterName("1clustername");
309+
}
310+
311+
@Test(expected = InvalidParameterValueException.class)
312+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameContainsOneDigit() {
313+
kubernetesClusterManager.validateKubernetesClusterName("1");
314+
}
315+
316+
@Test(expected = InvalidParameterValueException.class)
317+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameStartsWithNonAlphanumericCharacter() {
318+
kubernetesClusterManager.validateKubernetesClusterName("-clustername");
319+
}
320+
321+
@Test(expected = InvalidParameterValueException.class)
322+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameContainsOneHyphen() {
323+
kubernetesClusterManager.validateKubernetesClusterName("-");
324+
}
325+
326+
@Test(expected = InvalidParameterValueException.class)
327+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameEndsWithNonAlphanumericCharacter() {
328+
kubernetesClusterManager.validateKubernetesClusterName("clustername-");
329+
}
330+
331+
@Test(expected = InvalidParameterValueException.class)
332+
public void validateKubernetesClusterNameTestThrowExceptionWhenClusterNameContainsNonAlphanumericCharactersOtherThanHyphen() {
333+
kubernetesClusterManager.validateKubernetesClusterName("cluster$name");
334+
}
335+
336+
@Test
337+
public void validateKubernetesClusterNameTestValidateClusterNameWhenItCompliesWithTheNamingConvention() {
338+
kubernetesClusterManager.validateKubernetesClusterName("c-" + "c".repeat(41));
339+
}
340+
341+
@Test
342+
public void validateKubernetesClusterNameTestValidateClusterNameWithOneCharacter() {
343+
kubernetesClusterManager.validateKubernetesClusterName("k");
344+
}
295345
}

0 commit comments

Comments
 (0)