diff --git a/pkg/gke/components/CruGKE.vue b/pkg/gke/components/CruGKE.vue
index 0af4315d545..7e75d8bc072 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"
>
-
+
-
+
@@ -310,7 +310,7 @@ export default defineComponent({
:value="initialNodeCount"
label-key="gke.initialNodeCount.label"
:rules="rules.initialNodeCount"
- @input="$emit('update:initialNodeCount', $event)"
+ @update:value="$emit('update:initialNodeCount', $event)"
/>
@@ -319,7 +319,7 @@ export default defineComponent({
:mode="mode"
:value="maxPodsConstraint"
label-key="gke.maxPodsConstraint.label"
- @input="$emit('update:maxPodsConstraint', $event)"
+ @update:value="$emit('update:maxPodsConstraint', $event)"
/>
@@ -329,19 +329,19 @@ export default defineComponent({
:mode="mode"
:value="autoscaling"
label-key="gke.autoscaling.label"
- @input="$emit('update:autoscaling', $event)"
+ @update:value="$emit('update:autoscaling', $event)"
/>
@@ -351,7 +351,7 @@ export default defineComponent({
type="number"
:value="minNodeCount"
label-key="gke.minNodeCount.label"
- @input="$emit('update:minNodeCount', $event)"
+ @update:value="$emit('update:minNodeCount', $event)"
/>
@@ -360,7 +360,7 @@ export default defineComponent({
type="number"
:value="maxNodeCount"
label-key="gke.maxNodeCount.label"
- @input="$emit('update:maxNodeCount', $event)"
+ @update:value="$emit('update:maxNodeCount', $event)"
/>
@@ -443,7 +443,7 @@ export default defineComponent({
suffix="GB"
:disabled="!isNew"
:rules="rules.diskSizeGb"
- @input="$emit('update:diskSizeGb', $event)"
+ @update:value="$emit('update:diskSizeGb', $event)"
/>
@@ -453,7 +453,7 @@ export default defineComponent({
label-key="gke.localSsdCount.label"
:disabled="!isNew"
:rules="rules.ssdCount"
- @input="$emit('update:localSsdCount', $event)"
+ @update:value="$emit('update:localSsdCount', $event)"
/>
@@ -464,7 +464,7 @@ export default defineComponent({
:mode="mode"
:value="preemptible"
:disabled="!isNew"
- @input="$emit('update:preemptible', $event)"
+ @update:value="$emit('update:preemptible', $event)"
/>
@@ -476,7 +476,7 @@ export default defineComponent({
:disabled="!isNew"
:effect-values="{NO_SCHEDULE:'NoSchedule', PREFER_NO_SCHEDULE: 'PreferNoSchedule', NO_EXECUTE: 'NoExecute'}"
data-testid="gke-taints-comp"
- @input="$emit('update:taints', $event)"
+ @update:value="$emit('update:taints', $event)"
/>
@@ -491,7 +491,7 @@ export default defineComponent({
:title-protip="t('gke.nodeLabels.tooltip')"
:add-label="t('gke.nodeLabels.add')"
:disabled="!isNew"
- @input="$emit('update:labels', $event)"
+ @update:value="$emit('update:labels', $event)"
/>
@@ -502,7 +502,7 @@ export default defineComponent({
:value="tags"
:title="t('gke.tags.label')"
:add-label="t('gke.tags.add')"
- @input="$emit('update:tags', $event)"
+ @update:value="$emit('update:tags', $event)"
/>
@@ -511,7 +511,7 @@ export default defineComponent({
:mode="mode"
:value="oauthScopes"
:disabled="!isNew"
- @input="$emit('update:oauthScopes', $event)"
+ @update:value="$emit('update:oauthScopes', $event)"
/>
diff --git a/pkg/gke/l10n/en-us.yaml b/pkg/gke/l10n/en-us.yaml
index 0d913698afa..4d72cdee509 100644
--- a/pkg/gke/l10n/en-us.yaml
+++ b/pkg/gke/l10n/en-us.yaml
@@ -83,7 +83,7 @@ gke:
clusterNameStartEnd: Cluster name must startd and end with a letter or number.
diskSizeGb: Disk Size must be at least 10GB.
genericKey: Value
- initialNodeCount: Initial Node Count must be at least 1.
+ initialNodeCount: Initial Node Count must be at least 0, and no greater than 1000.
ipv4Cidr: '{key} must be a valid ipv4 cidr range.'
ipv4oripv6: '{key} must be a valid ipv6 or ipv4 CIDR address'
minMaxNodeCount: Minimum Node Count cannot exceed Maximum Node Count.
diff --git a/pkg/gke/util/__tests__/validators.test.ts b/pkg/gke/util/__tests__/validators.test.ts
new file mode 100644
index 00000000000..f7dc4459433
--- /dev/null
+++ b/pkg/gke/util/__tests__/validators.test.ts
@@ -0,0 +1,42 @@
+import { GKEInitialCount } from '../validators';
+
+const mockTranslation = (key: string) => 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;
+ };
+};