From d2d0a514e80c7176e3e80afa12e96fd1baf9f80e Mon Sep 17 00:00:00 2001 From: maslow Date: Thu, 19 Jan 2023 03:43:11 +0800 Subject: [PATCH] feat(gateway): refactor gateway in server instead of crd --- .vscode/settings.json | 8 +- server/package-lock.json | 35 +++++++-- server/package.json | 1 + server/prisma/schema.prisma | 40 +++++++++- server/src/app.module.ts | 4 +- .../application/application-task.service.ts | 20 +++-- .../src/application/application.controller.ts | 9 +-- server/src/application/application.module.ts | 4 +- server/src/application/application.service.ts | 1 + server/src/auth/application.auth.guard.ts | 2 +- server/src/auth/auth.controller.ts | 2 +- server/src/core/api/gateway.cr.ts | 77 ------------------- server/src/core/core.module.ts | 11 --- server/src/core/gateway.cr.service.ts | 63 --------------- server/src/database/database.controller.ts | 2 +- server/src/function/function.controller.ts | 2 +- server/src/gateway/apisix.service.ts | 75 ++++++++++++++++++ server/src/gateway/gateway.module.ts | 12 +++ server/src/gateway/gateway.service.ts | 71 +++++++++++++++++ server/src/region/cluster/cluster.service.ts | 2 +- .../src/{core/api => region/cluster}/types.ts | 0 server/src/storage/bucket.controller.ts | 2 +- server/src/user/pat.controller.ts | 2 +- server/src/utils/getter.ts | 2 +- server/src/utils/{types.ts => interface.ts} | 5 -- 25 files changed, 255 insertions(+), 197 deletions(-) delete mode 100644 server/src/core/api/gateway.cr.ts delete mode 100644 server/src/core/core.module.ts delete mode 100644 server/src/core/gateway.cr.service.ts create mode 100644 server/src/gateway/apisix.service.ts create mode 100644 server/src/gateway/gateway.module.ts create mode 100644 server/src/gateway/gateway.service.ts rename server/src/{core/api => region/cluster}/types.ts (100%) rename server/src/utils/{types.ts => interface.ts} (65%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 047a8981b9..aacdb2e38f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,9 +25,7 @@ "alipay", "apiextensions", "appid", - "appv", "automount", - "bitnami", "bodyparser", "bson", "buildah", @@ -46,17 +44,13 @@ "finalizers", "fullname", "ghaction", - "gonanoid", "healthz", "hokify", "hostpath", "Kube", - "kubebuilder", "kubeconfig", "Kubefile", "Kubernetes", - "Kustomization", - "kustomize", "labring", "lafjs", "lafyun", @@ -65,7 +59,6 @@ "MINIO", "moby", "MONOG", - "mycrd", "nestjs", "objs", "openebs", @@ -75,6 +68,7 @@ "readwrite", "Referer", "rolebinding", + "roundrobin", "runc", "runtimes", "runtimev", diff --git a/server/package-lock.json b/server/package-lock.json index 9f42df8ada..1ebb6bcc29 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -26,6 +26,7 @@ "@nestjs/terminus": "^9.1.2", "@nestjs/throttler": "^3.1.0", "@prisma/client": "^4.7.1", + "axios": "^1.2.3", "bson": "^4.7.0", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", @@ -6392,6 +6393,16 @@ "rxjs": "^6.0.0 || ^7.0.0" } }, + "node_modules/@nestjs/axios/node_modules/axios": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", + "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/@nestjs/cli": { "version": "9.1.5", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.1.5.tgz", @@ -8069,9 +8080,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "node_modules/axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -21913,6 +21924,18 @@ "integrity": "sha512-DzBIhmBPgPAf/Hf4oHVgNNrcYcmAwV6v1TeZFkEaotO5AtXEfCJ6c07Po4EmylAA0PFp+8+S77PBEcLNEMOCGQ==", "requires": { "axios": "1.1.3" + }, + "dependencies": { + "axios": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", + "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + } } }, "@nestjs/cli": { @@ -23203,9 +23226,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", diff --git a/server/package.json b/server/package.json index c762743cc5..7ad5b1a35b 100644 --- a/server/package.json +++ b/server/package.json @@ -41,6 +41,7 @@ "@nestjs/terminus": "^9.1.2", "@nestjs/throttler": "^3.1.0", "@prisma/client": "^4.7.1", + "axios": "^1.2.3", "bson": "^4.7.0", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 14fdb7c609..0da8c327ec 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -176,6 +176,7 @@ model Application { configuration ApplicationConfiguration? storageUser StorageUser? database Database? + domain ApplicationDomain? } type EnvironmentVariable { @@ -215,13 +216,14 @@ enum BucketPolicy { } model StorageBucket { - id String @id @default(auto()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId appid String - name String @unique + name String @unique shortName String policy BucketPolicy - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + domain BucketDomain? } // database schemas @@ -314,3 +316,33 @@ model CronTrigger { cloudFunction CloudFunction @relation(fields: [appid, target], references: [appid, name]) } + +// gateway schemas + +enum DomainState { + Active + Inactive +} + +model ApplicationDomain { + id String @id @default(auto()) @map("_id") @db.ObjectId + appid String @unique + domain String @unique + state DomainState @default(Active) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + application Application @relation(fields: [appid], references: [appid]) +} + +model BucketDomain { + id String @id @default(auto()) @map("_id") @db.ObjectId + appid String + bucketName String @unique + domain String @unique + state DomainState @default(Active) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + bucket StorageBucket @relation(fields: [bucketName], references: [name]) +} diff --git a/server/src/app.module.ts b/server/src/app.module.ts index baf246a65f..7622c45890 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -4,7 +4,6 @@ import { AppService } from './app.service' import { WebsitesModule } from './websites/websites.module' import { FunctionModule } from './function/function.module' import { HttpModule } from '@nestjs/axios' -import { CoreModule } from './core/core.module' import { ApplicationModule } from './application/application.module' import { AuthModule } from './auth/auth.module' import { ThrottlerModule } from '@nestjs/throttler' @@ -18,6 +17,7 @@ import { LogModule } from './log/log.module' import { DependencyModule } from './dependency/dependency.module' import { TriggerModule } from './trigger/trigger.module' import { RegionModule } from './region/region.module' +import { GatewayModule } from './gateway/gateway.module' @Module({ imports: [ @@ -30,7 +30,6 @@ import { RegionModule } from './region/region.module' WebsitesModule, HttpModule, AuthModule, - CoreModule, ApplicationModule, InitializerModule, InstanceModule, @@ -40,6 +39,7 @@ import { RegionModule } from './region/region.module' DependencyModule, TriggerModule, RegionModule, + GatewayModule, ], controllers: [AppController], providers: [AppService, PrismaService], diff --git a/server/src/application/application-task.service.ts b/server/src/application/application-task.service.ts index d2950bef19..d672943b66 100644 --- a/server/src/application/application-task.service.ts +++ b/server/src/application/application-task.service.ts @@ -1,14 +1,13 @@ import { Injectable, Logger } from '@nestjs/common' import { Cron, CronExpression } from '@nestjs/schedule' import { Application, ApplicationPhase } from '@prisma/client' -import { isConditionTrue } from '../utils/getter' -import { GatewayCoreService } from '../core/gateway.cr.service' -import { PrismaService } from '../prisma.service' import * as assert from 'node:assert' +import { PrismaService } from '../prisma.service' import { StorageService } from '../storage/storage.service' import { DatabaseService } from '../database/database.service' import { ClusterService } from 'src/region/cluster/cluster.service' import { RegionService } from 'src/region/region.service' +import { GatewayService } from 'src/gateway/gateway.service' @Injectable() export class ApplicationTaskService { @@ -17,9 +16,9 @@ export class ApplicationTaskService { constructor( private readonly regionService: RegionService, private readonly clusterService: ClusterService, - private readonly gatewayCore: GatewayCoreService, private readonly storageService: StorageService, private readonly databaseService: DatabaseService, + private readonly gatewayService: GatewayService, private readonly prisma: PrismaService, ) {} @@ -108,13 +107,13 @@ export class ApplicationTaskService { } // reconcile gateway - let gateway = await this.gatewayCore.findOne(appid) + let gateway = await this.gatewayService.findOne(appid) if (!gateway) { this.logger.debug(`Creating gateway for application ${appid}`) - gateway = await this.gatewayCore.create(app.appid) + gateway = await this.gatewayService.create(appid) } - if (!isConditionTrue('Ready', gateway?.status?.conditions)) return + if (!gateway) return if (!storage) return if (!database) return @@ -163,6 +162,13 @@ export class ApplicationTaskService { return } + // delete gateway + const gateway = await this.gatewayService.findOne(appid) + if (gateway) { + await this.gatewayService.delete(appid) + return + } + // update phase await this.prisma.application.updateMany({ where: { diff --git a/server/src/application/application.controller.ts b/server/src/application/application.controller.ts index 3593b82147..d891e9f890 100644 --- a/server/src/application/application.controller.ts +++ b/server/src/application/application.controller.ts @@ -16,7 +16,7 @@ import { ApiResponse, ApiTags, } from '@nestjs/swagger' -import { IRequest } from '../utils/types' +import { IRequest } from '../utils/interface' import { JwtAuthGuard } from '../auth/jwt.auth.guard' import { ResponseUtil } from '../utils/response' import { ApplicationAuthGuard } from '../auth/application.auth.guard' @@ -25,8 +25,8 @@ import { UpdateApplicationDto } from './dto/update-application.dto' import { ApplicationService } from './application.service' import { FunctionService } from '../function/function.service' import { StorageService } from 'src/storage/storage.service' -import { GatewayCoreService } from 'src/core/gateway.cr.service' import { RegionService } from 'src/region/region.service' +import { GatewayService } from 'src/gateway/gateway.service' @ApiTags('Application') @Controller('applications') @@ -37,7 +37,7 @@ export class ApplicationController { private readonly appService: ApplicationService, private readonly funcService: FunctionService, private readonly regionService: RegionService, - private readonly gatewayCore: GatewayCoreService, + private readonly gatewayService: GatewayService, private readonly storageService: StorageService, ) {} @@ -88,9 +88,9 @@ export class ApplicationController { async findOne(@Param('appid') appid: string) { const data = await this.appService.findOne(appid, { configuration: true, + domain: true, }) - const gateway = await this.gatewayCore.findOne(appid) const storage = await this.storageService.findOne(appid) // Security Warning: Do not response this region object to client since it contains sensitive information @@ -109,7 +109,6 @@ export class ApplicationController { const res = { ...data, - gateway, storage: { ...storage, credentials, diff --git a/server/src/application/application.module.ts b/server/src/application/application.module.ts index 17e53d05f4..6f39d8da9f 100644 --- a/server/src/application/application.module.ts +++ b/server/src/application/application.module.ts @@ -1,6 +1,5 @@ import { Module } from '@nestjs/common' import { ApplicationController } from './application.controller' -import { CoreModule } from '../core/core.module' import { ApplicationService } from './application.service' import { PrismaService } from '../prisma.service' import { ApplicationTaskService } from './application-task.service' @@ -12,9 +11,10 @@ import { EnvironmentVariableController } from './environment.controller' import { StorageModule } from '../storage/storage.module' import { RegionModule } from '../region/region.module' import { DatabaseModule } from 'src/database/database.module' +import { GatewayModule } from 'src/gateway/gateway.module' @Module({ - imports: [CoreModule, StorageModule, RegionModule, DatabaseModule], + imports: [StorageModule, RegionModule, DatabaseModule, GatewayModule], controllers: [ApplicationController, EnvironmentVariableController], providers: [ ApplicationService, diff --git a/server/src/application/application.service.ts b/server/src/application/application.service.ts index 085647e108..228cd53d71 100644 --- a/server/src/application/application.service.ts +++ b/server/src/application/application.service.ts @@ -85,6 +85,7 @@ export class ApplicationService { bundle: include?.bundle, runtime: include?.runtime, configuration: include?.configuration, + domain: include?.domain, }, }) diff --git a/server/src/auth/application.auth.guard.ts b/server/src/auth/application.auth.guard.ts index 835e6995ad..8d46e302b4 100644 --- a/server/src/auth/application.auth.guard.ts +++ b/server/src/auth/application.auth.guard.ts @@ -6,7 +6,7 @@ import { } from '@nestjs/common' import { User } from '@prisma/client' import { ApplicationService } from '../application/application.service' -import { IRequest } from '../utils/types' +import { IRequest } from '../utils/interface' @Injectable() export class ApplicationAuthGuard implements CanActivate { diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts index 4b844c44d5..d5895d31ec 100644 --- a/server/src/auth/auth.controller.ts +++ b/server/src/auth/auth.controller.ts @@ -16,7 +16,7 @@ import { } from '@nestjs/swagger' import { Response } from 'express' import { ApiResponseUtil, ResponseUtil } from '../utils/response' -import { IRequest } from '../utils/types' +import { IRequest } from '../utils/interface' import { UserDto } from '../user/dto/user.response' import { AuthService } from './auth.service' import { JwtAuthGuard } from './jwt.auth.guard' diff --git a/server/src/core/api/gateway.cr.ts b/server/src/core/api/gateway.cr.ts deleted file mode 100644 index 542d5bbda6..0000000000 --- a/server/src/core/api/gateway.cr.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { KubernetesObject } from '@kubernetes/client-node' -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' -import { Condition, GroupVersionKind, ObjectMeta } from './types' - -export class GatewaySpec { - @ApiProperty() - appid: string - - @ApiProperty() - buckets: string[] - - @ApiProperty() - websites: string[] -} - -export class GatewayRoute { - @ApiProperty() - domainName: string - - @ApiProperty() - domainNamespace: string - - @ApiProperty() - domain: string -} - -export class GatewayStatus { - @ApiProperty() - appRoute: GatewayRoute - - @ApiProperty() - bucketRoutes: { [key: string]: GatewayRoute }[] - - @ApiProperty() - websiteRoutes: { [key: string]: GatewayRoute }[] - - @ApiProperty() - conditions: Condition[] -} - -export class Gateway implements KubernetesObject { - @ApiProperty() - apiVersion: string - - @ApiProperty() - kind: string - - @ApiProperty() - metadata: ObjectMeta - - @ApiProperty() - spec: GatewaySpec - - @ApiPropertyOptional() - status?: GatewayStatus - - static readonly GVK = new GroupVersionKind( - 'gateway.laf.dev', - 'v1', - 'Gateway', - 'gateways', - ) - - constructor(name: string, namespace: string) { - this.apiVersion = Gateway.GVK.apiVersion - this.kind = Gateway.GVK.kind - this.metadata = new ObjectMeta(name, namespace) - this.spec = new GatewaySpec() - } - - static fromObject(obj: KubernetesObject): Gateway { - const gw = new Gateway(obj.metadata.name, obj.metadata.namespace) - delete obj.metadata['managedFields'] - Object.assign(gw, obj) - return gw - } -} diff --git a/server/src/core/core.module.ts b/server/src/core/core.module.ts deleted file mode 100644 index 5b0502df59..0000000000 --- a/server/src/core/core.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Global, Module } from '@nestjs/common' -import { RegionModule } from 'src/region/region.module' -import { GatewayCoreService } from './gateway.cr.service' - -@Global() -@Module({ - imports: [RegionModule], - providers: [GatewayCoreService], - exports: [GatewayCoreService], -}) -export class CoreModule {} diff --git a/server/src/core/gateway.cr.service.ts b/server/src/core/gateway.cr.service.ts deleted file mode 100644 index aaaa2f8875..0000000000 --- a/server/src/core/gateway.cr.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common' -import { GetApplicationNamespaceById } from '../utils/getter' -import * as assert from 'node:assert' -import { ResourceLabels } from '../constants' -import { Gateway } from './api/gateway.cr' -import { ClusterService } from '../region/cluster/cluster.service' -import { RegionService } from '../region/region.service' - -@Injectable() -export class GatewayCoreService { - private readonly logger = new Logger(GatewayCoreService.name) - - constructor( - private readonly clusterService: ClusterService, - private readonly regionService: RegionService, - ) {} - - async create(appid: string) { - const namespace = GetApplicationNamespaceById(appid) - const name = appid - const gw = new Gateway(name, namespace) - gw.metadata.labels = { - [ResourceLabels.APP_ID]: appid, - } - - gw.spec.appid = appid - gw.spec.buckets = [] - - const region = await this.regionService.findByAppId(appid) - const objectApi = this.clusterService.makeObjectApi(region) - - try { - const res = await objectApi.create(gw) - return Gateway.fromObject(res.body) - } catch (error) { - this.logger.error(error) - return null - } - } - - async findOne(appid: string) { - assert(appid, 'appid is required') - const namespace = GetApplicationNamespaceById(appid) - const name = appid - const region = await this.regionService.findByAppId(appid) - const customObjectApi = this.clusterService.makeCustomObjectApi(region) - try { - const res = await customObjectApi.getNamespacedCustomObject( - Gateway.GVK.group, - Gateway.GVK.version, - namespace, - Gateway.GVK.plural, - name, - ) - return Gateway.fromObject(res.body) - } catch (err) { - if (err?.response?.body?.reason === 'NotFound') return null - this.logger.error(err) - this.logger.debug(err.response?.body) - return null - } - } -} diff --git a/server/src/database/database.controller.ts b/server/src/database/database.controller.ts index b49c599cf6..a37878110a 100644 --- a/server/src/database/database.controller.ts +++ b/server/src/database/database.controller.ts @@ -3,7 +3,7 @@ import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger' import { Policy, Proxy } from 'database-proxy/dist' import { ApplicationAuthGuard } from 'src/auth/application.auth.guard' import { JwtAuthGuard } from 'src/auth/jwt.auth.guard' -import { IRequest } from 'src/utils/types' +import { IRequest } from 'src/utils/interface' import { DatabaseService } from './database.service' @ApiTags('Database') diff --git a/server/src/function/function.controller.ts b/server/src/function/function.controller.ts index a28897c58b..26345bf5f4 100644 --- a/server/src/function/function.controller.ts +++ b/server/src/function/function.controller.ts @@ -23,7 +23,7 @@ import { import { JwtAuthGuard } from '../auth/jwt.auth.guard' import { ApplicationAuthGuard } from '../auth/application.auth.guard' import { FunctionService } from './function.service' -import { IRequest } from '../utils/types' +import { IRequest } from '../utils/interface' import { CompileFunctionDto } from './dto/compile-function.dto.ts' import { MAX_FUNCTION_COUNT } from 'src/constants' diff --git a/server/src/gateway/apisix.service.ts b/server/src/gateway/apisix.service.ts new file mode 100644 index 0000000000..30184c2203 --- /dev/null +++ b/server/src/gateway/apisix.service.ts @@ -0,0 +1,75 @@ +import { Injectable, Logger } from '@nestjs/common' +import { Region } from '@prisma/client' +import axios from 'axios' +import { GetApplicationNamespaceById } from 'src/utils/getter' + +@Injectable() +export class ApisixService { + private readonly logger = new Logger(ApisixService.name) + + async createAppRoute(region: Region, appid: string, domain: string) { + const host = domain + const namespace = GetApplicationNamespaceById(appid) + const upstreamNode = `${appid}.${namespace}:8000` + + const id = `app-${appid}` + const data = { + name: id, + uri: '/*', + hosts: [host], + priority: 9, + upstream: { + type: 'roundrobin', + nodes: { + [upstreamNode]: 1, + }, + }, + timeout: { + connect: 600, + send: 600, + read: 600, + }, + plugins: { + cors: {}, + }, + enable_websocket: true, + } + + const res = await this.putRoute(region, id, data) + return res + } + + async deleteAppRoute(region: Region, appid: string) { + const id = `app-${appid}` + const res = await this.deleteRoute(region, id) + return res + } + + async putRoute(region: Region, id: string, data: any) { + const conf = region.gatewayConf + const api_url = `${conf.apiUrl}/routes/${id}` + + const res = await axios.put(api_url, data, { + headers: { + 'X-API-KEY': conf.apiKey, + 'Content-Type': 'application/json', + }, + }) + + return res.data + } + + async deleteRoute(region: Region, id: string) { + const conf = region.gatewayConf + const api_url = `${conf.apiUrl}/routes/${id}` + + const res = await axios.delete(api_url, { + headers: { + 'X-API-KEY': conf.apiKey, + 'Content-Type': 'application/json', + }, + }) + + return res.data + } +} diff --git a/server/src/gateway/gateway.module.ts b/server/src/gateway/gateway.module.ts new file mode 100644 index 0000000000..e25586bdef --- /dev/null +++ b/server/src/gateway/gateway.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common' +import { GatewayService } from './gateway.service' +import { ApisixService } from './apisix.service' +import { RegionModule } from 'src/region/region.module' +import { PrismaService } from 'src/prisma.service' + +@Module({ + imports: [RegionModule], + providers: [GatewayService, ApisixService, PrismaService], + exports: [GatewayService], +}) +export class GatewayModule {} diff --git a/server/src/gateway/gateway.service.ts b/server/src/gateway/gateway.service.ts new file mode 100644 index 0000000000..573e834406 --- /dev/null +++ b/server/src/gateway/gateway.service.ts @@ -0,0 +1,71 @@ +import { Injectable, Logger } from '@nestjs/common' +import { PrismaService } from '../prisma.service' +import * as assert from 'assert' +import { RegionService } from '../region/region.service' +import { ApisixService } from './apisix.service' + +@Injectable() +export class GatewayService { + private readonly logger = new Logger(GatewayService.name) + + constructor( + private readonly prisma: PrismaService, + private readonly regionService: RegionService, + private readonly apisixService: ApisixService, + ) {} + + async create(appid: string) { + const region = await this.regionService.findByAppId(appid) + assert(region, 'region not found') + + const app_domain = `${appid}.${region.gatewayConf.domain}` + + // create route first + const route = await this.apisixService.createAppRoute( + region, + appid, + app_domain, + ) + + this.logger.debug('route created:', route) + + // create domain in db + const doc = await this.prisma.applicationDomain.create({ + data: { + appid: appid, + domain: app_domain, + state: 'Active', + }, + }) + + return doc + } + + async findOne(appid: string) { + const doc = await this.prisma.applicationDomain.findFirst({ + where: { + appid: appid, + }, + }) + + return doc + } + + async delete(appid: string) { + // delete route first + const region = await this.regionService.findByAppId(appid) + assert(region, 'region not found') + + const res = await this.apisixService.deleteAppRoute(region, appid) + this.logger.debug('route deleted:', res) + + // delete domain in db + const doc = await this.prisma.applicationDomain.delete({ + where: { + appid: appid, + }, + }) + + return doc + } +} diff --git a/server/src/region/cluster/cluster.service.ts b/server/src/region/cluster/cluster.service.ts index c04e2f9973..f4d74333e7 100644 --- a/server/src/region/cluster/cluster.service.ts +++ b/server/src/region/cluster/cluster.service.ts @@ -5,7 +5,7 @@ import { Region } from '@prisma/client' import { GetApplicationNamespaceById } from 'src/utils/getter' import { ResourceLabels } from 'src/constants' import { compare } from 'fast-json-patch' -import { GroupVersionKind } from 'src/core/api/types' +import { GroupVersionKind } from 'src/region/cluster/types' @Injectable() export class ClusterService { diff --git a/server/src/core/api/types.ts b/server/src/region/cluster/types.ts similarity index 100% rename from server/src/core/api/types.ts rename to server/src/region/cluster/types.ts diff --git a/server/src/storage/bucket.controller.ts b/server/src/storage/bucket.controller.ts index 2b88878012..13ed93678c 100644 --- a/server/src/storage/bucket.controller.ts +++ b/server/src/storage/bucket.controller.ts @@ -19,7 +19,7 @@ import { ApiTags, } from '@nestjs/swagger' import { ApplicationAuthGuard } from '../auth/application.auth.guard' -import { IRequest } from '../utils/types' +import { IRequest } from '../utils/interface' import { JwtAuthGuard } from '../auth/jwt.auth.guard' import { ResponseUtil } from '../utils/response' import { CreateBucketDto } from './dto/create-bucket.dto' diff --git a/server/src/user/pat.controller.ts b/server/src/user/pat.controller.ts index 2c44d5b3d8..929e79decc 100644 --- a/server/src/user/pat.controller.ts +++ b/server/src/user/pat.controller.ts @@ -17,7 +17,7 @@ import { } from '@nestjs/swagger' import { JwtAuthGuard } from 'src/auth/jwt.auth.guard' import { ResponseUtil } from 'src/utils/response' -import { IRequest } from 'src/utils/types' +import { IRequest } from 'src/utils/interface' import { CreatePATDto } from './dto/create-pat.dto' import { PatService } from './pat.service' diff --git a/server/src/utils/getter.ts b/server/src/utils/getter.ts index 4f3abe5949..d8aae5dc9d 100644 --- a/server/src/utils/getter.ts +++ b/server/src/utils/getter.ts @@ -1,4 +1,4 @@ -import { Condition } from 'src/core/api/types' +import { Condition } from 'src/region/cluster/types' import { ServerConfig } from '../constants' /** diff --git a/server/src/utils/types.ts b/server/src/utils/interface.ts similarity index 65% rename from server/src/utils/types.ts rename to server/src/utils/interface.ts index 33f51273df..2fa0976781 100644 --- a/server/src/utils/types.ts +++ b/server/src/utils/interface.ts @@ -7,8 +7,3 @@ export interface IRequest extends Request { } export type IResponse = Response - -export function toQuantityString(value: number) { - const m = Math.floor(value / 1024 / 1024) - return `${m}Mi` -}