<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>
import rbd_mirroring
from rbd_ls import RbdLs, RbdPoolLs
from cephfs_clients import CephFSClients
+from rgw import RGWDaemons
log = logging.getLogger("dashboard")
# 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(
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))
--- /dev/null
+{% 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 %}
--- /dev/null
+# -*- 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'])
--- /dev/null
+{% 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 %}