initial code repo
[stor4nfv.git] / src / ceph / src / pybind / mgr / dashboard / filesystem.html
diff --git a/src/ceph/src/pybind/mgr/dashboard/filesystem.html b/src/ceph/src/pybind/mgr/dashboard/filesystem.html
new file mode 100644 (file)
index 0000000..60a97a0
--- /dev/null
@@ -0,0 +1,295 @@
+{% 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 }}/filesystem_data/" + content_data.fs_status.filesystem.id  + "/", function(data) {
+                    _.extend(content_data.fs_status, data);
+                    setTimeout(refresh, 5000);
+                });
+            };
+
+            // Generate a "width: xx%" style string for use with a progress
+            // bar element showing a pool's used space.
+            rivets.formatters.pool_size_bar = function(pool){
+                var ratio = pool.used / pool.avail;
+
+                return "width: " + Math.round(ratio * 100).toString() + "%";
+            };
+
+            rivets.bind($("div#content"), content_data.fs_status);
+            setTimeout(refresh, 5000);
+
+            // Convert ceph-mgr's time series format (list of 2-tuples
+            // with seconds-since-epoch timestamps) into what chart.js
+            // can handle (list of objects with millisecs-since-epoch
+            // timestamps)
+            var convert_timeseries = function(source_series)
+            {
+                var data = [];
+                _.each(source_series, function(dp) {
+                    data.push({
+                        x: dp[0] * 1000,
+                        y: dp[1]
+                    });
+                });
+
+                return data;
+            };
+
+            var delta_timeseries = function(source_series)
+            {
+                var i;
+                var prev = source_series[0];
+                var result = [];
+                for (i = 1; i < source_series.length; i++) {
+                    var cur = source_series[i];
+                    var tdelta = cur[0] - prev[0];
+                    var vdelta = cur[1] - prev[1];
+                    var rate = vdelta / tdelta;
+
+                    result.push({
+                        x: cur[0] * 1000,
+                        y: rate
+                    });
+
+                    prev = cur;
+                }
+                return result;
+            };
+
+            var charts = {};
+
+            var lhs_counter = 'mds.inodes';
+            var lhs_transform = convert_timeseries;
+            var rhs_counter = "mds_server.handle_client_request";
+            var rhs_transform = delta_timeseries;
+
+            var draw_chart = function() {
+                $.get("{{ url_prefix }}/mds_counters/" + content_data.fs_status.filesystem.id  + "/", function(data) {
+                    var top_chart = true;
+
+                    // Cull any chart elements that correspond to MDSs no
+                    // longer present in the data
+                    var existing_mds_names = {};
+                    _.each(data, function(mds_data, mds_name) {
+                        existing_mds_names[mds_name] = true;
+                    });
+
+                    $("#mds_charts canvas").each(function(i, e) {
+                        var el_mds_name = e.id.replace("mds_chart_", "");
+                        if (existing_mds_names[el_mds_name] != true) {
+                            e.remove();
+                        }
+                    });
+
+
+                    _.each(data, function(mds_data, mds_name) {
+                        if (! $("#mds_chart_" + mds_name).length) {
+                            // Construct new chart
+                            $("#mds_charts").append(
+                                $("<canvas height='64' id='mds_chart_" + mds_name + "'></canvas>")
+                            );
+
+                            var ctx = $("#mds_chart_" + mds_name);
+                            var lhs_data = lhs_transform(mds_data[lhs_counter]);
+                            var rhs_data = rhs_transform(mds_data[rhs_counter]);
+
+                            var chartInstance = new Chart(ctx, {
+                                type: 'line',
+                                data: {
+                                    datasets: [
+                                        {
+                                            label: lhs_counter,
+                                            yAxisID: 'LHS',
+                                            data: lhs_data,
+                                            tension: 0.1,
+                                            borderColor: "#dd2222",
+
+                                        },
+                                        {
+                                            label: rhs_counter,
+                                            yAxisID: 'RHS',
+                                            data: rhs_data,
+                                            tension: 0.1,
+                                            borderColor: "#2222dd",
+                                        },
+                                    ]
+                                },
+                                options: {
+                                    legend: {
+                                        position: 'top',
+                                        display: top_chart,
+                                        labels:{fontColor: "#ddd"}
+                                    },
+                                    scales: {
+                                        xAxes: [{
+                                            position: 'top',
+                                            type: 'time',
+                                            display: top_chart,
+                                            ticks: {fontColor:"#ddd"},
+                                            time: {
+                                                displayFormats: {
+                                                    quarter: 'MMM YYYY'
+                                                }
+                                            }
+                                        }],
+                                        yAxes: [{
+                                            id: 'LHS',
+                                            type: 'linear',
+                                            position: 'left',
+                                            ticks: {fontColor:"#ddd"},
+                                            min: 0
+                                        }, {
+                                            id: 'RHS',
+                                            type: 'linear',
+                                            position: 'right',
+                                            ticks: {fontColor:"#ddd"},
+                                            min: 0
+                                        }]
+                                    }
+                                }
+                            });
+                            charts[mds_name] = chartInstance;
+                        } else {
+                            // Update existing chart
+                            var chart = charts[mds_name];
+                            var lhs_data = lhs_transform(mds_data[lhs_counter]);
+                            var rhs_data = rhs_transform(mds_data[rhs_counter]);
+                            chart.data.datasets[0].data = lhs_data;
+                            chart.data.datasets[1].data = rhs_data;
+                            chart.update(0);
+                        };
+
+                        // FIXME: update the visibility of axes etc
+                        // when charts come and go.
+                        top_chart = false;
+                    });
+
+                    setTimeout(draw_chart, 5000);
+                });
+            };
+
+            // TODO periodic refresh
+            draw_chart();
+
+        });
+</script>
+
+
+<section class="content-header">
+    <h1>
+        Filesystem {filesystem.name}
+    </h1>
+</section>
+
+<section class="content">
+    <p style="font-size: 1.3em;">
+        <i class="fa fa-desktop"></i>&nbsp;&nbsp;Clients: <span style="font-weight:bold;">{filesystem.client_count}</span>
+        <a rv-href="filesystem.clients_url">Detail...</a>
+    </p>
+
+    <div class="row">
+        <div class="col-sm-6">
+            <div class="box">
+                <div class="box-header">
+                    <h3 class="box-title">Ranks</h3>
+                </div>
+                <div class="box-body">
+                    <table class="table table-condensed">
+                        <thead>
+                        <tr>
+                            <th>Rank</th>
+                            <th>State</th>
+                            <th>Daemon</th>
+                            <th>Activity</th>
+                            <th>Dentries</th>
+                            <th>Inodes</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr rv-each-rank="filesystem.ranks">
+                            <td>{rank.rank}</td>
+                            <td>{rank.state}</td>
+                            <td>{rank.mds}</td>
+                            <td>{rank.activity}</td>
+                            <td>{rank.dns | dimless}</td>
+                            <td>{rank.inos | dimless}</td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+        </div>
+        <div class="col-sm-6">
+            <div class="box">
+                <div class="box-header">
+                    <h3 class="box-title">Pools</h3>
+                </div>
+                <div class="box-body">
+                    <table class="table table-condensed">
+                        <thead>
+                        <tr>
+                            <th>Pool</th>
+                            <th>Type</th>
+                            <th>Used</th>
+                            <th>Avail</th>
+                            <th></th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr rv-each-pool="filesystem.pools">
+                            <td>{pool.pool}</td>
+                            <td>{pool.type}</td>
+                            <td>{pool.used | dimless}</td>
+                            <td>{pool.avail | dimless}</td>
+                            <td>
+                                <div class="progress"
+                                     style="width: 100px; height: 20px;">
+                                    <div class="progress-bar progress-bar-red"
+                                         rv-style="pool | pool_size_bar"></div>
+                                </div>
+                            </td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+        </div>
+
+    </div>
+    <div class="box">
+        <div class="box-header">
+            <h3 class="box-title">Standby daemons</h3>
+        </div>
+        <div class="box-body">
+            <table>
+                <thead>
+                <tr rv-show="standbys | length">
+                    <th>Daemon</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr rv-each-standby="standbys">
+                    <td>{standby.name}</td>
+                </tr>
+                <tr class="ceph-none-found" rv-hide="standbys | length">
+                    <td>None found</td>
+                </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+
+    <div id="mds_charts" style="color: #ddd;">
+    </div>
+
+</section>
+<!-- /.content -->
+
+{% endblock %}