Skip to content

Commit 8e46e9a

Browse files
authored
KB 9.0 compatibility (#2061)
* sync serve * sycn web * chore
1 parent 8f9bf34 commit 8e46e9a

File tree

37 files changed

+1633
-409
lines changed

37 files changed

+1633
-409
lines changed

server/src/application/application.controller.ts

Lines changed: 156 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ import { GroupWithRole } from 'src/group/entities/group'
5656
import { isEqual } from 'lodash'
5757
import { InstanceService } from 'src/instance/instance.service'
5858
import { QuotaService } from 'src/user/quota.service'
59+
import { DedicatedDatabaseService } from 'src/database/dedicated-database/dedicated-database.service'
60+
import {
61+
DedicatedDatabasePhase,
62+
DedicatedDatabaseState,
63+
} from 'src/database/entities/dedicated-database'
5964

6065
@ApiTags('Application')
6166
@Controller('applications')
@@ -73,6 +78,7 @@ export class ApplicationController {
7378
private readonly resource: ResourceService,
7479
private readonly runtimeDomain: RuntimeDomainService,
7580
private readonly quotaServiceTsService: QuotaService,
81+
private readonly dedicateDatabase: DedicatedDatabaseService,
7682
) {}
7783

7884
/**
@@ -253,6 +259,7 @@ export class ApplicationController {
253259
if (dto.state === ApplicationState.Deleted) {
254260
throw new ForbiddenException('cannot update state to deleted')
255261
}
262+
const ddb = await this.dedicateDatabase.findOne(appid)
256263
const userid = app.createdBy
257264

258265
// check account balance
@@ -265,8 +272,10 @@ export class ApplicationController {
265272
// check: only running application can restart
266273
if (
267274
dto.state === ApplicationState.Restarting &&
268-
app.state !== ApplicationState.Running &&
269-
app.phase !== ApplicationPhase.Started
275+
!(
276+
app.state === ApplicationState.Running &&
277+
app.phase === ApplicationPhase.Started
278+
)
270279
) {
271280
return ResponseUtil.error(
272281
'The application is not running, can not restart it',
@@ -276,8 +285,8 @@ export class ApplicationController {
276285
// check: only running application can stop
277286
if (
278287
dto.state === ApplicationState.Stopped &&
279-
app.state !== ApplicationState.Running &&
280-
app.phase !== ApplicationPhase.Started
288+
(app.state !== ApplicationState.Running ||
289+
app.phase !== ApplicationPhase.Started)
281290
) {
282291
return ResponseUtil.error(
283292
'The application is not running, can not stop it',
@@ -287,8 +296,8 @@ export class ApplicationController {
287296
// check: only stopped application can start
288297
if (
289298
dto.state === ApplicationState.Running &&
290-
app.state !== ApplicationState.Stopped &&
291-
app.phase !== ApplicationPhase.Stopped
299+
(app.state !== ApplicationState.Stopped ||
300+
app.phase !== ApplicationPhase.Stopped)
292301
) {
293302
return ResponseUtil.error(
294303
'The application is not stopped, can not start it',
@@ -304,6 +313,20 @@ export class ApplicationController {
304313
return ResponseUtil.error('no permission')
305314
}
306315

316+
if (ddb) {
317+
if (dto.state === ApplicationState.Restarting && dto?.onlyRuntimeFlag) {
318+
const doc = await this.application.updateState(appid, dto.state)
319+
return ResponseUtil.ok(doc)
320+
}
321+
322+
const doc = await this.application.updateState(appid, dto.state)
323+
await this.dedicateDatabase.updateState(
324+
appid,
325+
dto.state as unknown as DedicatedDatabaseState,
326+
)
327+
return ResponseUtil.ok(doc)
328+
}
329+
307330
const doc = await this.application.updateState(appid, dto.state)
308331
return ResponseUtil.ok(doc)
309332
}
@@ -322,6 +345,13 @@ export class ApplicationController {
322345
@InjectApplication() app: ApplicationWithRelations,
323346
@InjectUser() user: User,
324347
) {
348+
// only running application can update bundle
349+
if (app.phase !== ApplicationPhase.Started) {
350+
return ResponseUtil.error(
351+
'The application is not running, can not update bundle',
352+
)
353+
}
354+
325355
const error = dto.autoscaling.validate()
326356
if (error) {
327357
return ResponseUtil.error(error)
@@ -354,11 +384,44 @@ export class ApplicationController {
354384
return ResponseUtil.error('cannot change database type')
355385
}
356386

357-
const checkSpec = await this.checkResourceSpecification(dto, regionId)
387+
const checkSpec = await this.checkResourceSpecification(dto, regionId, app)
358388
if (!checkSpec) {
359389
return ResponseUtil.error('invalid resource specification')
360390
}
361391

392+
// Check if user is trying to change dedicated database resources
393+
const isTryingToChangeDedicatedDatabase =
394+
(dto.dedicatedDatabase?.cpu !== undefined &&
395+
dto.dedicatedDatabase?.cpu !==
396+
origin.resource.dedicatedDatabase?.limitCPU) ||
397+
(dto.dedicatedDatabase?.memory !== undefined &&
398+
dto.dedicatedDatabase?.memory !==
399+
origin.resource.dedicatedDatabase?.limitMemory) ||
400+
(dto.dedicatedDatabase?.replicas !== undefined &&
401+
dto.dedicatedDatabase?.replicas !==
402+
origin.resource.dedicatedDatabase?.replicas) ||
403+
(dto.dedicatedDatabase?.capacity !== undefined &&
404+
dto.dedicatedDatabase?.capacity !==
405+
origin.resource.dedicatedDatabase?.capacity)
406+
407+
if (isTryingToChangeDedicatedDatabase) {
408+
const ddb = await this.dedicateDatabase.findOne(appid)
409+
// Database must be running to change database resources
410+
if (!ddb) {
411+
return ResponseUtil.error(
412+
'DedicatedDatabase not found, cannot change DedicatedDatabase database resources',
413+
)
414+
}
415+
if (
416+
ddb.state !== DedicatedDatabaseState.Running ||
417+
ddb.phase !== DedicatedDatabasePhase.Started
418+
) {
419+
return ResponseUtil.error(
420+
'DedicatedDatabase is not in running state, cannot change DedicatedDatabase database resources',
421+
)
422+
}
423+
}
424+
362425
if (
363426
dto.dedicatedDatabase?.capacity &&
364427
origin.resource.dedicatedDatabase?.capacity &&
@@ -393,12 +456,15 @@ export class ApplicationController {
393456
const doc = await this.application.updateBundle(appid, dto, isTrialTier)
394457

395458
// restart running application if cpu or memory changed
396-
const isRunning = app.phase === ApplicationPhase.Started
397459
const isCpuChanged = origin.resource.limitCPU !== doc.resource.limitCPU
398460
const isMemoryChanged =
399461
origin.resource.limitMemory !== doc.resource.limitMemory
400462
const isAutoscalingCanceled =
401463
!doc.autoscaling.enable && origin.autoscaling.enable
464+
465+
const isRuntimeChanged =
466+
isCpuChanged || isMemoryChanged || isAutoscalingCanceled
467+
402468
const isDedicatedDatabaseChanged =
403469
!!origin.resource.dedicatedDatabase &&
404470
(!isEqual(
@@ -423,13 +489,16 @@ export class ApplicationController {
423489
await this.instance.reapplyHorizontalPodAutoscaler(app, hpa)
424490
}
425491

426-
if (
427-
isRunning &&
428-
(isCpuChanged ||
429-
isMemoryChanged ||
430-
isAutoscalingCanceled ||
431-
isDedicatedDatabaseChanged)
432-
) {
492+
if (isDedicatedDatabaseChanged) {
493+
await this.application.updateState(appid, ApplicationState.Restarting)
494+
await this.dedicateDatabase.updateState(
495+
appid,
496+
DedicatedDatabaseState.Restarting,
497+
)
498+
return ResponseUtil.ok(doc)
499+
}
500+
501+
if (isRuntimeChanged) {
433502
await this.application.updateState(appid, ApplicationState.Restarting)
434503
}
435504

@@ -540,8 +609,80 @@ export class ApplicationController {
540609
private async checkResourceSpecification(
541610
dto: UpdateApplicationBundleDto,
542611
regionId: ObjectId,
612+
app?: ApplicationWithRelations,
543613
) {
544614
const resourceOptions = await this.resource.findAllByRegionId(regionId)
615+
616+
if (app) {
617+
const checkSpec = resourceOptions.every((option) => {
618+
switch (option.type) {
619+
case 'cpu':
620+
return (
621+
option.specs.some((spec) => spec.value === dto.cpu) ||
622+
app.bundle.resource.limitCPU === dto.cpu
623+
)
624+
case 'memory':
625+
return (
626+
option.specs.some((spec) => spec.value === dto.memory) ||
627+
app.bundle.resource.limitMemory === dto.memory
628+
)
629+
case 'databaseCapacity':
630+
if (!dto.databaseCapacity) return true
631+
return (
632+
option.specs.some(
633+
(spec) => spec.value === dto.databaseCapacity,
634+
) || app.bundle.resource.databaseCapacity === dto.databaseCapacity
635+
)
636+
case 'storageCapacity':
637+
if (!dto.storageCapacity) return true
638+
return (
639+
option.specs.some((spec) => spec.value === dto.storageCapacity) ||
640+
app.bundle.resource.storageCapacity === dto.storageCapacity
641+
)
642+
// dedicated database
643+
case 'dedicatedDatabaseCPU':
644+
return (
645+
!dto.dedicatedDatabase?.cpu ||
646+
option.specs.some(
647+
(spec) => spec.value === dto.dedicatedDatabase.cpu,
648+
) ||
649+
app.bundle.resource.dedicatedDatabase?.limitCPU ===
650+
dto.dedicatedDatabase.cpu
651+
)
652+
case 'dedicatedDatabaseMemory':
653+
return (
654+
!dto.dedicatedDatabase?.memory ||
655+
option.specs.some(
656+
(spec) => spec.value === dto.dedicatedDatabase.memory,
657+
) ||
658+
app.bundle.resource.dedicatedDatabase?.limitMemory ===
659+
dto.dedicatedDatabase.memory
660+
)
661+
case 'dedicatedDatabaseCapacity':
662+
return (
663+
!dto.dedicatedDatabase?.capacity ||
664+
option.specs.some(
665+
(spec) => spec.value === dto.dedicatedDatabase.capacity,
666+
) ||
667+
app.bundle.resource.dedicatedDatabase?.capacity ===
668+
dto.dedicatedDatabase.capacity
669+
)
670+
case 'dedicatedDatabaseReplicas':
671+
return (
672+
!dto.dedicatedDatabase?.replicas ||
673+
option.specs.some(
674+
(spec) => spec.value === dto.dedicatedDatabase.replicas,
675+
) ||
676+
app.bundle.resource.dedicatedDatabase?.replicas ===
677+
dto.dedicatedDatabase.replicas
678+
)
679+
default:
680+
return true
681+
}
682+
})
683+
return checkSpec
684+
}
685+
545686
const checkSpec = resourceOptions.every((option) => {
546687
switch (option.type) {
547688
case 'cpu':

server/src/application/dto/update-application.dto.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
IsString,
99
Length,
1010
ValidateNested,
11+
IsBoolean,
1112
} from 'class-validator'
1213
import { ApplicationState } from '../entities/application'
1314
import { CreateAutoscalingDto } from './create-autoscaling.dto'
@@ -52,6 +53,15 @@ export class UpdateApplicationStateDto {
5253
@IsIn(STATES)
5354
@IsNotEmpty()
5455
state: ApplicationState
56+
57+
@ApiProperty({
58+
required: false,
59+
description: 'Flag for runtime only operations',
60+
type: Boolean,
61+
})
62+
@IsOptional()
63+
@IsBoolean()
64+
onlyRuntimeFlag?: boolean
5565
}
5666

5767
export class UpdateApplicationBundleDto {

server/src/billing/billing-payment-task.service.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'
22
import { Cron, CronExpression } from '@nestjs/schedule'
33
import {
44
Application,
5+
ApplicationPhase,
56
ApplicationState,
67
} from 'src/application/entities/application'
78
import { ServerConfig, TASK_LOCK_INIT_TIME } from 'src/constants'
@@ -16,6 +17,11 @@ import { AccountTransaction } from 'src/account/entities/account-transaction'
1617
import Decimal from 'decimal.js'
1718
import { NotificationService } from 'src/notification/notification.service'
1819
import { NotificationType } from 'src/notification/notification-type'
20+
import {
21+
DedicatedDatabase,
22+
DedicatedDatabasePhase,
23+
DedicatedDatabaseState,
24+
} from 'src/database/entities/dedicated-database'
1925

2026
@Injectable()
2127
export class BillingPaymentTaskService {
@@ -150,13 +156,40 @@ export class BillingPaymentTaskService {
150156
{ appid: billing.appid, state: ApplicationState.Running },
151157
{
152158
$set: {
159+
phase: ApplicationPhase.Stopping,
153160
state: ApplicationState.Stopped,
154161
forceStoppedAt: new Date(),
155162
},
156163
},
157164
{ session },
158165
)
159166

167+
const ddb = await db
168+
.collection<DedicatedDatabase>('DedicatedDatabase')
169+
.findOne(
170+
{
171+
appid: billing.appid,
172+
},
173+
{ session },
174+
)
175+
176+
if (ddb) {
177+
await db
178+
.collection<DedicatedDatabase>('DedicatedDatabase')
179+
.updateOne(
180+
{
181+
appid: billing.appid,
182+
},
183+
{
184+
$set: {
185+
phase: DedicatedDatabasePhase.Stopping,
186+
state: DedicatedDatabaseState.Stopped,
187+
},
188+
},
189+
{ session },
190+
)
191+
}
192+
160193
if (res.modifiedCount > 0) {
161194
this.logger.warn(
162195
`Application ${billing.appid} stopped due to insufficient balance`,

0 commit comments

Comments
 (0)