]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Nvmeof gateway group should account for labels
authorAfreen Misbah <afreen@ibm.com>
Thu, 23 Apr 2026 10:42:26 +0000 (16:12 +0530)
committerAfreen Misbah <afreen@ibm.com>
Wed, 29 Apr 2026 07:42:26 +0000 (13:12 +0530)
- updates gateway group sections to account for placement label

Signed-off-by: Afreen Misbah <afreen@ibm.com>
(cherry picked from commit e3ce6fe31277d6d7aaa93f7a546e991a45484230)

Conflicts:
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts

src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-group/nvmeof-gateway-group.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-gateway-node/nvmeof-gateway-node.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/nvmeof.service.ts

index 4b4ac02794f19d3fa405453a07784218463cebde..3ccef418bd08f4af86f5a96607ca802a2c9a8e51 100644 (file)
@@ -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) => {
index 833d31aaf624b53473d5919324c0882847cc3484..a8a6f7ca0ac8f38bc75560a0acbbc04af3f29716 100644 (file)
@@ -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<string>(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<string>(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;
index 9a4ab4a9f26c6ef7b06ec4d0830a5cf9de3e89bb..462f5569f14d108cd9256815350cbfd161140021 100644 (file)
@@ -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();
 
index 1cfdf54e656a1a5460c72c470c2a13920f6831a5..100bff76ab68b6fa1b67a91f30591f768e6423a1 100644 (file)
@@ -90,9 +90,22 @@ export class NvmeofService {
     }).pipe(
       map(({ groups, hosts }) => {
         const usedHosts = new Set<string>();
+
         (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 [];
       })