🌳
pt0/deployF/k8sF/kubeCpF.mts
5import fs from 'fs'
6import { spawn } from 'child_process'
9const doKubeCmd = async (...restCmd: string[]) => {
10 const {cluster_name} = getReqKlusterCtx()
11 const cmdA = [cluster_name, ...restCmd]
12 console.log(cmdA.join(' '))
13 await eptKubeCli(cmdA)
16type KubeCpDownProps = { podName: string, containerName?: string, fromRemotePath: string, toLocalPath: string }
17type KubeCpUpProps = { podName: string, containerName?: string, toRemotePath: string, fromLocalPath: string }
19export const kubeCpDown = async ({podName, fromRemotePath, toLocalPath}: KubeCpDownProps) => {
20 await doKubeCmd(
21 'cp', '--retries=-1', `${podName}:${fromRemotePath}`,
22 toLocalPath,
23 )
26export const kubeCpUp = async ({podName, containerName, toRemotePath, fromLocalPath}: KubeCpUpProps) => {
27 await doKubeCmd(
28 'cp', ...(containerName ? ['-c', containerName] : []), fromLocalPath,
29 `${podName}:${toRemotePath}`,
30 )
33type KubeExecCatProps = { podName: string, containerName?: string, fromRemotePath: string, toLocalPath: string, expectedSize?: number }
35const doKubeExecCatRange = async ({podName, containerName, fromRemotePath, toLocalPath, skipBytes}: KubeExecCatProps & {skipBytes: number}) => {
36 const {cluster_name} = getReqKlusterCtx()
37 const kubeConfigPath = getKubeConfigPath(cluster_name)
38 const resolvedPath = await getResolvedKubeConfigPath(cluster_name, kubeConfigPath)
39 const { kubeTlsInsecure = false } = getCurKlusterCfg(cluster_name) as { kubeTlsInsecure?: boolean }
40 const podCmd = skipBytes > 0
41 ? ['tail', '-c', `+${skipBytes + 1}`, fromRemotePath]
42 : ['cat', fromRemotePath]
43 const cmdA = [
44 'kubectl',
45 kubeTlsInsecure && '--insecure-skip-tls-verify',
46 'exec', '-i', podName,
47 ...(containerName ? ['-c', containerName] : []),
48 '--', ...podCmd,
49 ].filter(Boolean) as string[]
50 console.log(cmdA.join(' '))
52 return await new Promise<{code: number | null, stderr: string}>((resolv) => {
53 const flags = skipBytes > 0 ? 'a' : 'w'
54 const proc = spawn(cmdA[0], cmdA.slice(1), {
55 env: { ...process.env, KUBECONFIG: resolvedPath },
56 stdio: ['ignore', fs.openSync(toLocalPath, flags), 'pipe'],
57 })
58 let stderr = ''
59 if (proc.stderr) proc.stderr.on('data', (chunk: Buffer) => { stderr += chunk.toString() })
60 proc.on('close', (code) => {
61 resolv({code, stderr})
62 })
63 proc.on('error', (err) => {
64 resolv({code: -1, stderr: err.message})
65 })
66 })
69export const kubeExecCat = async (props: KubeExecCatProps) => {
70 const maxAttempts = 5
71 for (let attempt = 1; attempt <= maxAttempts; attempt++) {
72 const localSize = fs.existsSync(props.toLocalPath) ? fs.statSync(props.toLocalPath).size : 0
73 if (props.expectedSize && localSize === props.expectedSize) {
74 console.log(`kubeExecCat: size match ${localSize}`)
75 return
76 }
77 const {code, stderr} = await doKubeExecCatRange({...props, skipBytes: localSize})
78 const newLocalSize = fs.statSync(props.toLocalPath).size
79 if (code === 0 && (!props.expectedSize || newLocalSize === props.expectedSize)) {
80 return
81 }
82 console.log(`kubeExecCat attempt ${attempt}/${maxAttempts} code=${code} localSize=${newLocalSize} expectedSize=${props.expectedSize}`)
83 if (attempt < maxAttempts) await sleep(3000)
84 }
85 throw new Error(`!kubeExecCat ${maxAttempts} attempts`)