diff --git a/apps/server-nestjs/src/modules/registry/registry-client.service.ts b/apps/server-nestjs/src/modules/registry/registry-client.service.ts index 0e85eff9c9..356f094bda 100644 --- a/apps/server-nestjs/src/modules/registry/registry-client.service.ts +++ b/apps/server-nestjs/src/modules/registry/registry-client.service.ts @@ -1,5 +1,5 @@ import type { RegistryQuery, RegistryResponse } from './registry-http-client.service' -import { Inject, Injectable } from '@nestjs/common' +import { HttpStatus, Inject, Injectable } from '@nestjs/common' import { RegistryHttpClientService } from './registry-http-client.service' import { ROBOT_LIST_PAGE_SIZE } from './registry.constants' @@ -115,8 +115,8 @@ export class RegistryClientService { }) } - async createProject(projectName: string, storageLimit: number) { - return this.http.fetch('projects', { + async ensureProject(projectName: string, storageLimit: number): Promise { + const created = await this.http.fetch('projects', { method: 'POST', body: { project_name: projectName, @@ -124,6 +124,14 @@ export class RegistryClientService { storage_limit: storageLimit, }, }) + if (created.status >= HttpStatus.BAD_REQUEST && created.status !== HttpStatus.CONFLICT) { + throw new Error(`Harbor create project failed (${created.status})`) + } + const fetched = await this.getProjectByName(projectName) + if (fetched.status !== HttpStatus.OK || !fetched.data) { + throw new Error(`Harbor get project failed (${fetched.status})`) + } + return fetched.data } async deleteProjectByName(projectName: string) { @@ -157,12 +165,15 @@ export class RegistryClientService { }) } - async addGroupMember(projectName: string, body: HarborGroupMemberRequest) { - return this.http.fetch(`projects/${encodeURIComponent(projectName)}/members`, { + async ensureGroupMember(projectName: string, body: HarborGroupMemberRequest) { + const created = await this.http.fetch(`projects/${encodeURIComponent(projectName)}/members`, { method: 'POST', headers: { 'X-Is-Resource-Name': 'true' }, body, }) + if (created.status >= HttpStatus.BAD_REQUEST && created.status !== HttpStatus.CONFLICT) { + throw new Error(`Harbor create member failed (${created.status})`) + } } async removeGroupMember(projectName: string, memberId: number) { @@ -178,11 +189,16 @@ export class RegistryClientService { }) } - async createRobot(body: HarborRobotCreateRequest) { - return this.http.fetch('robots', { + async ensureRobot(body: HarborRobotCreateRequest): Promise { + const created = await this.http.fetch('robots', { method: 'POST', body, }) + if (created.status === HttpStatus.CONFLICT) return null + if (created.status >= HttpStatus.BAD_REQUEST || !created.data) { + throw new Error(`Harbor create robot failed (${created.status})`) + } + return created.data } async deleteRobot(robotId: number): Promise { @@ -198,6 +214,22 @@ export class RegistryClientService { return Number.isFinite(retentionId) ? retentionId : null } + async ensureRetention(projectName: string, body: HarborRetentionPolicy) { + const created = await this.createRetention(body) + if (created.status === HttpStatus.CONFLICT) { + const racedId = await this.getRetentionId(projectName) + if (racedId) { + const result = await this.updateRetention(racedId, body) + if (result.status >= HttpStatus.BAD_REQUEST) { + throw new Error(`Harbor retention policy failed (${result.status})`) + } + } + return + } + if (created.status >= HttpStatus.BAD_REQUEST) { + throw new Error(`Harbor retention policy failed (${created.status})`) + } + } async createRetention(body: HarborRetentionPolicy) { return this.http.fetch('retentions', { method: 'POST',