🌳
pt0/deployF/k8sF/resActionsF/index.mts
1import * as _ from 'lodash-es'
13import { getLogs } from './getLogsF.mts'
15import { spawnSync } from 'child_process'
23type ResActionProps = WithClusterAndResource
25export const resources = Object.assign(async ({resource}: {resource: KubeResource}) => {
26 const ctx = kubeCoalesceCtx.getStore()
27 if (ctx) {
28 const {resourcesA} = ctx
29 resourcesA.push(resource)
30 } else {
32 }
33}, {cliDescript: 'show json arr of k8s resources that would be created/applied'})
35export const awaitrollout = Object.assign(async ({resource, cluster_name}: ResActionProps) => {
36 if (!isKubeDeploy(resource)) return
37 await waitForDeploymentRollout({resource, cluster_name})
38}, {cliAdvanced: true})
40export const delpvcs = async ({resource, cluster_name}: ResActionProps) => {
41 if (!isDeleteSafeResource(resource)) return
42 const name = resource.metadata?.name
43 if (isPvc(resource)) process.stdout.write(`k8s ${cluster_name} delpvc: ${name} (${shortKind(resource.kind)})`)
44 await resPlainAction({resource, action: 'delete', cluster_name, noDelPvcs: false})
45 if (isPvc(resource)) {
46 await pollUntil({predicate: () => read2Resource({resource, cluster_name}), timeoutLabel: `delpvc ${name}`})
47 console.log(' done')
48 }
50delpvcs.cliSchema = forceCli
52export const pods = async ({resource, cluster_name}: ResActionProps) => {
53 if (!isKubeDeploy(resource)) return
54 await kubePods({cluster_name, labelSel: `name=${resource.metadata.name}`})
57const isCnpgCluster = (res: KubeResource) => res.apiVersion === 'postgresql.cnpg.io/v1' && res.kind === 'Cluster'
59export const restart = async ({resource, cluster_name}: ResActionProps) => {
60 const {name} = resource.metadata
61 if (isKubeDeploy(resource)) {
62 const kubeConfigPath = getKubeConfigPath(cluster_name)
63 spawnSync('kubectl', ['rollout', 'restart', `deployment/${name}`], {
64 stdio: 'inherit',
65 env: {...process.env, KUBECONFIG: kubeConfigPath},
66 })
67 await waitForDeploymentRollout({resource, cluster_name})
68 } else if (isCnpgCluster(resource)) {
69 await delMatchingPods({cluster_name, labels: {'cnpg.io/cluster': name}})
70 }
72restart.cliDescript = 'rollout restart the k8s deployment'
74export const fexec = Object.assign(async ({resource, cluster_name}: ResActionProps) => {
75 if (!isKubeDeploy(resource)) return
76 const allPods = await getAllPods({cluster_name, labels: {name: resource.metadata.name}})
77 const podArg = cliArg('--pod')
78 const podIdx = podArg ? parseInt(podArg, 10) - 1 : 0
79 const selectedPod = assertValidIdx(allPods, podIdx, {
80 podArg, validRange: `1-${allPods.length}`, podNames: _.map(allPods, 'podName'),
81 })
82 const kubeConfigPath = getKubeConfigPath(cluster_name)
83 const kubeEnv = { ...process.env, KUBECONFIG: kubeConfigPath }
84 const execCmd = cliActionArg()
85 if (execCmd) {
86 const result = spawnSync('kubectl', ['exec', selectedPod.podName, '--', 'sh', '-c', execCmd], {
87 stdio: 'inherit', env: kubeEnv,
88 })
89 process.exitCode = result.status ?? 1
90 } else {
91 spawnSync('kubectl', ['exec', selectedPod.podName, '-it', '--', 'sh'], {
92 stdio: 'inherit', env: kubeEnv,
93 })
94 }
95}, {
96 cliSchema: {pod: {type: 'string' as const, desc: 'N (1-based)'}},
97 cliAcceptsPositional: true,
98 cliDescript: `exec into pod, or run cmd: fexec 'ls -la' --pod=2`,
99})
101export const logs = Object.assign(async ({resource}: ResActionProps) => {
102 if (!isKubeDeploy(resource)) return
103 const name = resource.metadata.name
104 await getLogs({name})
105}, {
106 cliSchema: {pod: {type: 'string' as const, desc: 'N or "all"'}, follow: {flag: true as const, alias: 'f', desc: 'stream logs (-f)'}},
107 cliDescript: 'stream logs',
108})
110export const busybox = Object.assign(async (props: ResActionProps) => {
111 const {resource, cluster_name} = props
112 if (resource.kind != 'Deployment') return
113 betLog('busybox', inspect3KubeRes(resource))
114 const {containers} = (resource as any).spec?.template?.spec || {}
115 let lastContainer = _.last(containers) as Record<string, unknown> | undefined
116 if (!lastContainer) {
117 lastContainer = {name: 'busybox'}
118 _.set(resource, 'spec.template.spec.containers', [lastContainer])
119 }
120 Object.assign(lastContainer, {image: 'busybox', command: ['sleep', '99999'], args: []})
121 await resPlainAction({...props, action: 'patch'})
122 await pods(props)
123})
124busybox.cliDescript = 'replaces pod w busybox (when its crashing & you need to exec in)'
126export default {
127 resources,
128 awaitrollout,
129 delpvcs,
130 pods,
131 restart,
132 fexec,
133 logs,
134 busybox,