Skip to content

Commit bc66dbc

Browse files
authored
Merge pull request #2069 from devtron-labs/feat/secret-eso-dataFrom-template
feat: Secret: ESO - add support for esoSecretData.dataFrom & esoSecretData.template
2 parents d9b8ed3 + 621a52d commit bc66dbc

File tree

9 files changed

+116
-36
lines changed

9 files changed

+116
-36
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"homepage": "/dashboard",
66
"dependencies": {
7-
"@devtron-labs/devtron-fe-common-lib": "0.3.15",
7+
"@devtron-labs/devtron-fe-common-lib": "0.3.19",
88
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
99
"@rjsf/core": "^5.13.3",
1010
"@rjsf/utils": "^5.13.3",

src/Pages/Shared/ConfigMapSecret/ConfigMapSecret.constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export const SECRET_TOAST_INFO = {
4747
CHECK_KEY_SECRET_KEY: 'Please check key and secretKey',
4848
BOTH_STORE_UNAVAILABLE: 'Please provide secretStore or secretStoreRef',
4949
CHECK_KEY_NAME: 'Please check key and name',
50+
BOTH_ESO_DATA_AND_DATA_FROM_AVAILABLE: 'Please use either esoData or esoDataFrom',
51+
BOTH_ESO_DATA_AND_DATA_FROM_UNAVAILABLE: 'Please provide esoData or esoDataFrom',
5052
}
5153

5254
export const CM_SECRET_COMPONENT_NAME = {

src/Pages/Shared/ConfigMapSecret/ConfigMapSecret.reducer.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,27 @@ export const processCurrentData = (
5858
return [{ k: '', v: '', keyError: '', valueError: '' }]
5959
}
6060

61+
const getExternalSubPathValues = (configMapSecretData: CMSecretConfigData) => {
62+
const externalSubPathValues = {
63+
value: configMapSecretData?.data ? Object.keys(configMapSecretData.data).join(',') : '',
64+
error: '',
65+
}
66+
67+
if (!externalSubPathValues.value && configMapSecretData?.esoSubPath) {
68+
externalSubPathValues.value = configMapSecretData.esoSubPath.join(', ')
69+
}
70+
71+
return externalSubPathValues
72+
}
73+
6174
export const initState = (
6275
configMapSecretData,
6376
componentType: CMSecretComponentType,
6477
cmSecretStateLabel: CM_SECRET_STATE,
6578
): ConfigMapState | ConfigMapSecretState => {
6679
const secretInitState =
6780
componentType === CMSecretComponentType.Secret ? getSecretInitState(configMapSecretData) : {}
81+
6882
const initialState = {
6983
isFormDirty: false,
7084
loading: false,
@@ -87,10 +101,7 @@ export const initState = (
87101
selectedType: configMapSecretData?.type ?? 'environment',
88102
volumeMountPath: { value: configMapSecretData?.mountPath ?? configMapSecretData?.defaultMountPath, error: '' },
89103
isSubPathChecked: !!configMapSecretData?.subPath,
90-
externalSubpathValues: {
91-
value: configMapSecretData?.data ? Object.keys(configMapSecretData?.data).join(',') : '',
92-
error: '',
93-
},
104+
externalSubpathValues: getExternalSubPathValues(configMapSecretData),
94105
isFilePermissionChecked: !!configMapSecretData?.filePermission,
95106
configName: {
96107
value: configMapSecretData?.name ?? '',

src/Pages/Shared/ConfigMapSecret/ConfigMapSecret.scss

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
}
5252

5353
&.with-crud-btn {
54-
> .main-content {
54+
>.main-content {
5555
height: calc(100vh - 142px);
5656
}
5757
}
@@ -104,3 +104,9 @@
104104

105105
white-space: pre;
106106
}
107+
108+
.sub-path-checkbox {
109+
.form__checkbox-container {
110+
align-self: flex-start;
111+
}
112+
}

src/Pages/Shared/ConfigMapSecret/ConfigMapSecret.types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ export interface SecretState {
9797
externalType: string
9898
roleARN: ValueWithError
9999
esoData: any
100+
template: Record<string, any>
101+
esoDataFrom: Record<string, any>[]
100102
secretData: any
101103
secretDataYaml: string
102104
codeEditorRadio: string
@@ -196,6 +198,7 @@ export interface ConfigDatum {
196198
overridden: boolean
197199
mountPath?: string
198200
defaultMountPath?: string
201+
esoSubPath?: string[]
199202
}
200203

201204
export interface CMSecret extends Omit<ConfigMapSecretData, 'configData'> {

src/Pages/Shared/ConfigMapSecret/ConfigMapSecretForm.tsx

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -346,13 +346,16 @@ export const ConfigMapSecretForm = React.memo(
346346
} else if (componentType === CMSecretComponentType.Secret && (isHashiOrAWS || isESO)) {
347347
let isValidSecretData = false
348348
if (isESO) {
349-
isValidSecretData = state.esoData?.reduce(
350-
(_isValidSecretData, s) => {
351-
isValidSecretData = _isValidSecretData && !!s?.secretKey && !!s.key
352-
return isValidSecretData
353-
},
354-
!state.secretStore !== !state.secretStoreRef && !!state.esoData?.length,
355-
)
349+
isValidSecretData =
350+
!(state.esoData && state.esoDataFrom) &&
351+
(state.esoData || state.esoDataFrom) &&
352+
!state.secretStore !== !state.secretStoreRef
353+
if (state.esoData && isValidSecretData) {
354+
isValidSecretData = state.esoData.reduce(
355+
(_isValidSecretData, s) => _isValidSecretData && !!s?.secretKey && !!s.key,
356+
isValidSecretData,
357+
)
358+
}
356359
} else {
357360
isValidSecretData = state.secretData.reduce((_isValidSecretData, s) => {
358361
isValidSecretData = _isValidSecretData && !!s.fileName && !!s.name
@@ -361,7 +364,13 @@ export const ConfigMapSecretForm = React.memo(
361364
}
362365

363366
if (!isValidSecretData) {
364-
secretValidationInfoToast(isESO, state.secretStore, state.secretStoreRef)
367+
secretValidationInfoToast({
368+
isESO,
369+
esoData: state.esoData,
370+
secretStore: state.secretStore,
371+
secretStoreRef: state.secretStoreRef,
372+
esoDataFrom: state.esoDataFrom,
373+
})
365374
isFormValid = false
366375
}
367376
}
@@ -395,6 +404,7 @@ export const ConfigMapSecretForm = React.memo(
395404
mountPath: null,
396405
subPath: null,
397406
filePermission: null,
407+
esoSubPath: null,
398408
}
399409
if (
400410
(componentType === CMSecretComponentType.Secret && state.externalType === 'KubernetesSecret') ||
@@ -421,8 +431,14 @@ export const ConfigMapSecretForm = React.memo(
421431
esoData: state.esoData,
422432
secretStoreRef: state.secretStoreRef,
423433
refreshInterval: state.refreshInterval,
434+
// if null don't send these keys which is achieved by `undefined`
435+
esoDataFrom: state.esoDataFrom ?? undefined,
436+
template: state.template ?? undefined,
424437
}
425438
payload.roleARN = state.roleARN.value
439+
if (state.isSubPathChecked && state.externalSubpathValues.value) {
440+
payload.esoSubPath = state.externalSubpathValues.value.replace(/\s+/g, '').split(',')
441+
}
426442
}
427443
}
428444
if (state.selectedType === 'volume') {
@@ -795,18 +811,19 @@ export const ConfigMapSecretForm = React.memo(
795811
)
796812

797813
const renderSubPathCheckBoxContent = (): JSX.Element => (
798-
<span data-testid={`${CM_SECRET_COMPONENT_NAME[componentType]}-sub-path-checkbox`} className="mb-0">
799-
Set SubPath (same as
800-
<a
801-
href="https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath"
802-
className="ml-5 mr-5 anchor"
803-
target="_blank"
804-
rel="noreferrer"
805-
>
806-
subPath
807-
</a>
808-
for volume mount)
809-
<br />
814+
<p data-testid={`${CM_SECRET_COMPONENT_NAME[componentType]}-sub-path-checkbox`} className="flexbox-col m-0">
815+
<p className="m-0">
816+
<span>Set SubPath (same as</span>
817+
<a
818+
href="https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath"
819+
className="ml-5 mr-5 anchor"
820+
target="_blank"
821+
rel="noreferrer"
822+
>
823+
subPath
824+
</a>
825+
<span>for volume mount)</span>
826+
</p>
810827
{state.isSubPathChecked && (
811828
<span className="mb-0 cn-5 fs-11">
812829
{state.external
@@ -827,22 +844,23 @@ export const ConfigMapSecretForm = React.memo(
827844
</a>
828845
</span>
829846
)}
830-
</span>
847+
</p>
831848
)
832849

833850
const renderSubPath = (): JSX.Element => (
834851
<div className="mb-16">
835852
<Checkbox
836853
isChecked={state.isSubPathChecked}
837854
onClick={stopPropagation}
838-
rootClassName="top"
855+
rootClassName={`${state.isSubPathChecked ? 'sub-path-checkbox' : ''}`}
839856
disabled={!draftMode && (state.cmSecretState === CM_SECRET_STATE.INHERITED || readonlyView)}
840857
value={CHECKBOX_VALUE.CHECKED}
841858
onChange={toggleSubpath}
842859
>
843860
{renderSubPathCheckBoxContent()}
844861
</Checkbox>
845862
{(state.externalType === 'KubernetesSecret' ||
863+
isESO ||
846864
(componentType !== CMSecretComponentType.Secret && state.external)) &&
847865
state.isSubPathChecked && (
848866
<div className="mb-16">

src/Pages/Shared/ConfigMapSecret/Secret.utils.tsx

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,22 @@ export const hasESO = (externalType): boolean =>
337337

338338
export const hasProperty = (externalType): boolean => externalType === 'ESO_AWSSecretsManager'
339339

340-
export const secretValidationInfoToast = (isESO, secretStore, secretStoreRef) => {
340+
export const secretValidationInfoToast = ({
341+
isESO,
342+
esoData,
343+
esoDataFrom,
344+
secretStore,
345+
secretStoreRef,
346+
}: {
347+
isESO: boolean
348+
} & Pick<SecretState, 'esoData' | 'esoDataFrom' | 'secretStore' | 'secretStoreRef'>) => {
341349
let errorMessage = ''
342350
if (isESO) {
343-
if (secretStore && secretStoreRef) {
351+
if (esoDataFrom && esoData) {
352+
errorMessage = SECRET_TOAST_INFO.BOTH_ESO_DATA_AND_DATA_FROM_AVAILABLE
353+
} else if (!esoDataFrom && !esoData) {
354+
errorMessage = SECRET_TOAST_INFO.BOTH_ESO_DATA_AND_DATA_FROM_UNAVAILABLE
355+
} else if (secretStore && secretStoreRef) {
344356
errorMessage = SECRET_TOAST_INFO.BOTH_STORE_AVAILABLE
345357
} else if (secretStore || secretStoreRef) {
346358
errorMessage = SECRET_TOAST_INFO.CHECK_KEY_SECRET_KEY
@@ -428,10 +440,18 @@ const handleValidJson = (isESO: boolean, json, dispatch: (action: ConfigMapActio
428440
secretStoreRef: json.secretStoreRef,
429441
refreshInterval: json.refreshInterval,
430442
esoData: null,
443+
esoDataFrom: null,
444+
template: null,
431445
}
432446
if (Array.isArray(json?.esoData)) {
433447
payload.esoData = json.esoData
434448
}
449+
if (Array.isArray(json?.esoDataFrom)) {
450+
payload.esoDataFrom = json.esoDataFrom
451+
}
452+
if (typeof json?.template === 'object' && !Array.isArray(json.template)) {
453+
payload.template = json.template
454+
}
435455
dispatch({
436456
type: ConfigMapActionTypes.multipleOptions,
437457
payload,
@@ -497,18 +517,24 @@ export const getSecretInitState = (configMapSecretData): SecretState => {
497517
}))
498518
jsonForSecretDataYaml = transformSecretDataJSON(jsonForSecretDataYaml)
499519
const tempEsoSecretData =
500-
(configMapSecretData?.esoSecretData?.esoData || []).length === 0 && configMapSecretData?.defaultESOSecretData
520+
(configMapSecretData?.esoSecretData?.esoData || []).length === 0 &&
521+
!configMapSecretData?.esoSecretData?.template &&
522+
!configMapSecretData?.esoSecretData?.esoDataFrom &&
523+
configMapSecretData?.defaultESOSecretData
501524
? configMapSecretData?.defaultESOSecretData
502525
: configMapSecretData?.esoSecretData
503526
const isEsoSecretData: boolean =
504-
(tempEsoSecretData?.secretStore || tempEsoSecretData?.secretStoreRef) && tempEsoSecretData.esoData
527+
(tempEsoSecretData?.secretStore || tempEsoSecretData?.secretStoreRef) &&
528+
(tempEsoSecretData.esoData || tempEsoSecretData.template || tempEsoSecretData.esoDataFrom)
505529
return {
506530
externalType: configMapSecretData?.externalType ?? '',
507531
roleARN: {
508532
value: configMapSecretData?.roleARN ?? '',
509533
error: '',
510534
},
511535
esoData: tempEsoSecretData?.esoData,
536+
template: tempEsoSecretData?.template,
537+
esoDataFrom: tempEsoSecretData?.esoDataFrom,
512538
secretData: tempSecretData,
513539
secretDataYaml: YAMLStringify(jsonForSecretDataYaml),
514540
codeEditorRadio: CODE_EDITOR_RADIO_STATE.DATA,

src/components/app/details/cdDetails/service.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,20 @@ export const prepareConfigMapAndSecretData = (
100100
}
101101
if (rawData['subPath']) {
102102
secretValues['subPath'] = { displayName: 'Set SubPath', value: 'Yes' }
103+
104+
if (rawData.esoSubPath) {
105+
secretValues['subPathValues'] = { displayName: 'SubPath', value: rawData.esoSubPath.join(', ') }
106+
} else if (
107+
rawData.external &&
108+
rawData.externalType === 'KubernetesSecret' &&
109+
historyData.codeEditorValue?.resolvedValue
110+
) {
111+
const resolvedSecretData = JSON.parse(historyData.codeEditorValue.resolvedValue)
112+
secretValues['subPathValues'] = {
113+
displayName: 'SubPath',
114+
value: Object.keys(resolvedSecretData).join(', '),
115+
}
116+
}
103117
}
104118
if (rawData['filePermission']) {
105119
secretValues['filePermission'] = {

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,10 +1346,10 @@
13461346
dependencies:
13471347
"@jridgewell/trace-mapping" "0.3.9"
13481348

1349-
"@devtron-labs/[email protected].15":
1350-
version "0.3.15"
1351-
resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-0.3.15.tgz#280161b85463779fb94ec59a0445144b0ad5b851"
1352-
integrity sha512-PFZOVwZ/yW4UAXki5qS3za2YRLjRczCzw3n/cFE15jGRMX6+1jO7xBAPK7Vm/TyZjPFIsXOXvUcSX3tSOKOyDA==
1349+
"@devtron-labs/[email protected].19":
1350+
version "0.3.19"
1351+
resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-0.3.19.tgz#a1b22552e1e9d998c1d2d6690bf23afcef9253cc"
1352+
integrity sha512-sEUyag/2Ee7KG7JWRuv/IbJzZNQ9AbjqvDTty+VebuXTrCrOAhTUNXz+uGouUQ/x7J/bqDNY/M3d7Zwluw13yQ==
13531353
dependencies:
13541354
"@types/react-dates" "^21.8.6"
13551355
ansi_up "^5.2.1"

0 commit comments

Comments
 (0)