]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add option to set motd via api 68183/head
authorAashish Sharma <aashish@li-e9bf2ecc-2ad7-11b2-a85c-baf05c5182ab.ibm.com>
Thu, 2 Apr 2026 13:29:40 +0000 (18:59 +0530)
committerAashish Sharma <aashish@li-e9bf2ecc-2ad7-11b2-a85c-baf05c5182ab.ibm.com>
Wed, 22 Apr 2026 09:28:16 +0000 (14:58 +0530)
Signed-off-by: Aashish Sharma <aasharma@redhat.com>
src/pybind/mgr/dashboard/openapi.yaml
src/pybind/mgr/dashboard/plugins/motd.py

index 5f6024ca9de3d9767bc80f87dabc17a8634a7875..49275bc5b51ab39bd52e9bbe86152a760411d410 100644 (file)
@@ -11183,6 +11183,92 @@ paths:
       summary: Get Monitor Details
       tags:
       - Monitor
+  /api/motd:
+    post:
+      parameters: []
+      requestBody:
+        content:
+          application/json:
+            schema:
+              properties:
+                expires:
+                  type: string
+                message:
+                  type: string
+                severity:
+                  type: string
+              required:
+              - severity
+              - expires
+              - message
+              type: object
+      responses:
+        '201':
+          content:
+            application/json:
+              schema:
+                type: object
+            application/vnd.ceph.api.v1.0+json:
+              schema:
+                type: object
+          description: Resource created.
+        '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: []
+      tags:
+      - Motd
+  /api/motd/clear:
+    delete:
+      parameters: []
+      responses:
+        '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.
+        '204':
+          content:
+            application/json:
+              schema:
+                type: object
+            application/vnd.ceph.api.v1.0+json:
+              schema:
+                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: []
+      tags:
+      - Motd
   /api/multi-cluster/auth:
     post:
       parameters: []
@@ -27189,6 +27275,8 @@ tags:
   name: MonPerfCounter
 - description: Get Monitor Details
   name: Monitor
+- description: Message of the day API
+  name: Motd
 - description: Multi-cluster Management API
   name: Multi-cluster
 - description: NFS-Ganesha Cluster Management API
index cd673817f672f133b5d27b9d479f05607f642f12..c148c9bcca750975ba8924684a7ee4266a6370e7 100644 (file)
@@ -3,11 +3,12 @@
 import hashlib
 import json
 from enum import Enum
-from typing import Dict, NamedTuple, Optional
+from typing import Dict, NamedTuple, Optional, Union
 
 from ceph.utils import datetime_now, datetime_to_str, parse_timedelta, str_to_datetime
 
 from ..cli import DBCLICommand
+from ..exceptions import DashboardException
 from . import PLUGIN_MANAGER as PM
 from .plugin import SimplePlugin as SP
 
@@ -38,6 +39,35 @@ class Motd(SP):
         )
     ]
 
+    def _normalize_severity(self, severity: Union[MotdSeverity, str]) -> Optional[MotdSeverity]:
+        if isinstance(severity, MotdSeverity):
+            return severity
+        try:
+            return MotdSeverity(severity)
+        except ValueError:
+            return None
+
+    def _set_motd(self, severity: Union[MotdSeverity, str], expires: str, message: str):
+        severity = self._normalize_severity(severity)
+        if severity is None:
+            return 1, '', 'Invalid severity, use "info", "warning" or "danger"'
+
+        if expires != '0':
+            delta = parse_timedelta(expires)
+            if not delta:
+                return 1, '', 'Invalid expires format, use "2h", "10d" or "30s"'
+            expires = datetime_to_str(datetime_now() + delta)
+        else:
+            expires = ''
+        value: str = json.dumps({
+            'message': message,
+            'md5': hashlib.md5(message.encode()).hexdigest(),
+            'severity': severity.value,
+            'expires': expires
+        })
+        self.set_option(self.NAME, value)
+        return 0, 'Message of the day has been set.', ''
+
     @PM.add_hook
     def register_commands(self):
         @DBCLICommand("dashboard {name} get".format(name=self.NAME))
@@ -56,21 +86,7 @@ class Motd(SP):
 
         @DBCLICommand("dashboard {name} set".format(name=self.NAME))
         def _set(_, severity: MotdSeverity, expires: str, message: str):
-            if expires != '0':
-                delta = parse_timedelta(expires)
-                if not delta:
-                    return 1, '', 'Invalid expires format, use "2h", "10d" or "30s"'
-                expires = datetime_to_str(datetime_now() + delta)
-            else:
-                expires = ''
-            value: str = json.dumps({
-                'message': message,
-                'md5': hashlib.md5(message.encode()).hexdigest(),
-                'severity': severity.value,
-                'expires': expires
-            })
-            self.set_option(self.NAME, value)
-            return 0, 'Message of the day has been set.', ''
+            return self._set_motd(severity, expires, message)
 
         @DBCLICommand("dashboard {name} clear".format(name=self.NAME))
         def _clear(_):
@@ -79,7 +95,7 @@ class Motd(SP):
 
     @PM.add_hook
     def get_controllers(self):
-        from ..controllers import RESTController, UIRouter
+        from ..controllers import APIDoc, APIRouter, Endpoint, RESTController, UIRouter
 
         @UIRouter('/motd')
         class MessageOfTheDay(RESTController):
@@ -95,4 +111,21 @@ class Motd(SP):
                         return None
                 return data._asdict()
 
-        return [MessageOfTheDay]
+        @APIRouter('/motd')
+        @APIDoc('Message of the day API', "Motd")
+        class MessageOfTheDayApi(RESTController):
+            def create(_, severity: MotdSeverity, expires: str, message: str):  # pylint: disable=no-self-argument,line-too-long # noqa: E501
+                # pylint: disable=W0212
+                _, _, stderr = self._set_motd(severity, expires, message)
+                if stderr:
+                    raise DashboardException(
+                        code='invalid_motd',
+                        msg="Invalid MOTD input",
+                        component='dashboard'
+                    )
+
+            @Endpoint('DELETE')
+            def clear(_):  # pylint: disable=no-self-argument
+                self.set_option(self.NAME, '')
+
+        return [MessageOfTheDay, MessageOfTheDayApi]