Skip to content

Commit fbc24db

Browse files
committed
fix(core): enhance reload UI
1 parent 28ba84d commit fbc24db

29 files changed

Lines changed: 944 additions & 122 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ set(SOURCES
258258
src/runtime/resolver_coordinator.cpp
259259
src/runtime/runtime_state_machine.cpp
260260
src/runtime/operation_coordinator.cpp
261+
src/runtime/lifecycle_operation.cpp
261262
src/firewall/firewall_reconciler.cpp
262263
src/lists/ipset.cpp
263264
src/lists/kernel_set_tester.cpp

docs/openapi.yaml

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ paths:
3434
stopping the API process.
3535
operationId: postServiceStart
3636
responses:
37-
"200":
38-
description: Service start requested successfully
37+
"202":
38+
description: Lifecycle operation accepted
3939
content:
4040
application/json:
4141
schema:
42-
$ref: "#/components/schemas/ReloadResponse"
42+
$ref: "#/components/schemas/LifecycleOperationAcceptedResponse"
43+
"409":
44+
description: Another lifecycle operation is active
4345

4446
/api/service/stop:
4547
post:
@@ -50,12 +52,14 @@ paths:
5052
API process running.
5153
operationId: postServiceStop
5254
responses:
53-
"200":
54-
description: Service stop requested successfully
55+
"202":
56+
description: Lifecycle operation accepted
5557
content:
5658
application/json:
5759
schema:
58-
$ref: "#/components/schemas/ReloadResponse"
60+
$ref: "#/components/schemas/LifecycleOperationAcceptedResponse"
61+
"409":
62+
description: Another lifecycle operation is active
5963

6064
/api/service/restart:
6165
post:
@@ -65,12 +69,14 @@ paths:
6569
registration hooks for the managed resolver config.
6670
operationId: postServiceRestart
6771
responses:
68-
"200":
69-
description: Service restart requested successfully
72+
"202":
73+
description: Lifecycle operation accepted
7074
content:
7175
application/json:
7276
schema:
73-
$ref: "#/components/schemas/ReloadResponse"
77+
$ref: "#/components/schemas/LifecycleOperationAcceptedResponse"
78+
"409":
79+
description: Another lifecycle operation is active
7480

7581
/api/lists/refresh:
7682
post:
@@ -174,12 +180,14 @@ paths:
174180
it to the routing runtime.
175181
operationId: postConfigSave
176182
responses:
177-
"200":
178-
description: Config saved and applied successfully
183+
"202":
184+
description: Lifecycle operation accepted
179185
content:
180186
application/json:
181187
schema:
182-
$ref: "#/components/schemas/ConfigUpdateResponse"
188+
$ref: "#/components/schemas/LifecycleOperationAcceptedResponse"
189+
"409":
190+
description: Another lifecycle operation is active
183191
"400":
184192
description: No staged config or validation/dry-run failure
185193
content:
@@ -455,6 +463,11 @@ components:
455463
minimum: 1
456464
default: 30
457465
description: Deadline for privileged helper and hook processes.
466+
resolver_ready_timeout_seconds:
467+
type: integer
468+
minimum: 1
469+
default: 120
470+
description: Deadline for dnsmasq process stabilization and DNS readiness after a helper completes.
458471
exec_kill_grace_seconds:
459472
type: integer
460473
minimum: 0
@@ -1293,6 +1306,58 @@ components:
12931306
Whether a newer configuration has been staged in memory but not yet
12941307
persisted and applied.
12951308
example: false
1309+
lifecycle_operation:
1310+
$ref: "#/components/schemas/LifecycleOperation"
1311+
1312+
LifecycleOperationAcceptedResponse:
1313+
type: object
1314+
required: [operation_id, status]
1315+
properties:
1316+
operation_id:
1317+
type: string
1318+
example: "lifecycle-42"
1319+
status:
1320+
type: string
1321+
enum: [accepted]
1322+
1323+
LifecycleOperation:
1324+
type: object
1325+
required: [id, type, status, started_at, stages]
1326+
properties:
1327+
id:
1328+
type: string
1329+
type:
1330+
type: string
1331+
enum: [apply_config, start, stop, restart]
1332+
status:
1333+
type: string
1334+
enum: [running, succeeded, failed]
1335+
started_at:
1336+
type: integer
1337+
format: int64
1338+
finished_at:
1339+
type: integer
1340+
format: int64
1341+
error:
1342+
type: string
1343+
stages:
1344+
type: array
1345+
items:
1346+
$ref: "#/components/schemas/LifecycleOperationStage"
1347+
1348+
LifecycleOperationStage:
1349+
type: object
1350+
required: [id, title, status]
1351+
properties:
1352+
id:
1353+
type: string
1354+
title:
1355+
type: string
1356+
status:
1357+
type: string
1358+
enum: [pending, running, succeeded, failed, skipped]
1359+
detail:
1360+
type: string
12961361

12971362
ResolverConfigSyncState:
12981363
type: string

frontend/src/api/generated/keen-api.ts

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ import type {
3030
ConfigUpdateResponse,
3131
ErrorResponse,
3232
HealthResponse,
33+
LifecycleOperationAcceptedResponse,
3334
ListRefreshRequest,
3435
ListRefreshResponse,
35-
ReloadResponse,
3636
RoutingHealthErrorResponse,
3737
RoutingHealthResponse,
3838
RoutingTestRequest,
@@ -166,17 +166,24 @@ export function useGetHealthService<TData = Awaited<ReturnType<typeof getHealthS
166166
167167
* @summary Start routing runtime
168168
*/
169-
export type postServiceStartResponse200 = {
170-
data: ReloadResponse
171-
status: 200
169+
export type postServiceStartResponse202 = {
170+
data: LifecycleOperationAcceptedResponse
171+
status: 202
172+
}
173+
174+
export type postServiceStartResponse409 = {
175+
data: void
176+
status: 409
172177
}
173178

174-
export type postServiceStartResponseSuccess = (postServiceStartResponse200) & {
179+
export type postServiceStartResponseSuccess = (postServiceStartResponse202) & {
180+
headers: Headers;
181+
};
182+
export type postServiceStartResponseError = (postServiceStartResponse409) & {
175183
headers: Headers;
176184
};
177-
;
178185

179-
export type postServiceStartResponse = (postServiceStartResponseSuccess)
186+
export type postServiceStartResponse = (postServiceStartResponseSuccess | postServiceStartResponseError)
180187

181188
export const getPostServiceStartUrl = () => {
182189

@@ -200,7 +207,7 @@ export const postServiceStart = async ( options?: RequestInit): Promise<postServ
200207

201208

202209

203-
export const getPostServiceStartMutationOptions = <TError = unknown,
210+
export const getPostServiceStartMutationOptions = <TError = void,
204211
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postServiceStart>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
205212
): UseMutationOptions<Awaited<ReturnType<typeof postServiceStart>>, TError,void, TContext> => {
206213

@@ -229,12 +236,12 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
229236

230237
export type PostServiceStartMutationResult = NonNullable<Awaited<ReturnType<typeof postServiceStart>>>
231238

232-
export type PostServiceStartMutationError = unknown
239+
export type PostServiceStartMutationError = void
233240

234241
/**
235242
* @summary Start routing runtime
236243
*/
237-
export const usePostServiceStart = <TError = unknown,
244+
export const usePostServiceStart = <TError = void,
238245
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postServiceStart>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
239246
, queryClient?: QueryClient): UseMutationResult<
240247
Awaited<ReturnType<typeof postServiceStart>>,
@@ -250,17 +257,24 @@ export const usePostServiceStart = <TError = unknown,
250257
251258
* @summary Stop routing runtime
252259
*/
253-
export type postServiceStopResponse200 = {
254-
data: ReloadResponse
255-
status: 200
260+
export type postServiceStopResponse202 = {
261+
data: LifecycleOperationAcceptedResponse
262+
status: 202
263+
}
264+
265+
export type postServiceStopResponse409 = {
266+
data: void
267+
status: 409
256268
}
257269

258-
export type postServiceStopResponseSuccess = (postServiceStopResponse200) & {
270+
export type postServiceStopResponseSuccess = (postServiceStopResponse202) & {
271+
headers: Headers;
272+
};
273+
export type postServiceStopResponseError = (postServiceStopResponse409) & {
259274
headers: Headers;
260275
};
261-
;
262276

263-
export type postServiceStopResponse = (postServiceStopResponseSuccess)
277+
export type postServiceStopResponse = (postServiceStopResponseSuccess | postServiceStopResponseError)
264278

265279
export const getPostServiceStopUrl = () => {
266280

@@ -284,7 +298,7 @@ export const postServiceStop = async ( options?: RequestInit): Promise<postServi
284298

285299

286300

287-
export const getPostServiceStopMutationOptions = <TError = unknown,
301+
export const getPostServiceStopMutationOptions = <TError = void,
288302
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postServiceStop>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
289303
): UseMutationOptions<Awaited<ReturnType<typeof postServiceStop>>, TError,void, TContext> => {
290304

@@ -313,12 +327,12 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
313327

314328
export type PostServiceStopMutationResult = NonNullable<Awaited<ReturnType<typeof postServiceStop>>>
315329

316-
export type PostServiceStopMutationError = unknown
330+
export type PostServiceStopMutationError = void
317331

318332
/**
319333
* @summary Stop routing runtime
320334
*/
321-
export const usePostServiceStop = <TError = unknown,
335+
export const usePostServiceStop = <TError = void,
322336
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postServiceStop>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
323337
, queryClient?: QueryClient): UseMutationResult<
324338
Awaited<ReturnType<typeof postServiceStop>>,
@@ -334,17 +348,24 @@ export const usePostServiceStop = <TError = unknown,
334348
335349
* @summary Restart routing runtime
336350
*/
337-
export type postServiceRestartResponse200 = {
338-
data: ReloadResponse
339-
status: 200
351+
export type postServiceRestartResponse202 = {
352+
data: LifecycleOperationAcceptedResponse
353+
status: 202
340354
}
341355

342-
export type postServiceRestartResponseSuccess = (postServiceRestartResponse200) & {
356+
export type postServiceRestartResponse409 = {
357+
data: void
358+
status: 409
359+
}
360+
361+
export type postServiceRestartResponseSuccess = (postServiceRestartResponse202) & {
362+
headers: Headers;
363+
};
364+
export type postServiceRestartResponseError = (postServiceRestartResponse409) & {
343365
headers: Headers;
344366
};
345-
;
346367

347-
export type postServiceRestartResponse = (postServiceRestartResponseSuccess)
368+
export type postServiceRestartResponse = (postServiceRestartResponseSuccess | postServiceRestartResponseError)
348369

349370
export const getPostServiceRestartUrl = () => {
350371

@@ -368,7 +389,7 @@ export const postServiceRestart = async ( options?: RequestInit): Promise<postSe
368389

369390

370391

371-
export const getPostServiceRestartMutationOptions = <TError = unknown,
392+
export const getPostServiceRestartMutationOptions = <TError = void,
372393
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postServiceRestart>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
373394
): UseMutationOptions<Awaited<ReturnType<typeof postServiceRestart>>, TError,void, TContext> => {
374395

@@ -397,12 +418,12 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
397418

398419
export type PostServiceRestartMutationResult = NonNullable<Awaited<ReturnType<typeof postServiceRestart>>>
399420

400-
export type PostServiceRestartMutationError = unknown
421+
export type PostServiceRestartMutationError = void
401422

402423
/**
403424
* @summary Restart routing runtime
404425
*/
405-
export const usePostServiceRestart = <TError = unknown,
426+
export const usePostServiceRestart = <TError = void,
406427
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postServiceRestart>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
407428
, queryClient?: QueryClient): UseMutationResult<
408429
Awaited<ReturnType<typeof postServiceRestart>>,
@@ -737,25 +758,30 @@ export const usePostConfig = <TError = ErrorResponse,
737758
738759
* @summary Apply staged config
739760
*/
740-
export type postConfigSaveResponse200 = {
741-
data: ConfigUpdateResponse
742-
status: 200
761+
export type postConfigSaveResponse202 = {
762+
data: LifecycleOperationAcceptedResponse
763+
status: 202
743764
}
744765

745766
export type postConfigSaveResponse400 = {
746767
data: ErrorResponse
747768
status: 400
748769
}
749770

771+
export type postConfigSaveResponse409 = {
772+
data: void
773+
status: 409
774+
}
775+
750776
export type postConfigSaveResponse500 = {
751777
data: ErrorResponse
752778
status: 500
753779
}
754780

755-
export type postConfigSaveResponseSuccess = (postConfigSaveResponse200) & {
781+
export type postConfigSaveResponseSuccess = (postConfigSaveResponse202) & {
756782
headers: Headers;
757783
};
758-
export type postConfigSaveResponseError = (postConfigSaveResponse400 | postConfigSaveResponse500) & {
784+
export type postConfigSaveResponseError = (postConfigSaveResponse400 | postConfigSaveResponse409 | postConfigSaveResponse500) & {
759785
headers: Headers;
760786
};
761787

@@ -783,7 +809,7 @@ export const postConfigSave = async ( options?: RequestInit): Promise<postConfig
783809

784810

785811

786-
export const getPostConfigSaveMutationOptions = <TError = ErrorResponse,
812+
export const getPostConfigSaveMutationOptions = <TError = ErrorResponse | void,
787813
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postConfigSave>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
788814
): UseMutationOptions<Awaited<ReturnType<typeof postConfigSave>>, TError,void, TContext> => {
789815

@@ -812,12 +838,12 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
812838

813839
export type PostConfigSaveMutationResult = NonNullable<Awaited<ReturnType<typeof postConfigSave>>>
814840

815-
export type PostConfigSaveMutationError = ErrorResponse
841+
export type PostConfigSaveMutationError = ErrorResponse | void
816842

817843
/**
818844
* @summary Apply staged config
819845
*/
820-
export const usePostConfigSave = <TError = ErrorResponse,
846+
export const usePostConfigSave = <TError = ErrorResponse | void,
821847
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postConfigSave>>, TError,void, TContext>, request?: SecondParameter<typeof apiFetch>}
822848
, queryClient?: QueryClient): UseMutationResult<
823849
Awaited<ReturnType<typeof postConfigSave>>,

frontend/src/api/generated/model/daemonConfig.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export interface DaemonConfig {
4242
* @minimum 1
4343
*/
4444
exec_timeout_seconds?: number;
45+
/**
46+
* Deadline for dnsmasq process stabilization and DNS readiness after a helper completes.
47+
* @minimum 1
48+
*/
49+
resolver_ready_timeout_seconds?: number;
4550
/**
4651
* Grace period after SIGTERM before a timed-out helper receives SIGKILL.
4752
* @minimum 0

0 commit comments

Comments
 (0)