Skip to content

Commit

Permalink
Merge pull request #191 from ineilson/local_info-schema-checking
Browse files Browse the repository at this point in the history
Add local_info.xsd and xml schema validation
  • Loading branch information
gregcorbett authored May 5, 2023
2 parents fa12345 + 2051bd7 commit a8d8285
Show file tree
Hide file tree
Showing 10 changed files with 541 additions and 56 deletions.
2 changes: 2 additions & 0 deletions config/local_info.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>

<config>
<!--
Provide default values for all configuration elements.
See also local override information provided below this local_info element.
-->

<local_info>

<!-- If read-only is set as true, the portal will prevent changes to the
Expand Down
132 changes: 132 additions & 0 deletions config/local_info.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?xml version="1.0"?>

<!-- Copied from https://www.ibm.com/developerworks/library/x-validxphp/ -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:include schemaLocation="./web_portal/menu.xsd"/>

<xs:simpleType name="showType">
<xs:restriction base="xs:string">
<xs:enumeration value="hide"/>
<xs:enumeration value="show"/>
<xs:enumeration value="no"/>
<xs:enumeration value="yes"/>
<xs:enumeration value="false"/>
<xs:enumeration value="true"/>
</xs:restriction>
</xs:simpleType>

<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element name="local_info" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:all>

<xs:element name="page_banner" type="xs:string" minOccurs="0"/>
<xs:element name="read_only" type="xs:boolean" minOccurs="0"/>
<xs:element name="filter_downtimes_by_default_scope" type="xs:boolean" minOccurs="0"/>
<xs:element name="default_filter_by_scope" type="xs:boolean" minOccurs="0"/>
<xs:element name="menus" type="validMenus" minOccurs="0"/>

<!-- Note that we do not validate the email string values provided here -->
<xs:element name="email_from" type="xs:string" minOccurs="0"/>
<xs:element name="email_to" type="xs:string" minOccurs="0"/>

<xs:element name="aup" type="xs:anyURI" minOccurs="0"/>
<xs:element name="aup_title" type="xs:string" minOccurs="0"/>
<xs:element name="privacy_notice" type="xs:anyURI" minOccurs="0"/>
<xs:element name="privacy_notice_title" type="xs:string" minOccurs="0"/>

<xs:element name="restrict_personal_data" type="xs:boolean" minOccurs="0"/>

<xs:element name="API_all_auth_realms" type="xs:boolean" minOccurs="0"/>

<xs:element name="css" minOccurs="0">
<xs:complexType>
<xs:all>
<!-- Use string type to allow standard colour names -->
<xs:element name="backgroundColour1" type="xs:string"/>
<xs:element name="backgroundColour2" type="xs:string"/>
<xs:element name="backgroundColour3" type="xs:string"/>
<xs:element name="backgroundDirection" type="xs:string"/>
<xs:element name="headingTextColour" type="xs:string"/>

</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="name_mapping" minOccurs="0">
<xs:complexType>
<xs:all>
<xs:element name="Service">
<xs:complexType>
<xs:all>
<xs:element name="ServiceEndpoint" type="xs:string" minOccurs="0"/>
<xs:element name="endpoint" type="xs:string" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="web_portal_url" type="xs:anyURI" minOccurs="0"/>
<xs:element name="pi_url" type="xs:anyURI" minOccurs="0"/>
<xs:element name="server_base_url" type="xs:anyURI" minOccurs="0"/>
<xs:element name="write_api_user_docs_url" type="xs:anyURI" minOccurs="0"/>
<xs:element name="optional_features" minOccurs="0">
<xs:complexType>
<xs:all>
<xs:element name="siteless_services" type="xs:boolean"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="default_scope" minOccurs="0">
<xs:complexType>
<xs:all>
<xs:element name="name" type="xs:string"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="show_map_on_start_page" type="xs:boolean" minOccurs="0"/>
<xs:element name="default_scope_match" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="any"/>
<xs:enumeration value="all"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="minimum_scopes" minOccurs="0">
<xs:complexType>
<xs:all>
<xs:element name="ngi" type="xs:integer" minOccurs="0"/>
<xs:element name="site" type="xs:integer" minOccurs="0"/>
<xs:element name="service" type="xs:integer" minOccurs="0"/>
<xs:element name="service_group" type="xs:integer" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="reserved_scopes" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="scope" type="xs:string" minOccurs="1" maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="extensions" minOccurs="0">
<xs:complexType>
<xs:all>
<xs:element name="max" type="xs:integer"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="send_email" type="xs:boolean" minOccurs="0"/>
</xs:all>
<xs:attribute name="url" type="xs:anyURI"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>

</xs:schema>
57 changes: 57 additions & 0 deletions config/web_portal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Auto-generation of menu.xsd and its use in GOCDB configuration

## What *config/web_portal/menu.xsd* is for

This file is the schema file for the definiton of GOCDB's left-hand column menu, used to check that only valid menu names are included in the GOCDB main configuration file config/local_info.xml. The menu.xsd file is built automatically, **do not edit it** - see the next question.

GOCDB uses an XML definition (config/web_portal/menu.xml) to programatically draw the left-hand menu items on the user
interface. Which menu items are drawn is selected via the \<MENU> element in the GOCDB configuration file (config/local_info.xml). To check that only valid menu item names are given within the \<MENU> element it is necessary to generate an XML schema containing all valid menu names (config/web_portal/menu.xsd).

## What *config/web_portal/menu.xslt* is for

This file is the transformation file which builds the menu.xsd schema definition file - see the previous question - from the menu definition file config/web_portal/menu.xml.

To avoid having to specify menu names manually twice: once in the XML and once in the schema definition (config/local_info.xsd), an XSL Transformation file (config/web_portal/menu.xslt) is used to generate the menu schema (config/web_portal/menu.xsd) directly from the XML menu file. This menu schema is then included into the overall GOCDB schema when the configuration is validated.

## How to make changes made to the left-hand menu

Left-hand menu items can be added or deleted by editing the menu XML file (config/web_portal/menu.xml). You should then run the XSL Transformation processor command *xsltproc* to generate a new menu schema -

```bash
xsltproc -o menu.xsd menu.xslt menu.xml
```

The resulting .xsd file will automatically be included in the configuration validation.

## Why these files are used

To prevent mistypes and other difficult-to-spot configuration errors, GOCDB uses an XML schema file (config/local_info.xsd) to validate the XML elements given in the main configuration file (config/local_info.xml).

## How these files are used

Checking that the schema is correct is done as part of the operations monitoring tests (htdocs/web_portal/GOCDB_monitor/*).

An XSLT translation file is not used to build the main configuration schema file (config/local_info.xsd) because the menu XML is part of the codebase, whereas the main configuration XML is variable content to be validated against the main schema definition which is also part of the codebase.

```mermaid
---
title: Updating menu items and configuration validation
---
flowchart TB
menu.xml[config/web_portal/menu.xml]
menu.xsd[config/web_portal/menu.xsd]
menu.xslt[config/web_portal/menu.xslt]
local_info.xsd[config/local_info.xsd]
local_info.xml[config/local_info.xml]
edits([add or delete menu items]) -->menu.xml
menu.xml & menu.xslt --> xsltproc[[xsltproc translation]] -->menu.xsd
menu.xsd-->|include in|local_info.xsd
config([configuration value edits]) -->local_info.xml
local_info.xsd & local_info.xml --> validation[[XML validation]] --> result[\"#nbsp;Result: valid or invalid configuration#nbsp;"\]
```
36 changes: 36 additions & 0 deletions config/web_portal/menu.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0"?>
<!--
** DO NOT EDIT THIS FILE DIRECTLY. **
** THIS FILE IS AUTO GENERATED. **
** SEE menu.xslt FOR DETAILS. **
-->
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:complexType name="validMenus">
<xs:all>
<xs:element name="MySites" type="showType" minOccurs="0"/>
<xs:element name="Projects" type="showType" minOccurs="0"/>
<xs:element name="NGI" type="showType" minOccurs="0"/>
<xs:element name="Sites" type="showType" minOccurs="0"/>
<xs:element name="ServiceGroups" type="showType" minOccurs="0"/>
<xs:element name="Services" type="showType" minOccurs="0"/>
<xs:element name="Scopes" type="showType" minOccurs="0"/>
<xs:element name="RoleActionMappings" type="showType" minOccurs="0"/>
<xs:element name="AddSite" type="showType" minOccurs="0"/>
<xs:element name="AddServiceGroup" type="showType" minOccurs="0"/>
<xs:element name="AddService" type="showType" minOccurs="0"/>
<xs:element name="AddDowntime" type="showType" minOccurs="0"/>
<xs:element name="CurrentDowntimes" type="showType" minOccurs="0"/>
<xs:element name="Calendar" type="showType" minOccurs="0"/>
<xs:element name="HelpAndContact" type="showType" minOccurs="0"/>
<xs:element name="AddNGI" type="showType" minOccurs="0"/>
<xs:element name="AddProject" type="showType" minOccurs="0"/>
<xs:element name="MoveServiceEndPoint" type="showType" minOccurs="0"/>
<xs:element name="MoveSite" type="showType" minOccurs="0"/>
<xs:element name="ServiceTypes" type="showType" minOccurs="0"/>
<xs:element name="Users" type="showType" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:schema>

48 changes: 48 additions & 0 deletions config/web_portal/menu.xslt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0"?>
<!--
- Generate the schema definition for valid menu elements for including
- into config/local_info.xsd
-
- Example: # xsltproc -o menu.xsd menu.xslt menu.xml
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>

<xsl:strip-space elements="*"/>

<xsl:template match="/menus/main_menu">
<xsl:comment>
** DO NOT EDIT THIS FILE DIRECTLY. **
** THIS FILE IS AUTO GENERATED. **
** SEE menu.xslt FOR DETAILS. **
</xsl:comment>
<xsl:text disable-output-escaping="yes">&lt;xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
&gt;</xsl:text>
<xsl:text disable-output-escaping="yes">
&lt;xs:complexType name="validMenus"&gt;
&lt;xs:all&gt;</xsl:text>
<xsl:apply-templates/>
<xsl:text disable-output-escaping="yes">
&lt;/xs:all&gt;
&lt;/xs:complexType&gt;
&lt;/xs:schema&gt;&#xa;</xsl:text>
</xsl:template>

<xsl:template match="/menus/main_menu/*[not(self::spacer)]">
<!--
It would be better not to have to specify minOccurs repeatedly
but it is/seems to be necessary to allow the override sections not to be fully
specified.
-->
<xsl:text disable-output-escaping="yes">
&lt;xs:element name="</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text disable-output-escaping="yes">" type="showType" minOccurs="0"/&gt;</xsl:text>
</xsl:template>

<xsl:template match="/menus/main_menu/spacer">
</xsl:template>

</xsl:stylesheet>
75 changes: 47 additions & 28 deletions htdocs/web_portal/GOCDB_monitor/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,43 @@
<?php
require_once __DIR__ . '/tests.php';

echo "<p>URLs as defined by local_info.xml</p>";

$piUrl = Factory::getConfigService()->GetPiUrl().get_testPiMethod();
echo "<p>PI URL is: ".$piUrl."</p>";

$portalUrl = Factory::getConfigService()->GetPortalURL();
echo "<p>Portal URl is: ".$portalUrl."</p>";

$baseUrl = Factory::getConfigService()->getServerBaseUrl();
echo "<p>Server Base URL is: ".$baseUrl."</p>";
$config = Factory::getConfigService();

// GOCDB5 DB connection
$res = test_db_connection();
$test_statuses["GOCDB5 DB connection"] = $res["status"];
$test_messages["GOCDB5 DB connection"] = $res["message"];
$test_statuses[TEST_1] = $res["status"];
$test_messages[TEST_1] = $res["message"];

// GOCDBPI v5
$res = test_url($piUrl);
$test_statuses["GOCDBPI_v5 availability"] = $res["status"];
$test_messages["GOCDBPI_v5 availability"] = $res["message"];
// GOCDB5 configuration
$res = test_config($config);
$test_statuses[TEST_4] = $res["status"];
$test_messages[TEST_4] = $res["message"];

// GOCDB5 web portal
$res = test_url($portalUrl);
$test_statuses["GOCDB5 central portal availability"] = $res["status"];
$test_messages["GOCDB5 central portal availability"] = $res["message"];
// Following tests depend on the config file being valid.
if (strcasecmp($res["status"], OK) == 0) {
define_test_urls($config);
// GOCDBPI v5
$res = test_url(PI_URL);
$test_statuses[TEST_2] = $res["status"];
$test_messages[TEST_2] = $res["message"];
// GOCDB5 web portal
$res = test_url(SERVER_BASE_URL);
$test_statuses[TEST_3] = $res["status"];
$test_messages[TEST_3] = $res["message"];

// DISPLAY RESULTS
// DISPLAY RESULTS
echo "<p>URLs as defined by local_info.xml</p>";
echo "<p>PI URL is: " . PI_URL . "</p>";
echo "<p>Portal URl is: " . PORTAL_URL . "</p>";
echo "<p>Server Base URL is: " . SERVER_BASE_URL . "</p>";
} else {
echo "<p>Unable to extract URL information due to configuration test failure.</p>";
}
?>

<h2>Service status overview</h2>
<p>Other tests may have dependencies on the server configuration so may
show ERROR or UNKNOWN if the configuration is invalid.</p>
<table border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
Expand All @@ -48,10 +55,10 @@
<?php
foreach ($test_statuses as $test => $status) {
echo("<tr>");
echo("<td><font size='1'><span title=\"{$test_desc[$test]}\">$test</span></font></td>");
echo("<td><span title=\"{$test_desc[$test]}\">$test</span></font></td>");
echo($disp[$status]);
echo("<td><font size='1'>{$test_messages[$test]}</font></td>");
echo("<td><font size='1'>{$test_doc[$test]}</font></td>");
echo("<td>{$test_messages[$test]}</font></td>");
echo("<td>{$test_doc[$test]}</font></td>");
echo("</tr>");
}
?>
Expand All @@ -62,12 +69,24 @@

<h2>Other tests and check pages</h2>
<ul>
<li><a href='http://sumatran.esc.rl.ac.uk/ganglia/?r=day&amp;c=Grid+services&amp;h=gocdb-base.esc.rl.ac.uk'>GOCDB server ganglia page</a> - Useful to see if there are memory or CPU problems</li>
<li><a href='check.php'>Status check</a> - non vebose check of GOCDB service status. Just returns 'OK' if all the tests in \"service status overview\" are fine, 'WARNING' or 'ERROR' otherwise. Used for automatic tests</li>
<li><a href='http://sumatran.esc.rl.ac.uk/ganglia/?r=day&amp;
c=Grid+services&amp;h=gocdb-base.esc.rl.ac.uk'>GOCDB server
ganglia page</a> - Useful to see if there are memory or CPU
problems</li>
<li><a href='check.php'>Status check</a> - a less verbose check of
GOCDB service status. Returns the single line 'All GOCDB tests
are looking good' if all tests run without error and 'GOCDB
Web Portal is unable to connect to the GOCDB back end database'
otherwise. Used for automated tests.</li>
</ul>

<h2>Further documentation</h2>
<ul>
<li><a href='https://svn.esc.rl.ac.uk/repos/sct-docs/SCT Documents/Servers and Services/GOCDB/Cookbook and recipes/GOCDB_daily_maintenance.txt'>GOCDB_daily_maintenance.txt in SCT docs on SVN</a> - This is where it all starts...</li>
<li><a href='https://wiki.egi.eu/wiki/GOCDB_Documentation_Index'>GOCDB public documentation index</a> - The RTFM link to send to anyone who has questions</li>
<li><a href='https://svn.esc.rl.ac.uk/repos/sct-docs/SCT Documents/
Servers and Services/GOCDB/Cookbook and recipes/
GOCDB_daily_maintenance.txt'>GOCDB_daily_maintenance.txt in
SCT docs on SVN</a> - This is where it all starts...</li>
<li><a href='https://wiki.egi.eu/wiki/GOCDB_Documentation_Index'>
GOCDB public documentation index</a> - The RTFM link to send to
anyone who has questions</li>
</ul>
Loading

0 comments on commit a8d8285

Please sign in to comment.