mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Feature: Added a basic dashboard
This commit is contained in:
parent
15dd9af54d
commit
5da8971b2e
67
admin/dashboard.xsl
Normal file
67
admin/dashboard.xsl
Normal file
@ -0,0 +1,67 @@
|
||||
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
|
||||
<xsl:include href="includes/page.xsl"/>
|
||||
<xsl:variable name="title">Dashboard</xsl:variable>
|
||||
|
||||
<xsl:template name="content">
|
||||
<h2><xsl:value-of select="$title" /></h2>
|
||||
<xsl:for-each select="/report/incident">
|
||||
<xsl:for-each select="resource[@name='overall-status']">
|
||||
<section class="box">
|
||||
<h3 class="box_title">Overview for <code><xsl:value-of select="value[@member='global-config']/value[@member='hostname']/@value" /></code></h3>
|
||||
<ul class="boxnav">
|
||||
<li><a href="reloadconfig.xsl">Reload Configuration</a></li>
|
||||
</ul>
|
||||
<div class="side-by-side">
|
||||
<div>
|
||||
<h4>Health</h4>
|
||||
<div class="trafficlight colour-{value[@member='status']/@value}"> </div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Current load</h4>
|
||||
<table class="table-block">
|
||||
<tbody>
|
||||
<xsl:for-each select="value[@member='global-current']/value">
|
||||
<tr>
|
||||
<xsl:variable name="member" select="@member" />
|
||||
<xsl:variable name="of" select="../../value[@member='global-config']/value[@member=$member]/@value" />
|
||||
<td><xsl:value-of select="$member" /></td>
|
||||
<td class="barmeter">
|
||||
<span><xsl:value-of select="@value" /> of <xsl:value-of select="$of" /></span>
|
||||
<div style="width: calc(100% * {@value} / {$of});"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</xsl:for-each>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select="resource[@name='maintenance']">
|
||||
<section class="box">
|
||||
<h3 class="box_title">Maintenance</h3>
|
||||
<xsl:choose>
|
||||
<xsl:when test="value">
|
||||
<ul class="maintenance-container">
|
||||
<xsl:for-each select="value">
|
||||
<li class="maintenance-level-{value[@member='type']/@value}">
|
||||
<p><xsl:value-of select="text/text()" /></p>
|
||||
<ul class="references">
|
||||
<xsl:for-each select="reference">
|
||||
<li><a href="{@href}"><xsl:value-of select="concat(translate(substring(@type, 1, 1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), substring(@type, 2))" /></a></li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<p>Nothing to do.</p>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</section>
|
||||
</xsl:for-each>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
@ -9,6 +9,7 @@
|
||||
<h1>Icecast Server administration</h1>
|
||||
</a>
|
||||
<ul>
|
||||
<li class="adminlink"><a href="/admin/dashboard.xsl">Dashboard</a></li>
|
||||
<li class="adminlink"><a href="/admin/stats.xsl">Server status</a></li>
|
||||
<li class="adminlink"><a href="/admin/listmounts.xsl">Mountpoint list</a></li>
|
||||
<li class="adminlink"><a href="/admin/showlog.xsl">Logfiles</a></li>
|
||||
|
139
src/admin.c
139
src/admin.c
@ -94,6 +94,8 @@
|
||||
#define SHOWLOG_HTML_REQUEST "showlog.xsl"
|
||||
#define MARKLOG_RAW_REQUEST "marklog"
|
||||
#define MARKLOG_HTML_REQUEST "marklog.xsl"
|
||||
#define DASHBOARD_RAW_REQUEST "dashboard"
|
||||
#define DASHBOARD_HTML_REQUEST "dashboard.xsl"
|
||||
#define DEFAULT_RAW_REQUEST ""
|
||||
#define DEFAULT_HTML_REQUEST ""
|
||||
#define BUILDM3U_RAW_REQUEST "buildm3u"
|
||||
@ -119,6 +121,7 @@ static void command_updatemetadata (client_t *client, source_t *source, adm
|
||||
static void command_buildm3u (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_show_log (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_mark_log (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_dashboard (client_t *client, source_t *source, admin_format_t response);
|
||||
|
||||
static const admin_command_handler_t handlers[] = {
|
||||
{ "*", ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, NULL, NULL}, /* for ACL framework */
|
||||
@ -154,8 +157,10 @@ static const admin_command_handler_t handlers[] = {
|
||||
{ SHOWLOG_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_show_log, NULL},
|
||||
{ MARKLOG_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, command_mark_log, NULL},
|
||||
{ MARKLOG_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_mark_log, NULL},
|
||||
{ DEFAULT_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_stats, NULL},
|
||||
{ DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_stats, NULL}
|
||||
{ DASHBOARD_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, command_dashboard, NULL},
|
||||
{ DASHBOARD_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_dashboard, NULL},
|
||||
{ DEFAULT_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_dashboard, NULL},
|
||||
{ DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_dashboard, NULL}
|
||||
};
|
||||
|
||||
static admin_command_table_t command_tables[ADMIN_MAX_COMMAND_TABLES] = {
|
||||
@ -1336,3 +1341,133 @@ static void command_mark_log (client_t *client, source_t *source, adm
|
||||
|
||||
admin_send_response_simple(client, source, response, "Logfiles marked", 1);
|
||||
}
|
||||
|
||||
static void __reportxml_add_value(reportxml_node_t *parent, const char *type, const char *member, const char *str)
|
||||
{
|
||||
reportxml_node_t *value = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(value, "type", type);
|
||||
if (member)
|
||||
reportxml_node_set_attribute(value, "member", member);
|
||||
reportxml_node_set_attribute(value, "value", str);
|
||||
reportxml_node_add_child(parent, value);
|
||||
refobject_unref(value);
|
||||
}
|
||||
|
||||
#define __reportxml_add_value_string(parent,member,value) __reportxml_add_value((parent), "string", (member), (value))
|
||||
#define __reportxml_add_value_enum(parent,member,value) __reportxml_add_value((parent), "enum", (member), (value))
|
||||
|
||||
static void __reportxml_add_value_int(reportxml_node_t *parent, const char *member, long long int value)
|
||||
{
|
||||
char buf[80];
|
||||
snprintf(buf, sizeof(buf), "%lli", value);
|
||||
__reportxml_add_value(parent, "int", member, buf);
|
||||
}
|
||||
|
||||
static void __reportxml_add_maintenance(reportxml_node_t *parent, const char *type, const char *text, const char *docs)
|
||||
{
|
||||
reportxml_node_t *maintenance = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
|
||||
reportxml_node_set_attribute(maintenance, "type", "structure");
|
||||
reportxml_node_add_child(parent, maintenance);
|
||||
|
||||
__reportxml_add_value_enum(maintenance, "type", type);
|
||||
|
||||
if (text) {
|
||||
reportxml_node_t *textnode = reportxml_node_new(REPORTXML_NODE_TYPE_TEXT, NULL, NULL, NULL);
|
||||
reportxml_node_set_content(textnode, text);
|
||||
reportxml_node_add_child(maintenance, textnode);
|
||||
refobject_unref(textnode);
|
||||
}
|
||||
|
||||
if (docs) {
|
||||
reportxml_node_t *referenenode = reportxml_node_new(REPORTXML_NODE_TYPE_REFERENCE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(referenenode, "type", "documentation");
|
||||
reportxml_node_set_attribute(referenenode, "href", docs);
|
||||
reportxml_node_add_child(maintenance, referenenode);
|
||||
refobject_unref(referenenode);
|
||||
}
|
||||
|
||||
refobject_unref(maintenance);
|
||||
}
|
||||
|
||||
static void command_dashboard (client_t *client, source_t *source, admin_format_t response)
|
||||
{
|
||||
ice_config_t *config = config_get_config();
|
||||
reportxml_t *report = client_get_reportxml("0aa76ea1-bf42-49d1-887e-ca95fb307dc4", NULL, NULL);
|
||||
reportxml_node_t *incident = reportxml_get_node_by_type(report, REPORTXML_NODE_TYPE_INCIDENT, 0);
|
||||
reportxml_node_t *resource;
|
||||
reportxml_node_t *node;
|
||||
int has_sources;
|
||||
int has_many_clients;
|
||||
int has_too_many_clients;
|
||||
|
||||
|
||||
resource = reportxml_node_new(REPORTXML_NODE_TYPE_RESOURCE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(resource, "type", "result");
|
||||
reportxml_node_set_attribute(resource, "name", "overall-status");
|
||||
|
||||
node = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(node, "type", "structure");
|
||||
reportxml_node_set_attribute(node, "member", "global-config");
|
||||
__reportxml_add_value_string(node, "hostname", config->hostname);
|
||||
__reportxml_add_value_int(node, "clients", config->client_limit);
|
||||
__reportxml_add_value_int(node, "sources", config->source_limit);
|
||||
reportxml_node_add_child(resource, node);
|
||||
refobject_unref(node);
|
||||
|
||||
node = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(node, "type", "structure");
|
||||
reportxml_node_set_attribute(node, "member", "global-current");
|
||||
global_lock();
|
||||
__reportxml_add_value_int(node, "clients", global.clients);
|
||||
__reportxml_add_value_int(node, "sources", global.sources);
|
||||
has_sources = global.sources > 0;
|
||||
has_many_clients = global.clients > ((75 * config->client_limit) / 100);
|
||||
has_too_many_clients = global.clients > ((90 * config->client_limit) / 100);
|
||||
global_unlock();
|
||||
reportxml_node_add_child(resource, node);
|
||||
refobject_unref(node);
|
||||
|
||||
if (config->config_problems || has_too_many_clients) {
|
||||
__reportxml_add_value_enum(resource, "status", "red");
|
||||
} else if (!has_sources || has_many_clients) {
|
||||
__reportxml_add_value_enum(resource, "status", "yellow");
|
||||
} else {
|
||||
__reportxml_add_value_enum(resource, "status", "green");
|
||||
}
|
||||
|
||||
reportxml_node_add_child(incident, resource);
|
||||
refobject_unref(resource);
|
||||
|
||||
|
||||
resource = reportxml_node_new(REPORTXML_NODE_TYPE_RESOURCE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(resource, "type", "result");
|
||||
reportxml_node_set_attribute(resource, "name", "maintenance");
|
||||
|
||||
if (config->config_problems & CONFIG_PROBLEM_HOSTNAME)
|
||||
__reportxml_add_maintenance(resource, "warning", "Hostname is not set to anything useful in <hostname>.", NULL);
|
||||
if (config->config_problems & CONFIG_PROBLEM_LOCATION)
|
||||
__reportxml_add_maintenance(resource, "warning", "No useful location is given in <location>.", NULL);
|
||||
if (config->config_problems & CONFIG_PROBLEM_ADMIN)
|
||||
__reportxml_add_maintenance(resource, "warning", "No admin contact given in <admin>. YP directory support will is disabled.", NULL);
|
||||
|
||||
if (!has_sources)
|
||||
__reportxml_add_maintenance(resource, "info", "Currently no sources are connected to this server.", NULL);
|
||||
|
||||
if (has_too_many_clients) {
|
||||
__reportxml_add_maintenance(resource, "warning", "More than 90% of the server's configured maximum clients are connected", NULL);
|
||||
} else if (has_many_clients) {
|
||||
__reportxml_add_maintenance(resource, "info", "More than 75% of the server's configured maximum clients are connected", NULL);
|
||||
}
|
||||
|
||||
__reportxml_add_maintenance(resource, "todo", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "https://icecast.org/");
|
||||
|
||||
reportxml_node_add_child(incident, resource);
|
||||
refobject_unref(resource);
|
||||
|
||||
|
||||
refobject_unref(incident);
|
||||
|
||||
config_release_config();
|
||||
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, DASHBOARD_HTML_REQUEST, response, 200, NULL);
|
||||
}
|
||||
|
@ -302,6 +302,19 @@ aside {
|
||||
margin: 0.4em;
|
||||
}
|
||||
|
||||
.side-by-side {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.side-by-side > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.side-by-side > * {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.codeblock {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
@ -317,6 +330,62 @@ aside {
|
||||
background-color: #cccccc;
|
||||
}
|
||||
|
||||
.barmeter > *:first-child {
|
||||
float: right;
|
||||
display: inline;
|
||||
}
|
||||
.barmeter > *:nth-child(2) {
|
||||
background: #4f8cb0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.maintenance-container {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.maintenance-level-warning > *:first-child::before {
|
||||
font-weight: bold;
|
||||
content: "Warning: ";
|
||||
}
|
||||
|
||||
.maintenance-level-todo > *:first-child::before {
|
||||
font-weight: bold;
|
||||
content: "Todo: ";
|
||||
}
|
||||
|
||||
.maintenance-level-info > *:first-child::before {
|
||||
font-weight: bold;
|
||||
content: "Info: ";
|
||||
}
|
||||
|
||||
.references {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.references > li {
|
||||
display: inline;
|
||||
margin-right: 0.4em;
|
||||
}
|
||||
|
||||
.trafficlight {
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
border-radius: 2em;
|
||||
}
|
||||
|
||||
.colour-red {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.colour-yellow {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.colour-green {
|
||||
background: green;
|
||||
}
|
||||
|
||||
/* Error messages */
|
||||
|
||||
.error {
|
||||
|
Loading…
Reference in New Issue
Block a user