@shipfox/api-runners 12.3.0 → 12.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +22 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -2
- package/dist/config.js.map +1 -1
- package/dist/core/demand.d.ts +4 -2
- package/dist/core/demand.d.ts.map +1 -1
- package/dist/core/demand.js +22 -6
- package/dist/core/demand.js.map +1 -1
- package/dist/core/entities/reservation.d.ts +1 -0
- package/dist/core/entities/reservation.d.ts.map +1 -1
- package/dist/core/entities/reservation.js.map +1 -1
- package/dist/core/entities/runner-instance.d.ts +3 -0
- package/dist/core/entities/runner-instance.d.ts.map +1 -1
- package/dist/core/entities/runner-instance.js.map +1 -1
- package/dist/core/runner-activation.d.ts +4 -1
- package/dist/core/runner-activation.d.ts.map +1 -1
- package/dist/core/runner-activation.js +32 -3
- package/dist/core/runner-activation.js.map +1 -1
- package/dist/core/runner-control-sessions.d.ts +8 -4
- package/dist/core/runner-control-sessions.d.ts.map +1 -1
- package/dist/core/runner-control-sessions.js +55 -9
- package/dist/core/runner-control-sessions.js.map +1 -1
- package/dist/core/runner-instances.d.ts +1 -0
- package/dist/core/runner-instances.d.ts.map +1 -1
- package/dist/core/runner-instances.js +1 -0
- package/dist/core/runner-instances.js.map +1 -1
- package/dist/db/db.d.ts +68 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
- package/dist/db/ephemeral-registration-tokens.js +1 -1
- package/dist/db/ephemeral-registration-tokens.js.map +1 -1
- package/dist/db/reservation-locks.d.ts +6 -0
- package/dist/db/reservation-locks.d.ts.map +1 -0
- package/dist/db/reservation-locks.js +15 -0
- package/dist/db/reservation-locks.js.map +1 -0
- package/dist/db/reservations.d.ts +17 -3
- package/dist/db/reservations.d.ts.map +1 -1
- package/dist/db/reservations.js +246 -51
- package/dist/db/reservations.js.map +1 -1
- package/dist/db/runner-assignments.d.ts +17 -0
- package/dist/db/runner-assignments.d.ts.map +1 -1
- package/dist/db/runner-assignments.js +103 -8
- package/dist/db/runner-assignments.js.map +1 -1
- package/dist/db/runner-instances.d.ts +2 -2
- package/dist/db/runner-instances.d.ts.map +1 -1
- package/dist/db/runner-instances.js +124 -24
- package/dist/db/runner-instances.js.map +1 -1
- package/dist/db/runner-states.d.ts +2 -0
- package/dist/db/runner-states.d.ts.map +1 -0
- package/dist/db/runner-states.js +7 -0
- package/dist/db/runner-states.js.map +1 -0
- package/dist/db/schema/reservations.d.ts +18 -0
- package/dist/db/schema/reservations.d.ts.map +1 -1
- package/dist/db/schema/reservations.js +7 -1
- package/dist/db/schema/reservations.js.map +1 -1
- package/dist/db/schema/runner-instances.d.ts +18 -0
- package/dist/db/schema/runner-instances.d.ts.map +1 -1
- package/dist/db/schema/runner-instances.js +8 -0
- package/dist/db/schema/runner-instances.js.map +1 -1
- package/dist/metrics/index.d.ts +2 -2
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +1 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/instance.d.ts +24 -2
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +23 -0
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
- package/dist/presentation/dto/poll-demand.js +3 -0
- package/dist/presentation/dto/poll-demand.js.map +1 -1
- package/dist/presentation/dto/runner-instances.d.ts +4 -1
- package/dist/presentation/dto/runner-instances.d.ts.map +1 -1
- package/dist/presentation/dto/runner-instances.js +4 -1
- package/dist/presentation/dto/runner-instances.js.map +1 -1
- package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -1
- package/dist/presentation/routes/assign-runner-instances.js +3 -3
- package/dist/presentation/routes/assign-runner-instances.js.map +1 -1
- package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
- package/dist/presentation/routes/poll-demand.js +1 -0
- package/dist/presentation/routes/poll-demand.js.map +1 -1
- package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -1
- package/dist/presentation/routes/reconcile-runner-instances.js +4 -2
- package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -1
- package/dist/presentation/routes/runner-enrollment.d.ts +4 -1
- package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
- package/dist/presentation/routes/runner-enrollment.js +11 -6
- package/dist/presentation/routes/runner-enrollment.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0005_previous_lenny_balinger.sql +5 -0
- package/drizzle/meta/0005_snapshot.json +2220 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +2 -2
- package/src/config.test.ts +22 -0
- package/src/config.ts +15 -2
- package/src/core/demand.test.ts +192 -3
- package/src/core/demand.ts +44 -4
- package/src/core/entities/reservation.ts +1 -0
- package/src/core/entities/runner-instance.ts +4 -0
- package/src/core/runner-activation.ts +48 -2
- package/src/core/runner-control-sessions.test.ts +64 -3
- package/src/core/runner-control-sessions.ts +62 -9
- package/src/core/runner-instances.test.ts +19 -0
- package/src/core/runner-instances.ts +2 -0
- package/src/core/runner-sessions.test.ts +121 -1
- package/src/db/ephemeral-registration-tokens.test.ts +20 -1
- package/src/db/ephemeral-registration-tokens.ts +1 -0
- package/src/db/reservation-locks.ts +22 -0
- package/src/db/reservations.test.ts +733 -22
- package/src/db/reservations.ts +408 -144
- package/src/db/runner-assignments.test.ts +105 -1
- package/src/db/runner-assignments.ts +178 -9
- package/src/db/runner-instances.test.ts +265 -2
- package/src/db/runner-instances.ts +215 -55
- package/src/db/runner-states.ts +7 -0
- package/src/db/schema/reservations.ts +5 -1
- package/src/db/schema/runner-instances.ts +9 -0
- package/src/metrics/index.ts +10 -1
- package/src/metrics/instance.ts +59 -2
- package/src/metrics/service.test.ts +8 -1
- package/src/presentation/dto/poll-demand.ts +3 -0
- package/src/presentation/dto/runner-instances.ts +8 -1
- package/src/presentation/routes/assign-runner-instances.ts +6 -2
- package/src/presentation/routes/late-runner-enrollment.test.ts +219 -2
- package/src/presentation/routes/poll-demand.test.ts +56 -0
- package/src/presentation/routes/poll-demand.ts +1 -0
- package/src/presentation/routes/reconcile-runner-instances.test.ts +34 -2
- package/src/presentation/routes/reconcile-runner-instances.ts +7 -1
- package/src/presentation/routes/runner-enrollment.test.ts +316 -3
- package/src/presentation/routes/runner-enrollment.ts +8 -5
- package/test/factories/reservation.ts +2 -0
- package/test/factories/runner-instance.ts +6 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/routes/poll-demand.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireWorkspaceProvisionerContext,\n} from '@shipfox/api-auth-context';\nimport type {PollDemandTemplateDto} from '@shipfox/api-runners-dto';\nimport {pollDemandBodySchema, pollDemandResponseSchema} from '@shipfox/api-runners-dto';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {config} from '#config.js';\nimport {pollDemand, releaseReservationGrants} from '#core/demand.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {publishWorkspaceProvisionerCapabilitySnapshot} from '#db/provisioner-capability-snapshots.js';\nimport {\n listQueuedDemandWorkspaceIds,\n pollInstallationDemandAndReserve,\n type ReservationGrant,\n type ReservationTemplate,\n} from '#db/reservations.js';\nimport type {CreateRunnersModuleOptions} from '#installation-provisioning.js';\nimport {toPollDemandResponseDto} from '#presentation/dto/index.js';\n\nconst TERMINATE_INTENT_LIMIT = 1000;\n\nfunction toReservationTemplates(\n templates: PollDemandTemplateDto[],\n scope: 'installation' | 'workspace',\n): ReservationTemplate[] {\n return templates.map((template) => ({\n templateKey: template.template_key,\n labels: sanitizeRunnerLabels(template.labels, {\n scope,\n logLevel: 'debug',\n source: 'provisioner template advertisement',\n }),\n availableSlots: template.available_slots,\n starting: template.starting,\n running: template.running,\n }));\n}\n\nexport function createPollDemandRoute(options: CreateRunnersModuleOptions = {}) {\n return defineRoute({\n method: 'POST',\n path: '/demand/poll',\n description: 'Poll aggregate runner demand and reserve capacity for a provisioner',\n schema: {\n body: pollDemandBodySchema,\n response: {\n 200: pollDemandResponseSchema,\n },\n },\n handler: async (request, reply) => {\n const abortController = new AbortController();\n let responseFinished = false;\n let responseReservations: ReservationGrant[] = [];\n reply.raw.on('finish', () => {\n responseFinished = true;\n });\n reply.raw.on('close', () => {\n if (!responseFinished) {\n abortController.abort();\n void releaseReservationGrants(responseReservations).catch((error) => {\n logger().error(\n {err: error, reservationCount: responseReservations.length},\n 'Failed to release reservations after provisioner disconnect',\n );\n reportError(error, {\n boundary: 'runners.cleanup',\n operation: 'release-disconnected-reservations',\n extra: {reservationCount: responseReservations.length},\n });\n });\n }\n });\n const provisionerContext = requireProvisionerContext(request);\n const ttlSeconds = Math.min(\n request.body.reservation_ttl_seconds ?? config.RESERVATION_TTL_SECONDS,\n config.RESERVATION_TTL_MAX_SECONDS,\n );\n if (provisionerContext.scope === 'installation') {\n if (!options.installationProvisioning) {\n throw new ClientError(\n 'Installation provisioner credentials are not accepted on this host',\n 'forbidden',\n {\n status: 403,\n },\n );\n }\n const candidateWorkspaceIds = await listQueuedDemandWorkspaceIds();\n const eligibleWorkspaceIds =\n await options.installationProvisioning.policy.filterEligibleWorkspaceIds(\n candidateWorkspaceIds,\n );\n const templates = toReservationTemplates(request.body.templates, 'installation');\n const result = await pollInstallationDemandAndReserve({\n provisionerId: provisionerContext.provisionerTokenId,\n maxReservations: request.body.max_reservations,\n ttlSeconds,\n templates,\n capabilityWindowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,\n eligibleWorkspaceIds,\n signal: abortController.signal,\n onReservations: (reservations) => {\n responseReservations.push(...reservations);\n },\n });\n return toPollDemandResponseDto({\n ...result,\n terminateRunnerInstanceIds: [],\n });\n }\n const {provisionerTokenId, workspaceId} = requireWorkspaceProvisionerContext(request);\n\n const templates = toReservationTemplates(request.body.templates, 'workspace');\n await publishWorkspaceProvisionerCapabilitySnapshot({\n workspaceId,\n provisionerId: provisionerTokenId,\n templates,\n });\n\n const result = await pollDemand({\n workspaceId,\n provisionerId: provisionerTokenId,\n maxReservations: request.body.max_reservations,\n waitSeconds: request.body.wait_seconds,\n ttlSeconds,\n terminateIntentLimit: TERMINATE_INTENT_LIMIT,\n templates,\n signal: abortController.signal,\n });\n responseReservations = result.reservations;\n\n return toPollDemandResponseDto(result);\n },\n });\n}\n\nexport const pollDemandRoute = createPollDemandRoute();\n"],"names":["requireProvisionerContext","requireWorkspaceProvisionerContext","pollDemandBodySchema","pollDemandResponseSchema","reportError","ClientError","defineRoute","logger","config","pollDemand","releaseReservationGrants","sanitizeRunnerLabels","publishWorkspaceProvisionerCapabilitySnapshot","listQueuedDemandWorkspaceIds","pollInstallationDemandAndReserve","toPollDemandResponseDto","TERMINATE_INTENT_LIMIT","toReservationTemplates","templates","scope","map","template","templateKey","template_key","labels","logLevel","source","availableSlots","available_slots","starting","running","createPollDemandRoute","options","method","path","description","schema","body","response","handler","request","reply","abortController","AbortController","responseFinished","responseReservations","raw","on","abort","catch","error","err","reservationCount","length","boundary","operation","extra","provisionerContext","ttlSeconds","Math","min","reservation_ttl_seconds","RESERVATION_TTL_SECONDS","RESERVATION_TTL_MAX_SECONDS","installationProvisioning","status","candidateWorkspaceIds","eligibleWorkspaceIds","policy","filterEligibleWorkspaceIds","result","provisionerId","provisionerTokenId","maxReservations","max_reservations","capabilityWindowSeconds","PROVISIONER_ACTIVE_WINDOW_SECONDS","signal","onReservations","reservations","push","terminateRunnerInstanceIds","workspaceId","waitSeconds","wait_seconds","terminateIntentLimit","pollDemandRoute"],"mappings":"AAAA,SACEA,yBAAyB,EACzBC,kCAAkC,QAC7B,4BAA4B;AAEnC,SAAQC,oBAAoB,EAAEC,wBAAwB,QAAO,2BAA2B;AACxF,SAAQC,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,MAAM,QAAO,8BAA8B;AACnD,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,UAAU,EAAEC,wBAAwB,QAAO,kBAAkB;AACrE,SAAQC,oBAAoB,QAAO,yBAAyB;AAC5D,SAAQC,6CAA6C,QAAO,0CAA0C;AACtG,SACEC,4BAA4B,EAC5BC,gCAAgC,QAG3B,sBAAsB;AAE7B,SAAQC,uBAAuB,QAAO,6BAA6B;AAEnE,MAAMC,yBAAyB;AAE/B,SAASC,uBACPC,SAAkC,EAClCC,KAAmC;IAEnC,OAAOD,UAAUE,GAAG,CAAC,CAACC,WAAc,CAAA;YAClCC,aAAaD,SAASE,YAAY;YAClCC,QAAQb,qBAAqBU,SAASG,MAAM,EAAE;gBAC5CL;gBACAM,UAAU;gBACVC,QAAQ;YACV;YACAC,gBAAgBN,SAASO,eAAe;YACxCC,UAAUR,SAASQ,QAAQ;YAC3BC,SAAST,SAASS,OAAO;QAC3B,CAAA;AACF;AAEA,OAAO,SAASC,sBAAsBC,UAAsC,CAAC,CAAC;IAC5E,OAAO1B,YAAY;QACjB2B,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNC,MAAMnC;YACNoC,UAAU;gBACR,KAAKnC;YACP;QACF;QACAoC,SAAS,OAAOC,SAASC;YACvB,MAAMC,kBAAkB,IAAIC;YAC5B,IAAIC,mBAAmB;YACvB,IAAIC,uBAA2C,EAAE;YACjDJ,MAAMK,GAAG,CAACC,EAAE,CAAC,UAAU;gBACrBH,mBAAmB;YACrB;YACAH,MAAMK,GAAG,CAACC,EAAE,CAAC,SAAS;gBACpB,IAAI,CAACH,kBAAkB;oBACrBF,gBAAgBM,KAAK;oBACrB,KAAKtC,yBAAyBmC,sBAAsBI,KAAK,CAAC,CAACC;wBACzD3C,SAAS2C,KAAK,CACZ;4BAACC,KAAKD;4BAAOE,kBAAkBP,qBAAqBQ,MAAM;wBAAA,GAC1D;wBAEFjD,YAAY8C,OAAO;4BACjBI,UAAU;4BACVC,WAAW;4BACXC,OAAO;gCAACJ,kBAAkBP,qBAAqBQ,MAAM;4BAAA;wBACvD;oBACF;gBACF;YACF;YACA,MAAMI,qBAAqBzD,0BAA0BwC;YACrD,MAAMkB,aAAaC,KAAKC,GAAG,CACzBpB,QAAQH,IAAI,CAACwB,uBAAuB,IAAIrD,OAAOsD,uBAAuB,EACtEtD,OAAOuD,2BAA2B;YAEpC,IAAIN,mBAAmBtC,KAAK,KAAK,gBAAgB;gBAC/C,IAAI,CAACa,QAAQgC,wBAAwB,EAAE;oBACrC,MAAM,IAAI3D,YACR,sEACA,aACA;wBACE4D,QAAQ;oBACV;gBAEJ;gBACA,MAAMC,wBAAwB,MAAMrD;gBACpC,MAAMsD,uBACJ,MAAMnC,QAAQgC,wBAAwB,CAACI,MAAM,CAACC,0BAA0B,CACtEH;gBAEJ,MAAMhD,YAAYD,uBAAuBuB,QAAQH,IAAI,CAACnB,SAAS,EAAE;gBACjE,MAAMoD,SAAS,MAAMxD,iCAAiC;oBACpDyD,eAAed,mBAAmBe,kBAAkB;oBACpDC,iBAAiBjC,QAAQH,IAAI,CAACqC,gBAAgB;oBAC9ChB;
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/poll-demand.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireWorkspaceProvisionerContext,\n} from '@shipfox/api-auth-context';\nimport type {PollDemandTemplateDto} from '@shipfox/api-runners-dto';\nimport {pollDemandBodySchema, pollDemandResponseSchema} from '@shipfox/api-runners-dto';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {config} from '#config.js';\nimport {pollDemand, releaseReservationGrants} from '#core/demand.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {publishWorkspaceProvisionerCapabilitySnapshot} from '#db/provisioner-capability-snapshots.js';\nimport {\n listQueuedDemandWorkspaceIds,\n pollInstallationDemandAndReserve,\n type ReservationGrant,\n type ReservationTemplate,\n} from '#db/reservations.js';\nimport type {CreateRunnersModuleOptions} from '#installation-provisioning.js';\nimport {toPollDemandResponseDto} from '#presentation/dto/index.js';\n\nconst TERMINATE_INTENT_LIMIT = 1000;\n\nfunction toReservationTemplates(\n templates: PollDemandTemplateDto[],\n scope: 'installation' | 'workspace',\n): ReservationTemplate[] {\n return templates.map((template) => ({\n templateKey: template.template_key,\n labels: sanitizeRunnerLabels(template.labels, {\n scope,\n logLevel: 'debug',\n source: 'provisioner template advertisement',\n }),\n availableSlots: template.available_slots,\n starting: template.starting,\n running: template.running,\n }));\n}\n\nexport function createPollDemandRoute(options: CreateRunnersModuleOptions = {}) {\n return defineRoute({\n method: 'POST',\n path: '/demand/poll',\n description: 'Poll aggregate runner demand and reserve capacity for a provisioner',\n schema: {\n body: pollDemandBodySchema,\n response: {\n 200: pollDemandResponseSchema,\n },\n },\n handler: async (request, reply) => {\n const abortController = new AbortController();\n let responseFinished = false;\n let responseReservations: ReservationGrant[] = [];\n reply.raw.on('finish', () => {\n responseFinished = true;\n });\n reply.raw.on('close', () => {\n if (!responseFinished) {\n abortController.abort();\n void releaseReservationGrants(responseReservations).catch((error) => {\n logger().error(\n {err: error, reservationCount: responseReservations.length},\n 'Failed to release reservations after provisioner disconnect',\n );\n reportError(error, {\n boundary: 'runners.cleanup',\n operation: 'release-disconnected-reservations',\n extra: {reservationCount: responseReservations.length},\n });\n });\n }\n });\n const provisionerContext = requireProvisionerContext(request);\n const ttlSeconds = Math.min(\n request.body.reservation_ttl_seconds ?? config.RESERVATION_TTL_SECONDS,\n config.RESERVATION_TTL_MAX_SECONDS,\n );\n if (provisionerContext.scope === 'installation') {\n if (!options.installationProvisioning) {\n throw new ClientError(\n 'Installation provisioner credentials are not accepted on this host',\n 'forbidden',\n {\n status: 403,\n },\n );\n }\n const candidateWorkspaceIds = await listQueuedDemandWorkspaceIds();\n const eligibleWorkspaceIds =\n await options.installationProvisioning.policy.filterEligibleWorkspaceIds(\n candidateWorkspaceIds,\n );\n const templates = toReservationTemplates(request.body.templates, 'installation');\n const result = await pollInstallationDemandAndReserve({\n provisionerId: provisionerContext.provisionerTokenId,\n maxReservations: request.body.max_reservations,\n ttlSeconds,\n activationGraceSeconds: config.RESERVATION_TTL_SECONDS,\n templates,\n capabilityWindowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,\n eligibleWorkspaceIds,\n signal: abortController.signal,\n onReservations: (reservations) => {\n responseReservations.push(...reservations);\n },\n });\n return toPollDemandResponseDto({\n ...result,\n terminateRunnerInstanceIds: [],\n });\n }\n const {provisionerTokenId, workspaceId} = requireWorkspaceProvisionerContext(request);\n\n const templates = toReservationTemplates(request.body.templates, 'workspace');\n await publishWorkspaceProvisionerCapabilitySnapshot({\n workspaceId,\n provisionerId: provisionerTokenId,\n templates,\n });\n\n const result = await pollDemand({\n workspaceId,\n provisionerId: provisionerTokenId,\n maxReservations: request.body.max_reservations,\n waitSeconds: request.body.wait_seconds,\n ttlSeconds,\n terminateIntentLimit: TERMINATE_INTENT_LIMIT,\n templates,\n signal: abortController.signal,\n });\n responseReservations = result.reservations;\n\n return toPollDemandResponseDto(result);\n },\n });\n}\n\nexport const pollDemandRoute = createPollDemandRoute();\n"],"names":["requireProvisionerContext","requireWorkspaceProvisionerContext","pollDemandBodySchema","pollDemandResponseSchema","reportError","ClientError","defineRoute","logger","config","pollDemand","releaseReservationGrants","sanitizeRunnerLabels","publishWorkspaceProvisionerCapabilitySnapshot","listQueuedDemandWorkspaceIds","pollInstallationDemandAndReserve","toPollDemandResponseDto","TERMINATE_INTENT_LIMIT","toReservationTemplates","templates","scope","map","template","templateKey","template_key","labels","logLevel","source","availableSlots","available_slots","starting","running","createPollDemandRoute","options","method","path","description","schema","body","response","handler","request","reply","abortController","AbortController","responseFinished","responseReservations","raw","on","abort","catch","error","err","reservationCount","length","boundary","operation","extra","provisionerContext","ttlSeconds","Math","min","reservation_ttl_seconds","RESERVATION_TTL_SECONDS","RESERVATION_TTL_MAX_SECONDS","installationProvisioning","status","candidateWorkspaceIds","eligibleWorkspaceIds","policy","filterEligibleWorkspaceIds","result","provisionerId","provisionerTokenId","maxReservations","max_reservations","activationGraceSeconds","capabilityWindowSeconds","PROVISIONER_ACTIVE_WINDOW_SECONDS","signal","onReservations","reservations","push","terminateRunnerInstanceIds","workspaceId","waitSeconds","wait_seconds","terminateIntentLimit","pollDemandRoute"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reconcile-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,6BAA6B,iDAwBxC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { requireProvisionerContext } from '@shipfox/api-auth-context';
|
|
2
|
-
import { reconcileRunnerInstancesBodySchema, reconcileRunnerInstancesResponseSchema } from '@shipfox/api-runners-dto';
|
|
2
|
+
import { RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER, RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE, reconcileRunnerInstancesBodySchema, reconcileRunnerInstancesResponseSchema } from '@shipfox/api-runners-dto';
|
|
3
3
|
import { defineRoute } from '@shipfox/node-fastify';
|
|
4
4
|
import { reconcileRunnerInstances } from '#core/index.js';
|
|
5
5
|
import { toReconcileRunnerInstancesResponseDto } from '#presentation/dto/index.js';
|
|
@@ -20,7 +20,9 @@ export const reconcileRunnerInstancesRoute = defineRoute({
|
|
|
20
20
|
provisionerId: context.provisionerTokenId,
|
|
21
21
|
observedRunnerInstanceIds: request.body.observed_provider_runner_ids
|
|
22
22
|
});
|
|
23
|
-
return toReconcileRunnerInstancesResponseDto(result
|
|
23
|
+
return toReconcileRunnerInstancesResponseDto(result, {
|
|
24
|
+
includeIntendedReservationId: request.headers[RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER] === RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE
|
|
25
|
+
});
|
|
24
26
|
}
|
|
25
27
|
});
|
|
26
28
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"sourcesContent":["import {requireProvisionerContext} from '@shipfox/api-auth-context';\nimport {\n reconcileRunnerInstancesBodySchema,\n reconcileRunnerInstancesResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport {reconcileRunnerInstances} from '#core/index.js';\nimport {toReconcileRunnerInstancesResponseDto} from '#presentation/dto/index.js';\n\nexport const reconcileRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/reconcile',\n description: 'Reconcile provisioned runner state for a provisioner',\n schema: {\n body: reconcileRunnerInstancesBodySchema,\n response: {\n 200: reconcileRunnerInstancesResponseSchema,\n },\n },\n handler: async (request) => {\n const context = requireProvisionerContext(request);\n const result = await reconcileRunnerInstances({\n workspaceId: context.scope === 'workspace' ? context.workspaceId : null,\n provisionerId: context.provisionerTokenId,\n observedRunnerInstanceIds: request.body.observed_provider_runner_ids,\n });\n\n return toReconcileRunnerInstancesResponseDto(result);\n },\n});\n"],"names":["requireProvisionerContext","reconcileRunnerInstancesBodySchema","reconcileRunnerInstancesResponseSchema","defineRoute","reconcileRunnerInstances","toReconcileRunnerInstancesResponseDto","reconcileRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","context","result","workspaceId","scope","provisionerId","provisionerTokenId","observedRunnerInstanceIds","observed_provider_runner_ids"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,4BAA4B;AACpE,SACEC,kCAAkC,EAClCC,sCAAsC,QACjC,2BAA2B;AAClC,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,wBAAwB,QAAO,iBAAiB;AACxD,SAAQC,qCAAqC,QAAO,6BAA6B;AAEjF,OAAO,MAAMC,gCAAgCH,YAAY;IACvDI,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,MAAMV;QACNW,UAAU;YACR,KAAKV;QACP;IACF;IACAW,SAAS,OAAOC;QACd,MAAMC,
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"sourcesContent":["import {requireProvisionerContext} from '@shipfox/api-auth-context';\nimport {\n RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER,\n RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE,\n reconcileRunnerInstancesBodySchema,\n reconcileRunnerInstancesResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport {reconcileRunnerInstances} from '#core/index.js';\nimport {toReconcileRunnerInstancesResponseDto} from '#presentation/dto/index.js';\n\nexport const reconcileRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/reconcile',\n description: 'Reconcile provisioned runner state for a provisioner',\n schema: {\n body: reconcileRunnerInstancesBodySchema,\n response: {\n 200: reconcileRunnerInstancesResponseSchema,\n },\n },\n handler: async (request) => {\n const context = requireProvisionerContext(request);\n const result = await reconcileRunnerInstances({\n workspaceId: context.scope === 'workspace' ? context.workspaceId : null,\n provisionerId: context.provisionerTokenId,\n observedRunnerInstanceIds: request.body.observed_provider_runner_ids,\n });\n\n return toReconcileRunnerInstancesResponseDto(result, {\n includeIntendedReservationId:\n request.headers[RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER] ===\n RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE,\n });\n },\n});\n"],"names":["requireProvisionerContext","RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER","RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE","reconcileRunnerInstancesBodySchema","reconcileRunnerInstancesResponseSchema","defineRoute","reconcileRunnerInstances","toReconcileRunnerInstancesResponseDto","reconcileRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","context","result","workspaceId","scope","provisionerId","provisionerTokenId","observedRunnerInstanceIds","observed_provider_runner_ids","includeIntendedReservationId","headers"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,4BAA4B;AACpE,SACEC,sDAAsD,EACtDC,4DAA4D,EAC5DC,kCAAkC,EAClCC,sCAAsC,QACjC,2BAA2B;AAClC,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,wBAAwB,QAAO,iBAAiB;AACxD,SAAQC,qCAAqC,QAAO,6BAA6B;AAEjF,OAAO,MAAMC,gCAAgCH,YAAY;IACvDI,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,MAAMV;QACNW,UAAU;YACR,KAAKV;QACP;IACF;IACAW,SAAS,OAAOC;QACd,MAAMC,UAAUjB,0BAA0BgB;QAC1C,MAAME,SAAS,MAAMZ,yBAAyB;YAC5Ca,aAAaF,QAAQG,KAAK,KAAK,cAAcH,QAAQE,WAAW,GAAG;YACnEE,eAAeJ,QAAQK,kBAAkB;YACzCC,2BAA2BP,QAAQH,IAAI,CAACW,4BAA4B;QACtE;QAEA,OAAOjB,sCAAsCW,QAAQ;YACnDO,8BACET,QAAQU,OAAO,CAACzB,uDAAuD,KACvEC;QACJ;IACF;AACF,GAAG"}
|
|
@@ -8,7 +8,10 @@ type RunnerAssignmentPollParams = {
|
|
|
8
8
|
deadline: number;
|
|
9
9
|
intervalMs: number;
|
|
10
10
|
signal: AbortSignal;
|
|
11
|
-
getAssignment: () => Promise<
|
|
11
|
+
getAssignment: () => Promise<{
|
|
12
|
+
workspaceId: string | null;
|
|
13
|
+
runnerSessionId: string | null;
|
|
14
|
+
} | null>;
|
|
12
15
|
issueActivationToken: () => Promise<string | null>;
|
|
13
16
|
};
|
|
14
17
|
export declare function resolveRunnerAssignmentPollWaitSeconds(requestedWaitSeconds: number | undefined): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-enrollment.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/runner-enrollment.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,0BAA0B,
|
|
1
|
+
{"version":3,"file":"runner-enrollment.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/runner-enrollment.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,0BAA0B,iDA6BrC,CAAC;AAEH,eAAO,MAAM,mCAAmC,iDAmB9C,CAAC;AAEH,eAAO,MAAM,4BAA4B,iDA2BvC,CAAC;AAEH,eAAO,MAAM,iBAAiB,iDAuB5B,CAAC;AAEH,eAAO,MAAM,kCAAkC,iDAkB7C,CAAC;AAEH,eAAO,MAAM,2BAA2B,iDAYtC,CAAC;AAEH,KAAK,0BAA0B,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,aAAa,EAAE,MAAM,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAC,GAAG,IAAI,CAAC,CAAC;IAClG,oBAAoB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD,CAAC;AAEF,wBAAgB,sCAAsC,CACpD,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACvC,MAAM,CAQR;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAaxB;AACD,eAAO,MAAM,yBAAyB,iDA6BpC,CAAC"}
|
|
@@ -20,7 +20,7 @@ export const createRunnerInstancesRoute = defineRoute({
|
|
|
20
20
|
},
|
|
21
21
|
handler: async (request)=>{
|
|
22
22
|
const { provisionerTokenId } = requireProvisionerContext(request);
|
|
23
|
-
const
|
|
23
|
+
const result = await createRunnerInstancesWithBootstrapTokens({
|
|
24
24
|
provisionerId: provisionerTokenId,
|
|
25
25
|
...request.body.provider_kind ? {
|
|
26
26
|
providerKind: request.body.provider_kind
|
|
@@ -36,10 +36,14 @@ export const createRunnerInstancesRoute = defineRoute({
|
|
|
36
36
|
ttlSeconds: config.RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS
|
|
37
37
|
});
|
|
38
38
|
return {
|
|
39
|
-
runner_instances:
|
|
40
|
-
runner_instance_id:
|
|
41
|
-
bootstrap_token:
|
|
42
|
-
|
|
39
|
+
runner_instances: result.runnerInstances.map((runnerInstance)=>({
|
|
40
|
+
runner_instance_id: runnerInstance.runnerInstanceId,
|
|
41
|
+
bootstrap_token: runnerInstance.bootstrapToken,
|
|
42
|
+
request_index: runnerInstance.requestIndex
|
|
43
|
+
})),
|
|
44
|
+
...result.reservationUnavailable ? {
|
|
45
|
+
reservation_unavailable: true
|
|
46
|
+
} : {}
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
49
|
});
|
|
@@ -220,7 +224,8 @@ export const runnerAssignmentPollRoute = defineRoute({
|
|
|
220
224
|
getAssignment: ()=>getRunnerAssignment(session),
|
|
221
225
|
issueActivationToken: ()=>issueRunnerActivationToken({
|
|
222
226
|
...session,
|
|
223
|
-
ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS
|
|
227
|
+
ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,
|
|
228
|
+
surface: 'poll'
|
|
224
229
|
})
|
|
225
230
|
});
|
|
226
231
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/routes/runner-enrollment.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireRunnerControlSessionContext,\n} from '@shipfox/api-auth-context';\nimport {\n attachRunnerControlProviderIdBodySchema,\n createRunnerInstancesBodySchema,\n createRunnerInstancesResponseSchema,\n runnerAssignmentPollQuerySchema,\n runnerAssignmentPollResponseSchema,\n runnerBootstrapExchangeBodySchema,\n runnerBootstrapExchangeResponseSchema,\n runnerControlHeartbeatResponseSchema,\n runnerEnrollmentBodySchema,\n runnerEnrollmentResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {config} from '#config.js';\nimport {getRunnerAssignment, issueRunnerActivationToken} from '#core/runner-activation.js';\nimport {\n attachRunnerControlProviderId,\n createRunnerInstancesWithBootstrapTokens,\n enrollRunnerControlSession,\n exchangeRunnerBootstrapToken,\n RunnerBootstrapTokenInvalidError,\n RunnerControlSessionInvalidError,\n touchRunnerControlSession,\n} from '#core/runner-control-sessions.js';\nimport {attachRunnerInstanceProviderId} from '#core/runner-instances.js';\nimport {runnerBootstrapExchangeCount, runnerControlHeartbeatCount} from '#metrics/instance.js';\nimport {authenticateRunnerControlSession} from '#presentation/auth/index.js';\n\nexport const createRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/batch',\n description:\n 'Create provisioner-owned runner instances and one-use bootstrap tokens before launch',\n schema: {\n body: createRunnerInstancesBodySchema,\n response: {200: createRunnerInstancesResponseSchema},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n const results = await createRunnerInstancesWithBootstrapTokens({\n provisionerId: provisionerTokenId,\n ...(request.body.provider_kind ? {providerKind: request.body.provider_kind} : {}),\n runnerInstances: request.body.runner_instances.map((runner) => ({\n ...(runner.template_key ? {templateKey: runner.template_key} : {}),\n ...(runner.reservation_id ? {reservationId: runner.reservation_id} : {}),\n })),\n ttlSeconds: config.RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS,\n });\n return {\n runner_instances: results.map((result) => ({\n runner_instance_id: result.runnerInstanceId,\n bootstrap_token: result.bootstrapToken,\n })),\n };\n },\n});\n\nexport const attachRunnerInstanceProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/:runnerInstanceId/provider-runner',\n description: 'Attach the provider identity after the provisioner launches a runner instance',\n schema: {\n params: z.object({runnerInstanceId: z.string().uuid()}),\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n return {\n attached: await attachRunnerInstanceProviderId({\n runnerInstanceId: request.params.runnerInstanceId,\n provisionerId: provisionerTokenId,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const exchangeRunnerBootstrapRoute = defineRoute({\n method: 'POST',\n path: '/exchange',\n description: 'Exchange a one-use runner bootstrap token for a workspace-neutral control session',\n schema: {\n body: runnerBootstrapExchangeBodySchema,\n response: {200: runnerBootstrapExchangeResponseSchema},\n },\n errorHandler: (error) => {\n if (error instanceof RunnerBootstrapTokenInvalidError)\n runnerBootstrapExchangeCount.add(1, {outcome: 'rejected'});\n if (error instanceof RunnerBootstrapTokenInvalidError)\n throw new ClientError(error.message, 'runner-bootstrap-token-invalid', {status: 401});\n throw error;\n },\n handler: async (request) => {\n const result = await exchangeRunnerBootstrapToken({\n rawToken: request.body.bootstrap_token,\n ttlSeconds: config.RUNNER_CONTROL_SESSION_TTL_SECONDS,\n });\n runnerBootstrapExchangeCount.add(1, {outcome: 'accepted'});\n return {\n runner_instance_id: result.runnerInstanceId,\n control_session_token: result.controlSessionToken,\n expires_at: result.expiresAt.toISOString(),\n };\n },\n});\n\nexport const enrollRunnerRoute = defineRoute({\n method: 'POST',\n path: '/enrollment',\n description: 'Declare the authenticated runner instance labels and protocol capabilities',\n schema: {body: runnerEnrollmentBodySchema, response: {200: runnerEnrollmentResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n errorHandler: (error) => {\n if (error instanceof RunnerControlSessionInvalidError)\n throw new ClientError(error.message, 'runner-control-session-invalid', {status: 409});\n throw error;\n },\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n const activationToken = await enrollRunnerControlSession({\n runnerInstanceId: session.runnerInstanceId,\n provisionerId: session.provisionerId,\n labels: request.body.labels,\n ...(request.body.capabilities ? {capabilities: request.body.capabilities} : {}),\n providerKind: request.body.provider_kind,\n protocolVersion: request.body.protocol_version,\n });\n return {activation_token: activationToken};\n },\n});\n\nexport const attachRunnerControlProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/provider-runner',\n description: 'Attach the authenticated runner instance provider identity once',\n schema: {\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n return {\n attached: await attachRunnerControlProviderId({\n ...session,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const runnerControlHeartbeatRoute = defineRoute({\n method: 'POST',\n path: '/heartbeat',\n description: 'Record liveness for only the authenticated runner instance',\n schema: {response: {200: runnerControlHeartbeatResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n await touchRunnerControlSession(session.runnerInstanceId, session.provisionerId);\n runnerControlHeartbeatCount.add(1);\n return {ok: true};\n },\n});\n\ntype RunnerAssignmentPollParams = {\n deadline: number;\n intervalMs: number;\n signal: AbortSignal;\n getAssignment: () => Promise<unknown | null>;\n issueActivationToken: () => Promise<string | null>;\n};\n\nexport function resolveRunnerAssignmentPollWaitSeconds(\n requestedWaitSeconds: number | undefined,\n): number {\n return Math.max(\n 1,\n Math.min(\n requestedWaitSeconds ?? config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n ),\n );\n}\n\nexport async function pollForRunnerActivationToken(\n params: RunnerAssignmentPollParams,\n): Promise<string | null> {\n while (Date.now() < params.deadline) {\n if (params.signal.aborted) return null;\n const assignment = await params.getAssignment();\n if (assignment) {\n const activationToken = await params.issueActivationToken();\n if (activationToken) return activationToken;\n }\n const remainingMs = params.deadline - Date.now();\n if (remainingMs <= 0 || params.signal.aborted) return null;\n await new Promise((resolve) => setTimeout(resolve, Math.min(params.intervalMs, remainingMs)));\n }\n return null;\n}\nexport const runnerAssignmentPollRoute = defineRoute({\n method: 'GET',\n path: '/assignment',\n description: 'Wait for only the authenticated runner instance assignment',\n schema: {\n querystring: runnerAssignmentPollQuerySchema,\n response: {200: runnerAssignmentPollResponseSchema},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request, reply) => {\n const session = requireRunnerControlSessionContext(request);\n const waitSeconds = resolveRunnerAssignmentPollWaitSeconds(request.query.wait_seconds);\n const deadline = Date.now() + waitSeconds * 1000;\n const abortController = new AbortController();\n reply.raw.on('close', () => abortController.abort());\n const activationToken = await pollForRunnerActivationToken({\n deadline,\n intervalMs: config.RUNNER_ASSIGNMENT_POLL_INTERVAL_MS,\n signal: abortController.signal,\n getAssignment: () => getRunnerAssignment(session),\n issueActivationToken: () =>\n issueRunnerActivationToken({\n ...session,\n ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,\n }),\n });\n return {activation_token: activationToken};\n },\n});\n"],"names":["requireProvisionerContext","requireRunnerControlSessionContext","attachRunnerControlProviderIdBodySchema","createRunnerInstancesBodySchema","createRunnerInstancesResponseSchema","runnerAssignmentPollQuerySchema","runnerAssignmentPollResponseSchema","runnerBootstrapExchangeBodySchema","runnerBootstrapExchangeResponseSchema","runnerControlHeartbeatResponseSchema","runnerEnrollmentBodySchema","runnerEnrollmentResponseSchema","ClientError","defineRoute","z","config","getRunnerAssignment","issueRunnerActivationToken","attachRunnerControlProviderId","createRunnerInstancesWithBootstrapTokens","enrollRunnerControlSession","exchangeRunnerBootstrapToken","RunnerBootstrapTokenInvalidError","RunnerControlSessionInvalidError","touchRunnerControlSession","attachRunnerInstanceProviderId","runnerBootstrapExchangeCount","runnerControlHeartbeatCount","authenticateRunnerControlSession","createRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","provisionerTokenId","results","provisionerId","provider_kind","providerKind","runnerInstances","runner_instances","map","runner","template_key","templateKey","reservation_id","reservationId","ttlSeconds","RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS","result","runner_instance_id","runnerInstanceId","bootstrap_token","bootstrapToken","attachRunnerInstanceProviderIdRoute","params","object","string","uuid","attached","boolean","providerRunnerId","provider_runner_id","exchangeRunnerBootstrapRoute","errorHandler","error","add","outcome","message","status","rawToken","RUNNER_CONTROL_SESSION_TTL_SECONDS","control_session_token","controlSessionToken","expires_at","expiresAt","toISOString","enrollRunnerRoute","preHandler","session","activationToken","labels","capabilities","protocolVersion","protocol_version","activation_token","attachRunnerControlProviderIdRoute","runnerControlHeartbeatRoute","ok","resolveRunnerAssignmentPollWaitSeconds","requestedWaitSeconds","Math","max","min","RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS","pollForRunnerActivationToken","Date","now","deadline","signal","aborted","assignment","getAssignment","issueActivationToken","remainingMs","Promise","resolve","setTimeout","intervalMs","runnerAssignmentPollRoute","querystring","reply","waitSeconds","query","wait_seconds","abortController","AbortController","raw","on","abort","RUNNER_ASSIGNMENT_POLL_INTERVAL_MS","RUNNER_ACTIVATION_TOKEN_TTL_SECONDS"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/runner-enrollment.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireRunnerControlSessionContext,\n} from '@shipfox/api-auth-context';\nimport {\n attachRunnerControlProviderIdBodySchema,\n createRunnerInstancesBodySchema,\n createRunnerInstancesResponseSchema,\n runnerAssignmentPollQuerySchema,\n runnerAssignmentPollResponseSchema,\n runnerBootstrapExchangeBodySchema,\n runnerBootstrapExchangeResponseSchema,\n runnerControlHeartbeatResponseSchema,\n runnerEnrollmentBodySchema,\n runnerEnrollmentResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {config} from '#config.js';\nimport {getRunnerAssignment, issueRunnerActivationToken} from '#core/runner-activation.js';\nimport {\n attachRunnerControlProviderId,\n createRunnerInstancesWithBootstrapTokens,\n enrollRunnerControlSession,\n exchangeRunnerBootstrapToken,\n RunnerBootstrapTokenInvalidError,\n RunnerControlSessionInvalidError,\n touchRunnerControlSession,\n} from '#core/runner-control-sessions.js';\nimport {attachRunnerInstanceProviderId} from '#core/runner-instances.js';\nimport {runnerBootstrapExchangeCount, runnerControlHeartbeatCount} from '#metrics/instance.js';\nimport {authenticateRunnerControlSession} from '#presentation/auth/index.js';\n\nexport const createRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/batch',\n description:\n 'Create provisioner-owned runner instances and one-use bootstrap tokens before launch',\n schema: {\n body: createRunnerInstancesBodySchema,\n response: {200: createRunnerInstancesResponseSchema},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n const result = await createRunnerInstancesWithBootstrapTokens({\n provisionerId: provisionerTokenId,\n ...(request.body.provider_kind ? {providerKind: request.body.provider_kind} : {}),\n runnerInstances: request.body.runner_instances.map((runner) => ({\n ...(runner.template_key ? {templateKey: runner.template_key} : {}),\n ...(runner.reservation_id ? {reservationId: runner.reservation_id} : {}),\n })),\n ttlSeconds: config.RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS,\n });\n return {\n runner_instances: result.runnerInstances.map((runnerInstance) => ({\n runner_instance_id: runnerInstance.runnerInstanceId,\n bootstrap_token: runnerInstance.bootstrapToken,\n request_index: runnerInstance.requestIndex,\n })),\n ...(result.reservationUnavailable ? {reservation_unavailable: true as const} : {}),\n };\n },\n});\n\nexport const attachRunnerInstanceProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/:runnerInstanceId/provider-runner',\n description: 'Attach the provider identity after the provisioner launches a runner instance',\n schema: {\n params: z.object({runnerInstanceId: z.string().uuid()}),\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n return {\n attached: await attachRunnerInstanceProviderId({\n runnerInstanceId: request.params.runnerInstanceId,\n provisionerId: provisionerTokenId,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const exchangeRunnerBootstrapRoute = defineRoute({\n method: 'POST',\n path: '/exchange',\n description: 'Exchange a one-use runner bootstrap token for a workspace-neutral control session',\n schema: {\n body: runnerBootstrapExchangeBodySchema,\n response: {200: runnerBootstrapExchangeResponseSchema},\n },\n errorHandler: (error) => {\n if (error instanceof RunnerBootstrapTokenInvalidError)\n runnerBootstrapExchangeCount.add(1, {outcome: 'rejected'});\n if (error instanceof RunnerBootstrapTokenInvalidError)\n throw new ClientError(error.message, 'runner-bootstrap-token-invalid', {status: 401});\n throw error;\n },\n handler: async (request) => {\n const result = await exchangeRunnerBootstrapToken({\n rawToken: request.body.bootstrap_token,\n ttlSeconds: config.RUNNER_CONTROL_SESSION_TTL_SECONDS,\n });\n runnerBootstrapExchangeCount.add(1, {outcome: 'accepted'});\n return {\n runner_instance_id: result.runnerInstanceId,\n control_session_token: result.controlSessionToken,\n expires_at: result.expiresAt.toISOString(),\n };\n },\n});\n\nexport const enrollRunnerRoute = defineRoute({\n method: 'POST',\n path: '/enrollment',\n description: 'Declare the authenticated runner instance labels and protocol capabilities',\n schema: {body: runnerEnrollmentBodySchema, response: {200: runnerEnrollmentResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n errorHandler: (error) => {\n if (error instanceof RunnerControlSessionInvalidError)\n throw new ClientError(error.message, 'runner-control-session-invalid', {status: 409});\n throw error;\n },\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n const activationToken = await enrollRunnerControlSession({\n runnerInstanceId: session.runnerInstanceId,\n provisionerId: session.provisionerId,\n labels: request.body.labels,\n ...(request.body.capabilities ? {capabilities: request.body.capabilities} : {}),\n providerKind: request.body.provider_kind,\n protocolVersion: request.body.protocol_version,\n });\n return {activation_token: activationToken};\n },\n});\n\nexport const attachRunnerControlProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/provider-runner',\n description: 'Attach the authenticated runner instance provider identity once',\n schema: {\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n return {\n attached: await attachRunnerControlProviderId({\n ...session,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const runnerControlHeartbeatRoute = defineRoute({\n method: 'POST',\n path: '/heartbeat',\n description: 'Record liveness for only the authenticated runner instance',\n schema: {response: {200: runnerControlHeartbeatResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n await touchRunnerControlSession(session.runnerInstanceId, session.provisionerId);\n runnerControlHeartbeatCount.add(1);\n return {ok: true};\n },\n});\n\ntype RunnerAssignmentPollParams = {\n deadline: number;\n intervalMs: number;\n signal: AbortSignal;\n getAssignment: () => Promise<{workspaceId: string | null; runnerSessionId: string | null} | null>;\n issueActivationToken: () => Promise<string | null>;\n};\n\nexport function resolveRunnerAssignmentPollWaitSeconds(\n requestedWaitSeconds: number | undefined,\n): number {\n return Math.max(\n 1,\n Math.min(\n requestedWaitSeconds ?? config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n ),\n );\n}\n\nexport async function pollForRunnerActivationToken(\n params: RunnerAssignmentPollParams,\n): Promise<string | null> {\n while (Date.now() < params.deadline) {\n if (params.signal.aborted) return null;\n const assignment = await params.getAssignment();\n if (assignment) {\n const activationToken = await params.issueActivationToken();\n if (activationToken) return activationToken;\n }\n const remainingMs = params.deadline - Date.now();\n if (remainingMs <= 0 || params.signal.aborted) return null;\n await new Promise((resolve) => setTimeout(resolve, Math.min(params.intervalMs, remainingMs)));\n }\n return null;\n}\nexport const runnerAssignmentPollRoute = defineRoute({\n method: 'GET',\n path: '/assignment',\n description: 'Wait for only the authenticated runner instance assignment',\n schema: {\n querystring: runnerAssignmentPollQuerySchema,\n response: {200: runnerAssignmentPollResponseSchema},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request, reply) => {\n const session = requireRunnerControlSessionContext(request);\n const waitSeconds = resolveRunnerAssignmentPollWaitSeconds(request.query.wait_seconds);\n const deadline = Date.now() + waitSeconds * 1000;\n const abortController = new AbortController();\n reply.raw.on('close', () => abortController.abort());\n const activationToken = await pollForRunnerActivationToken({\n deadline,\n intervalMs: config.RUNNER_ASSIGNMENT_POLL_INTERVAL_MS,\n signal: abortController.signal,\n getAssignment: () => getRunnerAssignment(session),\n issueActivationToken: () =>\n issueRunnerActivationToken({\n ...session,\n ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,\n surface: 'poll',\n }),\n });\n return {activation_token: activationToken};\n },\n});\n"],"names":["requireProvisionerContext","requireRunnerControlSessionContext","attachRunnerControlProviderIdBodySchema","createRunnerInstancesBodySchema","createRunnerInstancesResponseSchema","runnerAssignmentPollQuerySchema","runnerAssignmentPollResponseSchema","runnerBootstrapExchangeBodySchema","runnerBootstrapExchangeResponseSchema","runnerControlHeartbeatResponseSchema","runnerEnrollmentBodySchema","runnerEnrollmentResponseSchema","ClientError","defineRoute","z","config","getRunnerAssignment","issueRunnerActivationToken","attachRunnerControlProviderId","createRunnerInstancesWithBootstrapTokens","enrollRunnerControlSession","exchangeRunnerBootstrapToken","RunnerBootstrapTokenInvalidError","RunnerControlSessionInvalidError","touchRunnerControlSession","attachRunnerInstanceProviderId","runnerBootstrapExchangeCount","runnerControlHeartbeatCount","authenticateRunnerControlSession","createRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","provisionerTokenId","result","provisionerId","provider_kind","providerKind","runnerInstances","runner_instances","map","runner","template_key","templateKey","reservation_id","reservationId","ttlSeconds","RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS","runnerInstance","runner_instance_id","runnerInstanceId","bootstrap_token","bootstrapToken","request_index","requestIndex","reservationUnavailable","reservation_unavailable","attachRunnerInstanceProviderIdRoute","params","object","string","uuid","attached","boolean","providerRunnerId","provider_runner_id","exchangeRunnerBootstrapRoute","errorHandler","error","add","outcome","message","status","rawToken","RUNNER_CONTROL_SESSION_TTL_SECONDS","control_session_token","controlSessionToken","expires_at","expiresAt","toISOString","enrollRunnerRoute","preHandler","session","activationToken","labels","capabilities","protocolVersion","protocol_version","activation_token","attachRunnerControlProviderIdRoute","runnerControlHeartbeatRoute","ok","resolveRunnerAssignmentPollWaitSeconds","requestedWaitSeconds","Math","max","min","RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS","pollForRunnerActivationToken","Date","now","deadline","signal","aborted","assignment","getAssignment","issueActivationToken","remainingMs","Promise","resolve","setTimeout","intervalMs","runnerAssignmentPollRoute","querystring","reply","waitSeconds","query","wait_seconds","abortController","AbortController","raw","on","abort","RUNNER_ASSIGNMENT_POLL_INTERVAL_MS","RUNNER_ACTIVATION_TOKEN_TTL_SECONDS","surface"],"mappings":"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"}
|