From 9d6d98badd3f57192368be6cfef08229ccd1517c Mon Sep 17 00:00:00 2001
From: Nancy <42977925+mantis-toboggan-md@users.noreply.github.com>
Date: Fri, 6 Sep 2024 15:42:48 -0700
Subject: [PATCH] [2.9]GKE - allow initial node count to be 0 (#11862)
* fix gke node pool count validation and event emitting from the gkenodepool component
* update gke node count validation and refactor to enable unit tests
* revert vue3 syntax change from cherry pick
---
pkg/gke/components/CruGKE.vue | 20 +++--------
pkg/gke/l10n/en-us.yaml | 2 +-
pkg/gke/util/__tests__/validators.test.ts | 42 +++++++++++++++++++++++
pkg/gke/util/validators.ts | 16 +++++++++
4 files changed, 63 insertions(+), 17 deletions(-)
create mode 100644 pkg/gke/util/__tests__/validators.test.ts
diff --git a/pkg/gke/components/CruGKE.vue b/pkg/gke/components/CruGKE.vue
index 4fb449db539..d6ea9010d54 100644
--- a/pkg/gke/components/CruGKE.vue
+++ b/pkg/gke/components/CruGKE.vue
@@ -34,7 +34,7 @@ import type { getGKEMachineTypesResponse, getGKEServiceAccountsResponse } from '
import type { GKEMachineTypeOption } from '../types/index.d.ts';
import debounce from 'lodash/debounce';
import {
- clusterNameChars, clusterNameStartEnd, requiredInCluster, ipv4WithCidr, ipv4oripv6WithCidr
+ clusterNameChars, clusterNameStartEnd, requiredInCluster, ipv4WithCidr, ipv4oripv6WithCidr, GKEInitialCount
} from '../util/validators';
import { diffUpstreamSpec, syncUpstreamConfig } from '@shell/utils/kontainer';
@@ -322,6 +322,7 @@ export default defineComponent({
nodeIpv4CidrBlockFormat: ipv4WithCidr(this, 'gke.nodeIpv4CidrBlock.label', 'gkeConfig.ipAllocationPolicy.nodeIpv4CidrBlock'),
servicesIpv4CidrBlockFormat: ipv4WithCidr(this, 'gke.servicesIpv4CidrBlock.label', 'gkeConfig.ipAllocationPolicy.servicesIpv4CidrBlock'),
clusterIpv4CidrFormat: ipv4oripv6WithCidr(this, 'gke.clusterIpv4Cidr.label', 'gkeConfig.clusterIpv4Cidr'),
+ initialNodeCount: GKEInitialCount(this),
/**
* The nodepool validators below are performing double duty. When passed directly to an input, the val argument is provided and validated - this generates the error icon in the input component.
* otherwise they're run in the fv mixin and ALL nodepools are validated - this disables the cruresource create button
@@ -339,19 +340,6 @@ export default defineComponent({
return !!this.nodePools.find((pool: GKENodePool) => !valid(pool.config.diskSizeGb || 0) ) ? this.t('gke.errors.diskSizeGb') : null;
},
- initialNodeCount: (val: number) => {
- if (!this.isAuthenticated) {
- return;
- }
- const valid = (input: number) => input >= 1;
-
- if (val || val === 0) {
- return !valid(val) ? this.t('gke.errors.initialNodeCount') : null;
- }
-
- return !!this.nodePools.find((pool: GKENodePool) => !valid(pool.initialNodeCount || 0) ) ? this.t('gke.errors.initialNodeCount') : null;
- },
-
ssdCount: (val: number) => {
if (!this.isAuthenticated) {
return;
@@ -686,7 +674,7 @@ export default defineComponent({
@error="e=>errors=e"
@finish="save"
>
-
+
-
+
key;
+
+describe('validate GKE node group initial count', () => {
+ it.each([
+ [-1, 'gke.errors.initialNodeCount'],
+ [0, null],
+ [2, null],
+ [1000, null],
+ [1001, 'gke.errors.initialNodeCount']
+ ])('should return an error if the initial node count is less than 0 or greater than 1000', (count, errMsg) => {
+ const ctx = {
+ config: { },
+ t: mockTranslation,
+ isAuthenticated: true
+ } as any;
+
+ const res = GKEInitialCount(ctx)(count);
+
+ expect(res).toBe(errMsg);
+ });
+
+ it.each([
+ [[{ initialNodeCount: -1 }], 'gke.errors.initialNodeCount'],
+ [[{ initialNodeCount: 0 }, { initialNodeCount: 1 }], null],
+ [[{ initialNodeCount: 1000 }, { initialNodeCount: 1 }], null],
+ [[{ initialNodeCount: 1001 }, { initialNodeCount: 1 }], 'gke.errors.initialNodeCount']
+
+ ])('should validate each node group in the component context if not called with a specific count value', (nodePools, errMsg) => {
+ const ctx = {
+ config: { },
+ t: mockTranslation,
+ nodePools,
+ isAuthenticated: true
+ } as any;
+
+ const res = GKEInitialCount(ctx)();
+
+ expect(res).toBe(errMsg);
+ });
+});
diff --git a/pkg/gke/util/validators.ts b/pkg/gke/util/validators.ts
index 63841369491..996e19df3de 100644
--- a/pkg/gke/util/validators.ts
+++ b/pkg/gke/util/validators.ts
@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { get } from '@shell/utils/object';
+import { GKENodePool } from '../types';
import ipaddr from 'ipaddr.js';
// no need to try to validate any fields if the user is still selecting a credential and the rest of the form isn't visible
@@ -69,3 +70,18 @@ export const ipv4oripv6WithCidr = (ctx: any, labelKey: string, clusterPath: stri
return isValid || !toValidate.length ? undefined : ctx.t('gke.errors.ipv4Cidr', { key: ctx.t(labelKey) || ctx.t('gke.errors.genericKey') });
};
};
+
+export const GKEInitialCount = (ctx:any) => {
+ return (val?: number) => {
+ if (!ctx.isAuthenticated) {
+ return;
+ }
+ const valid = (input?: number) => (!!input || input === 0) && input >= 0 && input <= 1000;
+
+ if (val || val === 0) {
+ return !valid(val) ? ctx.t('gke.errors.initialNodeCount') : null;
+ }
+
+ return !!ctx.nodePools.find((pool: GKENodePool) => !valid(pool.initialNodeCount) ) ? ctx.t('gke.errors.initialNodeCount') : null;
+ };
+};