From e5657ab645e37249ca66986437519f0bd98fc845 Mon Sep 17 00:00:00 2001 From: Imran Imtiaz Date: Mon, 8 Dec 2025 07:59:03 +0000 Subject: [PATCH] mgr/dashboard: add CRUD API endpoints for consistency group snapshots Signed-off-by: Imran Imtiaz Fixes: https://tracker.ceph.com/issues/74258 Create a set of consistency group dashboard API endpoints to: - List group snapshots - Get details about a particular snapshot - Create a snapshot - Delete a snapshot (rollback/update are handled separately) Signed-off-by: Imran Imtiaz (cherry picked from commit 2aed28db1a95d2fb43c833c05fcae9f71294c595) --- src/pybind/mgr/dashboard/controllers/rbd.py | 102 +++++++- src/pybind/mgr/dashboard/openapi.yaml | 244 ++++++++++++++++++++ 2 files changed, 345 insertions(+), 1 deletion(-) diff --git a/src/pybind/mgr/dashboard/controllers/rbd.py b/src/pybind/mgr/dashboard/controllers/rbd.py index 7d8cbd3afea..5cb83900ee8 100644 --- a/src/pybind/mgr/dashboard/controllers/rbd.py +++ b/src/pybind/mgr/dashboard/controllers/rbd.py @@ -6,7 +6,7 @@ import logging import math from datetime import datetime, timezone from functools import partial -from typing import Any, Dict +from typing import Any, Dict, Optional import cherrypy import rbd @@ -50,6 +50,22 @@ RBD_GROUP_GET_SCHEMA = [{ "images": ([str], '') }] +RBD_GROUP_SNAPSHOT_LIST_SCHEMA = [{ + "id": (str, 'snapshot id'), + "name": (str, 'snapshot name'), + "state": (int, 'snapshot state'), + "namespace_type": (int, 'namespace type') +}] + +RBD_GROUP_SNAPSHOT_GET_SCHEMA = { + "id": (str, 'snapshot id'), + "name": (str, 'snapshot name'), + "state": (int, 'snapshot state'), + "namespace_type": (int, 'namespace type'), + "image_snap_name": (str, 'image snapshot name'), + "image_snaps": ([dict], 'image snapshots') +} + # pylint: disable=not-callable def RbdTask(name, metadata, wait_for): # noqa: N802 @@ -593,3 +609,87 @@ class RbdGroup(RESTController): RbdService.validate_namespace(ioctx, namespace) ioctx.set_namespace(namespace) return group.remove_image(ioctx, image_name) + + +@APIRouter('/block/pool/{pool_name}/group/{group_name}/snap', Scope.RBD_IMAGE) +@APIDoc("RBD Group Snapshot Management API", "RbdGroupSnapshot") +class RbdGroupSnapshot(RESTController): + + RESOURCE_ID = "snapshot_name" + + def __init__(self): + super().__init__() + self.rbd_inst = rbd.RBD() + + @handle_rbd_error() + @EndpointDoc("List group snapshots", + parameters={ + 'pool_name': (str, 'Name of the pool'), + 'group_name': (str, 'Name of the group'), + }, + responses={200: RBD_GROUP_SNAPSHOT_LIST_SCHEMA}) + def list(self, pool_name: str, group_name: str, namespace: Optional[str] = None): + with mgr.rados.open_ioctx(pool_name) as ioctx: + RbdService.validate_namespace(ioctx, namespace) + ioctx.set_namespace(namespace) + group = rbd.Group(ioctx, group_name) + result = [] + for snap in group.list_snaps(): + result.append({ + 'id': snap['id'], + 'name': snap['name'], + 'state': snap['state'], + 'namespace_type': snap['namespace_type'] + }) + return result + + @handle_rbd_error() + @EndpointDoc("Get group snapshot information", + parameters={ + 'pool_name': (str, 'Name of the pool'), + 'group_name': (str, 'Name of the group'), + 'snapshot_name': (str, 'Name of the snapshot'), + }, + responses={200: RBD_GROUP_SNAPSHOT_GET_SCHEMA}) + def get(self, pool_name: str, group_name: str, snapshot_name: str, + namespace: Optional[str] = None): + with mgr.rados.open_ioctx(pool_name) as ioctx: + RbdService.validate_namespace(ioctx, namespace) + ioctx.set_namespace(namespace) + group = rbd.Group(ioctx, group_name) + return group.get_snap_info(snapshot_name) + + @RbdTask('group_snap/create', + ['{pool_name}', '{group_name}', '{snapshot_name}'], 2.0) + @EndpointDoc("Create a group snapshot", + parameters={ + 'pool_name': (str, 'Name of the pool'), + 'group_name': (str, 'Name of the group'), + 'snapshot_name': (str, 'Name of the snapshot'), + 'flags': (int, 'Snapshot creation flags'), + }, + responses={200: None}) + def create(self, pool_name: str, group_name: str, snapshot_name: str, + namespace: Optional[str] = None, flags: int = 0): + with mgr.rados.open_ioctx(pool_name) as ioctx: + RbdService.validate_namespace(ioctx, namespace) + ioctx.set_namespace(namespace) + group = rbd.Group(ioctx, group_name) + return group.create_snap(snapshot_name, flags) + + @RbdTask('group_snap/delete', + ['{pool_name}', '{group_name}', '{snapshot_name}'], 2.0) + @EndpointDoc("Delete a group snapshot", + parameters={ + 'pool_name': (str, 'Name of the pool'), + 'group_name': (str, 'Name of the group'), + 'snapshot_name': (str, 'Name of the snapshot'), + }, + responses={200: None}) + def delete(self, pool_name: str, group_name: str, snapshot_name: str, + namespace: Optional[str] = None): + with mgr.rados.open_ioctx(pool_name) as ioctx: + RbdService.validate_namespace(ioctx, namespace) + ioctx.set_namespace(namespace) + group = rbd.Group(ioctx, group_name) + return group.remove_snap(snapshot_name) diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 6a5b8b5e5bf..3e340340e11 100755 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -1939,6 +1939,248 @@ paths: summary: Add image to a group tags: - RbdGroup + /api/block/pool/{pool_name}/group/{group_name}/snap: + get: + parameters: + - description: Name of the pool + in: path + name: pool_name + required: true + schema: + type: string + - description: Name of the group + in: path + name: group_name + required: true + schema: + type: string + - allowEmptyValue: true + in: query + name: namespace + schema: + type: string + responses: + '200': + content: + application/vnd.ceph.api.v1.0+json: + schema: + items: + properties: + id: + description: snapshot id + type: string + name: + description: snapshot name + type: string + namespace_type: + description: namespace type + type: integer + state: + description: snapshot state + type: integer + type: object + required: + - id + - name + - state + - namespace_type + type: array + description: OK + '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: List group snapshots + tags: + - RbdGroupSnapshot + post: + parameters: + - description: Name of the pool + in: path + name: pool_name + required: true + schema: + type: string + - description: Name of the group + in: path + name: group_name + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + flags: + default: 0 + description: Snapshot creation flags + type: integer + namespace: + type: string + snapshot_name: + description: Name of the snapshot + type: string + required: + - snapshot_name + type: object + responses: + '201': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Resource created. + '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: Create a group snapshot + tags: + - RbdGroupSnapshot + /api/block/pool/{pool_name}/group/{group_name}/snap/{snapshot_name}: + delete: + parameters: + - description: Name of the pool + in: path + name: pool_name + required: true + schema: + type: string + - description: Name of the group + in: path + name: group_name + required: true + schema: + type: string + - description: Name of the snapshot + in: path + name: snapshot_name + required: true + schema: + type: string + - allowEmptyValue: true + in: query + name: namespace + schema: + type: string + responses: + '202': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Operation is still executing. Please check the task queue. + '204': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Resource deleted. + '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 a group snapshot + tags: + - RbdGroupSnapshot + get: + parameters: + - description: Name of the pool + in: path + name: pool_name + required: true + schema: + type: string + - description: Name of the group + in: path + name: group_name + required: true + schema: + type: string + - description: Name of the snapshot + in: path + name: snapshot_name + required: true + schema: + type: string + - allowEmptyValue: true + in: query + name: namespace + schema: + type: string + responses: + '200': + content: + application/vnd.ceph.api.v1.0+json: + schema: + properties: + id: + description: snapshot id + type: string + image_snap_name: + description: image snapshot name + type: string + image_snaps: + description: image snapshots + items: + type: object + type: array + name: + description: snapshot name + type: string + namespace_type: + description: namespace type + type: integer + state: + description: snapshot state + type: integer + required: + - id + - name + - state + - namespace_type + - image_snap_name + - image_snaps + type: object + description: OK + '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: Get group snapshot information + tags: + - RbdGroupSnapshot /api/block/pool/{pool_name}/namespace: get: parameters: @@ -19656,6 +19898,8 @@ tags: name: Rbd - description: RBD Group Management API name: RbdGroup +- description: RBD Group Snapshot Management API + name: RbdGroupSnapshot - description: RBD Mirroring Management API name: RbdMirroring - description: RBD Mirroring Pool Bootstrap Management API -- 2.47.3