// K8s ServiceAccount Schema - 由 ConfTemplate 生成 // 生成时间: 自动生成 export const k8sServiceAccountSchema = { id: 'k8s-serviceaccount', name: 'K8s ServiceAccount', icon: 'User', category: '云原生', description: 'Kubernetes 服务账户,用于 Pod 的身份认证', format: 'yaml', fileName: 'serviceaccount.yaml', groups: [ { title: '基础信息', fields: [ { key: 'name', label: 'ServiceAccount 名称', type: 'text', placeholder: 'my-serviceaccount', default: 'my-serviceaccount', required: true, tip: '将用作 ServiceAccount 的 metadata.name', }, { key: 'namespace', label: '命名空间', type: 'text', placeholder: 'default', default: 'default', }, ], }, { title: '账户配置', fields: [ { key: 'automountServiceAccountToken', label: '自动挂载 Token', type: 'switch', default: true, tip: '自动将 API Token 挂载到使用此 ServiceAccount 的 Pod', }, { key: 'enableImagePullSecrets', label: '配置镜像拉取 Secret', type: 'switch', default: false, tip: '为此 ServiceAccount 配置私有镜像仓库认证', }, { key: 'imagePullSecretName', label: '镜像拉取 Secret 名称', type: 'text', placeholder: 'my-registry-secret', default: '', dependsOn: { key: 'enableImagePullSecrets', value: true }, tip: '已存在的 docker-registry Secret 名称', }, ], }, ], } function yamlScalar(v) { if (v === null || v === undefined) return '' if (typeof v === 'number' || typeof v === 'boolean') return String(v) const s = String(v) if (/[:#\n"'`]|^[\s\-]|[\s]$/.test(s) || /^(true|false|null|yes|no|on|off|~)$/i.test(s)) { return JSON.stringify(s) } return s } function isEmptyMapping(o) { if (!o || typeof o !== 'object' || Array.isArray(o)) return false return Object.values(o).every(v => v === null || v === undefined || v === '' || (typeof v === 'object' && isEmptyMapping(v))) } function toYaml(obj, baseIndent = '') { const lines = [] for (const [key, value] of Object.entries(obj)) { if (value === null || value === undefined || value === '') continue if (Array.isArray(value)) { const items = value.filter(v => v !== null && v !== undefined && v !== '') if (!items.length) continue lines.push(`${baseIndent}${key}:`) for (const item of items) { if (item && typeof item === 'object' && !Array.isArray(item)) { if (isEmptyMapping(item)) continue const entries = Object.entries(item).filter(([, v]) => v !== null && v !== undefined && v !== '') if (!entries.length) continue const childIndent = baseIndent + ' ' const subAllIndent = childIndent + ' ' const subObj = {} for (const [k, v] of entries) subObj[k] = v const subRendered = toYaml(subObj, subAllIndent) const subLines = subRendered.split('\n') if (subLines[0].startsWith(subAllIndent)) { subLines[0] = childIndent + '- ' + subLines[0].slice(subAllIndent.length) } else { subLines[0] = childIndent + '- ' + subLines[0].trimStart() } lines.push(...subLines) } else { lines.push(`${baseIndent} - ${yamlScalar(item)}`) } } } else if (typeof value === 'object') { if (isEmptyMapping(value)) { lines.push(`${baseIndent}${key}: {}`) continue } lines.push(`${baseIndent}${key}:`) const childIndent = baseIndent + ' ' lines.push(toYaml(value, childIndent)) } else { lines.push(`${baseIndent}${key}: ${yamlScalar(value)}`) } } return lines.join('\n') } export function generateK8sServiceAccountYaml(config) { const sa = { apiVersion: 'v1', kind: 'ServiceAccount', metadata: { name: config.name, namespace: config.namespace, }, } if (config.automountServiceAccountToken === false) { sa.automountServiceAccountToken = false } if (config.enableImagePullSecrets && config.imagePullSecretName) { sa.imagePullSecrets = [{ name: config.imagePullSecretName }] } const header = `# K8s ServiceAccount - 由 ConfTemplate 生成 # 生成时间: ${new Date().toLocaleString('zh-CN')} # 部署命令: kubectl apply -f ${config.fileName || 'serviceaccount.yaml'} ` return header + '\n' + toYaml(sa) }