🌳
pt0/deployF/k8sF/k8sSecF.mts
1import * as _ from 'lodash-es'
2import { getPlainNoMappedSec, type secretNameType } from '../../serverF/secretsF/getPlainSecAI.mts'
7/** Minimal Secret resource for delete action - no data needed, just metadata for k8s to identify resource */
8export const secretStubForDelete = (name: string) => ({
9 apiVersion: 'v1' as const,
10 kind: 'Secret' as const,
11 metadata: {name},
12})
14/** Minimal Deployment resource for delete action - includes replicas/strategy to pass guard checks */
15export const deployStubForDelete = (name: string) => ({
16 apiVersion: 'apps/v1' as const,
17 kind: 'Deployment' as const,
18 metadata: {name},
19 spec: {replicas: 1, strategy: {type: 'Recreate' as const}},
20})
22/** When a feature is disabled and we're deleting, return stubs for idempotent cleanup of its resources */
23export const cleanupResOnDelete = ({action, enabled, secNames = [], deployNames = []}: {
24 action: string, enabled: boolean, secNames?: string[], deployNames?: string[],
25}) => {
26 if (enabled || action !== 'delete') return [] as ReturnType<typeof secretStubForDelete>[]
27 return [...secNames.map(secretStubForDelete), ...deployNames.map(deployStubForDelete)]
30export const secretTemplate = ({
31 name, namespace, secretsH
32}: {
33 name: string
34 namespace?: string
35 secretsH: Record<string, string>
36}) => {
38 const data = _.mapValues(secretsH, (val: string, key: string) => {
39 assertString(val, {key})
40 return Buffer.from(val).toString('base64')
41 })
43 return {
44 apiVersion: 'v1',
45 kind: 'Secret',
46 metadata: {
47 name, namespace,
48 },
49 data,
50 }
53export const secretNameToK8sResName = (name: string) => ['secrets2', name].join('-').replace(/[_\.]/g,'-').toLowerCase()
55// volume names are DNS labels (≤63 chars) while secret names are subdomains (≤253): long secret
56// names fit as a secret but overflow as a volume name. keep them decoupled — hash-suffix truncate.
57export const secretNameToK8sVolName = (name: string) => {
58 const resName = secretNameToK8sResName(name)
59 if (resName.length <= 63) return resName
60 return resName.slice(0, 63 - 10) + '-' + calcHash(resName).slice(0, 9)
63export const secretFileTemplate = ({name, kubeName}: {name: secretNameType, kubeName?: string}) => {
64 const secretVal = getPlainNoMappedSec(name).trim()
65 assertDefined(secretVal)
67 const resolvedKubeName = kubeName ?? secretNameToK8sResName(name)
69 const secretsH: Record<string, string> = {[name]: secretVal}
71 return secretTemplate({
72 name: resolvedKubeName,
73 secretsH,
74 })
77/** For secrets used with envFrom.secretRef - parses JSON file into individual env var keys */
78export const secretEnvTemplate = ({name, kubeName}: {name: secretNameType, kubeName?: string}) => {
79 const secretVal = getPlainNoMappedSec(name).trim()
80 assertDefined(secretVal)
82 const resolvedKubeName = kubeName ?? secretNameToK8sResName(name)
84 const secretsH: Record<string, string> = JSON.parse(secretVal)
86 return secretTemplate({
87 name: resolvedKubeName,
88 namespace: '',
89 secretsH,
90 })