]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add "connection get_io_statistics" to NVMeoF CLI 67810/head
authorGil Bregman <gbregman@il.ibm.com>
Mon, 16 Mar 2026 10:59:06 +0000 (12:59 +0200)
committerGil Bregman <gbregman@il.ibm.com>
Mon, 16 Mar 2026 21:30:25 +0000 (23:30 +0200)
Fixes: https://tracker.ceph.com/issues/74964
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 b65f449aaf2961511179c2c2c9bf25a95d2934f3..7c841335f8bccaf03b3799e1a073a5c3c9d52b1a 100644 (file)
@@ -194,6 +194,30 @@ else:
             )
             return gw_listener_info
 
+        @UpdatePermission
+        @Endpoint('PUT', '/io_stats')
+        @NvmeofCLICommand(
+            "nvmeof gateway set_io_stats_mode", model.RequestStatus,
+            alias="nvmeof gw set_io_stats_mode",
+            success_message_template="Set gateway IO statistics mode to {enabled}: Successful")
+        @EndpointDoc(
+            "Enable or disable IO statistics collection",
+            parameters={
+                "enabled": Param(bool, "Enable IO statistics collection"),
+                "gw_group": Param(str, "NVMeoF gateway group", True, None),
+                "server_address": Param(str, "NVMeoF gateway address", True, None),
+            },
+        )
+        @convert_to_model(model.RequestStatus)
+        @handle_nvmeof_error
+        def set_io_stats_mode(self, enabled: bool, gw_group: Optional[str] = None,
+                              server_address: Optional[str] = None):
+            io_stats = NVMeoFClient(gw_group=gw_group,
+                                    server_address=server_address).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):
@@ -306,9 +330,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),
@@ -318,7 +341,7 @@ 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, server_address: Optional[str] = None):
@@ -328,7 +351,7 @@ else:
             ).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
                 )
@@ -1677,6 +1700,72 @@ else:
                 NVMeoFClient.pb2.list_connections_req(subsystem=nqn)
             )
 
+        @NvmeofCLICommand(
+            "nvmeof connection get_io_statistics",
+            model.ConnectionIOStatistics,
+            success_message_template="Please use JSON format to see the statistics"
+        )
+        @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),
+                "server_address": Param(str, "NVMeoF gateway address", 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,
+            server_address: Optional[str] = None
+        ):
+            return NVMeoFClient(
+                gw_group=gw_group,
+                server_address=server_address
+            ).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,
+            success_message_template=(
+                "Resetting host's {host_nqn} in {nqn} IO statistics: Successful"
+            )
+        )
+        @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),
+                "server_address": Param(str, "NVMeoF gateway address", 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,
+            server_address: Optional[str] = None
+        ):
+            return NVMeoFClient(
+                gw_group=gw_group,
+                server_address=server_address
+            ).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 cc495b6bbc6693dcc79dcfb897109ec20b3a1cc5..ae029a8c46624d09c5ddaf44c14084bb723c1485 100644 (file)
@@ -41,6 +41,8 @@ class GatewayInfo(NamedTuple):
     max_namespaces: Annotated[int, CliFlags.DROP]
     max_namespaces_per_subsystem: Annotated[int, CliFlags.DROP]
     max_subsystems: Annotated[int, CliFlags.DROP]
+    gateway_initialization_over: Annotated[bool, CliFlags.DROP]
+    io_stats_enabled: Annotated[bool, CliFlags.DROP]
     spdk_version: Optional[str] = ""
 
 
@@ -119,6 +121,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 abcb4e51ef3a3b13f280925260c359ec330cda95..928e672074a8716355c3891b4b951188f08dee49 100644 (file)
@@ -12617,6 +12617,59 @@ 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
+                server_address:
+                  description: NVMeoF gateway address
+                  type: string
+              required:
+              - enabled
+              type: object
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                type: object
+            application/vnd.ceph.api.v1.0+json:
+              schema:
+                type: object
+          description: Resource updated.
+        '202':
+          content:
+            application/json:
+              schema:
+                type: object
+            application/vnd.ceph.api.v1.0+json:
+              schema:
+                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:
@@ -13007,10 +13060,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
@@ -13020,7 +13069,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