]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: create RGW page
authorChang Liu <liuchang0812@gmail.com>
Thu, 14 Dec 2017 09:11:11 +0000 (17:11 +0800)
committerChang Liu <liuchang0812@gmail.com>
Thu, 14 Dec 2017 09:21:30 +0000 (17:21 +0800)
Signed-off-by: Chang Liu <liuchang0812@gmail.com>
src/pybind/mgr/dashboard/base.html
src/pybind/mgr/dashboard/module.py
src/pybind/mgr/dashboard/rgw.html [new file with mode: 0644]
src/pybind/mgr/dashboard/rgw.py [new file with mode: 0644]
src/pybind/mgr/dashboard/rgw_detail.html [new file with mode: 0644]

index 742327079fcff7fc31cfb28a8f744022c9d3a715..72266fa55669dc273651494e7d203c22a1db6dbf 100644 (file)
@@ -413,6 +413,13 @@ Failed to load data from server <a href="javascript:window.location.reload(true)
             <li class="ceph-none-found" rv-hide="filesystems | length">None found</li>
           </ul>
         </li>
+
+        <li class="{%if path_info.startswith('/rgw')%}active{%endif%}">          
+            <a href="{{ url_prefix }}/rgw">                                                        
+ <i class="fa fa-files-o" aria-hidden="true"></i>
+            <span>RGW</span></a>                                                           
+        </li>  
+
       </ul>
       <!-- /.sidebar-menu -->
     </section>
index e141d54bf3254fe85b9f88fdf8a964e8de39ef30..d48f599373ce82f094366daf3ffa870b214221ef 100644 (file)
@@ -37,6 +37,7 @@ import rbd_iscsi
 import rbd_mirroring
 from rbd_ls import RbdLs, RbdPoolLs
 from cephfs_clients import CephFSClients
+from rgw import RGWDaemons
 
 log = logging.getLogger("dashboard")
 
@@ -142,6 +143,9 @@ class Module(MgrModule):
         # Stateful instances of CephFSClients, hold cached results.  Key to
         # dict is FSCID
         self.cephfs_clients = {}
+         
+        # Stateful instance of RGW
+        self.rgw_daemons = RGWDaemons(self)
 
         # A short history of pool df stats
         self.pool_stats = defaultdict(lambda: defaultdict(
@@ -1113,8 +1117,75 @@ class Module(MgrModule):
                     content_data=json.dumps(content_data, indent=2)
                 )
 
+        class RGWEndpoint(EndPoint):
+
+            @cherrypy.expose
+            def index(self):
+                """ List all RGW servers """
+
+                template = env.get_template("rgw.html")
+                toplevel_data = self._toplevel_data()
+
+                content_data = self._rgw_daemons()
+
+                return template.render(
+                    url_prefix = global_instance().url_prefix,
+                    ceph_version=global_instance().version,
+                    path_info='/rgw' + cherrypy.request.path_info,
+                    toplevel_data=json.dumps(toplevel_data, indent=2),
+                    content_data=json.dumps(content_data, indent=2)
+                )
+            
+            def _rgw_daemons(self):
+                status, data = global_instance().rgw_daemons.get()
+                if data is None:
+                    log.warning("Failed to get RGW status")
+                    return {}
+                return data
+
+            @cherrypy.expose
+            @cherrypy.tools.json_out()
+            def rgw_daemons_data(self):
+                return self._rgw_daemons()
+
+            
+            def _rgw(self, rgw_id):
+                daemons = self.rgw_daemons_data()
+                rgw_metadata = {}
+                rgw_status = {}
+
+                for daemon in daemons["daemons"]:
+                    if daemon["id"] != rgw_id:
+                        continue
+                    
+                    rgw_metadata = daemon["metadata"]
+                    rgw_status = daemon["status"]
+
+                return {
+                    "rgw_id": rgw_id,
+                    "rgw_metadata": rgw_metadata,
+                    "rgw_status": rgw_status,
+                }
+              
+            @cherrypy.expose
+            def detail(self, rgw_id):
+                template = env.get_template("rgw_detail.html")
+                toplevel_data = self._toplevel_data()
+                return template.render(
+                        url_prefix=global_instance().url_prefix,
+                        ceph_version=global_instance().version,
+                        path_info='/rgw' + cherrypy.request.path_info,
+                        toplevel_data=json.dumps(toplevel_data, indent=2),
+                        content_data=json.dumps(self.rgw_data(rgw_id), indent=2)
+                    )
+            @cherrypy.expose
+            @cherrypy.tools.json_out()
+            def rgw_data(self, rgw_id):
+               return self._rgw(rgw_id)
+
         cherrypy.tree.mount(Root(), get_prefixed_url("/"), conf)
         cherrypy.tree.mount(OSDEndpoint(), get_prefixed_url("/osd"), conf)
+        cherrypy.tree.mount(RGWEndpoint(), get_prefixed_url("/rgw"), conf)
 
         log.info("Starting engine on {0}:{1}...".format(
             server_addr, server_port))
diff --git a/src/pybind/mgr/dashboard/rgw.html b/src/pybind/mgr/dashboard/rgw.html
new file mode 100644 (file)
index 0000000..b7b2c3f
--- /dev/null
@@ -0,0 +1,61 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+<script>
+        $(document).ready(function(){
+            // Pre-populated initial data at page load
+            var content_data = {{ content_data }};
+
+            var refresh = function() {
+                $.get("{{ url_prefix }}/rgw/rgw_daemons_data", function(data) {
+                    content_data = data;
+                    setTimeout(refresh, 5000);
+                });
+            };
+            setTimeout(refresh, 5000);
+            console.log(content_data);
+            rivets.bind($("#content"), {rgw: content_data});
+        });
+</script>
+
+<section class="content-header">
+    <h1>
+        RGW daemons
+    </h1>
+</section>
+
+<section class="content">
+    <div class="box">
+        <div class="box-body">
+            <table class="table table-bordered">
+                <th>
+                    ID
+                </th>
+                <th>
+                    Hostname
+                </th>
+                <th>
+                    Version
+                </th>
+                </thead>
+                <tr rv-each-rgwdaemon="rgw.daemons">
+                    <td>
+                        <a rv-href="rgwdaemon.url">{rgwdaemon.id}</a>
+                    </td>
+                    <td>
+                        {rgwdaemon.server_hostname}
+                    </td>
+                    <td>
+                        {rgwdaemon.version | short_version}
+                    </td>
+
+                </tr>
+            </table>
+        </div>
+    </div>
+</section>
+<!-- /.content -->
+
+{% endblock %}
diff --git a/src/pybind/mgr/dashboard/rgw.py b/src/pybind/mgr/dashboard/rgw.py
new file mode 100644 (file)
index 0000000..3482163
--- /dev/null
@@ -0,0 +1,45 @@
+# -*- code: utf-8 -*-
+
+import json
+import re
+import rados
+from remote_view_cache import RemoteViewCache
+
+import logging
+
+log = logging.getLogger("dashboard")
+
+class RGWDaemons(RemoteViewCache):
+
+    def _get(self):
+        daemons = self.get_daemons()
+        return {
+            'daemons': daemons,
+        }
+
+    def get_daemons(self):
+        daemons = []
+        for server in self._module.list_servers():
+            for service in server['services']:
+                if service['type'] == 'rgw':
+                    metadata = self._module.get_metadata('rgw', service['id'])
+                    status = self._module.get_daemon_status('rgw', service['id'])
+                    try:
+                        status = json.loads(status['json'])
+                    except:
+                        status = {}
+                    
+                    # extract per-daemon service data and health
+                    daemon = {
+                        'id': service['id'],
+                        'version': metadata['ceph_version'],
+                        'server_hostname': server['hostname'],
+                        'service': service,
+                        'server': server,
+                        'metadata': metadata,
+                        'status': status,
+                        'url': "/rgw/detail/{0}".format(service['id'])
+                    }
+
+                    daemons.append(daemon)
+        return sorted(daemons, key=lambda k: k['id'])
diff --git a/src/pybind/mgr/dashboard/rgw_detail.html b/src/pybind/mgr/dashboard/rgw_detail.html
new file mode 100644 (file)
index 0000000..f367c4d
--- /dev/null
@@ -0,0 +1,101 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+<script>
+        $(document).ready(function(){
+            // Pre-populated initial data at page load
+            var content_data = {{ content_data }};
+
+            var refresh = function() {
+                $.get("{{ url_prefix }}/rgw/rgw_data/" + content_data.rgw_id + "/", function(data) {
+                   content_data = data;
+                   setTimeout(refresh, 3000);
+                });
+            };
+            setTimeout(refresh, 5000);
+
+            var post_load = function() {
+                content_data.rgw_metadata_list = [];
+                content_data.rgw_status_list = [];
+                _.each(content_data.rgw_metadata, function(v, k) {
+                    content_data.rgw_metadata_list.push({
+                        key: k,
+                        value: v
+                    });
+                });
+                _.each(content_data.rgw_status, function(v, k) {
+                    content_data.rgw_status_list.push({
+                        key: k,
+                        value: v
+                    });
+                });
+                
+                if (content_data.rgw_status_list.length() == 0) {
+                     content_data.rgw_status_show = false;
+                } else {
+                     content_data.rgw_status_show = true;
+                }
+            };
+
+            rivets.bind($("#content"), content_data);
+            post_load();
+        });
+</script>
+
+<section class="content-header">
+    <h1>
+        rgw.{rgw_id}
+    </h1>
+</section>
+
+<div class="box" rv-show="rgw_status_show">
+    <div class="box-header">
+        <h3 class="box-title">Status</h3>
+    </div>
+    <div class="box-body">
+        <table>
+            <thead>
+            <tr>
+                <th>Key</th>
+                <th>Value</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr rv-each-meta_item="rgw_status_list">
+                <td>{meta_item.key}</td>
+                <td>{meta_item.value}</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+
+
+<div class="box">
+    <div class="box-header">
+        <h3 class="box-title">Metadata</h3>
+    </div>
+    <div class="box-body">
+        <table class="table table-condensed">
+            <thead>
+            <tr>
+                <th>Key</th>
+                <th>Value</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr rv-each-meta_item="rgw_metadata_list">
+                <td>{meta_item.key}</td>
+                <td>{meta_item.value}</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+
+<!-- /.content -->
+
+{% endblock %}