🌳
pt0/deployF/servicesF/peertubeF/eptPeertubeAI.mts
4import * as _ from 'lodash-es'
15import { spawnSync } from 'child_process'
23import {
24 peertubeImage, peertubePort, redisImage, redisName, redisPort,
25 peertubeUid, storageSizeGb,
28type EptPeertubeProps = {
29 hostname: string
30 adminEmail: string
31 instanceName: string
34const name = 'peertube'
35const ptSecretName = tsSec('peertube-appsecret')
37export const eptPeertube = async ({hostname, adminEmail, instanceName}: EptPeertubeProps) => {
38 const {cluster_name} = getKlusterCtx()
39 const action = getAction()
40 appCfgCtx.enterWith({...getAppCfg(), name, dbQsCfg: {dbQsName: `${name}_qs`}})
42 await genPlainSecretIfMissing({secretName: ptSecretName, autoYes: true})
43 const rootPw = await genPlainSecretIfMissing({secretName: tsSec('peertube-rootpassword'), autoYes: true})
45 const {volumes: dataVols, volumeMounts: dataMnts} = pvcVolumeMounts({name, mountPath: '/data'})
47 const ingressAnnotH = {
48 'nginx.ingress.kubernetes.io/proxy-body-size': '0',
49 'nginx.ingress.kubernetes.io/proxy-read-timeout': '3600',
50 'nginx.ingress.kubernetes.io/proxy-send-timeout': '3600',
51 }
53 const peertubeDeployment = deployTmpl({
54 name,
55 strategy: {type: 'Recreate'},
56 volumes: dataVols,
57 initContainers: [{
58 name: 'fix-permissions',
59 image: 'busybox',
60 command: ['sh', '-c', `chown -R ${peertubeUid}:${peertubeUid} /data`],
61 volumeMounts: dataMnts,
62 }],
63 containers: [{
64 name, image: peertubeImage,
65 ports: [{containerPort: peertubePort}],
66 volumeMounts: dataMnts,
67 lifecycle: {
68 preStop: { exec: { command: ['sh', '-c', 'sleep 10'] } },
69 },
70 startupProbe: {
71 httpGet: {path: '/api/v1/config', port: peertubePort},
72 failureThreshold: 36, periodSeconds: 10,
73 },
74 readinessProbe: {
75 httpGet: {path: '/api/v1/config', port: peertubePort},
76 periodSeconds: 5,
77 },
78 env: envHToA({
79 PEERTUBE_WEBSERVER_HOSTNAME: hostname,
80 PEERTUBE_WEBSERVER_HTTPS: 'true',
81 PEERTUBE_DB_HOSTNAME: `${name}-rw.default`,
82 PEERTUBE_DB_PORT: '5432',
83 PEERTUBE_DB_USERNAME: 'app',
84 PEERTUBE_DB_NAME: 'app',
85 PEERTUBE_DB_SSL: 'false',
86 PEERTUBE_DB_PASSWORD: {secretKeyRef: {name: `${name}-app`, key: 'password'}},
87 PEERTUBE_REDIS_HOSTNAME: redisName,
88 PEERTUBE_REDIS_PORT: String(redisPort),
89 PEERTUBE_SECRET: {secretKeyRef: {name: `${name}-secret`, key: ptSecretName}},
90 PEERTUBE_ADMIN_EMAIL: adminEmail,
91 PEERTUBE_INSTANCE_NAME: instanceName,
92 UV_THREADPOOL_SIZE: '128',
93 }),
94 }],
95 })
97 const resources = _.compact([
98 secretFileTemplate({name: ptSecretName, kubeName: `${name}-secret`}),
100 name: redisName,
101 strategy: {type: 'Recreate'},
102 volumes: [{name: 'redis-data', emptyDir: {}}],
103 containers: [{
104 name: redisName, image: redisImage,
105 volumeMounts: [{name: 'redis-data', mountPath: '/data'}],
106 }],
107 }),
108 peertubeDeployment,
109 kubeSvcTmpl({name: redisName, portNo: redisPort}),
110 kubeSvcTmpl({name, portNo: peertubePort}),
111 genericIngressTmpl({name, hostname, portNo: peertubePort, ingressAnnotationsH: ingressAnnotH}),
112 ])
114 await Promise.all([
115 resourcesAction({resources, action, cluster_name}),
116 kubeActionPvc({action, cluster_name, name, sizeGb: storageSizeGb}),
117 ])
119 if (action === 'apply') {
120 await waitForDeploymentRollout({resource: peertubeDeployment, cluster_name})
121 if (rootPw) await ensureRootPw({cluster_name, rootPw})
122 }
124 if (_.includes(['info', 'apply'], action)) {
125 const rootPwVal = getPlainSecOpt(tsSec('peertube-rootpassword'))
126 const dbEps = getDbEntrypointsByQsName(`${name}_qs`)
127 betLog({url: `https://${hostname}`, login: 'root', rootPw: rootPwVal, adminEmail, dbEp: dbEps[0]?.regEpPath})
128 }
131const ensureRootPw = async ({cluster_name, rootPw}: {cluster_name: string, rootPw: string}) => {
132 const kubeConfigPath = getKubeConfigPath(cluster_name)
133 const kubeEnv = {...process.env, KUBECONFIG: kubeConfigPath}
134 const podName = await getMostRecentPod({cluster_name, name})
135 if (!podName) { betLog('peertube pod not found, skip rootPw set'); return }
137 for (let i = 0; i < 36; i++) {
138 const probe = spawnSync('kubectl', ['exec', podName, '--', 'curl', '-sf', 'http://localhost:9000/api/v1/config'],
139 {encoding: 'utf-8', env: kubeEnv, stdio: 'pipe'})
140 if (probe.status === 0) break
141 if (i === 35) { betLog('peertube not ready, skip rootPw set'); return }
142 await sleep(5000)
143 }
145 const result = spawnSync('kubectl', ['exec', '-i', podName, '--', 'npm', 'run', 'reset-password', '--', '-u', 'root'],
146 {input: `${rootPw}\n${rootPw}\n`, encoding: 'utf-8', env: kubeEnv, timeout: 30_000})
148 if (result.status === 0) {
149 betLog({rootPw})
150 } else {
151 betLog('!rootPw set failed — password is in data/secrets2/peertube-rootpassword for manual reset')
152 }