From 15dd9af54d06de4aac8dc8180db34f193c65112d Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 2 Oct 2020 18:14:22 +0000 Subject: [PATCH 1/6] Update: Made sane_hostname more formal config_problems and include flags for insane location and admin --- src/cfgfile.c | 19 ++++++++++++------- src/cfgfile.h | 7 ++++++- src/main.c | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index 3081ab47..1d661cac 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -936,6 +936,7 @@ static void _set_defaults(ice_config_t *configuration) static inline void __check_hostname(ice_config_t *configuration) { + int sane_hostname = 0; char *p; /* ensure we have a non-NULL buffer: */ @@ -948,10 +949,9 @@ static inline void __check_hostname(ice_config_t *configuration) *p += 'a' - 'A'; } - configuration->sane_hostname = 0; switch (util_hostcheck(configuration->hostname)) { case HOSTCHECK_SANE: - configuration->sane_hostname = 1; + sane_hostname = 1; break; case HOSTCHECK_ERROR: ICECAST_LOG_ERROR("Can not check hostname \"%s\".", @@ -985,6 +985,9 @@ static inline void __check_hostname(ice_config_t *configuration) "listings."); break; } + + if (!sane_hostname) + configuration->config_problems |= CONFIG_PROBLEM_HOSTNAME; } static void _parse_root(xmlDocPtr doc, @@ -1161,8 +1164,9 @@ static void _parse_root(xmlDocPtr doc, strcmp(configuration->location, CONFIG_DEFAULT_LOCATION) == 0) { ICECAST_LOG_WARN("Warning, not configured, using default " "value \"%s\".", CONFIG_DEFAULT_LOCATION); - if (!configuration->location) - configuration->location = (char *) xmlCharStrdup(CONFIG_DEFAULT_LOCATION); + if (!configuration->location) + configuration->location = (char *) xmlCharStrdup(CONFIG_DEFAULT_LOCATION); + configuration->config_problems |= CONFIG_PROBLEM_LOCATION; } if (!configuration->admin || @@ -1171,9 +1175,10 @@ static void _parse_root(xmlDocPtr doc, "default value \"%s\". This breaks YP directory listings. " "YP directory support will be disabled.", CONFIG_DEFAULT_ADMIN); /* FIXME actually disable YP */ - if (!configuration->admin) - configuration->admin = (char *) xmlCharStrdup(CONFIG_DEFAULT_ADMIN); - } + if (!configuration->admin) + configuration->admin = (char *) xmlCharStrdup(CONFIG_DEFAULT_ADMIN); + configuration->config_problems |= CONFIG_PROBLEM_ADMIN; + } } static void _parse_limits(xmlDocPtr doc, diff --git a/src/cfgfile.h b/src/cfgfile.h index a168d90e..edab5748 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -28,6 +28,10 @@ #define XMLSTR(str) ((xmlChar *)(str)) +#define CONFIG_PROBLEM_HOSTNAME 0x0001U +#define CONFIG_PROBLEM_LOCATION 0x0002U +#define CONFIG_PROBLEM_ADMIN 0x0004U + typedef enum _http_header_type { /* static: headers are passed as is to the client. */ HTTP_HEADER_TYPE_STATIC, @@ -198,6 +202,8 @@ typedef struct { struct ice_config_tag { char *config_filename; + unsigned int config_problems; + char *location; char *admin; @@ -220,7 +226,6 @@ struct ice_config_tag { struct event_registration_tag *event; char *hostname; - int sane_hostname; int port; char *mimetypes_fn; diff --git a/src/main.c b/src/main.c index bf7eecfc..31af8b9f 100644 --- a/src/main.c +++ b/src/main.c @@ -556,7 +556,7 @@ static inline void __log_system_name(void) { if (have_hostname) { config = config_get_config(); - if (!config->sane_hostname && util_hostcheck(hostname) == HOSTCHECK_SANE) { + if ((config->config_problems & CONFIG_PROBLEM_HOSTNAME) && util_hostcheck(hostname) == HOSTCHECK_SANE) { ICECAST_LOG_WARN("Hostname is not set to anything useful in , Consider setting it to the system's name \"%s\".", hostname); } config_release_config(); From 5da8971b2e7d24ee14042147392f98a231167274 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 2 Oct 2020 21:30:11 +0000 Subject: [PATCH 2/6] Feature: Added a basic dashboard --- admin/dashboard.xsl | 67 ++++++++++++++++++ admin/includes/header.xsl | 1 + src/admin.c | 139 +++++++++++++++++++++++++++++++++++++- web/assets/css/style.css | 69 +++++++++++++++++++ 4 files changed, 274 insertions(+), 2 deletions(-) create mode 100644 admin/dashboard.xsl diff --git a/admin/dashboard.xsl b/admin/dashboard.xsl new file mode 100644 index 00000000..3c8e65b4 --- /dev/null +++ b/admin/dashboard.xsl @@ -0,0 +1,67 @@ + + + + Dashboard + + +

+ + +
+

Overview for

+ +
+
+

Health

+
 
+
+
+

Current load

+ + + + + + + + + + + +
+ of +
 
+
+
+
+
+
+ +
+

Maintenance

+ + +
    + +
  • +

    +
      + +
    • +
      +
    +
  • +
    +
+
+ +

Nothing to do.

+
+
+
+
+
+
+
diff --git a/admin/includes/header.xsl b/admin/includes/header.xsl index 88a0ee2a..6c9e94f8 100644 --- a/admin/includes/header.xsl +++ b/admin/includes/header.xsl @@ -9,6 +9,7 @@

Icecast Server administration

    + diff --git a/src/admin.c b/src/admin.c index f992aa69..ba7cbdc3 100644 --- a/src/admin.c +++ b/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 .", NULL); + if (config->config_problems & CONFIG_PROBLEM_LOCATION) + __reportxml_add_maintenance(resource, "warning", "No useful location is given in .", NULL); + if (config->config_problems & CONFIG_PROBLEM_ADMIN) + __reportxml_add_maintenance(resource, "warning", "No admin contact given in . 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); +} diff --git a/web/assets/css/style.css b/web/assets/css/style.css index fabea6ba..f59bf054 100644 --- a/web/assets/css/style.css +++ b/web/assets/css/style.css @@ -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 { From c12cb226f11ecb04e02f33d62813fdd20f80fc6d Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 3 Oct 2020 07:44:57 +0000 Subject: [PATCH 3/6] Feature: Select default content for admin page via operation mode --- src/admin.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/admin.c b/src/admin.c index ba7cbdc3..43540054 100644 --- a/src/admin.c +++ b/src/admin.c @@ -106,6 +106,7 @@ typedef struct { const admin_command_handler_t *handlers; } admin_command_table_t; +static void command_default_selector (client_t *client, source_t *source, admin_format_t response); static void command_fallback (client_t *client, source_t *source, admin_format_t response); static void command_metadata (client_t *client, source_t *source, admin_format_t response); static void command_shoutcast_metadata (client_t *client, source_t *source, admin_format_t response); @@ -159,8 +160,8 @@ static const admin_command_handler_t handlers[] = { { MARKLOG_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_mark_log, 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} + { DEFAULT_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_default_selector, NULL}, + { DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_default_selector, NULL} }; static admin_command_table_t command_tables[ADMIN_MAX_COMMAND_TABLES] = { @@ -656,6 +657,16 @@ static void html_success(client_t *client, char *message) } +static void command_default_selector (client_t *client, source_t *source, admin_format_t response) +{ + if (client->mode == OMODE_LEGACY) { + command_stats(client, source, response); + } else { + command_dashboard(client, source, response); + } +} + + static void command_move_clients(client_t *client, source_t *source, admin_format_t response) From ddb94982b8c61a4110bcb310ed0333361324b654 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 3 Oct 2020 08:00:39 +0000 Subject: [PATCH 4/6] Cleanup: Removed demo Lorem ipsum --- src/admin.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/admin.c b/src/admin.c index 43540054..6ba428e2 100644 --- a/src/admin.c +++ b/src/admin.c @@ -1471,8 +1471,6 @@ static void command_dashboard (client_t *client, source_t *source, adm __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); From 91df2ddb40fe045a1021876a2c58a2df6623e8d0 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 3 Oct 2020 08:03:09 +0000 Subject: [PATCH 5/6] Update: uppercase first letter of @member --- admin/dashboard.xsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/dashboard.xsl b/admin/dashboard.xsl index 3c8e65b4..75125add 100644 --- a/admin/dashboard.xsl +++ b/admin/dashboard.xsl @@ -25,7 +25,7 @@ - + of
     
    From 4ccf3657d7d2582a542e4ef03246a8b0541b6c56 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 3 Oct 2020 08:05:15 +0000 Subject: [PATCH 6/6] Update: Select a nicer green for green trafic light --- web/assets/css/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/assets/css/style.css b/web/assets/css/style.css index f59bf054..37a5bbad 100644 --- a/web/assets/css/style.css +++ b/web/assets/css/style.css @@ -383,7 +383,7 @@ aside { } .colour-green { - background: green; + background: limegreen; } /* Error messages */