-
Notifications
You must be signed in to change notification settings - Fork 392
/
cleanupDangling.ts
102 lines (87 loc) · 3.16 KB
/
cleanupDangling.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* Situations can occur where cancelled test runs leave dangling resources behind.
* This function will clean up any dangling resources from previous test runs,
* determined by "older than 48 hours".
*/
import {testClient} from './environment'
const threshold = Date.now() - 48 * 60 * 60 * 1000
/* eslint-disable no-console */
export async function cleanupDangling(): Promise<void> {
console.log('Performing dangling resource cleanup: dataset aliases')
await deleteAliases()
console.log('Performing dangling resource cleanup: GraphQL APIs')
await deleteGraphQLAPIs()
console.log('Performing dangling resource cleanup: CORS origins')
await deleteCorsOrigins()
console.log('Performing dangling resource cleanup: datasets')
await deleteDatasets()
}
async function deleteAliases() {
const aliases = await testClient.request<{name: string}[]>({url: '/aliases'})
const toDelete = aliases.filter(({name}) => isTestEntityOlderThanThreshold(name))
await Promise.all(
toDelete.map((alias) =>
testClient
.request({method: 'DELETE', uri: `/aliases/${alias.name}`})
.catch(getErrorWarner('dataset alias', alias.name))
)
)
}
async function deleteGraphQLAPIs() {
const apis = await testClient.request<{dataset: string; tag: string}[]>({url: '/apis/graphql'})
const toDelete = apis.filter(({dataset}) => isTestEntityOlderThanThreshold(dataset))
await Promise.all(
toDelete.map(({dataset, tag}) =>
testClient
.request({url: `/apis/graphql/${dataset}/${tag}`, method: 'DELETE'})
.catch(getErrorWarner('graphql api', `${dataset}/${tag}`))
)
)
}
async function deleteCorsOrigins() {
const origins = await testClient.request<{id: number; origin: string}[]>({url: '/cors'})
const toDelete = origins.filter(({origin}) =>
isTestEntityOlderThanThreshold(origin.replace(/^https:\/\//, ''))
)
await Promise.all(
toDelete.map((origin) =>
testClient
.request({method: 'DELETE', uri: `/cors/${origin.id}`})
.catch(getErrorWarner('cors origin', origin.origin))
)
)
}
async function deleteDatasets() {
const datasets = await testClient.request<{name: string}[]>({url: '/datasets'})
const toDelete = datasets.filter(({name}) => isTestEntityOlderThanThreshold(name))
await Promise.all(
toDelete.map((ds) =>
testClient.datasets.delete(ds.name).catch(getErrorWarner('dataset', ds.name))
)
)
}
function isTestEntity(entity: string): boolean {
return /^test[-_]\d{8}[-_]/.test(entity)
}
function isTestEntityOlderThanThreshold(entity: string): boolean {
if (!isTestEntity(entity)) {
return false
}
// test-20220929-darwin-v16-wode-11664
// => 20220929
const dateOnly = entity.slice(5, 13)
// => 2022-09-29
const date = `${dateOnly.slice(0, 4)}-${dateOnly.slice(4, 6)}-${dateOnly.slice(6, 8)}`
// => 1664409600000
const timestamp = Date.parse(date)
return timestamp < threshold
}
function getErrorWarner(entity: string, id: string) {
return (err: unknown) => {
if (err instanceof Error) {
console.warn(`WARN: ${entity} "${id}" cleanup failed: ${err.message}`)
} else {
console.warn(`WARN: ${entity} "${id}" cleanup failed: ${err}`)
}
}
}