Skip to content

Commit dee2fdc

Browse files
fix: replace hanging kubectl delete command with api call (#2785)
Co-authored-by: svcAPLBot <[email protected]>
1 parent 222cd89 commit dee2fdc

File tree

2 files changed

+60
-17
lines changed

2 files changed

+60
-17
lines changed

src/cmd/apply-as-apps.ts

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { ApiException, V1ResourceRequirements } from '@kubernetes/client-node'
1+
import {
2+
ApiException,
3+
KubernetesObject,
4+
PatchStrategy,
5+
setHeaderOptions,
6+
V1ResourceRequirements,
7+
} from '@kubernetes/client-node'
28
import { existsSync, mkdirSync, rmSync } from 'fs'
39
import { readFile, writeFile } from 'fs/promises'
410
import { appPatches, genericPatch } from 'src/applicationPatches.json'
@@ -11,7 +17,7 @@ import { getImageTagFromValues, objectToYaml } from 'src/common/values'
1117
import { getParsedArgs, HelmArguments, helmOptions, setParsedArgs } from 'src/common/yargs'
1218
import { Argv, CommandModule } from 'yargs'
1319
import { $ } from 'zx'
14-
import { ARGOCD_APP_DEFAULT_SYNC_POLICY } from '../common/constants'
20+
import { ARGOCD_APP_DEFAULT_SYNC_POLICY, ARGOCD_APP_PARAMS } from '../common/constants'
1521
import { env } from '../common/envalid'
1622

1723
const cmdName = getFilename(__filename)
@@ -42,6 +48,8 @@ interface HelmRelease {
4248
chart: string
4349
version: string
4450
}
51+
const customApi = k8s.custom()
52+
4553
const getAppName = (release: HelmRelease): string => {
4654
return `${release.namespace}-${release.name}`
4755
}
@@ -84,17 +92,41 @@ const getArgocdAppManifest = (release: HelmRelease, values: Record<string, any>,
8492
}
8593

8694
const setFinalizers = async (name: string) => {
87-
d.info(`Setting finalizers for ${name}`)
88-
const resPatch =
89-
await $`kubectl -n argocd patch applications.argoproj.io ${name} -p '{"metadata": {"finalizers": ["resources-finalizer.argocd.argoproj.io"]}}' --type merge`
90-
if (resPatch.exitCode !== 0) {
91-
throw new Error(`Failed to set finalizers for ${name}: ${resPatch.stderr}`)
95+
try {
96+
d.info(`Setting finalizers for ${name}`)
97+
await customApi.patchNamespacedCustomObject(
98+
{
99+
...ARGOCD_APP_PARAMS,
100+
name,
101+
body: [
102+
{
103+
op: 'replace',
104+
path: '/metadata/finalizers',
105+
value: ['resources-finalizer.argocd.argoproj.io'],
106+
},
107+
],
108+
},
109+
setHeaderOptions('Content-Type', PatchStrategy.JsonPatch),
110+
)
111+
d.info(`Set finalizers for ${name}`)
112+
} catch (error) {
113+
d.error(`Failed to set finalizers for ${name}: ${error}`)
114+
throw error
92115
}
93116
}
94117

95118
const getFinalizers = async (name: string): Promise<string[]> => {
96-
const res = await $`kubectl -n argocd get applications.argoproj.io ${name} -o jsonpath='{.metadata.finalizers}'`
97-
return res.stdout ? JSON.parse(res.stdout) : []
119+
try {
120+
const response = await customApi.getNamespacedCustomObject({
121+
...ARGOCD_APP_PARAMS,
122+
name,
123+
})
124+
const app = response.body as any
125+
return Array.isArray(app.metadata?.finalizers) ? app.metadata.finalizers : []
126+
} catch (error) {
127+
d.warn(`Failed to get finalizers for ${name}: ${error}`)
128+
return []
129+
}
98130
}
99131

100132
const removeApplication = async (name: string): Promise<void> => {
@@ -103,8 +135,11 @@ const removeApplication = async (name: string): Promise<void> => {
103135
if (!finalizers.includes('resources-finalizer.argocd.argoproj.io')) {
104136
await setFinalizers(name)
105137
}
106-
const resDelete = await $`kubectl -n argocd delete applications.argoproj.io ${name}`
107-
d.info(resDelete.stdout.toString().trim())
138+
await customApi.deleteNamespacedCustomObject({
139+
...ARGOCD_APP_PARAMS,
140+
name,
141+
})
142+
d.info(`Deleted application ${name}`)
108143
} catch (e) {
109144
d.error(`Failed to delete application ${name}: ${e.message}`)
110145
}
@@ -141,8 +176,18 @@ async function patchArgocdResources(release: HelmRelease, values: Record<string,
141176
}
142177

143178
export const getApplications = async (): Promise<string[]> => {
144-
const res = await $`kubectl get application.argoproj.io -n argocd -oname`
145-
return res.stdout.split('\n')
179+
try {
180+
const response = await customApi.listNamespacedCustomObject({
181+
...ARGOCD_APP_PARAMS,
182+
})
183+
const apps = response.items || []
184+
return apps
185+
.filter((app: KubernetesObject) => app.metadata?.name && app.metadata.name !== '')
186+
.map((app: KubernetesObject) => app.metadata!.name!)
187+
} catch (error) {
188+
d.error(`Failed to list applications: ${error}`)
189+
return []
190+
}
146191
}
147192

148193
const writeApplicationManifest = async (release: HelmRelease, otomiVersion: string): Promise<void> => {
@@ -227,8 +272,7 @@ export const applyAsApps = async (argv: HelmArguments): Promise<boolean> => {
227272
if (release.installed) await writeApplicationManifest(release, otomiVersion)
228273
else {
229274
const appName = getAppName(release)
230-
const resourceName = `application.argoproj.io/${appName}`
231-
if (currentApplications.includes(resourceName)) {
275+
if (currentApplications.includes(appName)) {
232276
await removeApplication(appName)
233277
}
234278
}

src/common/values.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,12 @@ describe('generateSecrets', () => {
6363
}
6464
})
6565
it('should generate new secrets and return only secrets', async () => {
66-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
6766
const res = await generateSecrets(values, deps)
6867
expect(res).toEqual(expected)
6968
})
7069
it('should not overwrite old secrets', async () => {
7170
const valuesWithExisting = merge(cloneDeep(values), { nested: { twoStage: 'exists' } })
72-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
71+
7372
const res = await generateSecrets(valuesWithExisting, deps)
7473
expect(res.nested.twoStage).toBe('exists')
7574
})

0 commit comments

Comments
 (0)