]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add "connection get_io_statistics" to NVMeoF CLI 67844/head
authorGil Bregman <gbregman@il.ibm.com>
Mon, 16 Mar 2026 10:59:06 +0000 (12:59 +0200)
committerTomer Haskalovitch <tomer.haska@ibm.com>
Tue, 12 May 2026 06:50:19 +0000 (09:50 +0300)
Fixes: https://tracker.ceph.com/issues/74964
Signed-off-by: Gil Bregman <gbregman@il.ibm.com>
(cherry picked from commit d42c9cf1e52c3ce06b6b538f436ee81a9fd973ee)
Signed-off-by: Gil Bregman <gbregman@il.ibm.com>
src/pybind/mgr/dashboard/controllers/nvmeof.py
src/pybind/mgr/dashboard/model/nvmeof.py
src/pybind/mgr/dashboard/openapi.yaml

index ff199ac4ec8410b428c20ecb3c55ce77b719eb6e..73307844593c983a68c80b9059b92d585003cb2b 100644 (file)
@@ -136,6 +136,27 @@ else:
             )
             return gw_listener_info
 
+        @ReadPermission
+        @Endpoint('PUT', '/io_stats')
+        @NvmeofCLICommand(
+            "nvmeof gateway set_io_stats_mode", model.RequestStatus,
+            alias="nvmeof gw set_io_stats_mode")
+        @EndpointDoc(
+            "Enable or disable IO statistics collection",
+            parameters={
+                "enabled": Param(bool, "Enable IO statistics collection"),
+                "gw_group": Param(str, "NVMeoF gateway group", True, None),
+            },
+        )
+        @convert_to_model(model.RequestStatus)
+        @handle_nvmeof_error
+        def set_io_stats_mode(self, enabled: bool, gw_group: Optional[str] = None):
+            io_stats = NVMeoFClient(gw_group=gw_group,
+                                    ).stub.set_gateway_io_stats_mode(
+                NVMeoFClient.pb2.set_gateway_io_stats_mode_req(enabled=enabled)
+            )
+            return io_stats
+
     @APIRouter("/nvmeof/spdk", Scope.NVME_OF)
     @APIDoc("NVMe-oF SPDK Management API", "NVMe-oF SPDK")
     class NVMeoFSpdk(RESTController):
@@ -227,9 +248,8 @@ else:
             "Create a new NVMeoF subsystem",
             parameters={
                 "nqn": Param(str, "NVMeoF subsystem NQN"),
-                "enable_ha": Param(bool, "Enable high availability", True, None),
                 "max_namespaces": Param(int, "Maximum number of namespaces", True, None),
-                "no_group_append": Param(int, "Do not append gateway group name to the NQN",
+                "no_group_append": Param(bool, "Do not append gateway group name to the NQN",
                                          True, False),
                 "serial_number": Param(str, "Subsystem serial number", True, None),
                 "dhchap_key": Param(str, "Subsystem DH-HMAC-CHAP key", True, None),
@@ -239,14 +259,14 @@ else:
         )
         @convert_to_model(model.SubsystemStatus)
         @handle_nvmeof_error
-        def create(self, nqn: str, enable_ha: Optional[bool] = True,
+        def create(self, nqn: str,
                    max_namespaces: Optional[int] = None, no_group_append: Optional[bool] = False,
                    serial_number: Optional[str] = None, dhchap_key: Optional[str] = None,
                    gw_group: Optional[str] = None, traddr: Optional[str] = None):
             return NVMeoFClient(gw_group=gw_group, traddr=traddr).stub.create_subsystem(
                 NVMeoFClient.pb2.create_subsystem_req(
                     subsystem_nqn=nqn, serial_number=serial_number,
-                    max_namespaces=max_namespaces, enable_ha=enable_ha,
+                    max_namespaces=max_namespaces, enable_ha=True,
                     no_group_append=no_group_append,
                     dhchap_key=dhchap_key
                 )
@@ -1502,6 +1522,64 @@ else:
                 NVMeoFClient.pb2.list_connections_req(subsystem=nqn)
             )
 
+        @NvmeofCLICommand(
+            "nvmeof connection get_io_statistics",
+            model.ConnectionIOStatistics,
+        )
+        @EndpointDoc(
+            "Get the IO statistics for a connection",
+            parameters={
+                "nqn": Param(str, "NVMeoF subsystem NQN"),
+                "host_nqn": Param(str, "NVMeoF host NQN"),
+                "gw_group": Param(str, "NVMeoF gateway group", True, None),
+            },
+        )
+        @convert_to_model(model.ConnectionIOStatistics)
+        @handle_nvmeof_error
+        def get_io_stats(
+            self,
+            nqn: str,
+            host_nqn: str,
+            gw_group: Optional[str] = None,
+            traddr: Optional[str] = None
+        ):
+            return NVMeoFClient(
+                gw_group=gw_group, traddr=traddr
+            ).stub.get_connection_io_statistics(
+                NVMeoFClient.pb2.get_connection_io_statistics_req(subsystem_nqn=nqn,
+                                                                  host_nqn=host_nqn,
+                                                                  reset=False)
+            )
+
+        @NvmeofCLICommand(
+            "nvmeof connection reset_io_statistics",
+            model.ConnectionIOStatistics,
+        )
+        @EndpointDoc(
+            "Reset the IO statistics for a connection",
+            parameters={
+                "nqn": Param(str, "NVMeoF subsystem NQN"),
+                "host_nqn": Param(str, "NVMeoF host NQN"),
+                "gw_group": Param(str, "NVMeoF gateway group", True, None)
+            },
+        )
+        @convert_to_model(model.ConnectionIOStatistics)
+        @handle_nvmeof_error
+        def reset_io_stats(
+            self,
+            nqn: str,
+            host_nqn: str,
+            gw_group: Optional[str] = None,
+            traddr: Optional[str] = None
+        ):
+            return NVMeoFClient(
+                gw_group=gw_group, traddr=traddr
+            ).stub.get_connection_io_statistics(
+                NVMeoFClient.pb2.get_connection_io_statistics_req(subsystem_nqn=nqn,
+                                                                  host_nqn=host_nqn,
+                                                                  reset=True)
+            )
+
     @UIRouter('/nvmeof', Scope.NVME_OF)
     class NVMeoFTcpUI(BaseController):
         @Endpoint('GET', '/status')
index 1dcd6babf2c60b07833d68a69f099e42810b4922..9f043cc0f318c172b4a7189274cfda2d8dc379ba 100644 (file)
@@ -135,6 +135,35 @@ class ConnectionList(NamedTuple):
     connections: Annotated[List[Connection], CliFlags.EXCLUSIVE_LIST]
 
 
+class LatencyStats(NamedTuple):
+    min: int
+    max: int
+    mean: int
+
+
+class LatencyGroup(NamedTuple):
+    io_count: int
+    total: LatencyStats
+    bdev: LatencyStats
+    net: LatencyStats
+    qos: LatencyStats
+
+
+class BucketInfo(NamedTuple):
+    size: int
+    read: LatencyGroup
+    write: LatencyGroup
+
+
+class ConnectionIOStatistics(NamedTuple):
+    status: int
+    error_message: str
+    subsystem_nqn: str
+    host_nqn: str
+    total_num_ios: int
+    buckets: Annotated[List[BucketInfo], CliFlags.EXCLUSIVE_LIST]
+
+
 class NamespaceCreation(NamedTuple):
     status: Annotated[int, CliFlags.EXCLUSIVE_RESULT]
     error_message: str
index 4ddc6ead464d13719bd67639bb7c93e9a635424f..fae5382bc39a56780ceae3067737a7fca685d8eb 100644 (file)
@@ -9396,6 +9396,48 @@ paths:
       - jwt: []
       tags:
       - NVMe-oF Gateway
+  /api/nvmeof/gateway/io_stats:
+    put:
+      parameters: []
+      requestBody:
+        content:
+          application/json:
+            schema:
+              properties:
+                enabled:
+                  description: Enable IO statistics collection
+                  type: boolean
+                gw_group:
+                  description: NVMeoF gateway group
+                  type: string
+              required:
+              - enabled
+              type: object
+      responses:
+        '200':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Resource updated.
+        '202':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Operation is still executing. Please check the task queue.
+        '400':
+          description: Operation exception. Please check the response body for details.
+        '401':
+          description: Unauthenticated access. Please login first.
+        '403':
+          description: Unauthorized access. Please check your permissions.
+        '500':
+          description: Unexpected error. Please check the response body for the stack
+            trace.
+      security:
+      - jwt: []
+      summary: Enable or disable IO statistics collection
+      tags:
+      - NVMe-oF Gateway
   /api/nvmeof/gateway/listener_info/{nqn}:
     get:
       parameters:
@@ -9738,10 +9780,6 @@ paths:
                 dhchap_key:
                   description: Subsystem DH-HMAC-CHAP key
                   type: string
-                enable_ha:
-                  default: true
-                  description: Enable high availability
-                  type: boolean
                 gw_group:
                   description: NVMeoF gateway group
                   type: string
@@ -9751,7 +9789,7 @@ paths:
                 no_group_append:
                   default: false
                   description: Do not append gateway group name to the NQN
-                  type: integer
+                  type: boolean
                 nqn:
                   description: NVMeoF subsystem NQN
                   type: string