From 4e85760c85a1cb8c45236acae48b8d388da5cd5c Mon Sep 17 00:00:00 2001 From: Ashvin S Date: Tue, 17 Dec 2024 10:52:21 +0530 Subject: [PATCH] INFRA-4076 | Ashvin | Add availability zone field (#730) * INFRA-4076 | Ashvin | Add availability zone field This will let users choose the AWS AZ they want to deploy their services in. Backend and kutegen already supported this feature, see this for details https://github.com/navi-infra/kutegen/pull/218 * INFRA-4076 | Ashvin | Show AdvancedDeploymentConfigurationCard in all environments * INFRA-4076 | Ashvin | Add all AZ to new manifest --- Dockerfile | 4 +- src/components/manifest/Form.tsx | 2 +- src/components/manifest/constants.ts | 1 - src/coreform/FormUtil.tsx | 18 +---- .../deployment/DeploymentBasicTab.tsx | 78 ++++++++++++------- src/coreform/deployment/constants.tsx | 4 + src/helper/ChangeRequest.ts | 56 ++++--------- src/helper/changeRequestUtils.ts | 8 -- src/models/Manifest.ts | 4 +- src/models/ManifestValidationSchema.ts | 16 ++-- src/types/Deployment.d.ts | 7 -- 11 files changed, 85 insertions(+), 113 deletions(-) delete mode 100644 src/helper/changeRequestUtils.ts diff --git a/Dockerfile b/Dockerfile index 6c02984..0ed3f5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,6 @@ FROM 193044292705.dkr.ecr.ap-south-1.amazonaws.com/common/node:18.15.0-alpine3.16 as build WORKDIR /app COPY . /app -RUN yarn upgrade -RUN yarn cache clean RUN yarn install RUN yarn build @@ -31,4 +29,4 @@ ENTRYPOINT ["/entrypoint.sh"] USER 4000 -CMD ["nginx", "-g", "daemon off;"] +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/src/components/manifest/Form.tsx b/src/components/manifest/Form.tsx index 4333304..1e53c3a 100644 --- a/src/components/manifest/Form.tsx +++ b/src/components/manifest/Form.tsx @@ -213,7 +213,7 @@ const Form = (props: any) => { .forEach(breached => { const path = breached.path .split('/') - .filter(part => part.length > 0 && part !== '*') + .filter(part => part.length > 0) .map(part => (isNaN(part) ? part : parseInt(part, 10))); const pathKey = breached.limitPath; diff --git a/src/components/manifest/constants.ts b/src/components/manifest/constants.ts index 2227976..d59f12b 100644 --- a/src/components/manifest/constants.ts +++ b/src/components/manifest/constants.ts @@ -46,5 +46,4 @@ export const defaultValues = { '/deployment/instance/minMemory': '512Mi', '/deployment/instance/cpu': 5, '/deployment/instance/memory': '4095Mi', - '/deployment/allowEndpoint': [], }; diff --git a/src/coreform/FormUtil.tsx b/src/coreform/FormUtil.tsx index 7c79527..9ce355c 100644 --- a/src/coreform/FormUtil.tsx +++ b/src/coreform/FormUtil.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { TabPanelProps, TabType } from './Types'; import { FormikProps } from 'formik'; import { AutoCompleteOption } from '@src/types/Types'; -import { CiliumServiceEntry, ZoneElement } from '@src/types/Deployment'; +import { ZoneElement } from '@src/types/Deployment'; import * as _m from '../models/Manifest'; import { clusterZoneMapping, @@ -110,19 +110,3 @@ export const getClusters = (environment: string) => { } return []; }; - -export const populateServiceEntriesOptions = ( - preChangedServiceEntries: CiliumServiceEntry[] | undefined, - serviceEntries: CiliumServiceEntry[], -) => { - const serviceEntriesOptionsMap = preChangedServiceEntries?.reduce((acc, serviceEntry) => { - acc[`${serviceEntry.host}:${serviceEntry.port}`] = serviceEntry?.hashedIdentifier; - return acc; - }, {}); - return serviceEntries?.map(serviceEntry => { - return { - ...serviceEntry, - hashedIdentifier: serviceEntriesOptionsMap?.[`${serviceEntry.host}:${serviceEntry.port}`], - }; - }); -}; diff --git a/src/coreform/deployment/DeploymentBasicTab.tsx b/src/coreform/deployment/DeploymentBasicTab.tsx index 36b6729..6391193 100644 --- a/src/coreform/deployment/DeploymentBasicTab.tsx +++ b/src/coreform/deployment/DeploymentBasicTab.tsx @@ -1,17 +1,17 @@ -import React, { FC } from 'react'; +import * as React from 'react'; +import { FC, useEffect, useState } from 'react'; import Grid from '@material-ui/core/Grid'; import * as _m from '../../models/Manifest'; import { FormikTextField } from '../../components/common/FormikTextField'; import { FormikAutocomplete } from '../../components/common/FormikAutocomplete'; import { populateServiceEntriesOptions, toMenuItems } from '../FormUtil'; -import { useFormikContext, Field, setIn, useField } from 'formik'; -import { makeStyles, TableCell, styled, FormControlLabel, Tooltip } from '@material-ui/core'; +import { Field, useField, useFormikContext } from 'formik'; +import { FormControlLabel, makeStyles, styled, TableCell, Tooltip } from '@material-ui/core'; import { FormikTable } from '../../components/common/FormikTable'; import HealthCheckCard from './HealthCheckCard'; import { cardStyles } from '../Styles'; import AutoscalingCard from './AutoscalingCard'; import CardLayout from '../../components/common/CardLayout'; -import { useEffect, useState } from 'react'; import { httpClient } from '../../helper/api-client'; import { FormikCheckbox } from '../../components/common/FormikCheckbox'; import { Cluster } from '../../constants/Cluster'; @@ -20,10 +20,15 @@ import { Environment } from '../../constants/Environment'; import { InfoOutlined } from '@material-ui/icons'; import WarningDialog from '../../components/common/WarningDialog'; import { Manifest } from '@src/types/Manifest'; -import { ciliumEnabledCluster } from '@src/coreform/deployment/constants'; -import { CiliumServiceEntry } from '@src/types/Deployment'; +import { + AP_SOUTH_1A, + AP_SOUTH_1B, + AP_SOUTH_1C, + ciliumEnabledCluster, +} from '@src/coreform/deployment/constants'; import { useSelector } from 'react-redux'; import { RootState } from '@src/store'; +import FormikMultiSelect from '@components/common/FormikMultiSelect'; const useStyles = makeStyles({ ...cardStyles, @@ -54,6 +59,9 @@ const useStyles = makeStyles({ infoIcon: { verticalAlign: 'middle', }, + multiSelectMarginTop: { + marginTop: 10, + }, }); const MarginedFormControlLabel = styled(FormControlLabel)({ @@ -232,17 +240,21 @@ function renderGpu(team: string) { } function renderSpotNodeCard(environment: string) { - if (spotNodeEnabledEnvironments.has(environment)) { - return ; - } else { - return <>; - } + return ; } const disablegRPCCheckbox = (values: any, i: number) => { return values.deployment.exposedPorts[i].name === 'metrics'; }; -const SpotNodeCard = () => { + +interface AdvancedDeploymentConfigurationProps { + environment: string; +} + +const AdvancedDeploymentConfigurationCard = ( + props: AdvancedDeploymentConfigurationProps, +): React.JSX.Element => { + const classes = useStyles(); const { values, setFieldValue }: { values: any; setFieldValue: any } = useFormikContext(); const [isSpotNodeEnabled, setIsSpotNodeEnabled] = React.useState( values.deployment.scheduleOnSpotNodes, @@ -262,20 +274,34 @@ const SpotNodeCard = () => { }, [isSpotNodeEnabled, gpu.value]); return ( - - - - - } - label={'Schedule workload on spot nodes'} - /> - + <> + + + {toMenuItems([AP_SOUTH_1A, AP_SOUTH_1B, AP_SOUTH_1C])} + + {spotNodeEnabledEnvironments.has(props.environment) ? ( + + + + } + label={'Schedule workload on spot nodes'} + /> + ) : ( + <> + )} + + ); }; diff --git a/src/coreform/deployment/constants.tsx b/src/coreform/deployment/constants.tsx index ef1a66a..eb5562d 100644 --- a/src/coreform/deployment/constants.tsx +++ b/src/coreform/deployment/constants.tsx @@ -98,3 +98,7 @@ export const ciliumEnabledCluster = new Set([ Cluster.LENDING_PROD, Cluster.IAPL_PROD, ]); + +export const AP_SOUTH_1A = 'ap-south-1a'; +export const AP_SOUTH_1B = 'ap-south-1b'; +export const AP_SOUTH_1C = 'ap-south-1c'; diff --git a/src/helper/ChangeRequest.ts b/src/helper/ChangeRequest.ts index 1cb8565..3f9b8b2 100644 --- a/src/helper/ChangeRequest.ts +++ b/src/helper/ChangeRequest.ts @@ -1,6 +1,5 @@ import _ from 'lodash'; import { toast } from 'react-toastify'; -import { getHashedIdentifier } from './changeRequestUtils'; interface ValueWithWeight { type: string; @@ -19,18 +18,6 @@ const isObject = input => { ); }; -export const getBreachPath = ( - manifestPath: string, - key: string, - index: number, - hasHashedIdentifier: boolean, -): string => { - if (hasHashedIdentifier) { - return `${manifestPath}/${key}/*`; - } - return `${manifestPath}/${key}/${index}`; -}; - export const parseValue = str => { const len = str.length; const unit = str.substring(len - 2, len); @@ -169,16 +156,9 @@ const safeMapAccess = (preManifestObject, key) => { return preManifestObject[key]; }; -const safeArrayAccess = (array, identifier: number | string) => { - if (!Array.isArray(array)) { - return undefined; - } - if (typeof identifier === 'number') { - return array[identifier]; - } else if (typeof identifier === 'string') { - return array?.find(obj => obj.hashedIdentifier == identifier); - } - return undefined; +const safeArrayAccess = (array, idx) => { + if (isUndefined(array)) return undefined; + return array[idx]; }; const getBreachedLimits = ( @@ -196,22 +176,17 @@ const getBreachedLimits = ( const currentManifestObj = manifestObject[key]; const currentPreManifestObj = safeMapAccess(preManifestObject, key); if (isTarget(currentLimitObj)) { - if (currentLimitObj.hasOwnProperty('forEach') && currentManifestObj?.length) { + if (currentLimitObj.hasOwnProperty('forEach') && currentManifestObj?.length !== undefined) { for (let i = 0; i < currentManifestObj.length; i++) { const obj = currentManifestObj[i]; - const hasHashedIdentifier = currentLimitObj['hasHashedIdentifier'] == true; - const isBreach = - hasHashedIdentifier || - isChangeRequestRequired( - currentLimitObj['forEach'], - obj, - currentPreManifestObj, - manifestEnv, - ); - const path = getBreachPath(manifestPath, key, i, hasHashedIdentifier); - const identifier = hasHashedIdentifier ? getHashedIdentifier(obj, key) : i; - console.log(`path:${path}, limitPath:${limitPath} key:${key} identifier:${identifier}`); - if (isBreach && !_.isEqual(obj, safeArrayAccess(currentPreManifestObj, identifier))) { + const isBreach = isChangeRequestRequired( + currentLimitObj['forEach'], + obj, + currentPreManifestObj, + manifestEnv, + ); + const path = `${manifestPath}/${key}/${i}`; + if (isBreach && !_.isEqual(obj, safeArrayAccess(currentPreManifestObj, i))) { const diffObj = { op: getOp(currentPreManifestObj), path: path, @@ -219,7 +194,7 @@ const getBreachedLimits = ( value: obj, }; if (replaceWithPreviousValue) { - manifestObject[key] = safeMapAccess(preManifestObject, key); + manifestObject[key] = safeArrayAccess(preManifestObject, key); } breaches = breaches.concat(diffObj); } @@ -233,6 +208,7 @@ const getBreachedLimits = ( ); const path = `${manifestPath}/${key}`; if (isBreach && currentManifestObj !== currentPreManifestObj) { + console.log(`${path} is changed`); const obj = { op: getOp(currentPreManifestObj), path: path, @@ -240,11 +216,12 @@ const getBreachedLimits = ( value: currentManifestObj, }; if (replaceWithPreviousValue) { - manifestObject[key] = safeMapAccess(preManifestObject, key); + manifestObject[key] = safeArrayAccess(preManifestObject, key); } breaches = breaches.concat(obj); } } + if (!isObject(currentLimitObj)) return breaches; for (const nextKey in currentLimitObj) { const nextManifestPath = `${manifestPath}/${key}`; @@ -315,7 +292,6 @@ const getBreachedValues = ( ), ); } - console.log('Breached values:', breaches); return breaches; }; diff --git a/src/helper/changeRequestUtils.ts b/src/helper/changeRequestUtils.ts deleted file mode 100644 index 7d08a2c..0000000 --- a/src/helper/changeRequestUtils.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const getHashedIdentifier = (obj, key: string): string => { - switch (key) { - case 'allowEndpoint': - return btoa(`${obj?.host}:${obj?.port}`); - default: - return ''; - } -}; diff --git a/src/models/Manifest.ts b/src/models/Manifest.ts index 010d73e..c8f14b3 100644 --- a/src/models/Manifest.ts +++ b/src/models/Manifest.ts @@ -12,6 +12,7 @@ import { DEFAULT_ELASTIC_SEARCH_VERSION } from '../constants/ElasticSearchConsta import { LATEST_EC_VERSION } from '@src/coreform/elasticcache/constant'; import { FormType } from '@components/manifest/ShowSelectedForm'; import { DefaultFlinkAlerts } from '@src/coreform/flink/DefaultAlerts'; +import { AP_SOUTH_1A, AP_SOUTH_1B, AP_SOUTH_1C } from '@src/coreform/deployment/constants'; // lodash like path for resources in the manifest object export const path = { @@ -332,6 +333,7 @@ export const addDeployment = (manifest: any) => { }, isDeployed: false, isVpaEnabled: true, + zoneAffinity: [AP_SOUTH_1A, AP_SOUTH_1B, AP_SOUTH_1C], perfUtility: { mockServer: false, postgresServer: false, @@ -425,7 +427,7 @@ export const newOutboundConnectivity = () => { }; export const newAllowEndpoint = () => { - return { host: '', port: '', hashedIdentifier: '' }; + return { host: '', port: '' }; }; export const newHpaCronJob = () => { return { name: '', schedule: '' }; diff --git a/src/models/ManifestValidationSchema.ts b/src/models/ManifestValidationSchema.ts index 82a555e..e5a6f44 100644 --- a/src/models/ManifestValidationSchema.ts +++ b/src/models/ManifestValidationSchema.ts @@ -725,15 +725,12 @@ const perfValidationSchema = yup.object({ }), }); -const allowEndpointValidationSchema = yup - .array() - .of( - yup.object({ - host: yup.string().required('is Required'), - port: yup.string().required('is Required'), - }), - ) - .unique('Host and port combination should be unique', ({ host, port }) => `${host}:${port}`); +const allowEndpointValidationSchema = yup.array().of( + yup.object({ + host: yup.string().required('is Required'), + port: yup.string().required('is Required'), + }), +); const scyllaDbValidationSchema = yup.object({ name: yup @@ -806,6 +803,7 @@ const deploymentValidationSchema = yup.object({ efs: efsValidationSchema.default(undefined), fsx: fsxValidationSchema.default(undefined), perfUtility: perfValidationSchema.default(undefined), + zoneAffinity: yup.array().of(yup.string().required('is Required')).min(1), }); const docdbValidationScheme = yup.object({ diff --git a/src/types/Deployment.d.ts b/src/types/Deployment.d.ts index 19a1a67..c764ba0 100644 --- a/src/types/Deployment.d.ts +++ b/src/types/Deployment.d.ts @@ -32,7 +32,6 @@ export interface Deployment { instance: Instance; scheduleOnSpotNodes: boolean; isVpaEnabled: boolean; - allowEndpoint?: CiliumServiceEntry[]; } export interface ZoneElement { zone: string; @@ -56,9 +55,3 @@ export type LbEndpointProps = { getHostedZone: (index: number) => AutoCompleteOption; setHostedZone: (index: number, value: string) => void; }; - -export type CiliumServiceEntry = { - host: string; - port: string; - hashedIdentifier: string; -};