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=d42c9cf1e52c3ce06b6b538f436ee81a9fd973ee;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 --- diff --git a/src/pybind/mgr/dashboard/controllers/nvmeof.py b/src/pybind/mgr/dashboard/controllers/nvmeof.py index b65f449aaf2..7c841335f8b 100644 --- a/src/pybind/mgr/dashboard/controllers/nvmeof.py +++ b/src/pybind/mgr/dashboard/controllers/nvmeof.py @@ -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') diff --git a/src/pybind/mgr/dashboard/model/nvmeof.py b/src/pybind/mgr/dashboard/model/nvmeof.py index cc495b6bbc6..ae029a8c466 100644 --- a/src/pybind/mgr/dashboard/model/nvmeof.py +++ b/src/pybind/mgr/dashboard/model/nvmeof.py @@ -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 diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index abcb4e51ef3..928e672074a 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -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