Skip to content

Commit

Permalink
feat(server&web): separate database operations from runtime operations (
Browse files Browse the repository at this point in the history
  • Loading branch information
HUAHUAI23 authored Jul 24, 2024
1 parent 28a2c2c commit 8d456e9
Show file tree
Hide file tree
Showing 21 changed files with 615 additions and 203 deletions.
107 changes: 97 additions & 10 deletions server/src/application/application.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ import { InstanceService } from 'src/instance/instance.service'
import { BindCustomDomainDto } from './dto/bind-custom-domain.dto'
import { ClusterService } from 'src/region/cluster/cluster.service'
import { SealosManagerGuard } from 'src/authentication/sealos-manager.guard'
import { DedicatedDatabaseService } from 'src/database/dedicated-database/dedicated-database.service'
import { DedicatedDatabaseState } from 'src/database/entities/dedicated-database'

@ApiTags('Application')
@Controller('applications')
Expand All @@ -61,6 +63,7 @@ export class ApplicationController {

constructor(
private readonly application: ApplicationService,
private readonly dedicateDatabase: DedicatedDatabaseService,
private readonly instance: InstanceService,
private readonly fn: FunctionService,
private readonly region: RegionService,
Expand Down Expand Up @@ -220,7 +223,6 @@ export class ApplicationController {
if (dto.state === ApplicationState.Deleted) {
throw new ForbiddenException('cannot update state to deleted')
}

// check: only running application can restart
if (
dto.state === ApplicationState.Restarting &&
Expand Down Expand Up @@ -254,7 +256,16 @@ export class ApplicationController {
)
}

if (dto.state === ApplicationState.Restarting && dto?.onlyRuntimeFlag) {
const doc = await this.application.updateState(appid, dto.state)
return ResponseUtil.ok(doc)
}

const doc = await this.application.updateState(appid, dto.state)
await this.dedicateDatabase.updateState(
appid,
dto.state as unknown as DedicatedDatabaseState,
)
return ResponseUtil.ok(doc)
}

Expand All @@ -270,6 +281,16 @@ export class ApplicationController {
@Body() dto: UpdateApplicationBundleDto,
@InjectApplication() app: ApplicationWithRelations,
) {
// only running and stopped application can update bundle
if (
app.phase !== ApplicationPhase.Started &&
app.phase !== ApplicationPhase.Stopped
) {
return ResponseUtil.error(
'The application is not running or stopped, can not update bundle',
)
}

const error = dto.autoscaling.validate()
if (error) {
return ResponseUtil.error(error)
Expand All @@ -296,7 +317,7 @@ export class ApplicationController {

const origin = app.bundle

const checkSpec = await this.checkResourceSpecification(dto, regionId)
const checkSpec = await this.checkResourceSpecification(dto, regionId, app)
if (!checkSpec) {
return ResponseUtil.error('invalid resource specification')
}
Expand Down Expand Up @@ -328,8 +349,13 @@ export class ApplicationController {
const isCpuChanged = origin.resource.limitCPU !== doc.resource.limitCPU
const isMemoryChanged =
origin.resource.limitMemory !== doc.resource.limitMemory

const isAutoscalingCanceled =
!doc.autoscaling.enable && origin.autoscaling.enable

const isRuntimeChanged =
isCpuChanged || isMemoryChanged || isAutoscalingCanceled

const isDedicatedDatabaseChanged =
!!origin.resource.dedicatedDatabase &&
(!isEqual(
Expand All @@ -354,14 +380,16 @@ export class ApplicationController {
await this.instance.reapplyHorizontalPodAutoscaler(app, hpa)
}

if (
isRunning &&
(isCpuChanged ||
isMemoryChanged ||
isAutoscalingCanceled ||
isDedicatedDatabaseChanged)
) {
await this.application.updateState(appid, ApplicationState.Restarting)
if (isRunning) {
if (isRuntimeChanged && !isDedicatedDatabaseChanged) {
await this.application.updateState(appid, ApplicationState.Restarting)
} else if (isRuntimeChanged || isDedicatedDatabaseChanged) {
await this.application.updateState(appid, ApplicationState.Restarting)
await this.dedicateDatabase.updateState(
appid,
DedicatedDatabaseState.Restarting,
)
}
}

return ResponseUtil.ok(doc)
Expand Down Expand Up @@ -467,8 +495,67 @@ export class ApplicationController {
private async checkResourceSpecification(
dto: UpdateApplicationBundleDto,
regionId: ObjectId,
app?: ApplicationWithRelations,
) {
const resourceOptions = await this.resource.findAllByRegionId(regionId)

if (app) {
const checkSpec = resourceOptions.every((option) => {
switch (option.type) {
case 'cpu':
return (
option.specs.some((spec) => spec.value === dto.cpu) ||
app.bundle.resource.limitCPU === dto.cpu
)
case 'memory':
return (
option.specs.some((spec) => spec.value === dto.memory) ||
app.bundle.resource.limitMemory === dto.memory
)
// dedicated database
case 'dedicatedDatabaseCPU':
return (
!dto.dedicatedDatabase?.cpu ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.cpu,
) ||
app.bundle.resource.dedicatedDatabase?.limitCPU ===
dto.dedicatedDatabase.cpu
)
case 'dedicatedDatabaseMemory':
return (
!dto.dedicatedDatabase?.memory ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.memory,
) ||
app.bundle.resource.dedicatedDatabase?.limitMemory ===
dto.dedicatedDatabase.memory
)
case 'dedicatedDatabaseCapacity':
return (
!dto.dedicatedDatabase?.capacity ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.capacity,
) ||
app.bundle.resource.dedicatedDatabase?.capacity ===
dto.dedicatedDatabase.capacity
)
case 'dedicatedDatabaseReplicas':
return (
!dto.dedicatedDatabase?.replicas ||
option.specs.some(
(spec) => spec.value === dto.dedicatedDatabase.replicas,
) ||
app.bundle.resource.dedicatedDatabase?.replicas ===
dto.dedicatedDatabase.replicas
)
default:
return true
}
})
return checkSpec
}

const checkSpec = resourceOptions.every((option) => {
switch (option.type) {
case 'cpu':
Expand Down
11 changes: 11 additions & 0 deletions server/src/application/dto/update-application.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { CreateDedicatedDatabaseDto } from '../../database/dto/create-dedicated-database.dto'
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import {
IsBoolean,
IsIn,
IsInt,
IsNotEmpty,
IsOptional,
IsString,
Length,
ValidateNested,
Expand Down Expand Up @@ -51,6 +53,15 @@ export class UpdateApplicationStateDto {
@IsIn(STATES)
@IsNotEmpty()
state: ApplicationState

@ApiProperty({
required: false,
description: 'Flag for runtime only operations',
type: Boolean,
})
@IsOptional()
@IsBoolean()
onlyRuntimeFlag?: boolean
}

export class UpdateApplicationBundleDto {
Expand Down
Loading

0 comments on commit 8d456e9

Please sign in to comment.