mirror of https://github.com/rancher/dashboard.git
216 lines
7.9 KiB
TypeScript
216 lines
7.9 KiB
TypeScript
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
/**
|
|
* These validation rules are used by the form validation mixin but work a little differently from the validators defined in @shell/utils/validators/formRules
|
|
* Due to current limitations of the fv mixin
|
|
*/
|
|
|
|
import { get, set } from '@shell/utils/object';
|
|
import { LoadBalancerSku, OutboundType, AKSNodePool } from '../types';
|
|
|
|
// 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
|
|
export const needsValidation = (ctx: any): Boolean => {
|
|
return !!ctx.config.azureCredentialSecret && !!ctx.config.resourceLocation;
|
|
};
|
|
|
|
export const requiredTranslation = (ctx: any, labelKey = 'Value'): String => {
|
|
return ctx.t('validation.required', { key: ctx.t(labelKey) });
|
|
};
|
|
|
|
export const requiredInCluster = (ctx: any, labelKey: string, clusterPath: string) => {
|
|
return () :String | undefined => {
|
|
return needsValidation(ctx) && clusterPath && !get(ctx.normanCluster, clusterPath) ? requiredTranslation(ctx, labelKey) : undefined;
|
|
};
|
|
};
|
|
|
|
// cluster name
|
|
// Alphanumerics, underscores, and hyphens. Start and end with alphanumeric.
|
|
// https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules#microsoftcontainerservice
|
|
export const clusterNameChars = (ctx: any ) => {
|
|
return () :string | undefined => {
|
|
const { name = '' } = get(ctx, 'normanCluster');
|
|
const nameIsValid = name.match(/^[a-zA-Z0-9\-_]*$/);
|
|
|
|
return !needsValidation(ctx) || nameIsValid ? undefined : ctx.t('aks.errors.clusterName.chars');
|
|
};
|
|
};
|
|
|
|
export const clusterNameStartEnd = (ctx: any) => {
|
|
return () :string | undefined => {
|
|
const { name = '' } = get(ctx, 'normanCluster');
|
|
const nameIsValid = (!!name.match(/^([A-Z]|[a-z]|[0-9])+.*([A-Z]|[a-z]|[0-9])+$/) || !name.length);
|
|
|
|
return !needsValidation(ctx) || nameIsValid ? undefined : ctx.t('aks.errors.clusterName.startEnd');
|
|
};
|
|
};
|
|
|
|
export const clusterNameLength = (ctx: any) => {
|
|
return () : string | undefined => {
|
|
const { name = '' } = get(ctx, 'normanCluster');
|
|
const isValid = name.length <= 63;
|
|
|
|
return isValid ? undefined : ctx.t('aks.errors.clusterName.length');
|
|
};
|
|
};
|
|
|
|
export const resourceGroupLength = (ctx: any, labelKey:string, clusterPath:string) => {
|
|
return () :string | undefined => {
|
|
const resourceGroup = get(ctx.normanCluster, clusterPath) || '';
|
|
|
|
const isValid = resourceGroup.length <= 80;
|
|
|
|
return isValid ? undefined : ctx.t('aks.errors.resourceGroup.length', { key: ctx.t(labelKey) });
|
|
};
|
|
};
|
|
|
|
// letters, numbers, -, _, (, ), ., and unicode UppercaseLetter, LowercaseLetter, TitlecaseLetter, ModifierLetter, OtherLetter
|
|
// https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules#microsoftresources
|
|
export const resourceGroupChars = (ctx: any, labelKey:string, clusterPath:string) => {
|
|
return () :string | undefined => {
|
|
const resourceGroup = get(ctx.normanCluster, clusterPath) || '';
|
|
const isValid = resourceGroup.match(/^[A-Za-z0-9\p{Lu}\p{Ll}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\.\-_(\)]*$/);
|
|
|
|
return isValid || !resourceGroup.length ? undefined : ctx.t('aks.errors.resourceGroup.chars', { key: ctx.t(labelKey) });
|
|
};
|
|
};
|
|
|
|
export const resourceGroupEnd = (ctx: any, labelKey:string, clusterPath:string) => {
|
|
return () :string | undefined => {
|
|
const resourceGroup = get(ctx.normanCluster, clusterPath) || '';
|
|
|
|
const isValid = !resourceGroup.match(/^.*\.+$/u);
|
|
|
|
return isValid ? undefined : ctx.t('aks.errors.resourceGroup.periodEnd', { key: ctx.t(labelKey) });
|
|
};
|
|
};
|
|
|
|
// ipv4 regex from https://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp
|
|
|
|
// ipv4 with or without cidr
|
|
export const ipv4WithOrWithoutCidr = (ctx: any) => {
|
|
// this is used for an array of inputs; each input is passed in here to validate
|
|
return (ip = '') :string | undefined => {
|
|
const isValid = ip.match(/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/);
|
|
|
|
return isValid || !ip.length ? undefined : ctx.t('aks.errors.authorizedIpRanges');
|
|
};
|
|
};
|
|
|
|
export const ipv4WithoutCidr = (ctx: any, labelKey: string, clusterPath: string) => {
|
|
return () :string | undefined => {
|
|
const toValidate = get(ctx.normanCluster, clusterPath) || '';
|
|
|
|
const isValid = toValidate.match(/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/);
|
|
|
|
return isValid || !toValidate.length ? undefined : ctx.t('aks.errors.ipv4', { key: ctx.t(labelKey) });
|
|
};
|
|
};
|
|
|
|
export const ipv4WithCidr = (ctx: any, labelKey: string, clusterPath: string) => {
|
|
return () :string | undefined => {
|
|
const toValidate = get(ctx.normanCluster, clusterPath) || '';
|
|
|
|
const isValid = toValidate.match(/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(\/([0-9]|[1-2][0-9]|3[0-2]))$/);
|
|
|
|
return isValid || !toValidate.length ? undefined : ctx.t('aks.errors.ipv4Cidr', { key: ctx.t(labelKey) });
|
|
};
|
|
};
|
|
|
|
export const outboundTypeUserDefined = (ctx: any, labelKey: string, clusterPath: string) => {
|
|
return () :string | undefined => {
|
|
const outboundType = get(ctx.normanCluster, clusterPath) as OutboundType;
|
|
const loadBalancerSku = get(ctx.normanCluster, 'aksConfig.loadBalancerSku') as LoadBalancerSku;
|
|
|
|
if (loadBalancerSku !== 'Standard' && outboundType === 'UserDefinedRouting') {
|
|
return ctx.t('aks.errors.outboundType');
|
|
}
|
|
|
|
return undefined;
|
|
};
|
|
};
|
|
|
|
// https://learn.microsoft.com/en-us/azure/aks/private-clusters?tabs=azure-portal#configure-a-private-dns-zone
|
|
export const privateDnsZone = (ctx: any, labelKey: string, clusterPath: string) => {
|
|
return () :string | undefined => {
|
|
const toValidate = (get(ctx.normanCluster, clusterPath) || '').toLowerCase();
|
|
const subscriptionRegex = /^\/subscriptions\/.+\/resourcegroups\/.+\/providers\/microsoft\.network\/privatednszones\/([a-zA-Z0-9-]{1,32}\.){0,32}private(link){0,1}\.[a-zA-Z0-9]+\.azmk8s\.io$/;
|
|
const isValid = toValidate.match(subscriptionRegex) || toValidate === 'system';
|
|
|
|
return isValid || !toValidate.length ? undefined : ctx.t('aks.errors.privateDnsZone', {}, true);
|
|
};
|
|
};
|
|
|
|
export const nodePoolNames = (ctx: any) => {
|
|
return (poolName:string) :string | undefined => {
|
|
let allAvailable = true;
|
|
|
|
const isValid = (name:string) => name.match(/^[a-z]+[a-z0-9]*$/) && name.length <= 12;
|
|
|
|
if (poolName || poolName === '') {
|
|
return isValid(poolName) ? undefined : ctx.t('aks.errors.poolName');
|
|
} else {
|
|
ctx.nodePools.forEach((pool: AKSNodePool) => {
|
|
const name = pool.name || '';
|
|
|
|
if (!isValid(name)) {
|
|
set(pool._validation, '_validName', false);
|
|
|
|
allAvailable = false;
|
|
} else {
|
|
set(pool._validation, '_validName', true);
|
|
}
|
|
});
|
|
if (!allAvailable) {
|
|
return ctx.t('aks.errors.poolName');
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
export const nodePoolNamesUnique = (ctx: any) => {
|
|
return () :string | undefined => {
|
|
const poolNames = (ctx.nodePools || []).map((pool: AKSNodePool) => pool.name);
|
|
|
|
const hasDuplicates = poolNames.some((name: string, idx: number) => poolNames.indexOf(name) !== idx);
|
|
|
|
if (hasDuplicates) {
|
|
return ctx.t('aks.errors.poolNamesUnique');
|
|
}
|
|
};
|
|
};
|
|
|
|
export const nodePoolCount = (ctx:any) => {
|
|
return (count?: number, canBeZero = false) => {
|
|
let min = 1;
|
|
let errMsg = ctx.t('aks.errors.poolCount');
|
|
|
|
if (canBeZero) {
|
|
min = 0;
|
|
errMsg = ctx.t('aks.errors.poolUserCount');
|
|
}
|
|
if (count || count === 0) {
|
|
return count >= min ? undefined : errMsg;
|
|
} else {
|
|
let allValid = true;
|
|
|
|
ctx.nodePools.forEach((pool: AKSNodePool) => {
|
|
const { count = 0, mode } = pool;
|
|
|
|
if (mode === 'User') {
|
|
min = 0;
|
|
} else {
|
|
min = 1;
|
|
}
|
|
|
|
if (count < min) {
|
|
pool._validation['_validCount'] = false;
|
|
allValid = false;
|
|
} else {
|
|
pool._validation['_validCount'] = true;
|
|
}
|
|
});
|
|
|
|
return allValid ? undefined : ctx.t('aks.errors.poolCount');
|
|
}
|
|
};
|
|
};
|