From: Gil Bregman Date: Mon, 16 Mar 2026 10:59:06 +0000 (+0200) Subject: mgr/dashboard: Add "connection get_io_statistics" to NVMeoF CLI X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7d1db655f8d257998186928cfdb56ffe5c8802cf;p=ceph.git mgr/dashboard: Add "connection get_io_statistics" to NVMeoF CLI Fixes: https://tracker.ceph.com/issues/74964 Signed-off-by: Gil Bregman (cherry picked from commit d42c9cf1e52c3ce06b6b538f436ee81a9fd973ee) Signed-off-by: Gil Bregman --- diff --git a/src/pybind/mgr/dashboard/controllers/nvmeof.py b/src/pybind/mgr/dashboard/controllers/nvmeof.py index ff199ac4ec8..73307844593 100644 --- a/src/pybind/mgr/dashboard/controllers/nvmeof.py +++ b/src/pybind/mgr/dashboard/controllers/nvmeof.py @@ -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') diff --git a/src/pybind/mgr/dashboard/model/nvmeof.py b/src/pybind/mgr/dashboard/model/nvmeof.py index 1dcd6babf2c..9f043cc0f31 100644 --- a/src/pybind/mgr/dashboard/model/nvmeof.py +++ b/src/pybind/mgr/dashboard/model/nvmeof.py @@ -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 diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 4ddc6ead464..fae5382bc39 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -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