Skip to content

Commit d7a1d25

Browse files
authored
Handle KubeBlock v5 upgrade API call for horizontal scaling (#2063)
1 parent a97f3f7 commit d7a1d25

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

server/src/constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ export class ServerConfig {
192192
static get HTTP_INTERCEPTOR_URL() {
193193
return process.env.HTTP_INTERCEPTOR_URL
194194
}
195+
196+
static get KUBEBLOCK_V5_UPGRADE_URL() {
197+
return process.env.KUBEBLOCK_V5_UPGRADE_URL
198+
}
195199
}
196200

197201
export const LABEL_KEY_USER_ID = 'laf.dev/user.id'
@@ -255,3 +259,6 @@ export const STORAGE_LIMIT = 1000 // 1000 items
255259

256260
// HTTP interceptor
257261
export const HTTP_INTERCEPTOR_TIMEOUT = 3000 // 3s
262+
263+
// KubeBlock v5 upgrade API
264+
export const KUBEBLOCK_V5_UPGRADE_API_TIMEOUT = 3000 // 3s

server/src/database/dedicated-database/dedicated-database.service.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ApplicationBundle } from 'src/application/entities/application-bundle'
2020
import * as assert from 'assert'
2121
import { extractNumber } from 'src/utils/number'
2222
import { formatK8sErrorAsJson } from 'src/utils/k8s-error'
23+
import { ServerConfig, KUBEBLOCK_V5_UPGRADE_API_TIMEOUT } from 'src/constants'
2324

2425
const getDedicatedDatabaseName = (appid: string) => appid
2526

@@ -142,13 +143,18 @@ export class DedicatedDatabaseService {
142143
appid,
143144
'horizontalScaling',
144145
)
146+
145147
if (!OpsRequestManifest) {
146148
const result = await this.applyKubeBlockOpsRequestManifestForSpec(
147149
region,
148150
appid,
149151
spec,
150152
'horizontalScaling',
151153
)
154+
155+
// Call KubeBlock v5 compatibility API if needed
156+
await this.handleKubeBlockV5Upgrade(appid, manifest, spec.replicas)
157+
152158
results.push(result)
153159
this.logger.log(
154160
`Applied horizontalScaling ops request for ${appid}: replicas=${spec.replicas}`,
@@ -702,4 +708,116 @@ export class DedicatedDatabaseService {
702708
return false
703709
}
704710
}
711+
712+
/**
713+
* Handle KubeBlock v5 upgrade API call for horizontal scaling
714+
* This is a compatibility feature for KubeBlock v5 mongodb-5.0 clusters
715+
*
716+
* @param appid - Application ID
717+
* @param manifest - Current deployment manifest
718+
* @param replicas - Number of replicas
719+
*/
720+
private async handleKubeBlockV5Upgrade(
721+
appid: string,
722+
manifest: KubernetesObject & { spec: any; status: any },
723+
replicas: number,
724+
): Promise<void> {
725+
try {
726+
// Early return if not a v5 mongodb-5.0 cluster
727+
if (!this.isKubeBlockV5MongoDb(manifest)) {
728+
return
729+
}
730+
731+
const url = ServerConfig.KUBEBLOCK_V5_UPGRADE_URL
732+
if (!url) {
733+
this.logger.warn(
734+
`KubeBlock v5 upgrade URL not configured (KUBEBLOCK_V5_UPGRADE_URL env var not set) for ${appid}`,
735+
)
736+
return
737+
}
738+
739+
await this.callKubeBlockV5UpgradeAPI(appid, manifest, replicas, url)
740+
} catch (error) {
741+
this.logger.error(
742+
`Failed to call KubeBlock v5 upgrade API for ${appid}: ${error.message}`,
743+
)
744+
// Don't throw error, just log it as it's a compatibility feature
745+
}
746+
}
747+
748+
/**
749+
* Check if the manifest is a KubeBlock v5 mongodb-5.0 cluster
750+
*/
751+
private isKubeBlockV5MongoDb(
752+
manifest: KubernetesObject & { spec: any; status: any },
753+
): boolean {
754+
return (
755+
manifest?.metadata?.labels?.['clusterversion.kubeblocks.io/name'] ===
756+
'mongodb-5.0'
757+
)
758+
}
759+
760+
/**
761+
* Call KubeBlock v5 upgrade API with timeout control
762+
*/
763+
private async callKubeBlockV5UpgradeAPI(
764+
appid: string,
765+
manifest: KubernetesObject & { spec: any; status: any },
766+
replicas: number,
767+
url: string,
768+
): Promise<void> {
769+
const clusterName = manifest.metadata.name
770+
const namespace = manifest.metadata.namespace
771+
772+
// Create AbortController for timeout
773+
const controller = new AbortController()
774+
const timeoutId = setTimeout(
775+
() => controller.abort(),
776+
KUBEBLOCK_V5_UPGRADE_API_TIMEOUT,
777+
)
778+
779+
try {
780+
const response = await fetch(url, {
781+
method: 'POST',
782+
headers: {
783+
'Content-Type': 'application/json',
784+
},
785+
body: JSON.stringify({
786+
namespace,
787+
database_name: clusterName,
788+
replicas,
789+
}),
790+
signal: controller.signal,
791+
})
792+
793+
const responseData = await this.parseKubeBlockV5Response(response)
794+
795+
if (!response.ok) {
796+
throw new Error(
797+
`HTTP error! status: ${response.status}, statusText: ${
798+
response.statusText
799+
}, body: ${JSON.stringify(responseData)}`,
800+
)
801+
}
802+
803+
this.logger.log(
804+
`Called KubeBlock v5 upgrade API for ${appid}: cluster=${clusterName}, replicas=${replicas}, response: ${JSON.stringify(
805+
responseData,
806+
)}`,
807+
)
808+
} finally {
809+
clearTimeout(timeoutId)
810+
}
811+
}
812+
813+
/**
814+
* Parse response body from KubeBlock v5 API
815+
*/
816+
private async parseKubeBlockV5Response(response: Response): Promise<any> {
817+
const contentType = response.headers.get('content-type')
818+
if (contentType?.includes('application/json')) {
819+
return await response.json()
820+
}
821+
return await response.text()
822+
}
705823
}

0 commit comments

Comments
 (0)