🌳
pt0/deployF/k8sF/initialSetupF/certmanager/certManagerCoreF.mts
3import * as _ from 'lodash-es'
9import { getKlusterCtx, type KubeResource } from '../../ctxF/klusterCtxF.mts'
19const clusterIssuerTmpl = ({name, email, cfApiKeySecretName, cluster_name}: {name: string, email: string, cfApiKeySecretName: string, cluster_name: string}) => {
20 return {
21 apiVersion: 'cert-manager.io/v1',
22 kind: 'ClusterIssuer',
23 metadata: {
24 name,
25 labels: {cluster_name}
26 },
27 spec: {
28 acme: {
29 email,
30 privateKeySecretRef: {
31 name
32 },
33 server: 'https://acme-v02.api.letsencrypt.org/directory',
34 solvers: [
35 {
36 dns01: {
37 cloudflare: {
38 apiKeySecretRef: {
39 key: 'CF_API_KEY',
40 name: cfApiKeySecretName
41 },
42 email
43 }
44 }
45 }
46 ]
47 }
48 }
49 }
52const wcClusterIssuerTmpl = ({name, email, cfApiKeySecretName, cluster_name}: {name: string, email: string, cfApiKeySecretName: string, cluster_name: string}) => {
53 return {
54 apiVersion: 'cert-manager.io/v1',
55 kind: 'ClusterIssuer',
56 metadata: {
57 name,
58 labels: {cluster_name},
59 },
60 spec: {
61 acme: {
62 email,
63 privateKeySecretRef: {
64 name
65 },
66 server: 'https://acme-v02.api.letsencrypt.org/directory',
67 solvers: [
68 {
69 dns01: {
70 cloudflare: {
71 apiKeySecretRef: {
72 key: 'CF_API_KEY',
73 name: cfApiKeySecretName,
74 },
75 email
76 }
77 }
78 }
79 ]
80 }
81 }
82 }
85export const phasedApplyResources = async ({action, cluster_name, kustDir}: {action: string, cluster_name: string, kustDir: string}) => {
86 assertDefined(kustDir)
88 let resources = await getResources({path: kustDir, cluster_name}) as KubeResource[]
90 if (action == 'apply') {
91 const nsResA = _.filter(resources, ({kind}) => {
92 return kind == 'Namespace'
93 })
94 resources = _.difference(resources, nsResA)
95 await kube2ApplyK({action, resources: nsResA})
96 await debug1Sleep(10 * 1000)
98 const crdResA = _.filter(resources, ({kind}) => {
99 return kind == 'CustomResourceDefinition'
100 })
101 resources = _.difference(resources, crdResA)
102 await kube2ApplyK({action, resources: crdResA})
103 await debug1Sleep(10 * 1000)
104 }
106 await kube2ApplyK({action, resources})
109export const waitForCertManagerWebhook = async ({cluster_name}: {cluster_name: string}) => {
110 const webhookDeployRes = {
111 apiVersion: 'apps/v1',
112 kind: 'Deployment',
113 metadata: { name: 'cert-manager-webhook', namespace: 'cert-manager' }
114 }
116 process.stdout.write('waiting for cert-manager-webhook to be ready')
117 await pollUntil({
118 predicate: async () => {
119 const deployment = await read2Resource({resource: webhookDeployRes, cluster_name})
120 if (!deployment) return true // keep waiting
121 const {readyReplicas, replicas} = (deployment as {status?: {readyReplicas?: number, replicas?: number}}).status || {}
122 return !(readyReplicas && readyReplicas >= 1 && readyReplicas === replicas)
123 },
124 intervalMs: 5000,
125 timeoutLabel: 'cert-manager-webhook ready',
126 })
127 console.log(' ready')
128 await sleep(3 * 1000) // extra buffer for webhook to fully initialize
131export const guardHasCfSecret = () => {
132 const {cfApiKeySecretName} = getKlusterCtx()
133 if (!cfApiKeySecretName) throPtErr('!cfApiKeySecretName')
134 try {
135 return getReqJsonSecret(cfApiKeySecretName)
136 } catch {
138 filePath: secretsRelDir + '/' + cfApiKeySecretName,
139 helpText: `Please create with contents:
141 "CF_API_EMAIL": "email@domain.com",
142 "CF_API_KEY": "faketoken123abca39581a86ce7e6991f2d30"
143}`,
144 })
145 }
148export const syncCertManagerCore = async ({kustDir}: {kustDir: string}) => {
149 const {
150 cfApiKeySecretName, cluster_name,
152 const action = getAction()
154 const cfSecret = guardHasCfSecret()
156 const {CF_API_EMAIL: email} = cfSecret
158 const cfSecretTmpl = secretEnvTemplate({name: cfApiKeySecretName, kubeName: cfApiKeySecretName})
159 _.set(cfSecretTmpl, 'metadata.namespace', 'cert-manager')
161 await phasedApplyResources({action, cluster_name, kustDir})
163 if (action == 'apply') {
164 await waitForCertManagerWebhook({cluster_name})
165 }
167 const resources = [
168 wcClusterIssuerTmpl({name: leIssuerName, cfApiKeySecretName, email, cluster_name}),
169 clusterIssuerTmpl({name: 'letsencrypt-prod', email, cfApiKeySecretName, cluster_name}),
170 cfSecretTmpl,
171 secretFileTemplate({name: tsSec(cfApiKeySecretName), kubeName: cfApiKeySecretName}),
172 ]
173 await resourcesAction({resources, action, cluster_name})