summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClark Williams <williams@redhat.com>2012-01-12 10:09:19 -0600
committerClark Williams <williams@redhat.com>2012-01-12 10:09:19 -0600
commitfa1758387eff03d47c9049d8efcd5eabef622f55 (patch)
tree78cc5743722f50db6b88fc30f1fdb9323a060496
parentc9c862c407a27946931ca8f60f9a3a733f364d74 (diff)
parent53f19edb5795cbb31263f00a01d443f222deb970 (diff)
downloadrteval-fa1758387eff03d47c9049d8efcd5eabef622f55.tar.gz
rteval-fa1758387eff03d47c9049d8efcd5eabef622f55.tar.xz
rteval-fa1758387eff03d47c9049d8efcd5eabef622f55.zip
Merge remote-tracking branch 'davids/master' into work
Conflicts: rteval/hackbench.py rteval/rteval.py Signed-off-by: Clark Williams <williams@redhat.com>
-rw-r--r--Makefile2
-rw-r--r--server/Makefile.am19
-rw-r--r--server/README.xmlrpc24
-rw-r--r--server/apache-rteval-wsgi.conf.tpl41
-rw-r--r--server/configure.ac14
-rw-r--r--server/database.py2
-rwxr-xr-xserver/gen_config.sh6
-rw-r--r--server/parser/pgsql.c65
-rw-r--r--server/parser/xmlparser.c91
-rw-r--r--server/parser/xmlparser.h11
-rw-r--r--server/parser/xmlparser.xsl25
-rw-r--r--server/rteval-parser.spec14
-rw-r--r--server/rteval_xmlrpc.wsgi113
-rw-r--r--server/rtevaldb.py6
-rw-r--r--server/sql/delta-1.2_1.3.sql5
-rw-r--r--server/sql/delta-1.3_1.4.sql5
-rw-r--r--server/sql/rteval-1.3.sql206
-rw-r--r--server/sql/rteval-1.4.sql207
-rw-r--r--server/xmlrpc_API1.py2
19 files changed, 827 insertions, 31 deletions
diff --git a/Makefile b/Makefile
index 429156e..d373860 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ XSLSRC := rteval/rteval_dmi.xsl \
CONFSRC := rteval/rteval.conf
# XML-RPC related files
-XMLRPCVER := 1.3
+XMLRPCVER := 1.5
XMLRPCDIR := server
DESTDIR :=
diff --git a/server/Makefile.am b/server/Makefile.am
index e7392b3..bf56ac4 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -1,6 +1,6 @@
# Makefile.am - autotools configuration file
#
-# Copyright 2009 David Sommerseth <davids@redhat.com>
+# Copyright 2009-2011 David Sommerseth <davids@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -26,21 +26,32 @@ SUBDIRS = parser
dist_doc_DATA = parser/README.parser \
sql/delta-1.0_1.1.sql \
sql/delta-1.1_1.2.sql \
+ sql/delta-1.2_1.3.sql \
+ sql/delta-1.3_1.4.sql \
sql/rteval-$(SQLSCHEMAVER).sql
apache-rteval.conf:
- [ -n $(XMLRPCROOT) ] && $(srcdir)/gen_config.sh $(XMLRPCROOT)/API1
+if ENAB_MODPYTHON
+ [ -n $(XMLRPCROOT) ] && $(srcdir)/gen_config.sh apache-rteval.conf $(XMLRPCROOT)/API1
+else
+ [ -n $(XMLRPCROOT) ] && $(srcdir)/gen_config.sh apache-rteval-wsgi.conf $(XMLRPCROOT)/API1
+endif
clean-local:
-rm -f apache-rteval.conf *~
dist-hook:
- cp $(srcdir)/gen_config.sh $(srcdir)/apache-rteval.conf.tpl $(distdir)/
+ cp $(srcdir)/gen_config.sh $(srcdir)/apache-rteval.conf.tpl $(srcdir)/apache-rteval-wsgi.conf.tpl $(distdir)/
-rm -f $(distdir)/apache-rteval.conf
if ENAB_XMLRPC
xmlrpcdir = $(XMLRPCROOT)/API1
BUILT_SOURCES = apache-rteval.conf
dist_doc_DATA += README.xmlrpc apache-rteval.conf
- dist_xmlrpc_DATA = rteval_xmlrpc.py xmlrpc_API1.py rtevaldb.py database.py
+ dist_xmlrpc_DATA = xmlrpc_API1.py rtevaldb.py database.py
+if ENAB_MODPYTHON
+ dist_xmlrpc_DATA += rteval_xmlrpc.py
+else
+ dist_xmlrpc_DATA += rteval_xmlrpc.wsgi
+endif
endif
diff --git a/server/README.xmlrpc b/server/README.xmlrpc
index 438657a..20bade2 100644
--- a/server/README.xmlrpc
+++ b/server/README.xmlrpc
@@ -21,7 +21,7 @@ track how each system changes behaviour on different kernels.
** Requirements
**
- Apache web server
- - mod_python-3.3.x
+ - mod_python-3.3.x OR mod_wsgi-3.2 or newer.
- PostgreSQL v8.3 or later
- rteval 1.12 or later
@@ -37,7 +37,7 @@ The default path used for the rteval client is
If you have a HTTP setup which will follow this scheme, you do not
need to change any URLs at all.
-When installing the rteval-xmlrpc-1.1 RPM on a Fedora/RHEL based box,
+When installing the rteval-xmlrpc-1.4 RPM on a Fedora/RHEL based box,
Apache will be automatically configured. But the Apache web server
will need to be restarted when you have setup the database.
@@ -56,7 +56,7 @@ All reports are saved in a database. If you have not used the
rteval-xmlrpc interface before, you need to create the needed database
user and database, execute the following command line:
- # psql < /usr/share/doc/rteval-xmlrpc-1.1/rteval-1.2.sql
+ # psql < /usr/share/doc/rteval-xmlrpc-1.5/rteval-1.4.sql
This script will first create a database user called 'rtevxmlrpc' and
'rtevparser', assign default password before creating the database called
@@ -69,10 +69,11 @@ directory. You need to allow the xmlrpc user access from the web
server.
pg_hba.conf entry example:
-
+-----------------------------------------------------------------
# TYPE DATABASE USER CIDR-ADDRESS METHOD
hostssl rteval rtevxmlrpc 127.0.0.1/32 md5
hostssl rteval rtevparser 127.0.0.1/32 md5
+-----------------------------------------------------------------
The XML-RPC database connector will always try to connect via SSL. To
modify the default password, connect to the database with psql and
@@ -106,12 +107,21 @@ To find out which schema version you using, do the following:
This indicates that the database is at the schema version 1.1. If you do not
have the rteval_info table, you are for sure on schema version 1.0.
-* Update from schema version 1.0 to 1.1
+* Update from SQL schema version 1.0 to 1.1
psql rteval < /usr/share/doc/rteval-xmlrpc-1.1/delta-1.0_1.1.sql
-* Update from schema version 1.2 to 1.2
+* Update from SQL schema version 1.1 to 1.2
psql rteval < /usr/share/doc/rteval-xmlrpc-1.1/delta-1.1_1.2.sql
+* Update from SQL schema version 1.2 to 1.3
+ psql rteval < /usr/share/doc/rteval-xmlrpc-1.1/delta-1.2_1.3.sql
+
+* Update from SQL schema version 1.3 to 1.4
+ psql rteval < /usr/share/doc/rteval-xmlrpc-1.1/delta-1.3_1.4.sql
+
+You need to upgrade to the latest SQL schema available, and you must upgrade
+sequentially through all the version in between your version and the latest.
+
**
** Building an installing from source
@@ -137,7 +147,7 @@ install'. The default install prefix is /usr/local, unless you
changed it with --prefix=<path>. You will then find the
rteval_parserd installed under /usr/local/bin/rteval_parserd and
README files, the SQL scripts and an Apache config file will be found
-under /usr/local/share/doc/rteval-parser-1.1/
+under /usr/local/share/doc/rteval-parser-1.5/
The Apache configuration file can be copied into the configuration
directory Apache uses for its modules. On RHEL/Fedora based
diff --git a/server/apache-rteval-wsgi.conf.tpl b/server/apache-rteval-wsgi.conf.tpl
new file mode 100644
index 0000000..9bf5fea
--- /dev/null
+++ b/server/apache-rteval-wsgi.conf.tpl
@@ -0,0 +1,41 @@
+# File: apache-rteval.conf
+#
+# Apache config entry to enable the rteval XML-RPC server
+#
+# Copyright 2011 David Sommerseth <davids@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# For the avoidance of doubt the "preferred form" of this code is one which
+# is in an open unpatent encumbered format. Where cryptographic key signing
+# forms part of the process of creating an executable the information
+# including keys needed to generate an equivalently functional executable
+# are deemed to be part of the source code.
+#
+
+WSGISocketPrefix /var/run/wsgi
+WSGIDaemonProcess rtevalxmlrpc processes=3 threads=15 python-path={_INSTALLDIR_}
+WSGIScriptAlias /rteval/API1 {_INSTALLDIR_}/rteval_xmlrpc.wsgi
+
+<Directory "{_INSTALLDIR_}">
+ Options Indexes FollowSymLinks
+ AllowOverride None
+ Order allow,deny
+ Allow from all
+
+ WSGIProcessGroup rtevalxmlrpc
+ WSGICallableObject rtevalXMLRPC_handler
+</Directory>
+
diff --git a/server/configure.ac b/server/configure.ac
index f68194b..d0721c3 100644
--- a/server/configure.ac
+++ b/server/configure.ac
@@ -1,6 +1,6 @@
# configure.ac - autotools configuration file
#
-# Copyright 2009 David Sommerseth <davids@redhat.com>
+# Copyright 2009-2011 David Sommerseth <davids@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -25,8 +25,8 @@
# To create the ./configure script you need to run 'autoreconf --install'
#
-AC_INIT([rteval-xmlrpc], [1.3], [davids@redhat.com])
-SQLSCHEMAVER=1.2
+AC_INIT([rteval-xmlrpc], [1.5], [davids@redhat.com])
+SQLSCHEMAVER=1.4
AC_SUBST(SQLSCHEMAVER)
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
@@ -40,6 +40,14 @@ AC_ARG_WITH([xmlrpc-webroot],
AC_SUBST(XMLRPCROOT)
AM_CONDITIONAL([ENAB_XMLRPC], [test ! -z $XMLRPCROOT])
+AC_ARG_ENABLE([mod-python],
+ [AS_HELP_STRING([--with-mod-python],
+ [Enable the older mod_python support instead of mod_wsgi])],
+ [MODPYTHON="$enableval"]
+)
+AC_SUBST(MODPYTHON)
+AM_CONDITIONAL([ENAB_MODPYTHON], [test ! -z $MODPYTHON])
+
# Simple macro to abort on missing functions in libraries
AC_DEFUN([AX_msgMISSINGFUNC], AC_MSG_ERROR([Could not find function in library. Aborting]))
diff --git a/server/database.py b/server/database.py
index 389619c..c749593 100644
--- a/server/database.py
+++ b/server/database.py
@@ -168,7 +168,7 @@ class Database(object):
# If no action is setup (mainly for debugging), return empty result set
return {"table": table, "fields": [], "records": []}
except Exception, err:
- raise Exception, "** SQL ERROR *** %s\n** SQL ERROR ** Message: %s" % ((sql % where), str(err))
+ raise Exception, "** SQL ERROR *** %s\n** SQL ERROR ** Message: %s" % (where and (sql % where) or sql, str(err))
# Extract field names
fields = []
diff --git a/server/gen_config.sh b/server/gen_config.sh
index 4b57353..23181ee 100755
--- a/server/gen_config.sh
+++ b/server/gen_config.sh
@@ -1,12 +1,12 @@
#/bin/sh
-APACHECONF="apache-rteval.conf"
-INSTALLDIR="$1"
+APACHECONF="$1"
+INSTALLDIR="$2"
echo "Creating Apache config file: apache-rteval.conf"
escinstpath="$(echo ${INSTALLDIR} | sed -e 's/\//\\\\\//g')"
expr=$(echo "s/{_INSTALLDIR_}/${escinstpath}/")
-eval "sed -e ${expr} ${APACHECONF}.tpl" > ${APACHECONF}
+eval "sed -e ${expr} ${APACHECONF}.tpl" > apache-rteval.conf
echo "Copy the apache apache-rteval.conf into your Apache configuration"
echo "directory and restart your web server"
echo
diff --git a/server/parser/pgsql.c b/server/parser/pgsql.c
index 44032e5..8ea5d08 100644
--- a/server/parser/pgsql.c
+++ b/server/parser/pgsql.c
@@ -44,6 +44,14 @@
#include <log.h>
#include <statuses.h>
+/** forward declaration, to be able to setup dbhelper_func pointers */
+static char * pgsql_BuildArray(LogContext *log, xmlNode *sql_n);
+
+/** Helper functions the xmlparser might beed */
+static dbhelper_func pgsql_helpers = {
+ .dbh_FormatArray = &(pgsql_BuildArray)
+};
+
/**
* Connect to a database, based on the given configuration
*
@@ -106,7 +114,7 @@ dbconn *db_connect(eurephiaVALUES *cfg, unsigned int id, LogContext *log) {
if( dbr ) {
PQclear(dbr);
}
-
+ init_xmlparser(&pgsql_helpers);
return ret;
}
@@ -414,6 +422,61 @@ eurephiaVALUES *pgsql_INSERT(dbconn *dbc, xmlDoc *sqldoc) {
return res;
}
+/**
+ * @copydoc sqldataValueArray()
+ */
+static char * pgsql_BuildArray(LogContext *log, xmlNode *sql_n) {
+ char *ret = NULL, *ptr = NULL;
+ xmlNode *node = NULL;
+ size_t retlen = 0;
+
+ ret = malloc_nullsafe(log, 2);
+ if( ret == NULL ) {
+ writelog(log, LOG_ERR,
+ "Failed to allocate memory for a new PostgreSQL array");
+ return NULL;
+ }
+ strncat(ret, "{", 1);
+
+ /* Iterate all ./value/value elements and build up a PostgreSQL specific array */
+ foreach_xmlnode(sql_n->children, node) {
+ if( (node->type != XML_ELEMENT_NODE)
+ || xmlStrcmp(node->name, (xmlChar *) "value") != 0 ) {
+ // Skip uninteresting nodes
+ continue;
+ }
+ ptr = sqldataValueHash(log, node);
+ if( ptr ) {
+ retlen += strlen(ptr) + 4;
+ ret = realloc(ret, retlen);
+ if( ret == NULL ) {
+ writelog(log, LOG_ERR,
+ "Failed to allocate memory to expand "
+ "array to include '%s'", ptr);
+ free_nullsafe(ret);
+ free_nullsafe(ptr);
+ return NULL;
+ }
+ /* Newer PostgreSQL servers expects numbers to be without quotes */
+ if( isNumber(ptr) == 0 ) {
+ /* Data is a string */
+ strncat(ret, "'", 1);
+ strncat(ret, ptr, strlen(ptr));
+ strncat(ret, "',", 2);
+ } else {
+ /* Data is a number */
+ strncat(ret, ptr, strlen(ptr));
+ strncat(ret, ",", 1);
+ }
+ free_nullsafe(ptr);
+ }
+ }
+ /* Replace the last comma with a close-array marker */
+ ret[strlen(ret)-1] = '}';
+ ret[strlen(ret)] = 0;
+ return ret;
+}
+
/**
* Start an SQL transaction (SQL BEGIN)
diff --git a/server/parser/xmlparser.c b/server/parser/xmlparser.c
index fb1330a..0ff6e72 100644
--- a/server/parser/xmlparser.c
+++ b/server/parser/xmlparser.c
@@ -42,6 +42,8 @@
#include <sha1.h>
#include <log.h>
+static dbhelper_func const * xmlparser_dbhelpers = NULL;
+
/**
* Simple strdup() function which encapsulates the string in single quotes,
* which is needed for XSLT parameter values
@@ -84,6 +86,33 @@ static char *encapsInt(const unsigned int val) {
/**
+ * Simple function to determine if the given string is a number or not
+ *
+ * @param str Pointer to the tring to be checked
+ *
+ * @returns Returns 0 if not a number and a non-null value if it is a number
+ */
+int isNumber(const char * str)
+{
+ char *ptr = NULL;
+
+ if (str == NULL || *str == '\0' || isspace(*str))
+ return 0;
+
+ strtod (str, &ptr);
+ return *ptr == '\0';
+}
+
+/**
+ * Initialise the XML parser, setting some global variables
+ */
+void init_xmlparser(dbhelper_func const * dbhelpers)
+{
+ xmlparser_dbhelpers = dbhelpers;
+}
+
+
+/**
* Parses any XML input document into a sqldata XML format which can be used by pgsql_INSERT().
* The transformation must be defined in the input XSLT template.
*
@@ -100,6 +129,11 @@ xmlDoc *parseToSQLdata(LogContext *log, xsltStylesheet *xslt, xmlDoc *indata_d,
unsigned int idx = 0, idx_table = 0, idx_submid = 0,
idx_syskey = 0, idx_rterid = 0, idx_repfname = 0;
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return NULL;
+ }
+
if( params->table == NULL ) {
writelog(log, LOG_ERR, "Table is not defined");
return NULL;
@@ -170,16 +204,17 @@ xmlDoc *parseToSQLdata(LogContext *log, xsltStylesheet *xslt, xmlDoc *indata_d,
* @return Returns a pointer to a new buffer containing the value on success, otherwise NULL.
* This memory buffer must be free'd after usage.
*/
-static inline char *sqldataValueHash(LogContext *log, xmlNode *sql_n) {
+char * sqldataValueHash(LogContext *log, xmlNode *sql_n) {
const char *hash = NULL, *isnull = NULL;
SHA1Context shactx;
uint8_t shahash[SHA1_HASH_SIZE];
char *ret = NULL, *ptr = NULL;
int i;
- if( !sql_n || (xmlStrcmp(sql_n->name, (xmlChar *) "value") != 0)
- || (xmlStrcmp(sql_n->parent->name, (xmlChar *) "record") != 0) ) {
- return NULL;
+ if( !(sql_n && (xmlStrcmp(sql_n->name, (xmlChar *) "value") == 0)
+ && (xmlStrcmp(sql_n->parent->name, (xmlChar *) "record") == 0)
+ || (xmlStrcmp(sql_n->parent->name, (xmlChar *) "value") == 0)) ) {
+ return NULL;
}
isnull = xmlGetAttrValue(sql_n->properties, "isnull");
@@ -214,6 +249,27 @@ static inline char *sqldataValueHash(LogContext *log, xmlNode *sql_n) {
/**
+ * Extract the content of a //sqldata/records/record/value[@type='array']/value node set
+ * and format it in suitable array format for the database backend.
+ *
+ * @param log Log context
+ * @param sql_n sqldata values node containing the value to extract and format as an array.
+ *
+ * @return Returns a pointer to a new memory buffer containing the value as a string.
+ * On errors, NULL is returned. This memory buffer must be free'd after usage.
+ */
+static char * sqldataValueArray(LogContext *log, xmlNode *sql_n)
+{
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return NULL;
+ }
+
+ return xmlparser_dbhelpers->dbh_FormatArray(log, sql_n);
+}
+
+
+/**
* Extract the content of a '//sqldata/records/record/value' node. It will consider
* both the 'hash' and 'type' attributes of the 'value' tag.
*
@@ -226,6 +282,11 @@ static inline char *sqldataValueHash(LogContext *log, xmlNode *sql_n) {
char *sqldataExtractContent(LogContext *log, xmlNode *sql_n) {
const char *valtype = xmlGetAttrValue(sql_n->properties, "type");
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return NULL;
+ }
+
if( !sql_n || (xmlStrcmp(sql_n->name, (xmlChar *) "value") != 0)
|| (xmlStrcmp(sql_n->parent->name, (xmlChar *) "record") != 0) ) {
return NULL;
@@ -239,6 +300,8 @@ char *sqldataExtractContent(LogContext *log, xmlNode *sql_n) {
chld_n = chld_n->next;
}
return xmlNodeToString(log, chld_n);
+ } else if( valtype && (strcmp(valtype, "array") == 0) ) {
+ return sqldataValueArray(log, sql_n);
} else {
return sqldataValueHash(log, sql_n);
}
@@ -259,6 +322,11 @@ char *sqldataExtractContent(LogContext *log, xmlNode *sql_n) {
int sqldataGetFid(LogContext *log, xmlNode *sql_n, const char *fname) {
xmlNode *f_n = NULL;
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return -2;
+ }
+
if( !sql_n || (xmlStrcmp(sql_n->name, (xmlChar *) "sqldata") != 0) ) {
writelog(log, LOG_ERR,
"sqldataGetFid: Input XML document is not a valid sqldata document");
@@ -310,6 +378,11 @@ char *sqldataGetValue(LogContext *log, xmlDoc *sqld, const char *fname, int reci
xmlNode *r_n = NULL;
int fid = -3, rc = 0;
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return NULL;
+ }
+
if( recid < 0 ) {
writelog(log, LOG_ERR, "sqldataGetValue: Invalid recid");
return NULL;
@@ -384,6 +457,11 @@ xmlDoc *sqldataGetHostInfo(LogContext *log, xsltStylesheet *xslt, xmlDoc *summar
xmlDoc *hostinfo_d = NULL;
parseParams prms;
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return NULL;
+ }
+
memset(&prms, 0, sizeof(parseParams));
prms.table = "systems_hostname";
prms.syskey = syskey;
@@ -423,6 +501,11 @@ int sqldataGetRequiredSchemaVer(LogContext *log, xmlNode *sqldata_root)
char *schver = NULL, *cp = NULL, *ptr = NULL;
int majv = 0, minv = 0;
+ if( xmlparser_dbhelpers == NULL ) {
+ writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised");
+ return -1;
+ }
+
if( !sqldata_root || (xmlStrcmp(sqldata_root->name, (xmlChar *) "sqldata") != 0) ) {
writelog(log, LOG_ERR, "sqldataGetRequiredSchemaVer: Invalid document node");
return -1;
diff --git a/server/parser/xmlparser.h b/server/parser/xmlparser.h
index f903037..79c79a1 100644
--- a/server/parser/xmlparser.h
+++ b/server/parser/xmlparser.h
@@ -39,6 +39,16 @@ typedef struct {
unsigned int rterid; /**< References rtevalruns.rterid */
} parseParams;
+
+/**
+ * Database specific helper functions
+ */
+typedef struct {
+ char *(*dbh_FormatArray)(LogContext *log, xmlNode *sql_n); /** Formats data as arrays */
+} dbhelper_func;
+
+void init_xmlparser(dbhelper_func const * dbhelpers);
+char * sqldataValueHash(LogContext *log, xmlNode *sql_n);
xmlDoc *parseToSQLdata(LogContext *log, xsltStylesheet *xslt, xmlDoc *indata_d, parseParams *params);
char *sqldataExtractContent(LogContext *log, xmlNode *sql_n);
int sqldataGetFid(LogContext *log, xmlNode *sqld, const char *fname);
@@ -46,4 +56,5 @@ char *sqldataGetValue(LogContext *log, xmlDoc *sqld, const char *fname, int reci
xmlDoc *sqldataGetHostInfo(LogContext *log, xsltStylesheet *xslt, xmlDoc *summaryxml,
int syskey, char **hostname, char **ipaddr);
int sqldataGetRequiredSchemaVer(LogContext *log, xmlNode *sqldata_root);
+
#endif
diff --git a/server/parser/xmlparser.xsl b/server/parser/xmlparser.xsl
index 4330fec..2ee9370 100644
--- a/server/parser/xmlparser.xsl
+++ b/server/parser/xmlparser.xsl
@@ -23,6 +23,9 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
+ <!-- Used for iterating CPU topology information -->
+ <xsl:key name="pkgkey" match="cpu" use="@physical_package_id"/>
+
<xsl:template match="/rteval">
<xsl:choose>
<!-- TABLE: systems -->
@@ -132,13 +135,15 @@
<xsl:text>Invalid 'rterid' parameter value: </xsl:text><xsl:value-of select="$rterid"/>
</xsl:message>
</xsl:if>
- <sqldata schemaver="1.2" table="rtevalruns_details">
+ <sqldata schemaver="1.4" table="rtevalruns_details">
<fields>
<field fid="0">rterid</field>
<field fid="1">numa_nodes</field>
<field fid="2">num_cpu_cores</field>
<field fid="3">num_cpu_sockets</field>
<field fid="4">xmldata</field>
+ <field fid="5">annotation</field>
+ <field fid="6">cpu_core_spread</field>
</fields>
<records>
<record>
@@ -159,12 +164,20 @@
</value>
<value fid="4" type="xmlblob">
<rteval_details>
- <xsl:copy-of select="clocksource|services|kthreads|network_config|loads|cyclictest/command_line|run_info/annotate"/>
+ <xsl:copy-of select="clocksource|services|kthreads|network_config|loads|cyclictest/command_line"/>
<hardware>
<xsl:copy-of select="hardware/memory_size|hardware/cpu_topology"/>
</hardware>
</rteval_details>
</value>
+ <value fid="5"><xsl:value-of select="run_info/annotate"/></value>
+ <value fid="6" type="array">
+ <xsl:for-each select="hardware/cpu_topology/cpu[generate-id() = generate-id(key('pkgkey', @physical_package_id)[1])]">
+ <xsl:call-template name="count_core_spread">
+ <xsl:with-param name="pkgid" select="@physical_package_id"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </value>
</record>
</records>
</sqldata>
@@ -288,4 +301,12 @@
<value fid="3"><xsl:value-of select="@value"/></value>
</record>
</xsl:template>
+
+ <!-- Helper "function" for generating a core per physical socket spread overview -->
+ <xsl:template name="count_core_spread">
+ <xsl:param name="pkgid"/>
+ <value>
+ <xsl:value-of select="count(/rteval/hardware/cpu_topology/cpu[@physical_package_id = $pkgid])"/>
+ </value>
+ </xsl:template>
</xsl:stylesheet>
diff --git a/server/rteval-parser.spec b/server/rteval-parser.spec
index 3e6dac8..a348b01 100644
--- a/server/rteval-parser.spec
+++ b/server/rteval-parser.spec
@@ -1,6 +1,6 @@
Name: rteval-parser
-Version: 1.3
-%define sqlschemaver 1.2
+Version: 1.5
+%define sqlschemaver 1.4
Release: 1%{?dist}
Summary: Report parser daemon for rteval XML-RPC
%define pkgname rteval-xmlrpc-%{version}
@@ -12,7 +12,7 @@ Source0: %{pkgname}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: postgresql-devel libxml2-devel libxslt-devel
-Requires: postgresql httpd mod_python
+Requires: postgresql httpd mod_wsgi
Requires(post): chkconfig
Requires(preun): chkconfig
Requires(preun): /sbin/service
@@ -87,6 +87,14 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Fri Oct 7 2011 David Sommerseth <dazo@users.sourceforge.net> - 1.5-1
+- Added support for storing data as arrays in PostgreSQL
+- Updated SQL schema to store CPU topology/core spread as an array in the database
+
+* Fri Feb 4 2011 David Sommerseth <dazo@users.sourceforge.net> - 1.4-1
+- Added support for mod_wsgi
+- Updated SQL schema, to add rteval annotations to an explicit database column
+
* Fri Apr 9 2010 David Sommerseth <davids@redhat.com> - 1.3-1
- Updated XML-RPC server, added Hello method
diff --git a/server/rteval_xmlrpc.wsgi b/server/rteval_xmlrpc.wsgi
new file mode 100644
index 0000000..f782657
--- /dev/null
+++ b/server/rteval_xmlrpc.wsgi
@@ -0,0 +1,113 @@
+#
+# rteval_xmlrpc.wsgi
+# XML-RPC handler for the rteval server, using mod_wsgi
+#
+# Copyright 2011 David Sommerseth <davids@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# For the avoidance of doubt the "preferred form" of this code is one which
+# is in an open unpatent encumbered format. Where cryptographic key signing
+# forms part of the process of creating an executable the information
+# including keys needed to generate an equivalently functional executable
+# are deemed to be part of the source code.
+#
+
+from wsgiref.simple_server import make_server
+import types
+from xmlrpclib import dumps, loads, Fault
+from xmlrpc_API1 import XMLRPC_API1
+from rteval.rtevalConfig import rtevalConfig
+
+def rtevalXMLRPC_Dispatch(method, args):
+ # Default configuration
+ defcfg = {'xmlrpc_server': { 'datadir': './var/lib/rteval',
+ 'db_server': 'localhost',
+ 'db_port': 5432,
+ 'database': 'rteval',
+ 'db_username': 'rtevxmlrpc',
+ 'db_password': 'rtevaldb'
+ }
+ }
+
+ # Fetch configuration
+ cfg = rtevalConfig(defcfg)
+ cfg.Load(append=True)
+
+ # Prepare an object for executing the query
+ xmlrpc = XMLRPC_API1(config=cfg.GetSection('xmlrpc_server'))
+
+ # Exectute it
+ result = xmlrpc.Dispatch(method, args)
+
+ # Send the result
+ if type(result) == types.TupleType:
+ return dumps(result, None, methodresponse=1)
+ else:
+ return dumps((result,), None, methodresponse=1)
+
+
+def rtevalXMLRPC_handler(environ, start_response):
+
+ # the environment variable CONTENT_LENGTH may be empty or missing
+ try:
+ request_body_size = int(environ.get('CONTENT_LENGTH', 0))
+ except (ValueError):
+ request_body_size = 0
+
+ # When the method is POST the query string will be sent
+ # in the HTTP request body which is passed by the WSGI server
+ # in the file like wsgi.input environment variable.
+ try:
+ if (environ['REQUEST_METHOD'] != 'POST') or (request_body_size < 1):
+ raise Exception('Error in request')
+
+ request_body = environ['wsgi.input'].read(request_body_size)
+ try:
+ args, method = loads(request_body)
+ except:
+ raise Exception('Invalid XML-RPC request')
+
+ # Execute the XML-RPC call
+ status = '200 OK'
+ cont_type = 'text/xml'
+ response = [rtevalXMLRPC_Dispatch(method, args)]
+ except Exception, ex:
+ status = '500 Internal server error: %s' % str(ex)
+ cont_type = 'text/plain'
+ response = [
+ '500 Internal server error\n',
+ 'ERROR: %s' % str(ex)
+ ]
+ import traceback, sys
+ traceback.print_exc(file=sys.stderr)
+
+ response_headers = [('Content-Type', cont_type),
+ ('Content-Length', str(len("".join(response))))]
+ start_response(status, response_headers)
+ return response
+
+
+if __name__ == '__main__':
+ #
+ # Simple stand-alone XML-RPC server, if started manually
+ # Not suitable for production environments, but for testing
+ #
+ httpd = make_server('localhost', 65432, rtevalXMLRPC_handler)
+ try:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ print "\nShutting down"
+
diff --git a/server/rtevaldb.py b/server/rtevaldb.py
index 7a0ccaf..e778358 100644
--- a/server/rtevaldb.py
+++ b/server/rtevaldb.py
@@ -66,9 +66,11 @@ def database_status(config, debug=False, noaction=False):
return {"status": "Could not query database pgsql://%s:%s/%s" % (config.db_server,
config.db_port,
config.database)}
+ last_rterid = res['records'][0][1] and res['records'][0][1] or "(None)"
+ last_submid = res['records'][0][1] and res['records'][0][2] or "(None)"
return {"status": "OK",
"server_time": res['records'][0][0],
- "last_rterid": res['records'][0][1],
- "last_submid": res['records'][0][2]
+ "last_rterid": last_rterid,
+ "last_submid": last_submid
}
diff --git a/server/sql/delta-1.2_1.3.sql b/server/sql/delta-1.2_1.3.sql
new file mode 100644
index 0000000..b869756
--- /dev/null
+++ b/server/sql/delta-1.2_1.3.sql
@@ -0,0 +1,5 @@
+-- SQL delta update from rteval-1.2.sql to rteval-1.3.sql
+
+UPDATE rteval_info SET value = '1.3' WHERE key = 'sql_schema_ver';
+
+ALTER TABLE rtevalruns_details ADD COLUMN annotation TEXT;
diff --git a/server/sql/delta-1.3_1.4.sql b/server/sql/delta-1.3_1.4.sql
new file mode 100644
index 0000000..bfa4152
--- /dev/null
+++ b/server/sql/delta-1.3_1.4.sql
@@ -0,0 +1,5 @@
+-- SQL delta update from rteval-1.3.sql to rteval-1.4.sql
+
+UPDATE rteval_info SET value = '1.4' WHERE key = 'sql_schema_ver';
+
+ALTER TABLE rtevalruns_details ADD COLUMN cpu_core_spread INTEGER[];
diff --git a/server/sql/rteval-1.3.sql b/server/sql/rteval-1.3.sql
new file mode 100644
index 0000000..0723cc1
--- /dev/null
+++ b/server/sql/rteval-1.3.sql
@@ -0,0 +1,206 @@
+-- Create rteval database users
+--
+CREATE USER rtevxmlrpc NOSUPERUSER ENCRYPTED PASSWORD 'rtevaldb';
+CREATE USER rtevparser NOSUPERUSER ENCRYPTED PASSWORD 'rtevaldb_parser';
+
+-- Create rteval database
+--
+CREATE DATABASE rteval ENCODING 'utf-8';
+
+\c rteval
+
+-- TABLE: rteval_info
+-- Contains information the current rteval XML-RPC and parser installation
+--
+ CREATE TABLE rteval_info (
+ key varchar(32) NOT NULL,
+ value TEXT NOT NULL,
+ rtiid SERIAL,
+ PRIMARY KEY(rtiid)
+ );
+ GRANT SELECT ON rteval_info TO rtevparser;
+ INSERT INTO rteval_info (key, value) VALUES ('sql_schema_ver','1.3');
+
+-- Enable plpgsql. It is expected that this PL/pgSQL is available.
+ CREATE LANGUAGE 'plpgsql';
+
+-- FUNCTION: trgfnc_submqueue_notify
+-- Trigger function which is called on INSERT queries to the submissionqueue table.
+-- It will send a NOTIFY rteval_submq on INSERTs.
+--
+ CREATE FUNCTION trgfnc_submqueue_notify() RETURNS TRIGGER
+ AS $BODY$
+ DECLARE
+ BEGIN
+ NOTIFY rteval_submq;
+ RETURN NEW;
+ END
+ $BODY$ LANGUAGE 'plpgsql';
+
+ -- The user(s) which are allowed to do INSERT on the submissionqueue
+ -- must also be allowed to call this trigger function.
+ GRANT EXECUTE ON FUNCTION trgfnc_submqueue_notify() TO rtevxmlrpc;
+
+-- TABLE: submissionqueue
+-- All XML-RPC clients registers their submissions into this table. Another parser thread
+-- will pickup the records where parsestart IS NULL.
+--
+ CREATE TABLE submissionqueue (
+ clientid varchar(128) NOT NULL,
+ filename VARCHAR(1024) NOT NULL,
+ status INTEGER DEFAULT '0',
+ received TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+ parsestart TIMESTAMP WITH TIME ZONE,
+ parseend TIMESTAMP WITH TIME ZONE,
+ submid SERIAL,
+ PRIMARY KEY(submid)
+ ) WITH OIDS;
+ CREATE INDEX submissionq_status ON submissionqueue(status);
+
+ CREATE TRIGGER trg_submissionqueue AFTER INSERT
+ ON submissionqueue FOR EACH STATEMENT
+ EXECUTE PROCEDURE trgfnc_submqueue_notify();
+
+ GRANT SELECT, INSERT ON submissionqueue TO rtevxmlrpc;
+ GRANT USAGE ON submissionqueue_submid_seq TO rtevxmlrpc;
+ GRANT SELECT, UPDATE ON submissionqueue TO rtevparser;
+
+-- TABLE: systems
+-- Overview table over all systems which have sent reports
+-- The dmidata column will keep the complete DMIdata available
+-- for further information about the system.
+--
+ CREATE TABLE systems (
+ syskey SERIAL NOT NULL,
+ sysid VARCHAR(64) NOT NULL,
+ dmidata xml NOT NULL,
+ PRIMARY KEY(syskey)
+ ) WITH OIDS;
+
+ GRANT SELECT,INSERT ON systems TO rtevparser;
+ GRANT USAGE ON systems_syskey_seq TO rtevparser;
+
+-- TABLE: systems_hostname
+-- This table is used to track the hostnames and IP addresses
+-- a registered system have used over time
+--
+ CREATE TABLE systems_hostname (
+ syskey INTEGER REFERENCES systems(syskey) NOT NULL,
+ hostname VARCHAR(256) NOT NULL,
+ ipaddr cidr
+ ) WITH OIDS;
+ CREATE INDEX systems_hostname_syskey ON systems_hostname(syskey);
+ CREATE INDEX systems_hostname_hostname ON systems_hostname(hostname);
+ CREATE INDEX systems_hostname_ipaddr ON systems_hostname(ipaddr);
+
+ GRANT SELECT, INSERT ON systems_hostname TO rtevparser;
+
+
+-- TABLE: rtevalruns
+-- Overview over all rteval runs, when they were run and how long they ran.
+--
+ CREATE TABLE rtevalruns (
+ rterid SERIAL NOT NULL, -- RTEval Run Id
+ submid INTEGER REFERENCES submissionqueue(submid) NOT NULL,
+ syskey INTEGER REFERENCES systems(syskey) NOT NULL,
+ kernel_ver VARCHAR(32) NOT NULL,
+ kernel_rt BOOLEAN NOT NULL,
+ arch VARCHAR(12) NOT NULL,
+ distro VARCHAR(64),
+ run_start TIMESTAMP WITH TIME ZONE NOT NULL,
+ run_duration INTEGER NOT NULL,
+ load_avg REAL NOT NULL,
+ version VARCHAR(4), -- Version of rteval
+ report_filename TEXT,
+ PRIMARY KEY(rterid)
+ ) WITH OIDS;
+
+ GRANT SELECT,INSERT ON rtevalruns TO rtevparser;
+ GRANT USAGE ON rtevalruns_rterid_seq TO rtevparser;
+
+-- TABLE rtevalruns_details
+-- More specific information on the rteval run. The data is stored
+-- in XML for flexibility
+--
+-- Tags being saved here includes: /rteval/clocksource, /rteval/hardware,
+-- /rteval/loads and /rteval/cyclictest/command_line
+--
+ CREATE TABLE rtevalruns_details (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ annotation TEXT,
+ num_cpu_cores INTEGER,
+ num_cpu_sockets INTEGER,
+ numa_nodes INTEGER,
+ xmldata xml NOT NULL,
+ PRIMARY KEY(rterid)
+ );
+ GRANT INSERT ON rtevalruns_details TO rtevparser;
+
+-- TABLE: cyclic_statistics
+-- This table keeps statistics overview over a particular rteval run
+--
+ CREATE TABLE cyclic_statistics (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ coreid INTEGER, -- NULL=system
+ priority INTEGER, -- NULL=system
+ num_samples BIGINT NOT NULL,
+ lat_min REAL NOT NULL,
+ lat_max REAL NOT NULL,
+ lat_mean REAL NOT NULL,
+ mode REAL NOT NULL,
+ range REAL NOT NULL,
+ median REAL NOT NULL,
+ stddev REAL NOT NULL,
+ mean_abs_dev REAL NOT NULL,
+ variance REAL NOT NULL,
+ cstid SERIAL NOT NULL, -- unique record ID
+ PRIMARY KEY(cstid)
+ ) WITH OIDS;
+ CREATE INDEX cyclic_statistics_rterid ON cyclic_statistics(rterid);
+
+ GRANT INSERT ON cyclic_statistics TO rtevparser;
+ GRANT USAGE ON cyclic_statistics_cstid_seq TO rtevparser;
+
+-- TABLE: cyclic_histogram
+-- This table keeps the raw histogram data for each rteval run being
+-- reported.
+--
+ CREATE TABLE cyclic_histogram (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ core INTEGER, -- NULL=system
+ index INTEGER NOT NULL,
+ value BIGINT NOT NULL
+ ) WITHOUT OIDS;
+ CREATE INDEX cyclic_histogram_rterid ON cyclic_histogram(rterid);
+
+ GRANT INSERT ON cyclic_histogram TO rtevparser;
+
+-- TABLE: cyclic_rawdata
+-- This table keeps the raw data for each rteval run being reported.
+-- Due to that it will be an enormous amount of data, we avoid using
+-- OID on this table.
+--
+ CREATE TABLE cyclic_rawdata (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ cpu_num INTEGER NOT NULL,
+ sampleseq INTEGER NOT NULL,
+ latency REAL NOT NULL
+ ) WITHOUT OIDS;
+ CREATE INDEX cyclic_rawdata_rterid ON cyclic_rawdata(rterid);
+
+ GRANT INSERT ON cyclic_rawdata TO rtevparser;
+
+-- TABLE: notes
+-- This table is purely to make notes, connected to different
+-- records in the database
+--
+ CREATE TABLE notes (
+ ntid SERIAL NOT NULL,
+ reftbl CHAR NOT NULL, -- S=systems, R=rtevalruns
+ refid INTEGER NOT NULL, -- reference id, to the corresponding table
+ notes TEXT NOT NULL,
+ createdby VARCHAR(48),
+ created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(ntid)
+ ) WITH OIDS;
+ CREATE INDEX notes_refid ON notes(reftbl,refid);
diff --git a/server/sql/rteval-1.4.sql b/server/sql/rteval-1.4.sql
new file mode 100644
index 0000000..048600c
--- /dev/null
+++ b/server/sql/rteval-1.4.sql
@@ -0,0 +1,207 @@
+-- Create rteval database users
+--
+CREATE USER rtevxmlrpc NOSUPERUSER ENCRYPTED PASSWORD 'rtevaldb';
+CREATE USER rtevparser NOSUPERUSER ENCRYPTED PASSWORD 'rtevaldb_parser';
+
+-- Create rteval database
+--
+CREATE DATABASE rteval ENCODING 'utf-8';
+
+\c rteval
+
+-- TABLE: rteval_info
+-- Contains information the current rteval XML-RPC and parser installation
+--
+ CREATE TABLE rteval_info (
+ key varchar(32) NOT NULL,
+ value TEXT NOT NULL,
+ rtiid SERIAL,
+ PRIMARY KEY(rtiid)
+ );
+ GRANT SELECT ON rteval_info TO rtevparser;
+ INSERT INTO rteval_info (key, value) VALUES ('sql_schema_ver','1.4');
+
+-- Enable plpgsql. It is expected that this PL/pgSQL is available.
+ CREATE LANGUAGE 'plpgsql';
+
+-- FUNCTION: trgfnc_submqueue_notify
+-- Trigger function which is called on INSERT queries to the submissionqueue table.
+-- It will send a NOTIFY rteval_submq on INSERTs.
+--
+ CREATE FUNCTION trgfnc_submqueue_notify() RETURNS TRIGGER
+ AS $BODY$
+ DECLARE
+ BEGIN
+ NOTIFY rteval_submq;
+ RETURN NEW;
+ END
+ $BODY$ LANGUAGE 'plpgsql';
+
+ -- The user(s) which are allowed to do INSERT on the submissionqueue
+ -- must also be allowed to call this trigger function.
+ GRANT EXECUTE ON FUNCTION trgfnc_submqueue_notify() TO rtevxmlrpc;
+
+-- TABLE: submissionqueue
+-- All XML-RPC clients registers their submissions into this table. Another parser thread
+-- will pickup the records where parsestart IS NULL.
+--
+ CREATE TABLE submissionqueue (
+ clientid varchar(128) NOT NULL,
+ filename VARCHAR(1024) NOT NULL,
+ status INTEGER DEFAULT '0',
+ received TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+ parsestart TIMESTAMP WITH TIME ZONE,
+ parseend TIMESTAMP WITH TIME ZONE,
+ submid SERIAL,
+ PRIMARY KEY(submid)
+ ) WITH OIDS;
+ CREATE INDEX submissionq_status ON submissionqueue(status);
+
+ CREATE TRIGGER trg_submissionqueue AFTER INSERT
+ ON submissionqueue FOR EACH STATEMENT
+ EXECUTE PROCEDURE trgfnc_submqueue_notify();
+
+ GRANT SELECT, INSERT ON submissionqueue TO rtevxmlrpc;
+ GRANT USAGE ON submissionqueue_submid_seq TO rtevxmlrpc;
+ GRANT SELECT, UPDATE ON submissionqueue TO rtevparser;
+
+-- TABLE: systems
+-- Overview table over all systems which have sent reports
+-- The dmidata column will keep the complete DMIdata available
+-- for further information about the system.
+--
+ CREATE TABLE systems (
+ syskey SERIAL NOT NULL,
+ sysid VARCHAR(64) NOT NULL,
+ dmidata xml NOT NULL,
+ PRIMARY KEY(syskey)
+ ) WITH OIDS;
+
+ GRANT SELECT,INSERT ON systems TO rtevparser;
+ GRANT USAGE ON systems_syskey_seq TO rtevparser;
+
+-- TABLE: systems_hostname
+-- This table is used to track the hostnames and IP addresses
+-- a registered system have used over time
+--
+ CREATE TABLE systems_hostname (
+ syskey INTEGER REFERENCES systems(syskey) NOT NULL,
+ hostname VARCHAR(256) NOT NULL,
+ ipaddr cidr
+ ) WITH OIDS;
+ CREATE INDEX systems_hostname_syskey ON systems_hostname(syskey);
+ CREATE INDEX systems_hostname_hostname ON systems_hostname(hostname);
+ CREATE INDEX systems_hostname_ipaddr ON systems_hostname(ipaddr);
+
+ GRANT SELECT, INSERT ON systems_hostname TO rtevparser;
+
+
+-- TABLE: rtevalruns
+-- Overview over all rteval runs, when they were run and how long they ran.
+--
+ CREATE TABLE rtevalruns (
+ rterid SERIAL NOT NULL, -- RTEval Run Id
+ submid INTEGER REFERENCES submissionqueue(submid) NOT NULL,
+ syskey INTEGER REFERENCES systems(syskey) NOT NULL,
+ kernel_ver VARCHAR(32) NOT NULL,
+ kernel_rt BOOLEAN NOT NULL,
+ arch VARCHAR(12) NOT NULL,
+ distro VARCHAR(64),
+ run_start TIMESTAMP WITH TIME ZONE NOT NULL,
+ run_duration INTEGER NOT NULL,
+ load_avg REAL NOT NULL,
+ version VARCHAR(4), -- Version of rteval
+ report_filename TEXT,
+ PRIMARY KEY(rterid)
+ ) WITH OIDS;
+
+ GRANT SELECT,INSERT ON rtevalruns TO rtevparser;
+ GRANT USAGE ON rtevalruns_rterid_seq TO rtevparser;
+
+-- TABLE rtevalruns_details
+-- More specific information on the rteval run. The data is stored
+-- in XML for flexibility
+--
+-- Tags being saved here includes: /rteval/clocksource, /rteval/hardware,
+-- /rteval/loads and /rteval/cyclictest/command_line
+--
+ CREATE TABLE rtevalruns_details (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ annotation TEXT,
+ num_cpu_cores INTEGER,
+ num_cpu_sockets INTEGER,
+ cpu_core_spread INTEGER[],
+ numa_nodes INTEGER,
+ xmldata xml NOT NULL,
+ PRIMARY KEY(rterid)
+ );
+ GRANT INSERT ON rtevalruns_details TO rtevparser;
+
+-- TABLE: cyclic_statistics
+-- This table keeps statistics overview over a particular rteval run
+--
+ CREATE TABLE cyclic_statistics (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ coreid INTEGER, -- NULL=system
+ priority INTEGER, -- NULL=system
+ num_samples BIGINT NOT NULL,
+ lat_min REAL NOT NULL,
+ lat_max REAL NOT NULL,
+ lat_mean REAL NOT NULL,
+ mode REAL NOT NULL,
+ range REAL NOT NULL,
+ median REAL NOT NULL,
+ stddev REAL NOT NULL,
+ mean_abs_dev REAL NOT NULL,
+ variance REAL NOT NULL,
+ cstid SERIAL NOT NULL, -- unique record ID
+ PRIMARY KEY(cstid)
+ ) WITH OIDS;
+ CREATE INDEX cyclic_statistics_rterid ON cyclic_statistics(rterid);
+
+ GRANT INSERT ON cyclic_statistics TO rtevparser;
+ GRANT USAGE ON cyclic_statistics_cstid_seq TO rtevparser;
+
+-- TABLE: cyclic_histogram
+-- This table keeps the raw histogram data for each rteval run being
+-- reported.
+--
+ CREATE TABLE cyclic_histogram (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ core INTEGER, -- NULL=system
+ index INTEGER NOT NULL,
+ value BIGINT NOT NULL
+ ) WITHOUT OIDS;
+ CREATE INDEX cyclic_histogram_rterid ON cyclic_histogram(rterid);
+
+ GRANT INSERT ON cyclic_histogram TO rtevparser;
+
+-- TABLE: cyclic_rawdata
+-- This table keeps the raw data for each rteval run being reported.
+-- Due to that it will be an enormous amount of data, we avoid using
+-- OID on this table.
+--
+ CREATE TABLE cyclic_rawdata (
+ rterid INTEGER REFERENCES rtevalruns(rterid) NOT NULL,
+ cpu_num INTEGER NOT NULL,
+ sampleseq INTEGER NOT NULL,
+ latency REAL NOT NULL
+ ) WITHOUT OIDS;
+ CREATE INDEX cyclic_rawdata_rterid ON cyclic_rawdata(rterid);
+
+ GRANT INSERT ON cyclic_rawdata TO rtevparser;
+
+-- TABLE: notes
+-- This table is purely to make notes, connected to different
+-- records in the database
+--
+ CREATE TABLE notes (
+ ntid SERIAL NOT NULL,
+ reftbl CHAR NOT NULL, -- S=systems, R=rtevalruns
+ refid INTEGER NOT NULL, -- reference id, to the corresponding table
+ notes TEXT NOT NULL,
+ createdby VARCHAR(48),
+ created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(ntid)
+ ) WITH OIDS;
+ CREATE INDEX notes_refid ON notes(reftbl,refid);
diff --git a/server/xmlrpc_API1.py b/server/xmlrpc_API1.py
index 71e23d6..064f1b2 100644
--- a/server/xmlrpc_API1.py
+++ b/server/xmlrpc_API1.py
@@ -45,6 +45,8 @@ class XMLRPC_API1():
def __mkdatadir(self, dirpath):
startdir = os.getcwd()
+ if dirpath[0] == '/':
+ os.chdir('/')
for dir in dirpath.split("/"):
if dir is '':
continue