-
Notifications
You must be signed in to change notification settings - Fork 8.3k
/
Copy pathrestore.ts
129 lines (115 loc) · 4.27 KB
/
restore.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { schema, TypeOf } from '@kbn/config-schema';
import { SnapshotRestore, SnapshotRestoreShardEs } from '../../../common/types';
import { serializeRestoreSettings } from '../../../common/lib';
import { deserializeRestoreShard } from '../../lib';
import { RouteDependencies } from '../../types';
import { addBasePath } from '../helpers';
import { restoreSettingsSchema } from './validate_schemas';
export function registerRestoreRoutes({ router, license, lib: { isEsError } }: RouteDependencies) {
// GET all snapshot restores
router.get(
{ path: addBasePath('restores'), validate: false },
license.guardApiRoute(async (ctx, req, res) => {
const { callAsCurrentUser } = ctx.snapshotRestore!.client;
try {
const snapshotRestores: SnapshotRestore[] = [];
const recoveryByIndexName: {
[key: string]: {
shards: SnapshotRestoreShardEs[];
};
} = await callAsCurrentUser('indices.recovery', {
human: true,
});
// Filter to snapshot-recovered shards only
Object.keys(recoveryByIndexName).forEach((index) => {
const recovery = recoveryByIndexName[index];
let latestActivityTimeInMillis: number = 0;
let latestEndTimeInMillis: number | null = null;
const snapshotShards = (recovery.shards || [])
.filter((shard) => shard.type === 'SNAPSHOT')
.sort((a, b) => a.id - b.id)
.map((shard) => {
const deserializedShard = deserializeRestoreShard(shard);
const { startTimeInMillis, stopTimeInMillis } = deserializedShard;
// Set overall latest activity time
latestActivityTimeInMillis = Math.max(
startTimeInMillis || 0,
stopTimeInMillis || 0,
latestActivityTimeInMillis
);
// Set overall end time
if (stopTimeInMillis === undefined) {
latestEndTimeInMillis = null;
} else if (
latestEndTimeInMillis === null ||
stopTimeInMillis > latestEndTimeInMillis
) {
latestEndTimeInMillis = stopTimeInMillis;
}
return deserializedShard;
});
if (snapshotShards.length > 0) {
snapshotRestores.push({
index,
latestActivityTimeInMillis,
shards: snapshotShards,
isComplete: latestEndTimeInMillis !== null,
});
}
});
// Sort by latest activity
snapshotRestores.sort(
(a, b) => b.latestActivityTimeInMillis - a.latestActivityTimeInMillis
);
return res.ok({ body: snapshotRestores });
} catch (e) {
if (isEsError(e)) {
return res.customError({
statusCode: e.statusCode,
body: e,
});
}
// Case: default
return res.internalError({ body: e });
}
})
);
// Restore snapshot
const restoreParamsSchema = schema.object({
repository: schema.string(),
snapshot: schema.string(),
});
router.post(
{
path: addBasePath('restore/{repository}/{snapshot}'),
validate: { body: restoreSettingsSchema, params: restoreParamsSchema },
},
license.guardApiRoute(async (ctx, req, res) => {
const { callAsCurrentUser } = ctx.snapshotRestore!.client;
const { repository, snapshot } = req.params as TypeOf<typeof restoreParamsSchema>;
const restoreSettings = req.body as TypeOf<typeof restoreSettingsSchema>;
try {
const response = await callAsCurrentUser('snapshot.restore', {
repository,
snapshot,
body: serializeRestoreSettings(restoreSettings),
});
return res.ok({ body: response });
} catch (e) {
if (isEsError(e)) {
return res.customError({
statusCode: e.statusCode,
body: e,
});
}
// Case: default
return res.internalError({ body: e });
}
})
);
}