From fddf70c9855faf870450f8f3e39cb396e17227a0 Mon Sep 17 00:00:00 2001 From: chyoo Date: Wed, 8 Jul 2026 17:13:52 +0900 Subject: [PATCH] connect tailscale node status through platform gateway --- src/tailscale/tailscale.controller.ts | 10 +++++ src/tailscale/tailscale.service.ts | 54 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/tailscale/tailscale.controller.ts b/src/tailscale/tailscale.controller.ts index 3d860dd..ead04fe 100644 --- a/src/tailscale/tailscale.controller.ts +++ b/src/tailscale/tailscale.controller.ts @@ -10,4 +10,14 @@ export class TailscaleController { listNodes() { return this.tailscaleService.listNodes(); } + + @Get('routes') + listRoutes() { + return this.tailscaleService.listRoutes(); + } + + @Get('acl') + getAcl() { + return this.tailscaleService.getAcl(); + } } diff --git a/src/tailscale/tailscale.service.ts b/src/tailscale/tailscale.service.ts index ecbb207..fc27aa3 100644 --- a/src/tailscale/tailscale.service.ts +++ b/src/tailscale/tailscale.service.ts @@ -63,6 +63,60 @@ export class TailscaleService { } } + async listRoutes() { + if (!this.gatewayUrl || !this.gatewayToken) { + return { + routes: [], + source: 'platform-gateway', + error: 'PLATFORM_GATEWAY_URL 또는 PLATFORM_GATEWAY_TOKEN이 설정되어 있지 않습니다.', + }; + } + + try { + const body = await this.request('/api/admin/tailscale/routes'); + const routes = isRecord(body) && Array.isArray(body.routes) ? body.routes : []; + return { + routes, + source: 'platform-gateway', + fetchedAt: new Date().toISOString(), + }; + } catch (error) { + return { + routes: [], + source: 'platform-gateway', + error: error instanceof Error ? error.message : 'Platform Gateway Tailscale Route API 요청이 실패했습니다.', + }; + } + } + + async getAcl() { + if (!this.gatewayUrl || !this.gatewayToken) { + return { + policy: { groups: {}, tagOwners: {}, acls: [] }, + source: 'platform-gateway', + error: 'PLATFORM_GATEWAY_URL 또는 PLATFORM_GATEWAY_TOKEN이 설정되어 있지 않습니다.', + }; + } + + try { + const body = await this.request('/api/admin/tailscale/acl'); + const policy = isRecord(body) && isRecord(body.policy) + ? body.policy + : { groups: {}, tagOwners: {}, acls: [] }; + return { + policy, + source: 'platform-gateway', + fetchedAt: new Date().toISOString(), + }; + } catch (error) { + return { + policy: { groups: {}, tagOwners: {}, acls: [] }, + source: 'platform-gateway', + error: error instanceof Error ? error.message : 'Platform Gateway Tailscale ACL API 요청이 실패했습니다.', + }; + } + } + private async request(path: string): Promise { const response = await fetch(`${this.gatewayUrl}${path}`, { headers: {