Add UI for limit upstream registry connection

Signed-off-by: stonezdj <stone.zhang@broadcom.com>
This commit is contained in:
stonezdj 2025-09-12 16:40:45 +08:00
parent 2c62b502e2
commit 3379f6b4a6
No known key found for this signature in database
GPG Key ID: 869A6492598C9031
16 changed files with 167 additions and 14 deletions

View File

@ -281,6 +281,55 @@
</clr-control-error>
</div>
</div>
<div
class="clr-form-control mt-05"
[style.visibility]="
isSystemAdmin && enableProxyCache ? 'visible' : 'hidden'
">
<label for="maxUpStreamConn" class="clr-control-label required">
{{ 'PROJECT.CONNECTION_LIMIT' | translate }}
<clr-tooltip>
<clr-icon
clrTooltipTrigger
shape="info-circle"
size="24"></clr-icon>
<clr-tooltip-content
clrPosition="bottom-left"
clrSize="lg"
*clrIfOpen>
<span>{{
'PROJECT.PROXY_CACHE_MAX_UPSTREAM_CONN_TIP'
| translate
}}</span>
</clr-tooltip-content>
</clr-tooltip>
</label>
<div
class="clr-control-container"
[class.clr-error]="maxUpstreamConnError">
<input
type="number"
id="maxUpStreamConn"
[(ngModel)]="project.metadata.max_upstream_conn"
name="maxUpStreamConn"
class="clr-input width-164 mr-10"
placeholder="Enter upstream connection limit"
autocomplete="off"
(ngModelChange)="validateMaxUpstreamConnections()" />
<clr-icon
*ngIf="maxUpstreamConnError"
class="clr-validate-icon"
shape="exclamation-circle"></clr-icon>
<clr-control-error
*ngIf="maxUpstreamConnError"
class="tooltip-content">
{{
'PROJECT.PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP'
| translate
}}
</clr-control-error>
</div>
</div>
</form>
</div>
<div class="modal-footer">

View File

@ -112,6 +112,8 @@ export class CreateProjectComponent
// **Added property for bandwidth error message**
bandwidthError: string | null = null;
maxUpstreamConnError: string | null = null;
constructor(
private projectService: ProjectService,
private translateService: TranslateService,
@ -320,12 +322,33 @@ export class CreateProjectComponent
(!Number.isInteger(value) && value !== -1) ||
(value <= 0 && value !== -1)
) {
this.bandwidthError =
'Please enter -1 or an integer greater than 0.';
this.translateService
.get('PROJECT.PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP')
.subscribe((res: string) => {
this.bandwidthError = res;
});
} else {
this.bandwidthError = null;
}
}
validateMaxUpstreamConnections(): void {
const value = Number(this.project.metadata.max_upstream_conn);
if (
isNaN(value) ||
(!Number.isInteger(value) && value !== -1) ||
(value <= 0 && value !== -1)
) {
this.translateService
.get('PROJECT.PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP')
.subscribe((res: string) => {
this.maxUpstreamConnError = res;
});
} else {
this.maxUpstreamConnError = null;
}
}
convertSpeedValue(realSpeed: number): number {
if (this.selectedSpeedLimitUnit == BandwidthUnit.MB) {
return realSpeed * KB_TO_MB;
@ -342,6 +365,12 @@ export class CreateProjectComponent
return;
}
this.validateMaxUpstreamConnections();
if (this.bandwidthError) {
this.inlineAlert.showInlineError(this.maxUpstreamConnError);
return;
}
this.project.metadata.bandwidth = this.convertSpeedValue(
this.speedLimit
);
@ -364,6 +393,8 @@ export class CreateProjectComponent
public: this.project.metadata.public ? 'true' : 'false',
proxy_speed_kb:
this.project.metadata.bandwidth.toString(),
max_upstream_conn:
this.project.metadata.max_upstream_conn.toString(),
},
storage_limit: +storageByte,
registry_id: registryId,
@ -408,6 +439,7 @@ export class CreateProjectComponent
this.storageLimitUnit = this.storageDefaultLimitUnit;
this.selectedSpeedLimitUnit = BandwidthUnit.KB;
this.speedLimit = -1;
this.project.metadata.max_upstream_conn = -1;
}
public get isValid(): boolean {

View File

@ -92,6 +92,36 @@
</clr-control-error>
</div>
</div>
<div class="row-inline ml-2" clrInline>
<label class="clr-control-label">
{{ 'PROJECT.CONNECTION_LIMIT' | translate }}
</label>
<div
class="clr-control-container ml-1"
[class.clr-error]="maxUpstreamConnError">
<input
type="number"
id="max_upstream_conn"
[(ngModel)]="projectPolicy.MaxUpstreamConn"
name="max_upstream_conn"
disabled="!allowUpdateProxyCacheConfiguration"
class="clr-input width-164 mr-10 clr-input-underline"
autocomplete="off"
(ngModelChange)="validateMaxUpstreamConnections()" />
<clr-icon
*ngIf="maxUpstreamConnError"
class="clr-validate-icon"
shape="exclamation-circle"></clr-icon>
<clr-control-error
*ngIf="maxUpstreamConnError"
class="tooltip-content">
{{
'PROJECT.PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP'
| translate
}}
</clr-control-error>
</div>
</div>
</div>
<clr-checkbox-container *ngIf="!isProxyCacheProject" clrInline>

View File

@ -58,6 +58,7 @@ export class ProjectPolicy {
ProxyCacheEnabled: boolean;
RegistryId?: number | null;
ProxySpeedKb?: number | null;
MaxUpstreamConn?: number | null;
constructor() {
this.Public = false;
@ -70,6 +71,7 @@ export class ProjectPolicy {
this.ProxyCacheEnabled = false;
this.RegistryId = null;
this.ProxySpeedKb = -1;
this.MaxUpstreamConn = -1;
}
initByProject(pro: Project) {
@ -88,6 +90,9 @@ export class ProjectPolicy {
this.ProxySpeedKb = pro.metadata.proxy_speed_kb
? pro.metadata.proxy_speed_kb
: -1;
this.MaxUpstreamConn = pro.metadata.max_upstream_conn
? pro.metadata.max_upstream_conn
: -1;
}
}
const PAGE_SIZE: number = 100;
@ -149,6 +154,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
];
// **Added property for bandwidth error message**
bandwidthError: string | null = null;
maxUpstreamConnError: string | null = null;
registries: Registry[] = [];
supportedRegistryTypeQueryString: string =
'type={docker-hub harbor azure-acr aws-ecr google-gcr quay docker-registry github-ghcr jfrog-artifactory}';
@ -200,8 +206,11 @@ export class ProjectPolicyConfigComponent implements OnInit {
(!Number.isInteger(value) && value !== -1) ||
(value <= 0 && value !== -1)
) {
this.bandwidthError =
'Please enter -1 or an integer greater than 0.';
this.translate
.get('PROJECT.SPEED_LIMIT_TIP')
.subscribe((res: string) => {
this.bandwidthError = res;
});
} else {
this.bandwidthError = null;
}

View File

@ -36,6 +36,7 @@ export class Project {
auto_sbom_generation: string | boolean;
reuse_sys_cve_allowlist?: string;
proxy_speed_kb?: number | null;
max_upstream_conn?: number | null;
};
cve_allowlist?: object;
constructor() {

View File

@ -36,9 +36,11 @@ export class Project {
auto_sbom_generation: string | boolean;
retention_id: number;
bandwidth: number;
max_upstream_conn: number;
};
constructor() {
this.metadata = <any>{};
this.metadata.public = false;
this.metadata.max_upstream_conn = -1;
}
}

View File

@ -271,7 +271,10 @@
"PROXY_CACHE_TOOLTIP": "Die Aktivierung der Funktion erlaubt es dem Projekt, als Cache für eine andere Registry Instanz zu dienen. Harbor unterstützt die Proxy Funktion nur für DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Alibaba Cloud ACR, Quay, Google GCR, JFrog Artifactory, und Github GHCR",
"ENDPOINT": "Endpunkt",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpunkt",
"NO_PROJECT": "Es konnte kein Projekt gefunden werden"
"NO_PROJECT": "Es konnte kein Projekt gefunden werden",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Zusammenfassung",

View File

@ -271,7 +271,10 @@
"PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Alibaba Cloud ACR, Quay, Google GCR, Github GHCR, and JFrog Artifactory registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint",
"NO_PROJECT": "We couldn't find any projects"
"NO_PROJECT": "We couldn't find any projects",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Summary",

View File

@ -272,7 +272,10 @@
"PROXY_CACHE_TOOLTIP": "Habilite esta opción para permitir que este proyecto actúe como caché de extracción para una instancia de registro de destino en particular. Harbor solo puede actuar como proxy para los registros DockerHub, Docker Registry, Harbor, AWS ECR, Azure ACR, Quay, Google GCR, JFrog Artifactory y Github GHCR.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint",
"NO_PROJECT": "No pudimos encontrar ningún proyecto"
"NO_PROJECT": "No pudimos encontrar ningún proyecto",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Resumen",

View File

@ -271,7 +271,10 @@
"PROXY_CACHE_TOOLTIP": "Activez cette option pour permettre à ce projet d'agir comme un cache de pull pour un espace de noms particulier dans un registre cible. Harbor ne peut agir en tant que proxy que pour les registres DockerHub et Harbor.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Endpoint du Proxy Cache",
"NO_PROJECT": "Nous n'avons trouvé aucun projet."
"NO_PROJECT": "Nous n'avons trouvé aucun projet.",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Résumé",

View File

@ -271,7 +271,10 @@
"PROXY_CACHE_TOOLTIP": "이 프로젝트가 특정 대상 레지스트리 인스턴스에 대한 풀스루 캐시 역할을 할 수 있도록 하려면 이 옵션을 활성화합니다. Harbor는 DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay, Google GCR, Github GHCR 및 JFrog Artifactory 레지스트리에 대해서만 프록시 역할을 할 수 있습니다.",
"ENDPOINT": "엔드포인트",
"PROXY_CACHE_ENDPOINT": "프록시 캐시 엔드포인트",
"NO_PROJECT": "프로젝트를 찾을 수 없습니다"
"NO_PROJECT": "프로젝트를 찾을 수 없습니다",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "요약",

View File

@ -269,7 +269,10 @@
"PROXY_CACHE": "Cache do Proxy",
"PROXY_CACHE_TOOLTIP": "Habilite para fazer deste projeto um cache local de outros repositórios remotos (registries). O Harbor pode servir de cache apenas para outros repositórios Harbor, Docker Hub, AWS ECR, Azure ACR, Alibaba Cloud ACR, Quay, Google GCR, Github GHCR, JFrog Artifactory, e repositórios compatíveis com o protocolo Docker Registry",
"ENDPOINT": "Endereço",
"PROXY_CACHE_ENDPOINT": "Endereço do Proxy Cache"
"PROXY_CACHE_ENDPOINT": "Endereço do Proxy Cache",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Resumo",

View File

@ -256,7 +256,10 @@
"PROXY_CACHE_TOOLTIP": "Включите это, чтобы разрешить проекту действовать как прокси-кэш для определенного экземпляра реестра. Harbor может действовать как прокси для DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay, Google GCR, Github GHCR и JFrog Artifactory.",
"ENDPOINT": "Конечная точка",
"PROXY_CACHE_ENDPOINT": "Конечная точка прокси-кэша",
"NO_PROJECT": "Мы не смогли найти никаких проектов"
"NO_PROJECT": "Мы не смогли найти никаких проектов",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Сводка",

View File

@ -272,7 +272,10 @@
"PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Alibaba Cloud ACR, Quay, Google GCR, JFrog Artifactory, and Github GHCR registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint",
"NO_PROJECT": "We couldn't find any projects"
"NO_PROJECT": "We couldn't find any projects",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "Özet",

View File

@ -270,7 +270,10 @@
"PROXY_CACHE_TOOLTIP": "开启此项,以使得该项目成为目标仓库的镜像代理.仅支持 DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Alibaba Cloud ACR, Quay, Google GCR, JFrog Artifactory, 和 Github GHCR 类型的仓库",
"ENDPOINT": "地址",
"PROXY_CACHE_ENDPOINT": "镜像代理地址",
"NO_PROJECT": "未发现任何项目"
"NO_PROJECT": "未发现任何项目",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if less than 0, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "请输入-1或者大于0的整数"
},
"PROJECT_DETAIL": {
"SUMMARY": "概要",

View File

@ -269,7 +269,10 @@
"PROXY_CACHE_TOOLTIP": "啟用此選項可讓此專案作為特定目標 Registry 實例的拉取快取。Harbor 僅可作為 DockerHub、Docker Registry、Harbor、AWS ECR、Azure ACR、Alibaba Cloud ACR、Quay、Google GCR、GitHub GHCR 和 JFrog Artifactory Registry 的代理。",
"ENDPOINT": "端點",
"PROXY_CACHE_ENDPOINT": "代理快取端點",
"NO_PROJECT": "找不到任何專案"
"NO_PROJECT": "找不到任何專案",
"CONNECTION_LIMIT": "Max connection to upstream registry",
"PROXY_CACHE_MAX_UPSTREAM_CONN_TIP": "The max connection to the upstream registry for this proxy cache project, if -1, then there is no limit",
"PROXY_CACHE_MAX_UPSTREAM_CONN_INPUT_TIP": "Please enter -1 or an integer greater than 0. "
},
"PROJECT_DETAIL": {
"SUMMARY": "摘要",