From: Afreen Misbah Date: Thu, 23 Apr 2026 10:42:26 +0000 (+0530) Subject: mgr/dashboard: Nvmeof gateway group should account for labels X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=34e3f27f90ad0ed1a83c2e198ae511fae8979b44;p=ceph.git mgr/dashboard: Nvmeof gateway group should account for labels - updates gateway group sections to account for placement label Signed-off-by: Afreen Misbah (cherry picked from commit e3ce6fe31277d6d7aaa93f7a546e991a45484230) Conflicts: src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group/nvmeof-gateway-group.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group/nvmeof-gateway-group.component.ts index 4b4ac02794f1..3ccef418bd08 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group/nvmeof-gateway-group.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group/nvmeof-gateway-group.component.ts @@ -228,6 +228,7 @@ export class NvmeofGatewayGroupComponent implements OnInit { } }); } + private checkNodesAvailability(): void { forkJoin([this.nvmeofService.listGatewayGroups(), this.hostService.getAllHosts()]).subscribe( ([groups, hosts]: [GatewayGroup[][], any[]]) => { @@ -236,6 +237,15 @@ export class NvmeofGatewayGroupComponent implements OnInit { groupList.forEach((group: CephServiceSpec) => { const placementHosts = group.placement?.hosts || []; placementHosts.forEach((hostname: string) => usedHosts.add(hostname)); + + const placementLabel = group.placement?.label; + if (placementLabel) { + (hosts || []).forEach((host) => { + if (host.labels?.includes(placementLabel)) { + usedHosts.add(host.hostname); + } + }); + } }); const availableHosts = (hosts || []).filter((host) => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts index 833d31aaf624..a8a6f7ca0ac8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts @@ -277,8 +277,16 @@ export class NvmeofGatewayNodeComponent implements OnInit, OnDestroy { groupList.forEach((group: CephServiceSpec) => { const hosts = group.placement?.hosts || (group.spec as any)?.placement?.hosts || []; hosts.forEach((hostname: string) => allUsedHostnames.add(hostname)); - }); + const label = group.placement?.label || group.spec?.placement?.label; + if (label) { + (hostList || []).forEach((host: Host) => { + if (host.labels?.includes(label as string)) { + allUsedHostnames.add(host.hostname); + } + }); + } + }); this.usedHostnames = allUsedHostnames; // Check if there are any available hosts globally (not used by any group) @@ -301,12 +309,20 @@ export class NvmeofGatewayNodeComponent implements OnInit, OnDestroy { this.hosts = []; } else { const placementHosts = - this.serviceSpec.placement?.hosts || (this.serviceSpec.spec as any)?.placement?.hosts || []; - const currentGroupHosts = new Set(placementHosts); - - this.hosts = (hostList || []).filter((host: Host) => { - return currentGroupHosts.has(host.hostname); - }); + this.serviceSpec.placement?.hosts || this.serviceSpec.spec?.placement?.hosts || []; + const placementLabel = + this.serviceSpec.placement?.label || this.serviceSpec.spec?.placement?.label; + + if (placementHosts.length > 0) { + const currentGroupHosts = new Set(placementHosts); + this.hosts = (hostList || []).filter((host: Host) => currentGroupHosts.has(host.hostname)); + } else if (placementLabel) { + this.hosts = (hostList || []).filter((host: Host) => + host.labels?.includes(placementLabel as string) + ); + } else { + this.hosts = []; + } } this.count = this.hosts.length; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.spec.ts index 9a4ab4a9f26c..462f5569f14d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.spec.ts @@ -104,7 +104,7 @@ describe('ServiceFormComponent', () => { // placement labels take only single value formHelper.setValue('service_type', 'mgr'); formHelper.setValue('placement', 'label'); - formHelper.setValue('label', 'foo'); + formHelper.setValue('label', "{content: 'foo', selected: true}"); component.onSubmit(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts index 1cfdf54e656a..100bff76ab68 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts @@ -90,9 +90,22 @@ export class NvmeofService { }).pipe( map(({ groups, hosts }) => { const usedHosts = new Set(); + (groups?.[0] ?? []).forEach((group: CephServiceSpec) => { - group.placement?.hosts?.forEach((hostname: string) => usedHosts.add(hostname)); + const placementHosts = group.placement?.hosts || []; + const placementLabel = group.placement?.label; + + placementHosts.forEach((hostname: string) => usedHosts.add(hostname)); + + if (placementLabel) { + (hosts || []).forEach((host: Host) => { + if (host.labels?.includes(placementLabel as string)) { + usedHosts.add(host.hostname); + } + }); + } }); + return (hosts || []).filter((host: Host) => { const isAvailable = host.status === HostStatus.AVAILABLE || host.status === HostStatus.RUNNING; @@ -130,15 +143,8 @@ export class NvmeofService { if (hosts?.length) { return allHosts.filter((host: Host) => hosts.includes(host.hostname)); - } else if (label?.length) { - if (typeof label === 'string') { - return allHosts.filter((host: Host) => host?.labels?.includes(label)); - } - return allHosts.filter( - (host: Host) => - host?.labels?.length === label?.length && - _.isEqual([...host.labels].sort(), [...label].sort()) - ); + } else if (label) { + return allHosts.filter((host: Host) => host?.labels?.includes(label as string)); } return []; })