Skip to content

Commit

Permalink
feat(server): implement function creation (#427)
Browse files Browse the repository at this point in the history
Signed-off-by: maslow <wangfugen@126.com>
  • Loading branch information
maslow authored Nov 24, 2022
1 parent 4d56e64 commit 9759453
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 23 deletions.
1 change: 0 additions & 1 deletion server/src/applications/applications.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export class ApplicationsController {
* Create application
* @returns
*/
// @ApiResponse({ type: ResponseUtil<CreateApplicationDto> })
@ApiResponseUtil(Application)
@UseGuards(JwtAuthGuard)
@Post()
Expand Down
14 changes: 5 additions & 9 deletions server/src/applications/applications.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,11 @@ export class ApplicationsService {

async create(userid: string, appid: string, dto: CreateApplicationDto) {
// create app resources
const app = new Application(dto.name, appid)
app.metadata.name = dto.name
app.metadata.namespace = appid
app.metadata.labels = {
[ResourceLabels.APP_ID]: appid,
[ResourceLabels.USER_ID]: userid,
}
const namespace = GetApplicationNamespaceById(appid)
const app = new Application(dto.name, namespace)
app.setAppid(appid)
app.setUserId(userid)

app.spec = new ApplicationSpec({
appid,
state: dto.state,
Expand All @@ -61,8 +59,6 @@ export class ApplicationsService {
runtimeName: dto.runtimeName,
})

console.log(app)

try {
const res = await this.k8sClient.objectApi.create(app)
return res.body
Expand Down
29 changes: 25 additions & 4 deletions server/src/applications/entities/application.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { KubernetesObject } from '@kubernetes/client-node'
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import { ResourceLabels } from 'src/constants'
import { Condition, ObjectMeta } from '../../core/kubernetes.interface'
import { BundleSpec } from './bundle.entity'
import { RuntimeSpec } from './runtime.entity'
Expand Down Expand Up @@ -94,12 +95,32 @@ export class Application implements KubernetesObject {
constructor(name: string, namespace: string) {
this.apiVersion = Application.GroupVersion
this.kind = Application.Kind
this.metadata = {
name,
namespace,
}
this.metadata = new ObjectMeta(name, namespace)
this.metadata.labels = {}
this.spec = new ApplicationSpec()
}

setAppid(appid: string) {
this.metadata.labels = {
...this.metadata.labels,
[ResourceLabels.APP_ID]: appid,
}
}

get appid() {
return this.metadata.labels?.[ResourceLabels.APP_ID]
}

setUserId(userid: string) {
this.metadata.labels = {
...this.metadata.labels,
[ResourceLabels.USER_ID]: userid,
}
}

get userid() {
return this.metadata.labels?.[ResourceLabels.USER_ID]
}
}
export class ApplicationList {
@ApiProperty()
Expand Down
40 changes: 39 additions & 1 deletion server/src/functions/dto/create-function.dto.ts
Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
export class CreateFunctionDto {}
import { ApiProperty } from '@nestjs/swagger'

export class CreateFunctionDto {
@ApiProperty({
description: 'Function name is unique in the application',
})
name: string

@ApiProperty()
description: string

@ApiProperty()
websocket: boolean

@ApiProperty({
enum: ['HEAD', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
})
methods: string[] = []

@ApiProperty({
description: 'The source code of the function',
})
codes: string

validate() {
if (!this.name) {
return 'name is required'
}

const valid = this.methods.every((method) => {
return ['HEAD', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)
})
if (!valid) {
return 'methods is invalid'
}

return null
}
}
96 changes: 95 additions & 1 deletion server/src/functions/entities/function.entity.ts
Original file line number Diff line number Diff line change
@@ -1 +1,95 @@
export class Function {}
import { KubernetesListObject, KubernetesObject } from '@kubernetes/client-node'
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import { ObjectMeta } from 'src/core/kubernetes.interface'

export class CloudFunctionSource {
@ApiProperty()
codes: string

@ApiProperty()
uri?: string

@ApiProperty()
version: number

constructor() {
this.version = 0
}
}

export class CloudFunctionSpec {
@ApiProperty()
description: string

@ApiProperty()
websocket: boolean

@ApiProperty()
methods: string[]

@ApiProperty()
source: CloudFunctionSource

constructor() {
this.source = new CloudFunctionSource()
}
}

export enum CloudFunctionState {
Deployed = 'Deployed',
}

export class CloudFunctionStatus {
@ApiProperty({
enum: CloudFunctionState,
})
state: CloudFunctionState
}

export class CloudFunction implements KubernetesObject {
@ApiProperty()
apiVersion: string

@ApiProperty()
kind: string

@ApiProperty()
metadata: ObjectMeta

@ApiProperty()
spec: CloudFunctionSpec

@ApiPropertyOptional()
status?: CloudFunctionStatus

static readonly Group = 'runtime.laf.dev'
static readonly Version = 'v1'
static readonly PluralName = 'functions'
static readonly Kind = 'Function'
static get GroupVersion() {
return `${this.Group}/${this.Version}`
}

constructor(name: string, namespace: string) {
this.apiVersion = CloudFunction.GroupVersion
this.kind = CloudFunction.Kind
this.metadata = {
name,
namespace,
}
this.spec = new CloudFunctionSpec()
}
}

export class CloudFunctionList implements KubernetesListObject<CloudFunction> {
@ApiProperty()
apiVersion?: string

@ApiProperty()
kind?: string = 'FunctionList'

@ApiProperty({
type: [CloudFunction],
})
items: CloudFunction[]
}
29 changes: 26 additions & 3 deletions server/src/functions/functions.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,48 @@ import {
Patch,
Param,
Delete,
UseGuards,
Req,
} from '@nestjs/common'
import { FunctionsService } from './functions.service'
import { CreateFunctionDto } from './dto/create-function.dto'
import { UpdateFunctionDto } from './dto/update-function.dto'
import { ApiResponseUtil, ResponseUtil } from 'src/common/response'
import { CloudFunction, CloudFunctionList } from './entities/function.entity'
import { ApiTags } from '@nestjs/swagger'
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'
import { ApplicationAuthGuard } from 'src/applications/application.auth.guard'
import { IRequest } from 'src/common/types'

@Controller('functions')
@ApiTags('Functions')
@Controller('apps/:appid/functions')
export class FunctionsController {
constructor(private readonly functionsService: FunctionsService) {}

@ApiResponseUtil(CloudFunction)
@UseGuards(JwtAuthGuard, ApplicationAuthGuard)
@Post()
create(@Body() createFunctionDto: CreateFunctionDto) {
return this.functionsService.create(createFunctionDto)
async create(@Body() dto: CreateFunctionDto, @Req() req: IRequest) {
const error = dto.validate()
if (error) {
return ResponseUtil.error(error)
}

const appid = req.application.appid
const res = await this.functionsService.create(appid, dto)
if (!res) {
return ResponseUtil.error('create function error')
}
return ResponseUtil.ok(res)
}

@ApiResponseUtil(CloudFunctionList)
@Get()
findAll() {
return this.functionsService.findAll()
}

@ApiResponseUtil(CloudFunction)
@Get(':id')
findOne(@Param('id') id: string) {
return this.functionsService.findOne(+id)
Expand Down
3 changes: 2 additions & 1 deletion server/src/functions/functions.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common'
import { FunctionsService } from './functions.service'
import { FunctionsController } from './functions.controller'
import { ApplicationsService } from 'src/applications/applications.service'

@Module({
controllers: [FunctionsController],
providers: [FunctionsService],
providers: [FunctionsService, ApplicationsService],
})
export class FunctionsModule {}
26 changes: 23 additions & 3 deletions server/src/functions/functions.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import { Injectable } from '@nestjs/common'
import { Injectable, Logger } from '@nestjs/common'
import { GetApplicationNamespaceById } from 'src/common/getter'
import { KubernetesService } from 'src/core/kubernetes.service'
import { CreateFunctionDto } from './dto/create-function.dto'
import { UpdateFunctionDto } from './dto/update-function.dto'
import { CloudFunction } from './entities/function.entity'

@Injectable()
export class FunctionsService {
create(createFunctionDto: CreateFunctionDto) {
return 'This action adds a new function'
private logger = new Logger(FunctionsService.name)

constructor(private readonly k8sClient: KubernetesService) {}

async create(appid: string, dto: CreateFunctionDto) {
const namespace = GetApplicationNamespaceById(appid)
const func = new CloudFunction(dto.name, namespace)
func.spec.description = dto.description
func.spec.methods = dto.methods
func.spec.source.codes = dto.codes
func.spec.websocket = dto.websocket

try {
const res = await this.k8sClient.objectApi.create(func)
return res.body
} catch (error) {
this.logger.error(error, error?.response.body)
return null
}
}

findAll() {
Expand Down

0 comments on commit 9759453

Please sign in to comment.