]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: add 'dashboard connect-rgw' command
authorSage Weil <sage@newdream.net>
Thu, 8 Jul 2021 17:10:23 +0000 (13:10 -0400)
committerAlfonso Martínez <almartin@redhat.com>
Tue, 10 Aug 2021 12:06:03 +0000 (14:06 +0200)
Signed-off-by: Sage Weil <sage@newdream.net>
src/pybind/mgr/dashboard/module.py
src/pybind/mgr/dashboard/services/rgw_client.py

index 802c5411137a892804d9ce3b6f73282d08860408..512fd4ebcc1ddcad3116f499fd1c5330f21e5d3c 100644 (file)
@@ -29,6 +29,7 @@ from .controllers import generate_routes, json_error_page
 from .grafana import push_local_dashboards
 from .services.auth import AuthManager, AuthManagerTool, JwtManager
 from .services.exception import dashboard_exception_handler
+from .services.rgw_client import configure_rgw_users
 from .services.sso import SSO_COMMANDS, handle_sso_command
 from .settings import handle_option_command, options_command_list, options_schema_list
 from .tools import NotificationQueue, RequestLoggingTool, TaskManager, \
@@ -406,6 +407,11 @@ class Module(MgrModule, CherryPyConfig):
             return result
         return 0, 'Self-signed certificate created', ''
 
+    @CLIWriteCommand("dashboard connect-rgw")
+    def connect_rgw(self):
+        configure_rgw_users()
+        return 0, '', ''
+
     def handle_command(self, inbuf, cmd):
         # pylint: disable=too-many-return-statements
         res = handle_option_command(cmd, inbuf)
index 9573d245806728b1bfc0af5ccfa20a66d98d9df3..fd3ecdb5adeafabafec62759fcae4d95d2ad53db 100644 (file)
@@ -1,8 +1,10 @@
 # -*- coding: utf-8 -*-
 
 import ipaddress
+import json
 import logging
 import re
+import subprocess
 import xml.etree.ElementTree as ET  # noqa: N814
 from distutils.util import strtobool
 
@@ -183,6 +185,86 @@ def _parse_frontend_config(config) -> Tuple[int, bool]:
     raise LookupError('Failed to determine RGW port from "{}"'.format(config))
 
 
+def radosgw_admin(args: List[str]) -> Tuple[int, str, str]:
+    try:
+        result = subprocess.run(
+            [
+                'radosgw-admin',
+                '-c', str(mgr.get_ceph_conf_path()),
+                '-k', str(mgr.get_ceph_option('keyring')),
+                '-n', f'mgr.{mgr.get_mgr_id()}',
+            ] + args,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            timeout=10,
+        )
+        return result.returncode, result.stdout.decode('utf-8'), result.stderr.decode('utf-8')
+    except subprocess.CalledProcessError as ex:
+        mgr.log.error(f'Error executing radosgw-admin {ex.cmd}: {ex.output}')
+        raise
+    except subprocess.TimeoutExpired as ex:
+        mgr.log.error(f'Timeout (10s) executing radosgw-admin {ex.cmd}')
+        raise
+
+
+def configure_rgw_users():
+    mgr.log.info('Configuring dashboard RGW credentials')
+    user = 'dashboard'
+
+    def parse_secrets(user: str, out: str) -> Tuple[Optional[str], Optional[str]]:
+        r = json.loads(out)
+        for k in r.get('keys', []):
+            if k.get('user') == user and r.get('system') in ['true', True]:
+                access_key = k.get('access_key')
+                secret_key = k.get('secret_key')
+                return access_key, secret_key
+        return None, None
+
+    def get_keys(realm: Optional[str]) -> Tuple[str, str]:
+        cmd = ['user', 'info', '--uid', user]
+        if realm:
+            cmd += ['--rgw-realm', realm]
+        rc, out, _ = radosgw_admin(cmd)
+        access_key = None
+        secret_key = None
+        if not rc:
+            access_key, secret_key = parse_secrets(user, out)
+        if not access_key:
+            rc, out, err = radosgw_admin([
+                'user', 'create',
+                '--uid', user,
+                '--display-name', 'Ceph Dashboard',
+                '--system',
+            ])
+            if not rc:
+                access_key, secret_key = parse_secrets(user, out)
+        if not access_key:
+            mgr.log.error(f'Unable to create rgw {user} user: {err}')
+        assert access_key
+        assert secret_key
+        return access_key, secret_key
+
+    rc, out, err = radosgw_admin(['realm', 'list'])
+    if rc:
+        mgr.log.error(f'Unable to list RGW realms: {err}')
+        return
+    j = json.loads(out)
+    realms = j.get('realms', [])
+    access_key = None
+    secret_key = None
+    if realms:
+        als = {}
+        sls = {}
+        for realm in realms:
+            als[realm], sls[realm] = get_keys(realm)
+        access_key = json.dumps(als)
+        secret_key = json.dumps(sls)
+    else:
+        access_key, secret_key = get_keys(None)
+    Settings.RGW_API_ACCESS_KEY = access_key
+    Settings.RGW_API_SECRET_KEY = secret_key
+
+
 class RgwClient(RestClient):
     _host = None
     _port = None