From: Gil Bregman Date: Fri, 27 Feb 2026 10:09:14 +0000 (+0200) Subject: mgr/dashboard: Add DHCHAP controller key to NVME host commands X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=f8693e01e36387f114ee72c5950e864a3ec30619;p=ceph.git mgr/dashboard: Add DHCHAP controller key to NVME host commands Fixes: https://tracker.ceph.com/issues/74939 Signed-off-by: Gil Bregman (cherry picked from commit aca4d32a48bf407cdb6108569101d21513f710fb) Signed-off-by: Gil Bregman --- diff --git a/src/pybind/mgr/dashboard/controllers/nvmeof.py b/src/pybind/mgr/dashboard/controllers/nvmeof.py index f1bf1c118242..46a50841f19f 100644 --- a/src/pybind/mgr/dashboard/controllers/nvmeof.py +++ b/src/pybind/mgr/dashboard/controllers/nvmeof.py @@ -15,7 +15,7 @@ from ..services.orchestrator import OrchClient from ..tools import str_to_bool from . import APIDoc, APIRouter, BaseController, CreatePermission, \ DeletePermission, Endpoint, EndpointDoc, Param, ReadPermission, \ - RESTController, UIRouter + RESTController, UIRouter, UpdatePermission logger = logging.getLogger(__name__) @@ -1125,9 +1125,19 @@ else: ) ) + def _normalize_enum_key(val): + return val.replace("_", " ").title() + def _update_hosts(hosts_info_resp): if hosts_info_resp.get('allow_any_host'): hosts_info_resp['hosts'].insert(0, {"nqn": "*"}) + hosts = hosts_info_resp.get('hosts') + if not hosts: + hosts = [] + for h in hosts: + orig = h.get("dhchap_controller_origin") + if orig: + h["dhchap_controller_origin"] = _normalize_enum_key(orig) return hosts_info_resp @APIRouter("/nvmeof/subsystem/{nqn}/host", Scope.NVME_OF) @@ -1169,11 +1179,14 @@ else: @handle_nvmeof_error def create( self, nqn: str, host_nqn: str, dhchap_key: Optional[str] = None, + dhchap_controller_key: Optional[str] = None, psk: Optional[str] = None, gw_group: Optional[str] = None, traddr: Optional[str] = None ): return NVMeoFClient(gw_group=gw_group, traddr=traddr).stub.add_host( NVMeoFClient.pb2.add_host_req(subsystem_nqn=nqn, host_nqn=host_nqn, - dhchap_key=dhchap_key, psk=psk) + dhchap_key=dhchap_key, + dhchap_ctrlr_key=dhchap_controller_key, + psk=psk) ) @empty_response @@ -1195,6 +1208,8 @@ else: ) @empty_response + @Endpoint('PUT', '{host_nqn}/change_key') + @UpdatePermission @NvmeofCLICommand("nvmeof host change_key", model.RequestStatus) @EndpointDoc( "Change host DH-HMAC-CHAP key", @@ -1214,10 +1229,39 @@ else: return NVMeoFClient(gw_group=gw_group, traddr=traddr).stub.change_host_key( NVMeoFClient.pb2.change_host_key_req(subsystem_nqn=nqn, host_nqn=host_nqn, - dhchap_key=dhchap_key) + dhchap_key=dhchap_key, + dhchap_ctrlr_key="-") + ) + + @empty_response + @Endpoint('PUT', '{host_nqn}/change_controller_key') + @UpdatePermission + @NvmeofCLICommand("nvmeof host change_controller_key", model.RequestStatus) + @EndpointDoc( + "Change host DH-HMAC-CHAP controller key", + parameters={ + "nqn": Param(str, "NVMeoF subsystem NQN"), + "host_nqn": Param(str, 'NVMeoF host NQN'), + "dhchap_controller_key": Param(str, 'Host DH-HMAC-CHAP controller key'), + "gw_group": Param(str, "NVMeoF gateway group", True, None), + }, + ) + @convert_to_model(model.RequestStatus) + @handle_nvmeof_error + def change_controller_key( + self, nqn: str, host_nqn: str, dhchap_controller_key: str, + gw_group: Optional[str] = None, traddr: Optional[str] = None + ): + return NVMeoFClient(gw_group=gw_group, traddr=traddr).stub.change_host_key( + NVMeoFClient.pb2.change_host_key_req(subsystem_nqn=nqn, + host_nqn=host_nqn, + dhchap_key="-", + dhchap_ctrlr_key=dhchap_controller_key) ) @empty_response + @Endpoint('PUT', '{host_nqn}/del_key') + @UpdatePermission @NvmeofCLICommand("nvmeof host del_key", model.RequestStatus) @EndpointDoc( "Delete host DH-HMAC-CHAP key", @@ -1236,9 +1280,49 @@ else: return NVMeoFClient(gw_group=gw_group, traddr=traddr).stub.change_host_key( NVMeoFClient.pb2.change_host_key_req(subsystem_nqn=nqn, host_nqn=host_nqn, - dhchap_key=None) + dhchap_key=None, + dhchap_ctrlr_key="-") ) + @empty_response + @Endpoint('PUT', '{host_nqn}/del_controller_key') + @UpdatePermission + @NvmeofCLICommand("nvmeof host del_controller_key", model.RequestStatus) + @EndpointDoc( + "Delete host DH-HMAC-CHAP controller key", + 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.RequestStatus) + @handle_nvmeof_error + def del_controller_key( + self, nqn: str, host_nqn: str, gw_group: Optional[str] = None, + traddr: Optional[str] = None + ): + return NVMeoFClient( + gw_group=gw_group, + traddr=traddr + ).stub.change_host_key( + NVMeoFClient.pb2.change_host_key_req(subsystem_nqn=nqn, + host_nqn=host_nqn, + dhchap_key="-", + dhchap_ctrlr_key=None) + ) + + def _update_connections(connection_list_resp): + conns = connection_list_resp.get('connections') + if not conns: + conns = [] + for con in conns: + orig = con.get("dhchap_controller_origin") + if orig: + con["dhchap_controller_origin"] = _normalize_enum_key( + orig) + return connection_list_resp + @APIRouter("/nvmeof/subsystem/{nqn}/connection", Scope.NVME_OF) @APIDoc("NVMe-oF Subsystem Connection Management API", "NVMe-oF Subsystem Connection") class NVMeoFConnection(RESTController): @@ -1251,7 +1335,7 @@ else: "gw_group": Param(str, "NVMeoF gateway group", True, None), }, ) - @convert_to_model(model.ConnectionList) + @convert_to_model(model.ConnectionList, finalize=_update_connections) @handle_nvmeof_error def list(self, nqn: Optional[str] = None, gw_group: Optional[str] = None, traddr: Optional[str] = None): diff --git a/src/pybind/mgr/dashboard/model/nvmeof.py b/src/pybind/mgr/dashboard/model/nvmeof.py index d5dde3cea4c0..69c0739ebdba 100644 --- a/src/pybind/mgr/dashboard/model/nvmeof.py +++ b/src/pybind/mgr/dashboard/model/nvmeof.py @@ -97,6 +97,7 @@ class SubsystemStatus(NamedTuple): class Connection(NamedTuple): + nqn: str traddr: str trsvcid: int trtype: str @@ -106,6 +107,7 @@ class Connection(NamedTuple): controller_id: int use_psk: Optional[bool] use_dhchap: Optional[bool] + dhchap_controller_origin: Optional[str] subsystem: Optional[str] disconnected_due_to_keepalive_timeout: Optional[bool] @@ -200,6 +202,7 @@ class Host(NamedTuple): nqn: str use_psk: Optional[bool] use_dhchap: Optional[bool] + dhchap_controller_origin: Optional[str] disconnected_due_to_keepalive_timeout: Annotated[Optional[bool], CliFlags.DROP] diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index dec615b3d053..18d75fd1c324 100755 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -9876,6 +9876,8 @@ paths: application/json: schema: properties: + dhchap_controller_key: + type: string dhchap_key: type: string gw_group: @@ -9967,6 +9969,220 @@ paths: summary: Disallow hosts from accessing an NVMeoF subsystem tags: - NVMe-oF Subsystem Host Allowlist + /api/nvmeof/subsystem/{nqn}/host/{host_nqn}/change_controller_key: + put: + parameters: + - description: NVMeoF subsystem NQN + in: path + name: nqn + required: true + schema: + type: string + - description: NVMeoF host NQN + in: path + name: host_nqn + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + dhchap_controller_key: + description: Host DH-HMAC-CHAP controller key + type: string + gw_group: + description: NVMeoF gateway group + type: string + traddr: + type: string + required: + - dhchap_controller_key + 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: Change host DH-HMAC-CHAP controller key + tags: + - NVMe-oF Subsystem Host Allowlist + /api/nvmeof/subsystem/{nqn}/host/{host_nqn}/change_key: + put: + parameters: + - description: NVMeoF subsystem NQN + in: path + name: nqn + required: true + schema: + type: string + - description: NVMeoF host NQN + in: path + name: host_nqn + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + dhchap_key: + description: Host DH-HMAC-CHAP key + type: string + gw_group: + description: NVMeoF gateway group + type: string + traddr: + type: string + required: + - dhchap_key + 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: Change host DH-HMAC-CHAP key + tags: + - NVMe-oF Subsystem Host Allowlist + /api/nvmeof/subsystem/{nqn}/host/{host_nqn}/del_controller_key: + put: + parameters: + - description: NVMeoF subsystem NQN + in: path + name: nqn + required: true + schema: + type: string + - description: NVMeoF host NQN. + in: path + name: host_nqn + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + gw_group: + description: NVMeoF gateway group + type: string + traddr: + type: string + 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: Delete host DH-HMAC-CHAP controller key + tags: + - NVMe-oF Subsystem Host Allowlist + /api/nvmeof/subsystem/{nqn}/host/{host_nqn}/del_key: + put: + parameters: + - description: NVMeoF subsystem NQN + in: path + name: nqn + required: true + schema: + type: string + - description: NVMeoF host NQN. + in: path + name: host_nqn + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + gw_group: + description: NVMeoF gateway group + type: string + traddr: + type: string + 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: Delete host DH-HMAC-CHAP key + tags: + - NVMe-oF Subsystem Host Allowlist /api/nvmeof/subsystem/{nqn}/listener: get: parameters: