mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
- merge trac #191 (Implement a initial version of stats)
- remove obsoleted stats files git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@3218 e5f2f494-b856-4b98-b285-d166d9295462
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
109. [func] naokikambe
|
||||
Added the initial version of the stats module for the statistics
|
||||
feature of BIND 10, which supports the restricted features and
|
||||
items and reports via bindctl command (Trac #191, rXXXX)
|
||||
Added the document of the stats module, which is about how stats
|
||||
module collects the data (Trac #170, [wiki:StatsModule])
|
||||
|
||||
108. [func] jerry
|
||||
src/bin/zonemgr: Provide customizable configurations for
|
||||
lowerbound_refresh, lowerbound_retry, max_transfer_timeout and
|
||||
|
11
configure.ac
11
configure.ac
@@ -471,6 +471,8 @@ AC_CONFIG_FILES([Makefile
|
||||
src/bin/xfrout/tests/Makefile
|
||||
src/bin/zonemgr/Makefile
|
||||
src/bin/zonemgr/tests/Makefile
|
||||
src/bin/stats/Makefile
|
||||
src/bin/stats/tests/Makefile
|
||||
src/bin/usermgr/Makefile
|
||||
src/bin/tests/Makefile
|
||||
src/lib/Makefile
|
||||
@@ -523,6 +525,12 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
|
||||
src/bin/zonemgr/zonemgr.spec.pre
|
||||
src/bin/zonemgr/tests/zonemgr_test
|
||||
src/bin/zonemgr/run_b10-zonemgr.sh
|
||||
src/bin/stats/stats.py
|
||||
src/bin/stats/stats_stub.py
|
||||
src/bin/stats/stats.spec.pre
|
||||
src/bin/stats/run_b10-stats.sh
|
||||
src/bin/stats/run_b10-stats_stub.sh
|
||||
src/bin/stats/tests/stats_test
|
||||
src/bin/bind10/bind10.py
|
||||
src/bin/bind10/tests/bind10_test
|
||||
src/bin/bind10/run_bind10.sh
|
||||
@@ -556,6 +564,9 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
|
||||
chmod +x src/bin/xfrin/run_b10-xfrin.sh
|
||||
chmod +x src/bin/xfrout/run_b10-xfrout.sh
|
||||
chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
|
||||
chmod +x src/bin/stats/tests/stats_test
|
||||
chmod +x src/bin/stats/run_b10-stats.sh
|
||||
chmod +x src/bin/stats/run_b10-stats_stub.sh
|
||||
chmod +x src/bin/bind10/run_bind10.sh
|
||||
chmod +x src/bin/cmdctl/tests/cmdctl_test
|
||||
chmod +x src/bin/xfrin/tests/xfrin_test
|
||||
|
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout \
|
||||
usermgr zonemgr tests
|
||||
usermgr zonemgr stats tests
|
||||
|
||||
check-recursive: all-recursive
|
||||
|
@@ -73,6 +73,9 @@ isc.utils.process.rename(sys.argv[0])
|
||||
# number, and the overall BIND 10 version number (set in configure.ac).
|
||||
VERSION = "bind10 20100916 (BIND 10 @PACKAGE_VERSION@)"
|
||||
|
||||
# This is for bind10.boottime of stats module
|
||||
_BASETIME = time.gmtime()
|
||||
|
||||
class RestartSchedule:
|
||||
"""
|
||||
Keeps state when restarting something (in this case, a process).
|
||||
@@ -424,6 +427,27 @@ class BoB:
|
||||
sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" %
|
||||
zonemgr.pid)
|
||||
|
||||
# start b10-stats
|
||||
stats_args = ['b10-stats']
|
||||
if self.verbose:
|
||||
sys.stdout.write("[bind10] Starting b10-stats\n")
|
||||
stats_args += ['-v']
|
||||
try:
|
||||
statsd = ProcessInfo("b10-stats", stats_args,
|
||||
c_channel_env)
|
||||
except Exception as e:
|
||||
c_channel.process.kill()
|
||||
bind_cfgd.process.kill()
|
||||
xfrout.process.kill()
|
||||
auth.process.kill()
|
||||
xfrind.process.kill()
|
||||
zonemgr.process.kill()
|
||||
return "Unable to start b10-stats; " + str(e)
|
||||
|
||||
self.processes[statsd.pid] = statsd
|
||||
if self.verbose:
|
||||
sys.stdout.write("[bind10] Started b10-stats (PID %d)\n" % statsd.pid)
|
||||
|
||||
# start the b10-cmdctl
|
||||
# XXX: we hardcode port 8080
|
||||
cmdctl_args = ['b10-cmdctl']
|
||||
@@ -440,6 +464,7 @@ class BoB:
|
||||
auth.process.kill()
|
||||
xfrind.process.kill()
|
||||
zonemgr.process.kill()
|
||||
statsd.process.kill()
|
||||
return "Unable to start b10-cmdctl; " + str(e)
|
||||
self.processes[cmd_ctrld.pid] = cmd_ctrld
|
||||
if self.verbose:
|
||||
@@ -459,6 +484,7 @@ class BoB:
|
||||
self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
|
||||
self.cc_session.group_sendmsg(cmd, "Boss", "Xfrin")
|
||||
self.cc_session.group_sendmsg(cmd, "Boss", "Zonemgr")
|
||||
self.cc_session.group_sendmsg(cmd, "Boss", "Stats")
|
||||
|
||||
def stop_process(self, process):
|
||||
"""Stop the given process, friendly-like."""
|
||||
@@ -723,6 +749,17 @@ def main():
|
||||
sys.exit(1)
|
||||
sys.stdout.write("[bind10] BIND 10 started\n")
|
||||
|
||||
# send "bind10.boot_time" to b10-stats
|
||||
time.sleep(1) # wait a second
|
||||
if options.verbose:
|
||||
sys.stdout.write("[bind10] send \"bind10.boot_time\" to b10-stats\n")
|
||||
cmd = isc.config.ccsession.create_command('set',
|
||||
{ "stats_data": {
|
||||
'bind10.boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
|
||||
}
|
||||
})
|
||||
boss_of_bind.cc_session.group_sendmsg(cmd, 'Stats')
|
||||
|
||||
# In our main loop, we check for dead processes or messages
|
||||
# on the c-channel.
|
||||
wakeup_fd = wakeup_pipe[0]
|
||||
|
@@ -20,7 +20,7 @@ export PYTHON_EXEC
|
||||
|
||||
BIND10_PATH=@abs_top_builddir@/src/bin/bind10
|
||||
|
||||
PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
|
||||
PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
|
||||
export PATH
|
||||
|
||||
PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs
|
||||
|
37
src/bin/stats/Makefile.am
Normal file
37
src/bin/stats/Makefile.am
Normal file
@@ -0,0 +1,37 @@
|
||||
SUBDIRS = tests
|
||||
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
|
||||
pkglibexec_SCRIPTS = b10-stats
|
||||
noinst_SCRIPTS = b10-stats_stub
|
||||
|
||||
b10_statsdir = $(DESTDIR)$(pkgdatadir)
|
||||
b10_stats_DATA = stats.spec
|
||||
|
||||
CLEANFILES = stats.spec b10-stats stats.pyc stats.pyo b10-stats_stub stats_stub.pyc stats_stub.pyo
|
||||
|
||||
man_MANS = b10-stats.8
|
||||
EXTRA_DIST = $(man_MANS) b10-stats.xml
|
||||
|
||||
if ENABLE_MAN
|
||||
|
||||
b10-stats.8: b10-stats.xml
|
||||
xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml
|
||||
|
||||
endif
|
||||
|
||||
stats.spec: stats.spec.pre
|
||||
$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats.spec.pre >$@
|
||||
|
||||
# TODO: does this need $$(DESTDIR) also?
|
||||
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
|
||||
b10-stats: stats.py
|
||||
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
|
||||
-e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" \
|
||||
-e "s|.*#@@REMOVED@@$$||" stats.py >$@
|
||||
chmod a+x $@
|
||||
|
||||
b10-stats_stub: stats_stub.py stats.py
|
||||
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
|
||||
-e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats_stub.py >$@
|
||||
chmod a+x $@
|
68
src/bin/stats/b10-stats.8
Normal file
68
src/bin/stats/b10-stats.8
Normal file
@@ -0,0 +1,68 @@
|
||||
'\" t
|
||||
.\" Title: b10-stats
|
||||
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
|
||||
.\" Date: Oct 15, 2010
|
||||
.\" Manual: BIND10
|
||||
.\" Source: BIND10
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "B10\-STATS" "8" "Oct 15, 2010" "BIND10" "BIND10"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
b10-stats \- BIND 10 statistics module
|
||||
.SH "SYNOPSIS"
|
||||
.HP \w'\fBb10\-stats\fR\ 'u
|
||||
\fBb10\-stats\fR [\fB\-v\fR] [\fB\-\-verbose\fR]
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
The
|
||||
\fBb10\-stats\fR
|
||||
is a daemon forked by
|
||||
\fBbind10\fR\&. Stats module collects statistics data from each module and reports statistics information via
|
||||
\fBbindctl\fR\&. It communicates by using the Command Channel by
|
||||
\fBb10\-msgq\fR
|
||||
with other modules like
|
||||
\fBbind10\fR,
|
||||
\fBb10\-auth\fR
|
||||
and so on\&. It waits for coming data from other modules, then other modules send data to stats module periodically\&. Other modules send stats data to stats module independently from implementation of stats module, so the frequency of sending data may not be constant\&. Stats module collects data and aggregates it\&.
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
The arguments are as follows:
|
||||
.PP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
.RS 4
|
||||
This
|
||||
\fBb10\-stats\fR
|
||||
switches to verbose mode\&. It sends verbose messages to STDOUT\&.
|
||||
.RE
|
||||
.SH "FILES"
|
||||
.PP
|
||||
/usr/local/share/bind10\-devel/stats\&.spec
|
||||
\(em This is a spec file for
|
||||
\fBb10\-stats\fR\&. It contains definitions of statistics items of BIND 10 and commands received vi bindctl\&.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
|
||||
\fBbind10\fR(8),
|
||||
\fBbindctl\fR(1),
|
||||
\fBb10-auth\fR(8),
|
||||
BIND 10 Guide\&.
|
||||
.SH "HISTORY"
|
||||
.PP
|
||||
The
|
||||
\fBb10\-stats\fR
|
||||
daemon was initially designed and implemented by Naoki Kambe of JPRS in Oct 2010\&.
|
||||
.SH "COPYRIGHT"
|
||||
.br
|
||||
Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
.br
|
124
src/bin/stats/b10-stats.xml
Normal file
124
src/bin/stats/b10-stats.xml
Normal file
@@ -0,0 +1,124 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
|
||||
[<!ENTITY mdash "—">]>
|
||||
<!--
|
||||
- Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
-
|
||||
- Permission to use, copy, modify, and/or distribute this software for any
|
||||
- purpose with or without fee is hereby granted, provided that the above
|
||||
- copyright notice and this permission notice appear in all copies.
|
||||
-
|
||||
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- $Id$ -->
|
||||
<refentry>
|
||||
|
||||
<refentryinfo>
|
||||
<date>Oct 15, 2010</date>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>b10-stats</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo>BIND10</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>b10-stats</refname>
|
||||
<refpurpose>BIND 10 statistics module</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<docinfo>
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<holder>Internet Systems Consortium, Inc. ("ISC")</holder>
|
||||
</copyright>
|
||||
</docinfo>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>b10-stats</command>
|
||||
<arg><option>-v</option></arg>
|
||||
<arg><option>--verbose</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
<para>
|
||||
The <command>b10-stats</command> is a daemon forked by
|
||||
<command>bind10</command>. Stats module collects statistics data
|
||||
from each module and reports statistics information
|
||||
via <command>bindctl</command>. It communicates by using the
|
||||
Command Channel by <command>b10-msgq</command> with other
|
||||
modules
|
||||
like <command>bind10</command>, <command>b10-auth</command> and
|
||||
so on. It waits for coming data from other modules, then other
|
||||
modules send data to stats module periodically. Other modules
|
||||
send stats data to stats module independently from
|
||||
implementation of stats module, so the frequency of sending data
|
||||
may not be constant. Stats module collects data and aggregates
|
||||
it.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
<para>The arguments are as follows:</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-v</option>, <option>--verbose</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This <command>b10-stats</command> switches to verbose
|
||||
mode. It sends verbose messages to STDOUT.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>FILES</title>
|
||||
<para><filename>/usr/local/share/bind10-devel/stats.spec</filename>
|
||||
— This is a spec file for <command>b10-stats</command>. It
|
||||
contains definitions of statistics items of BIND 10 and commands
|
||||
received vi bindctl.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citetitle>BIND 10 Guide</citetitle>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>HISTORY</title>
|
||||
<para>
|
||||
The <command>b10-stats</command> daemon was initially designed
|
||||
and implemented by Naoki Kambe of JPRS in Oct 2010.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry><!--
|
||||
- Local variables:
|
||||
- mode: sgml
|
||||
- End:
|
||||
-->
|
30
src/bin/stats/run_b10-stats.sh.in
Normal file
30
src/bin/stats/run_b10-stats.sh.in
Normal file
@@ -0,0 +1,30 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
|
||||
export PYTHON_EXEC
|
||||
|
||||
PYTHONPATH=@abs_top_builddir@/src/lib/python
|
||||
export PYTHONPATH
|
||||
|
||||
B10_FROM_BUILD=@abs_top_builddir@
|
||||
export B10_FROM_BUILD
|
||||
|
||||
STATS_PATH=@abs_top_builddir@/src/bin/stats
|
||||
|
||||
cd ${STATS_PATH}
|
||||
exec ${PYTHON_EXEC} -O b10-stats $*
|
30
src/bin/stats/run_b10-stats_stub.sh.in
Normal file
30
src/bin/stats/run_b10-stats_stub.sh.in
Normal file
@@ -0,0 +1,30 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
|
||||
export PYTHON_EXEC
|
||||
|
||||
PYTHONPATH=@abs_top_builddir@/src/lib/python
|
||||
export PYTHONPATH
|
||||
|
||||
B10_FROM_BUILD=@abs_top_srcdir@
|
||||
export B10_FROM_BUILD
|
||||
|
||||
STATS_PATH=@abs_top_builddir@/src/bin/stats
|
||||
|
||||
cd ${STATS_PATH}
|
||||
exec ${PYTHON_EXEC} -O b10-stats_stub $*
|
416
src/bin/stats/stats.py.in
Normal file
416
src/bin/stats/stats.py.in
Normal file
@@ -0,0 +1,416 @@
|
||||
#!@PYTHON@
|
||||
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
__version__ = "$Revision$"
|
||||
|
||||
import sys; sys.path.append ('@@PYTHONPATH@@')
|
||||
import os
|
||||
import signal
|
||||
import select
|
||||
from time import time, strftime, gmtime
|
||||
from optparse import OptionParser, OptionValueError
|
||||
from collections import defaultdict
|
||||
from isc.config.ccsession import ModuleCCSession, create_answer
|
||||
from isc.cc import Session, SessionError
|
||||
# Note: Following lines are removed in b10-stats #@@REMOVED@@
|
||||
if __name__ == 'stats': #@@REMOVED@@
|
||||
try: #@@REMOVED@@
|
||||
from fake_time import time, strftime, gmtime #@@REMOVED@@
|
||||
except ImportError: #@@REMOVED@@
|
||||
pass #@@REMOVED@@
|
||||
|
||||
# for setproctitle
|
||||
import isc.utils.process
|
||||
isc.utils.process.rename()
|
||||
|
||||
# If B10_FROM_BUILD is set in the environment, we use data files
|
||||
# from a directory relative to that, otherwise we use the ones
|
||||
# installed on the system
|
||||
if "B10_FROM_BUILD" in os.environ:
|
||||
SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
|
||||
else:
|
||||
PREFIX = "@prefix@"
|
||||
DATAROOTDIR = "@datarootdir@"
|
||||
SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
|
||||
|
||||
class Singleton(type):
|
||||
"""
|
||||
A abstract class of singleton pattern
|
||||
"""
|
||||
# Because of singleton pattern:
|
||||
# At the beginning of coding, one UNIX domain socket is needed
|
||||
# for config manager, another socket is needed for stats module,
|
||||
# then stats module might need two sockets. So I adopted the
|
||||
# singleton pattern because I avoid creating multiple sockets in
|
||||
# one stats module. But in the initial version stats module
|
||||
# reports only via bindctl, so just one socket is needed. To use
|
||||
# the singleton pattern is not important now. :(
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
type.__init__(self, *args, **kwargs)
|
||||
self._instances = {}
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
if args not in self._instances:
|
||||
self._instances[args]={}
|
||||
kw = tuple(kwargs.items())
|
||||
if kw not in self._instances[args]:
|
||||
self._instances[args][kw] = type.__call__(self, *args, **kwargs)
|
||||
return self._instances[args][kw]
|
||||
|
||||
class Callback():
|
||||
"""
|
||||
A Callback handler class
|
||||
"""
|
||||
def __init__(self, name=None, callback=None, args=(), kwargs={}):
|
||||
self.name = name
|
||||
self.callback = callback
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
if not args:
|
||||
args = self.args
|
||||
if not kwargs:
|
||||
kwargs = self.kwargs
|
||||
if self.callback:
|
||||
return self.callback(*args, **kwargs)
|
||||
|
||||
class Subject():
|
||||
"""
|
||||
A abstract subject class of observer pattern
|
||||
"""
|
||||
# Because of observer pattern:
|
||||
# In the initial release, I'm also sure that observer pattern
|
||||
# isn't definitely needed because the interface between gathering
|
||||
# and reporting statistics data is single. However in the future
|
||||
# release, the interfaces may be multiple, that is, multiple
|
||||
# listeners may be needed. For example, one interface, which
|
||||
# stats module has, is for between ''config manager'' and stats
|
||||
# module, another interface is for between ''HTTP server'' and
|
||||
# stats module, and one more interface is for between ''SNMP
|
||||
# server'' and stats module. So by considering that stats module
|
||||
# needs multiple interfaces in the future release, I adopted the
|
||||
# observer pattern in stats module. But I don't have concrete
|
||||
# ideas in case of multiple listener currently.
|
||||
|
||||
def __init__(self):
|
||||
self._listeners = []
|
||||
|
||||
def attach(self, listener):
|
||||
if not listener in self._listeners:
|
||||
self._listeners.append(listener)
|
||||
|
||||
def detach(self, listener):
|
||||
try:
|
||||
self._listeners.remove(listener)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def notify(self, event, modifier=None):
|
||||
for listener in self._listeners:
|
||||
if modifier != listener:
|
||||
listener.update(event)
|
||||
|
||||
class Listener():
|
||||
"""
|
||||
A abstract listener class of observer pattern
|
||||
"""
|
||||
def __init__(self, subject):
|
||||
self.subject = subject
|
||||
self.subject.attach(self)
|
||||
self.events = {}
|
||||
|
||||
def update(self, name):
|
||||
if name in self.events:
|
||||
callback = self.events[name]
|
||||
return callback()
|
||||
|
||||
def add_event(self, event):
|
||||
self.events[event.name]=event
|
||||
|
||||
class SessionSubject(Subject, metaclass=Singleton):
|
||||
"""
|
||||
A concrete subject class which creates CC session object
|
||||
"""
|
||||
def __init__(self, session=None, verbose=False):
|
||||
Subject.__init__(self)
|
||||
self.verbose = verbose
|
||||
self.session=session
|
||||
self.running = False
|
||||
|
||||
def start(self):
|
||||
self.running = True
|
||||
self.notify('start')
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
self.notify('stop')
|
||||
|
||||
def check(self):
|
||||
self.notify('check')
|
||||
|
||||
class CCSessionListener(Listener):
|
||||
"""
|
||||
A concrete listener class which creates SessionSubject object and
|
||||
ModuleCCSession object
|
||||
"""
|
||||
def __init__(self, subject, verbose=False):
|
||||
Listener.__init__(self, subject)
|
||||
self.verbose = verbose
|
||||
self.session = subject.session
|
||||
self.boot_time = get_datetime()
|
||||
|
||||
# create ModuleCCSession object
|
||||
self.cc_session = ModuleCCSession(SPECFILE_LOCATION,
|
||||
self.config_handler,
|
||||
self.command_handler,
|
||||
self.session)
|
||||
|
||||
self.session = self.subject.session = self.cc_session._session
|
||||
|
||||
# initialize internal data
|
||||
self.config_spec = self.cc_session.get_module_spec().get_config_spec()
|
||||
self.stats_spec = self.config_spec
|
||||
self.stats_data = self.initialize_data(self.stats_spec)
|
||||
|
||||
# add event handler invoked via SessionSubject object
|
||||
self.add_event(Callback('start', self.start))
|
||||
self.add_event(Callback('stop', self.stop))
|
||||
self.add_event(Callback('check', self.check))
|
||||
# don't add 'command_' suffix to the special commands in
|
||||
# order to prevent executing internal command via bindctl
|
||||
|
||||
# get commands spec
|
||||
self.commands_spec = self.cc_session.get_module_spec().get_commands_spec()
|
||||
|
||||
# add event handler related command_handler of ModuleCCSession
|
||||
# invoked via bindctl
|
||||
for cmd in self.commands_spec:
|
||||
try:
|
||||
# add prefix "command_"
|
||||
name = "command_" + cmd["command_name"]
|
||||
callback = getattr(self, name)
|
||||
kwargs = self.initialize_data(cmd["command_args"])
|
||||
self.add_event(Callback(name=name, callback=callback, args=(), kwargs=kwargs))
|
||||
except AttributeError as ae:
|
||||
sys.stderr.write("[b10-stats] Caught undefined command while parsing spec file: "
|
||||
+str(cmd["command_name"])+"\n")
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
start the cc chanel
|
||||
"""
|
||||
# set initial value
|
||||
self.stats_data['stats.boot_time'] = self.boot_time
|
||||
self.stats_data['stats.start_time'] = get_datetime()
|
||||
self.stats_data['stats.last_update_time'] = get_datetime()
|
||||
self.stats_data['stats.lname'] = self.session.lname
|
||||
return self.cc_session.start()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
stop the cc chanel
|
||||
"""
|
||||
return self.cc_session.close()
|
||||
|
||||
def check(self):
|
||||
"""
|
||||
check the cc chanel
|
||||
"""
|
||||
return self.cc_session.check_command()
|
||||
|
||||
def config_handler(self, new_config):
|
||||
"""
|
||||
handle a configure from the cc channel
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] newconfig received: "+str(new_config)+"\n")
|
||||
|
||||
# do nothing currently
|
||||
return create_answer(0)
|
||||
|
||||
def command_handler(self, command, *args, **kwargs):
|
||||
"""
|
||||
handle commands from the cc channel
|
||||
"""
|
||||
# add 'command_' suffix in order to executing command via bindctl
|
||||
name = 'command_' + command
|
||||
|
||||
if name in self.events:
|
||||
event = self.events[name]
|
||||
return event(*args, **kwargs)
|
||||
else:
|
||||
return self.command_unknown(command, args)
|
||||
|
||||
def command_shutdown(self, args):
|
||||
"""
|
||||
handle shutdown command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] 'shutdown' command received\n")
|
||||
self.subject.running = False
|
||||
return create_answer(0)
|
||||
|
||||
def command_set(self, args, stats_data={}):
|
||||
"""
|
||||
handle set command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] 'set' command received, args: "+str(args)+"\n")
|
||||
|
||||
# 'args' must be dictionary type
|
||||
self.stats_data.update(args['stats_data'])
|
||||
|
||||
# overwrite "stats.LastUpdateTime"
|
||||
self.stats_data['stats.last_update_time'] = get_datetime()
|
||||
|
||||
return create_answer(0)
|
||||
|
||||
def command_remove(self, args, stats_item_name=''):
|
||||
"""
|
||||
handle remove command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] 'remove' command received, args: "+str(args)+"\n")
|
||||
|
||||
# 'args' must be dictionary type
|
||||
if args and args['stats_item_name'] in self.stats_data:
|
||||
stats_item_name = args['stats_item_name']
|
||||
|
||||
# just remove one item
|
||||
self.stats_data.pop(stats_item_name)
|
||||
|
||||
return create_answer(0)
|
||||
|
||||
def command_show(self, args, stats_item_name=''):
|
||||
"""
|
||||
handle show command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] 'show' command received, args: "+str(args)+"\n")
|
||||
|
||||
# always overwrite 'report_time' and 'stats.timestamp'
|
||||
# if "show" command invoked
|
||||
self.stats_data['report_time'] = get_datetime()
|
||||
self.stats_data['stats.timestamp'] = get_timestamp()
|
||||
|
||||
# if with args
|
||||
if args and args['stats_item_name'] in self.stats_data:
|
||||
stats_item_name = args['stats_item_name']
|
||||
return create_answer(0, {stats_item_name: self.stats_data[stats_item_name]})
|
||||
|
||||
return create_answer(0, self.stats_data)
|
||||
|
||||
def command_reset(self, args):
|
||||
"""
|
||||
handle reset command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] 'reset' command received\n")
|
||||
|
||||
# re-initialize internal variables
|
||||
self.stats_data = self.initialize_data(self.stats_spec)
|
||||
|
||||
# reset initial value
|
||||
self.stats_data['stats.boot_time'] = self.boot_time
|
||||
self.stats_data['stats.start_time'] = get_datetime()
|
||||
self.stats_data['stats.last_update_time'] = get_datetime()
|
||||
self.stats_data['stats.lname'] = self.session.lname
|
||||
|
||||
return create_answer(0)
|
||||
|
||||
def command_status(self, args):
|
||||
"""
|
||||
handle status command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] 'status' command received\n")
|
||||
# just return "I'm alive."
|
||||
return create_answer(0, "I'm alive.")
|
||||
|
||||
def command_unknown(self, command, args):
|
||||
"""
|
||||
handle an unknown command
|
||||
"""
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats] Unknown command received: '"
|
||||
+ str(command) + "'\n")
|
||||
return create_answer(1, "Unknown command: '"+str(command)+"'")
|
||||
|
||||
|
||||
def initialize_data(self, spec):
|
||||
"""
|
||||
initialize stats data
|
||||
"""
|
||||
def __get_init_val(spec):
|
||||
if spec['item_type'] == 'null':
|
||||
return None
|
||||
elif spec['item_type'] == 'boolean':
|
||||
return bool(spec.get('item_default', False))
|
||||
elif spec['item_type'] == 'string':
|
||||
return str(spec.get('item_default', ''))
|
||||
elif spec['item_type'] in set(['number', 'integer']):
|
||||
return int(spec.get('item_default', 0))
|
||||
elif spec['item_type'] in set(['float', 'double', 'real']):
|
||||
return float(spec.get('item_default', 0.0))
|
||||
elif spec['item_type'] in set(['list', 'array']):
|
||||
return spec.get('item_default',
|
||||
[ __get_init_val(s) for s in spec['list_item_spec'] ])
|
||||
elif spec['item_type'] in set(['map', 'object']):
|
||||
return spec.get('item_default',
|
||||
dict([ (s['item_name'], __get_init_val(s)) for s in spec['map_item_spec'] ]) )
|
||||
else:
|
||||
return spec.get('item_default')
|
||||
return dict([ (s['item_name'], __get_init_val(s)) for s in spec ])
|
||||
|
||||
def get_timestamp():
|
||||
"""
|
||||
get current timestamp
|
||||
"""
|
||||
return time()
|
||||
|
||||
def get_datetime():
|
||||
"""
|
||||
get current datetime
|
||||
"""
|
||||
return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
|
||||
|
||||
def main(session=None):
|
||||
try:
|
||||
parser = OptionParser()
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="display more about what is going on")
|
||||
(options, args) = parser.parse_args()
|
||||
subject = SessionSubject(session=session, verbose=options.verbose)
|
||||
listener = CCSessionListener(subject, verbose=options.verbose)
|
||||
subject.start()
|
||||
while subject.running:
|
||||
subject.check()
|
||||
subject.stop()
|
||||
|
||||
except OptionValueError:
|
||||
sys.stderr.write("[b10-stats] Error parsing options\n")
|
||||
except SessionError as se:
|
||||
sys.stderr.write("[b10-stats] Error creating Stats module, "
|
||||
+ "is the command channel daemon running?\n")
|
||||
except KeyboardInterrupt as kie:
|
||||
sys.stderr.write("[b10-stats] Interrupted, exiting\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
140
src/bin/stats/stats.spec.pre.in
Normal file
140
src/bin/stats/stats.spec.pre.in
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"module_spec": {
|
||||
"module_name": "Stats",
|
||||
"module_description": "Stats daemon",
|
||||
"config_data": [
|
||||
{
|
||||
"item_name": "report_time",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "1970-01-01T00:00:00Z",
|
||||
"item_title": "Report time",
|
||||
"item_description": "A date time when stats module reports",
|
||||
"item_format": "date-time"
|
||||
},
|
||||
{
|
||||
"item_name": "bind10.boot_time",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "1970-01-01T00:00:00Z",
|
||||
"item_title": "stats.BootTime",
|
||||
"item_description": "A date time when bind10 process starts initially",
|
||||
"item_format": "date-time"
|
||||
},
|
||||
{
|
||||
"item_name": "stats.boot_time",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "1970-01-01T00:00:00Z",
|
||||
"item_title": "stats.BootTime",
|
||||
"item_description": "A date time when the stats module starts initially or when the stats module restarts",
|
||||
"item_format": "date-time"
|
||||
},
|
||||
{
|
||||
"item_name": "stats.start_time",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "1970-01-01T00:00:00Z",
|
||||
"item_title": "stats.StartTime",
|
||||
"item_description": "A date time when the stats module starts collecting data or resetting values last time",
|
||||
"item_format": "date-time"
|
||||
},
|
||||
{
|
||||
"item_name": "stats.last_update_time",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "1970-01-01T00:00:00Z",
|
||||
"item_title": "stats.LastUpdateTime",
|
||||
"item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
|
||||
"item_format": "date-time"
|
||||
},
|
||||
{
|
||||
"item_name": "stats.timestamp",
|
||||
"item_type": "real",
|
||||
"item_optional": false,
|
||||
"item_default": 0.0,
|
||||
"item_title": "stats.Timestamp",
|
||||
"item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
|
||||
"item_format": "second"
|
||||
},
|
||||
{
|
||||
"item_name": "stats.lname",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "",
|
||||
"item_title": "stats.LocalName",
|
||||
"item_description": "A localname of stats module given via CC protocol"
|
||||
},
|
||||
{
|
||||
"item_name": "auth.queries.tcp",
|
||||
"item_type": "integer",
|
||||
"item_optional": false,
|
||||
"item_default": 0,
|
||||
"item_title": "auth.queries.tcp",
|
||||
"item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
|
||||
},
|
||||
{
|
||||
"item_name": "auth.queries.udp",
|
||||
"item_type": "integer",
|
||||
"item_optional": false,
|
||||
"item_default": 0,
|
||||
"item_title": "auth.queries.udp",
|
||||
"item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command_name": "status",
|
||||
"command_description": "identify whether stats module is alive or not",
|
||||
"command_args": []
|
||||
},
|
||||
{
|
||||
"command_name": "show",
|
||||
"command_description": "show the specified/all statistics data",
|
||||
"command_args": [
|
||||
{
|
||||
"item_name": "stats_item_name",
|
||||
"item_type": "string",
|
||||
"item_optional": true,
|
||||
"item_default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"command_name": "set",
|
||||
"command_description": "set the value of specified name in statistics data",
|
||||
"command_args": [
|
||||
{
|
||||
"item_name": "stats_data",
|
||||
"item_type": "map",
|
||||
"item_optional": false,
|
||||
"item_default": {},
|
||||
"map_item_spec": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"command_name": "remove",
|
||||
"command_description": "remove the specified name from statistics data",
|
||||
"command_args": [
|
||||
{
|
||||
"item_name": "stats_item_name",
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"command_name": "reset",
|
||||
"command_description": "reset all statistics data to default values except for several constant names",
|
||||
"command_args": []
|
||||
},
|
||||
{
|
||||
"command_name": "shutdown",
|
||||
"command_description": "Shut down the stats module",
|
||||
"command_args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
155
src/bin/stats/stats_stub.py.in
Normal file
155
src/bin/stats/stats_stub.py.in
Normal file
@@ -0,0 +1,155 @@
|
||||
#!@PYTHON@
|
||||
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
__version__ = "$Revision$"
|
||||
|
||||
import sys; sys.path.append ('@@PYTHONPATH@@')
|
||||
import os
|
||||
import time
|
||||
from optparse import OptionParser, OptionValueError
|
||||
from isc.config.ccsession import ModuleCCSession, create_command, parse_answer, parse_command, create_answer
|
||||
from isc.cc import Session, SessionError
|
||||
from stats import get_datetime
|
||||
|
||||
# for setproctitle
|
||||
import isc.utils.process
|
||||
isc.utils.process.rename()
|
||||
|
||||
# If B10_FROM_BUILD is set in the environment, we use data files
|
||||
# from a directory relative to that, otherwise we use the ones
|
||||
# installed on the system
|
||||
if "B10_FROM_BUILD" in os.environ:
|
||||
SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
|
||||
else:
|
||||
PREFIX = "@prefix@"
|
||||
DATAROOTDIR = "@datarootdir@"
|
||||
SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
|
||||
|
||||
class CCSessionStub:
|
||||
"""
|
||||
This class is intended to behaves as a sender to Stats module. It
|
||||
creates MoudleCCSession object and send specified command.
|
||||
"""
|
||||
def __init__(self, session=None, verbose=False):
|
||||
# create ModuleCCSession object
|
||||
self.verbose = verbose
|
||||
self.cc_session = ModuleCCSession(SPECFILE_LOCATION,
|
||||
self.__dummy, self.__dummy, session)
|
||||
self.module_name = self.cc_session._module_name
|
||||
self.session = self.cc_session._session
|
||||
|
||||
def __dummy(self, *args):
|
||||
pass
|
||||
|
||||
def send_command(self, command, args):
|
||||
"""
|
||||
send command to stats module with args
|
||||
"""
|
||||
cmd = create_command(command, args)
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats_stub] send command : " + str(cmd) + "\n")
|
||||
seq = self.session.group_sendmsg(cmd, self.module_name)
|
||||
msg, env = self.session.group_recvmsg(False, seq) # non-blocking is False
|
||||
if self.verbose:
|
||||
sys.stdout.write("[b10-stats_stub] received env : " + str(env) + "\n")
|
||||
sys.stdout.write("[b10-stats_stub] received message : " + str(msg) + "\n")
|
||||
(ret, arg) = (None, None)
|
||||
if 'result' in msg:
|
||||
ret, arg = parse_answer(msg)
|
||||
elif 'command' in msg:
|
||||
ret, arg = parse_command(msg)
|
||||
self.session.group_reply(env, create_answer(0))
|
||||
return ret, arg, env
|
||||
|
||||
class BossModuleStub:
|
||||
"""
|
||||
This class is customized from CCSessionStub and is intended to behaves
|
||||
as a virtual Boss module to send to Stats Module.
|
||||
"""
|
||||
def __init__(self, session=None, verbose=False):
|
||||
self.stub = CCSessionStub(session=session, verbose=verbose)
|
||||
|
||||
def send_boottime(self):
|
||||
return self.stub.send_command("set", {"stats_data": {"bind10.boot_time": get_datetime()}})
|
||||
|
||||
class AuthModuleStub:
|
||||
"""
|
||||
This class is customized CCSessionStub and is intended to behaves
|
||||
as a virtual Auth module to send to Stats Module.
|
||||
"""
|
||||
def __init__(self, session=None, verbose=False):
|
||||
self.stub = CCSessionStub(session=session, verbose=verbose)
|
||||
self.count = { "udp": 0, "tcp": 0 }
|
||||
|
||||
def send_udp_query_count(self, cmd="set", cnt=0):
|
||||
"""
|
||||
count up udp query count
|
||||
"""
|
||||
prt = "udp"
|
||||
self.count[prt] = 1
|
||||
if cnt > 0:
|
||||
self.count[prt] = cnt
|
||||
return self.stub.send_command(cmd,
|
||||
{"stats_data":
|
||||
{"auth.queries."+prt: self.count[prt]}
|
||||
})
|
||||
|
||||
def send_tcp_query_count(self, cmd="set", cnt=0):
|
||||
"""
|
||||
set udp query count
|
||||
"""
|
||||
prt = "tcp"
|
||||
self.count[prt] = self.count[prt] + 1
|
||||
if cnt > 0:
|
||||
self.count[prt] = cnt
|
||||
return self.stub.send_command(cmd,
|
||||
{"stats_data":
|
||||
{"auth.queries."+prt: self.count[prt]}
|
||||
})
|
||||
|
||||
def main(session=None):
|
||||
try:
|
||||
parser=OptionParser()
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="display more about what is going on")
|
||||
(options, args) = parser.parse_args()
|
||||
stub = CCSessionStub(session=session, verbose=options.verbose)
|
||||
boss = BossModuleStub(session=stub.session, verbose=options.verbose)
|
||||
auth = AuthModuleStub(session=stub.session, verbose=options.verbose)
|
||||
stub.send_command("status", None)
|
||||
boss.send_boottime()
|
||||
t_cnt=0
|
||||
u_cnt=81120
|
||||
auth.send_udp_query_count(cnt=u_cnt) # This is an example.
|
||||
while True:
|
||||
u_cnt = u_cnt + 1
|
||||
t_cnt = t_cnt + 1
|
||||
auth.send_udp_query_count(cnt=u_cnt)
|
||||
auth.send_tcp_query_count(cnt=t_cnt)
|
||||
time.sleep(1)
|
||||
|
||||
except OptionValueError:
|
||||
sys.stderr.write("[b10-stats_stub] Error parsing options\n")
|
||||
except SessionError as se:
|
||||
sys.stderr.write("[b10-stats_stub] Error creating Stats module, "
|
||||
+ "is the command channel daemon running?\n")
|
||||
except KeyboardInterrupt as kie:
|
||||
sys.stderr.write("[b10-stats_stub] Interrupted, exiting\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# This program collects 'counters' from 'statistics' channel.
|
||||
# It accepts one command: 'Boss' group 'shutdown'
|
||||
|
||||
import isc.cc
|
||||
import time
|
||||
import select
|
||||
import os
|
||||
|
||||
bossgroup = 'Boss'
|
||||
myname = 'statsd'
|
||||
debug = 0
|
||||
|
||||
def total(s):
|
||||
def totalsub(d,s):
|
||||
for k in s.keys():
|
||||
if (k == 'component' or k == 'version'
|
||||
or k == 'timestamp' or k == 'from'):
|
||||
continue
|
||||
if (k in d):
|
||||
if (isinstance(s[k], dict)):
|
||||
totalsub(d[k], s[k])
|
||||
else:
|
||||
d[k] = s[k] + d[k]
|
||||
else:
|
||||
d[k] = s[k]
|
||||
|
||||
if (len(s) == 0):
|
||||
return {}
|
||||
if (len(s) == 1):
|
||||
for k in s.keys():
|
||||
out = s[k]
|
||||
out['components'] = 1
|
||||
out['timestamp2'] = out['timestamp']
|
||||
del out['from']
|
||||
return out
|
||||
_time1 = 0
|
||||
_time2 = 0
|
||||
out = {}
|
||||
for i in s.values():
|
||||
if (_time1 == 0 or _time1 < i['timestamp']):
|
||||
_time1 = i['timestamp']
|
||||
if (_time2 == 0 or _time2 > i['timestamp']):
|
||||
_time2 = i['timestamp']
|
||||
totalsub(out, i)
|
||||
out['components'] = len(s)
|
||||
out['timestamp'] = _time1;
|
||||
out['timestamp2'] = _time2;
|
||||
return out
|
||||
|
||||
def dicttoxml(stats, level = 0):
|
||||
def dicttoxmlsub(s, level):
|
||||
output = ''
|
||||
spaces = ' ' * level
|
||||
for k in s.keys():
|
||||
if (isinstance(s[k], dict)):
|
||||
output += spaces + ('<%s>\n' %k) \
|
||||
+ dicttoxmlsub(s[k], level+1) \
|
||||
+ spaces + '</%s>\n' %k
|
||||
else:
|
||||
output += spaces + '<%s>%s</%s>\n' % (k, s[k], k)
|
||||
return output
|
||||
|
||||
for k in stats.keys():
|
||||
space = ' ' * level
|
||||
output = space + '<component component="%s">\n' % k
|
||||
s = stats[k]
|
||||
if ('component' in s or 'components' in s):
|
||||
output += dicttoxmlsub(s, level+1)
|
||||
else:
|
||||
for l in s.keys():
|
||||
output += space + ' <from from="%s">\n' % l \
|
||||
+ dicttoxmlsub(s[l], level+2) \
|
||||
+ space + ' </from>\n'
|
||||
output += space + '</component>\n'
|
||||
return output
|
||||
|
||||
def dump_stats(statpath, statcount, stat, statraw):
|
||||
newfile = open(statpath + '.new', 'w')
|
||||
newfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||
newfile.write('<!-- created at '+time.strftime('%Y%m%d %H%M%S')+' -->\n')
|
||||
newfile.write('<isc version="0.0">\n')
|
||||
newfile.write(' <bind10>\n')
|
||||
newfile.write(' <total>\n')
|
||||
newfile.write(dicttoxml(stat, 3))
|
||||
newfile.write(' </total>\n')
|
||||
newfile.write(' <each>\n')
|
||||
newfile.write(dicttoxml(statraw, 3))
|
||||
newfile.write(' </each>\n')
|
||||
newfile.write(' </bind10>\n')
|
||||
newfile.write('</isc>\n')
|
||||
newfile.close()
|
||||
loop = statcount
|
||||
while(loop > 0):
|
||||
old = statpath + '.%d' % loop
|
||||
loop -= 1
|
||||
new = statpath + '.%d' % loop
|
||||
if (os.access(new, os.F_OK)):
|
||||
os.rename(new, old)
|
||||
if (os.access(statpath, os.F_OK)):
|
||||
os.rename(statpath, new)
|
||||
os.rename(statpath + '.new', statpath)
|
||||
|
||||
def collector(statgroup,step,statpath,statcount):
|
||||
cc = isc.cc.Session()
|
||||
if debug:
|
||||
print ("cc.lname=",cc.lname)
|
||||
cc.group_subscribe(statgroup)
|
||||
cc.group_subscribe(bossgroup, myname)
|
||||
wrote_time = -1
|
||||
last_wrote_time = -1
|
||||
last_recvd_time = -1
|
||||
stats = {}
|
||||
statstotal = {}
|
||||
while 1:
|
||||
wait = wrote_time + step - time.time()
|
||||
if wait <= 0 and last_recvd_time > wrote_time:
|
||||
if debug:
|
||||
print ("dump stats")
|
||||
dump_stats(statpath, statcount, statstotal, stats)
|
||||
last_wrote_time = wrote_time;
|
||||
wrote_time = time.time();
|
||||
wait = last_wrote_time + step - time.time()
|
||||
if wait < 0:
|
||||
wait = step
|
||||
r,w,e = select.select([cc._socket],[],[], wait)
|
||||
for sock in r:
|
||||
if sock == cc._socket:
|
||||
data,envelope = cc.group_recvmsg(False)
|
||||
if (envelope['group'] == bossgroup):
|
||||
if ('shutdown' in data):
|
||||
exit()
|
||||
if (envelope['group'] == statgroup):
|
||||
# Check received data
|
||||
if (not('component' in data and 'version' in data
|
||||
and 'stats' in data)):
|
||||
continue
|
||||
component = data['component']
|
||||
_from = envelope['from']
|
||||
data['from'] = _from
|
||||
if debug:
|
||||
print ("received from ",_from)
|
||||
if (not (component in stats)):
|
||||
stats[component] = {}
|
||||
(stats[component])[_from] = data;
|
||||
statstotal[component] = total(stats[component])
|
||||
last_recvd_time = time.time()
|
||||
|
||||
if __name__ == '__main__':
|
||||
collector('statistics', 10, '/tmp/stats.xml', 100)
|
@@ -1,55 +0,0 @@
|
||||
= Statistics overview =
|
||||
|
||||
Result of 26 Jan 2010 evening discussion,
|
||||
statistics overview was almost fixed.
|
||||
|
||||
Statsd listens msgq "statistics" channel, gathers statistics
|
||||
from each BIND 10 components and dump them into a XML file periodically.
|
||||
|
||||
= Statsd current status =
|
||||
|
||||
Statsd can run with msgq.
|
||||
Statsd is not controlled by BoB.
|
||||
Statsd does not read configuration from cfgd.
|
||||
File path, dump frequency, rotate generations are fixed.
|
||||
Statsd dumps to "/tmp/stats" every 10 seconds except no statistics received.
|
||||
"/tmp/stats" are preserved 100 generations.
|
||||
|
||||
Current implementation is put on "bind10/branches/parkinglot/src/bin/stats/".
|
||||
|
||||
= statistics channel Message format =
|
||||
|
||||
The Statsd accepts python dictionary format data from msgq
|
||||
"statistics" channel.
|
||||
|
||||
The data need to contain "components", "version", "timestamp", "stats" keys.
|
||||
|
||||
The statistics data format is { "component" : "<component_name>",
|
||||
"version": "<version number>", "timestamp": "<unixtime>", "stats":
|
||||
<python dictionary format statistics>}.
|
||||
|
||||
"stats" data may be nested.
|
||||
"stats" data is defined by each component.
|
||||
|
||||
Each component sends statistics data to "statistics" group periodically
|
||||
without joining the group.
|
||||
|
||||
See a example component: "stats/test/test-agent.py".
|
||||
|
||||
= How to publish statistics from each component =
|
||||
|
||||
For example, parkinglot auth server has one "counter".
|
||||
Then, parkinglot's statistics message may be
|
||||
{ "component":"parkinglot", "version":1, "timestamp":unixtime,
|
||||
stats: { "counter": counter } }.
|
||||
Send it to msgq "statistics" channel periodically
|
||||
(For example, every 10 second).
|
||||
|
||||
Then "Statsd" will write it to the statistics file periodically.
|
||||
|
||||
= TODO =
|
||||
|
||||
- statsd.spec
|
||||
- read configuration from cfgd.
|
||||
- how to publish statistics data
|
||||
- controlled by BoB
|
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import isc
|
||||
cc = isc.cc.Session()
|
||||
cc.group_subscribe("Boss")
|
||||
cc.group_sendmsg({ "command":"shutdown"},"Boss")
|
@@ -1,178 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This program acts statistics agent.
|
||||
# It has pseudo counters which is incremented each 10 second and
|
||||
# sends data to "statistics" channel periodically.
|
||||
# One command is available
|
||||
# "Boss" group: "shutdown"
|
||||
|
||||
import isc
|
||||
import time
|
||||
import select
|
||||
import random
|
||||
|
||||
step_time = 10
|
||||
statgroup = "statistics"
|
||||
|
||||
cc = isc.cc.Session()
|
||||
print (cc.lname)
|
||||
#cc.group_subscribe(statgroup)
|
||||
cc.group_subscribe("Boss")
|
||||
|
||||
# counters
|
||||
|
||||
NSSTATDESC={}
|
||||
NSSTATDESC["counterid"] = 0
|
||||
NSSTATDESC["requestv4"] = 0
|
||||
NSSTATDESC["requestv6"] = 0
|
||||
NSSTATDESC["edns0in"] = 0
|
||||
NSSTATDESC["badednsver"] = 0
|
||||
NSSTATDESC["tsigin"] = 0
|
||||
NSSTATDESC["sig0in"] = 0
|
||||
NSSTATDESC["invalidsig"] = 0
|
||||
NSSTATDESC["tcp"] = 0
|
||||
NSSTATDESC["authrej"] = 0
|
||||
NSSTATDESC["recurserej"] = 0
|
||||
NSSTATDESC["xfrrej"] = 0
|
||||
NSSTATDESC["updaterej"] = 0
|
||||
NSSTATDESC["response"] = 0
|
||||
NSSTATDESC["truncatedresp"] = 0
|
||||
NSSTATDESC["edns0out"] = 0
|
||||
NSSTATDESC["tsigout"] = 0
|
||||
NSSTATDESC["sig0out"] = 0
|
||||
NSSTATDESC["success"] = 0
|
||||
NSSTATDESC["authans"] = 0
|
||||
NSSTATDESC["nonauthans"] = 0
|
||||
NSSTATDESC["referral"] = 0
|
||||
NSSTATDESC["nxrrset"] = 0
|
||||
NSSTATDESC["servfail"] = 0
|
||||
NSSTATDESC["formerr"] = 0
|
||||
NSSTATDESC["nxdomain"] = 0
|
||||
NSSTATDESC["recursion"] = 0
|
||||
NSSTATDESC["duplicate"] = 0
|
||||
NSSTATDESC["dropped"] = 0
|
||||
NSSTATDESC["failure"] = 0
|
||||
NSSTATDESC["xfrdone"] = 0
|
||||
NSSTATDESC["updatereqfwd"] = 0
|
||||
NSSTATDESC["updaterespfwd"] = 0
|
||||
NSSTATDESC["updatefwdfail"] = 0
|
||||
NSSTATDESC["updatedone"] = 0
|
||||
NSSTATDESC["updatefail"] = 0
|
||||
NSSTATDESC["updatebadprereq"] = 0
|
||||
RESSTATDESC={}
|
||||
RESSTATDESC["counterid"] = 0
|
||||
RESSTATDESC["queryv4"] = 0
|
||||
RESSTATDESC["queryv6"] = 0
|
||||
RESSTATDESC["responsev4"] = 0
|
||||
RESSTATDESC["responsev6"] = 0
|
||||
RESSTATDESC["nxdomain"] = 0
|
||||
RESSTATDESC["servfail"] = 0
|
||||
RESSTATDESC["formerr"] = 0
|
||||
RESSTATDESC["othererror"] = 0
|
||||
RESSTATDESC["edns0fail"] = 0
|
||||
RESSTATDESC["mismatch"] = 0
|
||||
RESSTATDESC["truncated"] = 0
|
||||
RESSTATDESC["lame"] = 0
|
||||
RESSTATDESC["retry"] = 0
|
||||
RESSTATDESC["dispabort"] = 0
|
||||
RESSTATDESC["dispsockfail"] = 0
|
||||
RESSTATDESC["querytimeout"] = 0
|
||||
RESSTATDESC["gluefetchv4"] = 0
|
||||
RESSTATDESC["gluefetchv6"] = 0
|
||||
RESSTATDESC["gluefetchv4fail"] = 0
|
||||
RESSTATDESC["gluefetchv6fail"] = 0
|
||||
RESSTATDESC["val"] = 0
|
||||
RESSTATDESC["valsuccess"] = 0
|
||||
RESSTATDESC["valnegsuccess"] = 0
|
||||
RESSTATDESC["valfail"] = 0
|
||||
RESSTATDESC["queryrtt0"] = 0
|
||||
RESSTATDESC["queryrtt1"] = 0
|
||||
RESSTATDESC["queryrtt2"] = 0
|
||||
RESSTATDESC["queryrtt3"] = 0
|
||||
RESSTATDESC["queryrtt4"] = 0
|
||||
RESSTATDESC["queryrtt5"] = 0
|
||||
SOCKSTATDESC={}
|
||||
SOCKSTATDESC["counterid"] = 0
|
||||
SOCKSTATDESC["udp4open"] = 0
|
||||
SOCKSTATDESC["udp6open"] = 0
|
||||
SOCKSTATDESC["tcp4open"] = 0
|
||||
SOCKSTATDESC["tcp6open"] = 0
|
||||
SOCKSTATDESC["unixopen"] = 0
|
||||
SOCKSTATDESC["udp4openfail"] = 0
|
||||
SOCKSTATDESC["udp6openfail"] = 0
|
||||
SOCKSTATDESC["tcp4openfail"] = 0
|
||||
SOCKSTATDESC["tcp6openfail"] = 0
|
||||
SOCKSTATDESC["unixopenfail"] = 0
|
||||
SOCKSTATDESC["udp4close"] = 0
|
||||
SOCKSTATDESC["udp6close"] = 0
|
||||
SOCKSTATDESC["tcp4close"] = 0
|
||||
SOCKSTATDESC["tcp6close"] = 0
|
||||
SOCKSTATDESC["unixclose"] = 0
|
||||
SOCKSTATDESC["fdwatchclose"] = 0
|
||||
SOCKSTATDESC["udp4bindfail"] = 0
|
||||
SOCKSTATDESC["udp6bindfail"] = 0
|
||||
SOCKSTATDESC["tcp4bindfail"] = 0
|
||||
SOCKSTATDESC["tcp6bindfail"] = 0
|
||||
SOCKSTATDESC["unixbindfail"] = 0
|
||||
SOCKSTATDESC["fdwatchbindfail"] = 0
|
||||
SOCKSTATDESC["udp4connectfail"] = 0
|
||||
SOCKSTATDESC["udp6connectfail"] = 0
|
||||
SOCKSTATDESC["tcp4connectfail"] = 0
|
||||
SOCKSTATDESC["tcp6connectfail"] = 0
|
||||
SOCKSTATDESC["unixconnectfail"] = 0
|
||||
SOCKSTATDESC["fdwatchconnectfail"] = 0
|
||||
SOCKSTATDESC["udp4connect"] = 0
|
||||
SOCKSTATDESC["udp6connect"] = 0
|
||||
SOCKSTATDESC["tcp4connect"] = 0
|
||||
SOCKSTATDESC["tcp6connect"] = 0
|
||||
SOCKSTATDESC["unixconnect"] = 0
|
||||
SOCKSTATDESC["fdwatchconnect"] = 0
|
||||
SOCKSTATDESC["tcp4acceptfail"] = 0
|
||||
SOCKSTATDESC["tcp6acceptfail"] = 0
|
||||
SOCKSTATDESC["unixacceptfail"] = 0
|
||||
SOCKSTATDESC["tcp4accept"] = 0
|
||||
SOCKSTATDESC["tcp6accept"] = 0
|
||||
SOCKSTATDESC["unixaccept"] = 0
|
||||
SOCKSTATDESC["udp4sendfail"] = 0
|
||||
SOCKSTATDESC["udp6sendfail"] = 0
|
||||
SOCKSTATDESC["tcp4sendfail"] = 0
|
||||
SOCKSTATDESC["tcp6sendfail"] = 0
|
||||
SOCKSTATDESC["unixsendfail"] = 0
|
||||
SOCKSTATDESC["fdwatchsendfail"] = 0
|
||||
SOCKSTATDESC["udp4recvfail"] = 0
|
||||
SOCKSTATDESC["udp6recvfail"] = 0
|
||||
SOCKSTATDESC["tcp4recvfail"] = 0
|
||||
SOCKSTATDESC["tcp6recvfail"] = 0
|
||||
SOCKSTATDESC["unixrecvfail"] = 0
|
||||
SOCKSTATDESC["fdwatchrecvfail"] = 0
|
||||
SYSSTATDESC={}
|
||||
SYSSTATDESC['sockets'] = 0
|
||||
SYSSTATDESC['memory'] = 0
|
||||
|
||||
sent = -1
|
||||
last_sent = -1
|
||||
loop = 0
|
||||
|
||||
while 1:
|
||||
NSSTATDESC["requestv4"] += random.randint(1,1000)
|
||||
wait = sent + step_time - time.time()
|
||||
if wait <= 0:
|
||||
last_sent = sent;
|
||||
sent = time.time();
|
||||
msg = {'component':'auth', 'version':1, 'timestamp':time.time(),'stats':{'NSSTATDESC':NSSTATDESC,'RESSTATDESC':RESSTATDESC,'SOCKSTATDESC':SOCKSTATDESC,'SYSSTATDESC':SYSSTATDESC}}
|
||||
print (msg)
|
||||
print (cc.group_sendmsg(msg, statgroup))
|
||||
wait = last_sent + step_time - time.time()
|
||||
if wait < 0:
|
||||
wait = step_time
|
||||
loop += 1
|
||||
r,w,e = select.select([cc._socket],[],[], wait)
|
||||
for sock in r:
|
||||
if sock == cc._socket:
|
||||
data,envelope = cc.group_recvmsg(False)
|
||||
print (data)
|
||||
if (envelope["group"] == "Boss"):
|
||||
if ("shutdown" in data):
|
||||
exit()
|
||||
else:
|
||||
print ("Unknown data: ", envelope,data)
|
@@ -1,54 +0,0 @@
|
||||
import sys
|
||||
sys.path.insert(0, '.')
|
||||
from statsd import *
|
||||
|
||||
def test_total():
|
||||
stats = {
|
||||
'auth': {
|
||||
'from1': {
|
||||
'component':'auth',
|
||||
'version':1,
|
||||
'from':'from1',
|
||||
'timestamp':20100125,
|
||||
'stats': {
|
||||
'AUTH': {
|
||||
'counterid': 1,
|
||||
'requestv4': 2,
|
||||
'requestv6': 4,
|
||||
},
|
||||
'SYS': {
|
||||
'sockets': 8,
|
||||
'memory': 16,
|
||||
},
|
||||
},
|
||||
},
|
||||
'from2': {
|
||||
'component':'auth',
|
||||
'version':1,
|
||||
'from':'from1',
|
||||
'timestamp':20100126,
|
||||
'stats': {
|
||||
'AUTH': {
|
||||
'counterid': 256,
|
||||
'requestv4': 512,
|
||||
'requestv6': 1024,
|
||||
},
|
||||
'SYS': {
|
||||
'sockets': 2048,
|
||||
'memory': 4096,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
t = {}
|
||||
for key in stats:
|
||||
t[key] = total(stats[key])
|
||||
print (stats)
|
||||
print (dicttoxml(stats))
|
||||
print (t)
|
||||
print (dicttoxml(t))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_total()
|
14
src/bin/stats/tests/Makefile.am
Normal file
14
src/bin/stats/tests/Makefile.am
Normal file
@@ -0,0 +1,14 @@
|
||||
PYTESTS = b10-stats_test.py b10-stats_stub_test.py
|
||||
EXTRA_DIST = $(PYTESTS)
|
||||
CLEANFILES = unittest_fakesession.pyc
|
||||
|
||||
# later will have configure option to choose this, like: coverage run --branch
|
||||
PYCOVERAGE = $(PYTHON)
|
||||
# test using command-line arguments, so use check-local target instead of TESTS
|
||||
check-local:
|
||||
for pytest in $(PYTESTS) ; do \
|
||||
echo Running test: $$pytest ; \
|
||||
env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/stats \
|
||||
B10_FROM_BUILD=$(abs_top_builddir) \
|
||||
$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
|
||||
done
|
116
src/bin/stats/tests/b10-stats_stub_test.py
Normal file
116
src/bin/stats/tests/b10-stats_stub_test.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
__version__ = "$Revision$"
|
||||
|
||||
#
|
||||
# Tests for the stats stub module
|
||||
#
|
||||
import unittest
|
||||
import time
|
||||
import os
|
||||
import imp
|
||||
import stats_stub
|
||||
from isc.cc.session import Session
|
||||
from stats_stub import CCSessionStub, BossModuleStub, AuthModuleStub
|
||||
from stats import get_datetime
|
||||
|
||||
class TestStats(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.session = Session()
|
||||
self.stub = CCSessionStub(session=self.session, verbose=True)
|
||||
self.boss = BossModuleStub(session=self.session, verbose=True)
|
||||
self.auth = AuthModuleStub(session=self.session, verbose=True)
|
||||
self.env = {'from': self.session.lname, 'group': 'Stats',
|
||||
'instance': '*', 'to':'*',
|
||||
'type':'send','seq':0}
|
||||
self.result_ok = {'result': [0]}
|
||||
|
||||
def tearDown(self):
|
||||
self.session.close()
|
||||
|
||||
def test_stub(self):
|
||||
"""
|
||||
Test for send_command of CCSessionStub object
|
||||
"""
|
||||
env = self.env
|
||||
result_ok = self.result_ok
|
||||
self.assertEqual(('status', None, env),
|
||||
self.stub.send_command('status', None))
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
self.assertEqual(('shutdown', None, env),
|
||||
self.stub.send_command('shutdown', None))
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
self.assertEqual(('show', None, env),
|
||||
self.stub.send_command('show', None))
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
self.assertEqual(('set', {'atest': 100.0}, env),
|
||||
self.stub.send_command('set', {'atest': 100.0}))
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
|
||||
def test_boss_stub(self):
|
||||
"""
|
||||
Test for send_command of BossModuleStub object
|
||||
"""
|
||||
env = self.env
|
||||
result_ok = self.result_ok
|
||||
self.assertEqual(('set', {"stats_data":
|
||||
{"bind10.boot_time": get_datetime()}
|
||||
}, env), self.boss.send_boottime())
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
|
||||
def test_auth_stub(self):
|
||||
"""
|
||||
Test for send_command of AuthModuleStub object
|
||||
"""
|
||||
env = self.env
|
||||
result_ok = self.result_ok
|
||||
self.assertEqual(
|
||||
('set', {"stats_data": {"auth.queries.udp": 1}}, env),
|
||||
self.auth.send_udp_query_count())
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
self.assertEqual(
|
||||
('set', {"stats_data": {"auth.queries.tcp": 1}}, env),
|
||||
self.auth.send_tcp_query_count())
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
self.assertEqual(
|
||||
('set', {"stats_data": {"auth.queries.udp": 100}}, env),
|
||||
self.auth.send_udp_query_count(cmd='set', cnt=100))
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
self.assertEqual(
|
||||
('set', {"stats_data": {"auth.queries.tcp": 99}}, env),
|
||||
self.auth.send_tcp_query_count(cmd='set', cnt=99))
|
||||
self.assertEqual(result_ok, self.session.get_message("Stats", None))
|
||||
|
||||
def test_func_main(self):
|
||||
# explicitly make failed
|
||||
self.session.close()
|
||||
stats_stub.main(session=self.session)
|
||||
|
||||
def test_osenv(self):
|
||||
"""
|
||||
test for not having environ "B10_FROM_BUILD"
|
||||
"""
|
||||
if "B10_FROM_BUILD" in os.environ:
|
||||
path = os.environ["B10_FROM_BUILD"]
|
||||
os.environ.pop("B10_FROM_BUILD")
|
||||
imp.reload(stats_stub)
|
||||
os.environ["B10_FROM_BUILD"] = path
|
||||
imp.reload(stats_stub)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
646
src/bin/stats/tests/b10-stats_test.py
Normal file
646
src/bin/stats/tests/b10-stats_test.py
Normal file
@@ -0,0 +1,646 @@
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
__version__ = "$Revision$"
|
||||
|
||||
#
|
||||
# Tests for the stats module
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
import imp
|
||||
from isc.cc.session import Session, SessionError
|
||||
from isc.config.ccsession import ModuleCCSession, ModuleCCSessionError
|
||||
import stats
|
||||
from stats import SessionSubject, CCSessionListener, get_timestamp, get_datetime
|
||||
from fake_time import _TEST_TIME_SECS, _TEST_TIME_STRF
|
||||
|
||||
# setting Constant
|
||||
if sys.path[0] == '':
|
||||
TEST_SPECFILE_LOCATION = "./testdata/stats_test.spec"
|
||||
else:
|
||||
TEST_SPECFILE_LOCATION = sys.path[0] + "/testdata/stats_test.spec"
|
||||
|
||||
class TestStats(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.session = Session()
|
||||
self.subject = SessionSubject(session=self.session, verbose=True)
|
||||
self.listener = CCSessionListener(self.subject, verbose=True)
|
||||
self.stats_spec = self.listener.cc_session.get_module_spec().get_config_spec()
|
||||
self.module_name = self.listener.cc_session.get_module_spec().get_module_name()
|
||||
self.stats_data = {
|
||||
'report_time' : get_datetime(),
|
||||
'bind10.boot_time' : "1970-01-01T00:00:00Z",
|
||||
'stats.timestamp' : get_timestamp(),
|
||||
'stats.lname' : self.session.lname,
|
||||
'auth.queries.tcp': 0,
|
||||
'auth.queries.udp': 0,
|
||||
"stats.boot_time": get_datetime(),
|
||||
"stats.start_time": get_datetime(),
|
||||
"stats.last_update_time": get_datetime()
|
||||
}
|
||||
# check starting
|
||||
self.assertFalse(self.subject.running)
|
||||
self.subject.start()
|
||||
self.assertTrue(self.subject.running)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
self.assertEqual(self.module_name, 'Stats')
|
||||
|
||||
def tearDown(self):
|
||||
# check closing
|
||||
self.subject.stop()
|
||||
self.assertFalse(self.subject.running)
|
||||
self.subject.detach(self.listener)
|
||||
self.listener.stop()
|
||||
self.session.close()
|
||||
|
||||
def test_local_func(self):
|
||||
"""
|
||||
Test for local function
|
||||
|
||||
"""
|
||||
# test for result_ok
|
||||
self.assertEqual(type(result_ok()), dict)
|
||||
self.assertEqual(result_ok(), {'result': [0]})
|
||||
self.assertEqual(result_ok(1), {'result': [1]})
|
||||
self.assertEqual(result_ok(0,'OK'), {'result': [0, 'OK']})
|
||||
self.assertEqual(result_ok(1,'Not good'), {'result': [1, 'Not good']})
|
||||
self.assertEqual(result_ok(None,"It's None"), {'result': [None, "It's None"]})
|
||||
self.assertNotEqual(result_ok(), {'RESULT': [0]})
|
||||
|
||||
# test for get_timestamp
|
||||
self.assertEqual(get_timestamp(), _TEST_TIME_SECS)
|
||||
|
||||
# test for get_datetime
|
||||
self.assertEqual(get_datetime(), _TEST_TIME_STRF)
|
||||
|
||||
def test_show_command(self):
|
||||
"""
|
||||
Test for show command
|
||||
|
||||
"""
|
||||
# test show command without arg
|
||||
self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
# ignore under 0.9 seconds
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test show command with arg
|
||||
self.session.group_sendmsg({"command": [ "show", {"stats_item_name": "stats.lname"}]}, "Stats")
|
||||
self.assertEqual(len(self.subject.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.subject.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'stats.lname': self.stats_data['stats.lname']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.subject.session.message_queue), 0)
|
||||
|
||||
# test show command with arg which has wrong name
|
||||
self.session.group_sendmsg({"command": [ "show", {"stats_item_name": "stats.dummy"}]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
# ignore under 0.9 seconds
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_set_command(self):
|
||||
"""
|
||||
Test for set command
|
||||
|
||||
"""
|
||||
# test set command
|
||||
self.stats_data['auth.queries.udp'] = 54321
|
||||
self.assertEqual(self.stats_data['auth.queries.udp'], 54321)
|
||||
self.assertEqual(self.stats_data['auth.queries.tcp'], 0)
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"set", {
|
||||
'stats_data': {'auth.queries.udp': 54321 }
|
||||
} ] },
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test show command
|
||||
self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set command 2
|
||||
self.stats_data['auth.queries.udp'] = 0
|
||||
self.assertEqual(self.stats_data['auth.queries.udp'], 0)
|
||||
self.assertEqual(self.stats_data['auth.queries.tcp'], 0)
|
||||
self.session.group_sendmsg({ "command": [ "set", {'stats_data': {'auth.queries.udp': 0}} ]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test show command 2
|
||||
self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set command 3
|
||||
self.stats_data['auth.queries.tcp'] = 54322
|
||||
self.assertEqual(self.stats_data['auth.queries.udp'], 0)
|
||||
self.assertEqual(self.stats_data['auth.queries.tcp'], 54322)
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"set", {
|
||||
'stats_data': {'auth.queries.tcp': 54322 }
|
||||
} ] },
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test show command 3
|
||||
self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_remove_command(self):
|
||||
"""
|
||||
Test for remove command
|
||||
|
||||
"""
|
||||
self.session.group_sendmsg({"command":
|
||||
[ "remove", {"stats_item_name": 'bind10.boot_time' }]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
self.assertEqual(self.stats_data.pop('bind10.boot_time'), "1970-01-01T00:00:00Z")
|
||||
self.assertFalse('bind10.boot_time' in self.stats_data)
|
||||
|
||||
# test show command with arg
|
||||
self.session.group_sendmsg({"command":
|
||||
[ "show", {"stats_item_name": 'bind10.boot_time'}]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertFalse('bind10.boot_time' in result_data['result'][1])
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_reset_command(self):
|
||||
"""
|
||||
Test for reset command
|
||||
|
||||
"""
|
||||
self.session.group_sendmsg({"command": [ "reset" ] }, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test show command
|
||||
self.session.group_sendmsg({"command": [ "show" ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_status_command(self):
|
||||
"""
|
||||
Test for status command
|
||||
|
||||
"""
|
||||
self.session.group_sendmsg({"command": [ "status" ] }, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(0, "I'm alive."),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_unknown_command(self):
|
||||
"""
|
||||
Test for unknown command
|
||||
|
||||
"""
|
||||
self.session.group_sendmsg({"command": [ "hoge", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(1, "Unknown command: 'hoge'"),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_shutdown_command(self):
|
||||
"""
|
||||
Test for shutdown command
|
||||
|
||||
"""
|
||||
self.session.group_sendmsg({"command": [ "shutdown", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.assertTrue(self.subject.running)
|
||||
self.subject.check()
|
||||
self.assertFalse(self.subject.running)
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
|
||||
def test_some_commands(self):
|
||||
"""
|
||||
Test for some commands in a row
|
||||
|
||||
"""
|
||||
# test set command
|
||||
self.stats_data['bind10.boot_time'] = '2010-08-02T14:47:56Z'
|
||||
self.assertEqual(self.stats_data['bind10.boot_time'], '2010-08-02T14:47:56Z')
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"set", {
|
||||
'stats_data': {'bind10.boot_time': '2010-08-02T14:47:56Z' }
|
||||
}]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check its value
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"show", { 'stats_item_name': 'bind10.boot_time' }
|
||||
] }, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'bind10.boot_time': '2010-08-02T14:47:56Z'}),
|
||||
result_data)
|
||||
self.assertEqual(result_ok(0, {'bind10.boot_time': self.stats_data['bind10.boot_time']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set command 2nd
|
||||
self.stats_data['auth.queries.udp'] = 98765
|
||||
self.assertEqual(self.stats_data['auth.queries.udp'], 98765)
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"set", { 'stats_data': {
|
||||
'auth.queries.udp':
|
||||
self.stats_data['auth.queries.udp']
|
||||
} }
|
||||
] }, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check its value
|
||||
self.session.group_sendmsg({"command": [
|
||||
"show", {'stats_item_name': 'auth.queries.udp'}
|
||||
] }, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'auth.queries.udp': 98765}),
|
||||
result_data)
|
||||
self.assertEqual(result_ok(0, {'auth.queries.udp': self.stats_data['auth.queries.udp']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set command 3
|
||||
self.stats_data['auth.queries.tcp'] = 4321
|
||||
self.session.group_sendmsg({"command": [
|
||||
"set",
|
||||
{'stats_data': {'auth.queries.tcp': 4321 }} ]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check value
|
||||
self.session.group_sendmsg({"command": [ "show", {'stats_item_name': 'auth.queries.tcp'} ]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'auth.queries.tcp': 4321}),
|
||||
result_data)
|
||||
self.assertEqual(result_ok(0, {'auth.queries.tcp': self.stats_data['auth.queries.tcp']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
self.session.group_sendmsg({"command": [ "show", {'stats_item_name': 'auth.queries.udp'} ]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'auth.queries.udp': 98765}),
|
||||
result_data)
|
||||
self.assertEqual(result_ok(0, {'auth.queries.udp': self.stats_data['auth.queries.udp']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set command 4
|
||||
self.stats_data['auth.queries.tcp'] = 67890
|
||||
self.session.group_sendmsg({"command": [
|
||||
"set", {'stats_data': {'auth.queries.tcp': 67890 }} ]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test show command for all values
|
||||
self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, self.stats_data), result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_some_commands2(self):
|
||||
"""
|
||||
Test for some commands in a row using list-type value
|
||||
|
||||
"""
|
||||
self.stats_data['listtype'] = [1, 2, 3]
|
||||
self.assertEqual(self.stats_data['listtype'], [1, 2, 3])
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"set", {'stats_data': {'listtype': [1, 2, 3] }}
|
||||
]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check its value
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"show", { 'stats_item_name': 'listtype'}
|
||||
]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'listtype': [1, 2, 3]}),
|
||||
result_data)
|
||||
self.assertEqual(result_ok(0, {'listtype': self.stats_data['listtype']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set list-type value
|
||||
self.assertEqual(self.stats_data['listtype'], [1, 2, 3])
|
||||
self.session.group_sendmsg({"command": [
|
||||
"set", {'stats_data': {'listtype': [3, 2, 1, 0] }}
|
||||
]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check its value
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"show", { 'stats_item_name': 'listtype' }
|
||||
] }, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'listtype': [3, 2, 1, 0]}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_some_commands3(self):
|
||||
"""
|
||||
Test for some commands in a row using dictionary-type value
|
||||
|
||||
"""
|
||||
self.stats_data['dicttype'] = {"a": 1, "b": 2, "c": 3}
|
||||
self.assertEqual(self.stats_data['dicttype'], {"a": 1, "b": 2, "c": 3})
|
||||
self.session.group_sendmsg({ "command": [
|
||||
"set", {
|
||||
'stats_data': {'dicttype': {"a": 1, "b": 2, "c": 3} }
|
||||
}]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check its value
|
||||
self.session.group_sendmsg({ "command": [ "show", { 'stats_item_name': 'dicttype' } ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'dicttype': {"a": 1, "b": 2, "c": 3}}),
|
||||
result_data)
|
||||
self.assertEqual(result_ok(0, {'dicttype': self.stats_data['dicttype']}),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# test set list-type value
|
||||
self.assertEqual(self.stats_data['dicttype'], {"a": 1, "b": 2, "c": 3})
|
||||
self.session.group_sendmsg({"command": [
|
||||
"set", {'stats_data': {'dicttype': {"a": 3, "b": 2, "c": 1, "d": 0} }} ]},
|
||||
"Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
# check its value
|
||||
self.session.group_sendmsg({ "command": [ "show", { 'stats_item_name': 'dicttype' }]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
result_data = self.session.get_message("Stats", None)
|
||||
self.assertEqual(result_ok(0, {'dicttype': {"a": 3, "b": 2, "c": 1, "d": 0} }),
|
||||
result_data)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
|
||||
def test_config_update(self):
|
||||
"""
|
||||
Test for config update
|
||||
|
||||
"""
|
||||
# test show command without arg
|
||||
self.session.group_sendmsg({"command": [ "config_update", {"x-version":999} ]}, "Stats")
|
||||
self.assertEqual(len(self.session.message_queue), 1)
|
||||
self.subject.check()
|
||||
self.assertEqual(result_ok(),
|
||||
self.session.get_message("Stats", None))
|
||||
|
||||
class TestStats2(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.session = Session(verbose=True)
|
||||
self.subject = SessionSubject(session=self.session, verbose=True)
|
||||
self.listener = CCSessionListener(self.subject, verbose=True)
|
||||
self.module_name = self.listener.cc_session.get_module_spec().get_module_name()
|
||||
# check starting
|
||||
self.assertFalse(self.subject.running)
|
||||
self.subject.start()
|
||||
self.assertTrue(self.subject.running)
|
||||
self.assertEqual(len(self.session.message_queue), 0)
|
||||
self.assertEqual(self.module_name, 'Stats')
|
||||
|
||||
def tearDown(self):
|
||||
# check closing
|
||||
self.subject.stop()
|
||||
self.assertFalse(self.subject.running)
|
||||
self.subject.detach(self.listener)
|
||||
self.listener.stop()
|
||||
|
||||
def test_specfile(self):
|
||||
"""
|
||||
Test for specfile
|
||||
|
||||
"""
|
||||
if "B10_FROM_BUILD" in os.environ:
|
||||
self.assertEqual(stats.SPECFILE_LOCATION,
|
||||
os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec")
|
||||
imp.reload(stats)
|
||||
# change path of SPECFILE_LOCATION
|
||||
stats.SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
|
||||
self.assertEqual(stats.SPECFILE_LOCATION, TEST_SPECFILE_LOCATION)
|
||||
self.subject = stats.SessionSubject(session=self.session, verbose=True)
|
||||
self.session = self.subject.session
|
||||
self.listener = stats.CCSessionListener(self.subject, verbose=True)
|
||||
|
||||
self.assertEqual(self.listener.stats_spec, [])
|
||||
self.assertEqual(self.listener.stats_data, {})
|
||||
|
||||
self.assertEqual(self.listener.commands_spec, [
|
||||
{
|
||||
"command_name": "status",
|
||||
"command_description": "identify whether stats module is alive or not",
|
||||
"command_args": []
|
||||
},
|
||||
{
|
||||
"command_name": "the_dummy",
|
||||
"command_description": "this is for testing",
|
||||
"command_args": []
|
||||
}])
|
||||
|
||||
def test_func_initialize_data(self):
|
||||
"""
|
||||
Test for initialize_data function
|
||||
|
||||
"""
|
||||
# prepare for sample data set
|
||||
stats_spec = [
|
||||
{
|
||||
"item_name": "none_sample",
|
||||
"item_type": "null",
|
||||
"item_default": "None"
|
||||
},
|
||||
{
|
||||
"item_name": "boolean_sample",
|
||||
"item_type": "boolean",
|
||||
"item_default": True
|
||||
},
|
||||
{
|
||||
"item_name": "string_sample",
|
||||
"item_type": "string",
|
||||
"item_default": "A something"
|
||||
},
|
||||
{
|
||||
"item_name": "int_sample",
|
||||
"item_type": "integer",
|
||||
"item_default": 9999999
|
||||
},
|
||||
{
|
||||
"item_name": "real_sample",
|
||||
"item_type": "real",
|
||||
"item_default": 0.0009
|
||||
},
|
||||
{
|
||||
"item_name": "list_sample",
|
||||
"item_type": "list",
|
||||
"item_default": [0, 1, 2, 3, 4],
|
||||
"list_item_spec": []
|
||||
},
|
||||
{
|
||||
"item_name": "map_sample",
|
||||
"item_type": "map",
|
||||
"item_default": {'name':'value'},
|
||||
"map_item_spec": []
|
||||
},
|
||||
{
|
||||
"item_name": "other_sample",
|
||||
"item_type": "__unknown__",
|
||||
"item_default": "__unknown__"
|
||||
}
|
||||
]
|
||||
# data for comparison
|
||||
stats_data = {
|
||||
'none_sample': None,
|
||||
'boolean_sample': True,
|
||||
'string_sample': 'A something',
|
||||
'int_sample': 9999999,
|
||||
'real_sample': 0.0009,
|
||||
'list_sample': [0, 1, 2, 3, 4],
|
||||
'map_sample': {'name':'value'},
|
||||
'other_sample': '__unknown__'
|
||||
}
|
||||
self.assertEqual(self.listener.initialize_data(stats_spec), stats_data)
|
||||
|
||||
def test_func_main(self):
|
||||
# explicitly make failed
|
||||
self.session.close()
|
||||
stats.main(session=self.session)
|
||||
|
||||
def test_osenv(self):
|
||||
"""
|
||||
test for not having environ "B10_FROM_BUILD"
|
||||
"""
|
||||
if "B10_FROM_BUILD" in os.environ:
|
||||
path = os.environ["B10_FROM_BUILD"]
|
||||
os.environ.pop("B10_FROM_BUILD")
|
||||
imp.reload(stats)
|
||||
os.environ["B10_FROM_BUILD"] = path
|
||||
imp.reload(stats)
|
||||
|
||||
def result_ok(*args):
|
||||
if args:
|
||||
return { 'result': list(args) }
|
||||
else:
|
||||
return { 'result': [ 0 ] }
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
48
src/bin/stats/tests/fake_time.py
Normal file
48
src/bin/stats/tests/fake_time.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
__version__ = "$Revision$"
|
||||
|
||||
# This is a dummy time class against a Python standard time class.
|
||||
# It is just testing use only.
|
||||
# Other methods which time class has is not implemented.
|
||||
# (This class isn't orderloaded for time class.)
|
||||
|
||||
# These variables are constant. These are example.
|
||||
_TEST_TIME_SECS = 1283364938.229088
|
||||
_TEST_TIME_STRF = '2010-09-01T18:15:38Z'
|
||||
|
||||
def time():
|
||||
"""
|
||||
This is a dummy time() method against time.time()
|
||||
"""
|
||||
# return float constant value
|
||||
return _TEST_TIME_SECS
|
||||
|
||||
def gmtime():
|
||||
"""
|
||||
This is a dummy gmtime() method against time.gmtime()
|
||||
"""
|
||||
# always return nothing
|
||||
return None
|
||||
|
||||
def strftime(*arg):
|
||||
"""
|
||||
This is a dummy gmtime() method against time.gmtime()
|
||||
"""
|
||||
return _TEST_TIME_STRF
|
||||
|
||||
|
0
src/bin/stats/tests/isc/__init__.py
Normal file
0
src/bin/stats/tests/isc/__init__.py
Normal file
1
src/bin/stats/tests/isc/cc/__init__.py
Normal file
1
src/bin/stats/tests/isc/cc/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from isc.cc.session import *
|
127
src/bin/stats/tests/isc/cc/session.py
Normal file
127
src/bin/stats/tests/isc/cc/session.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
# This module is a mock-up class of isc.cc.session
|
||||
|
||||
__version__ = "$Revision$"
|
||||
|
||||
import sys
|
||||
|
||||
# set a dummy lname
|
||||
_TEST_LNAME = '123abc@xxxx'
|
||||
|
||||
class Queue():
|
||||
def __init__(self, msg=None, env={}):
|
||||
self.msg = msg
|
||||
self.env = env
|
||||
|
||||
def dump(self):
|
||||
return { 'msg': self.msg, 'env': self.env }
|
||||
|
||||
class SessionError(Exception):
|
||||
pass
|
||||
|
||||
class Session:
|
||||
def __init__(self, socket_file=None, verbose=False):
|
||||
self._lname = _TEST_LNAME
|
||||
self.message_queue = []
|
||||
self.old_message_queue = []
|
||||
self._socket = True
|
||||
self.verbose = verbose
|
||||
|
||||
@property
|
||||
def lname(self):
|
||||
return self._lname
|
||||
|
||||
def close(self):
|
||||
self._socket = False
|
||||
|
||||
def _next_sequence(self, que=None):
|
||||
return len(self.message_queue)
|
||||
|
||||
def enqueue(self, msg=None, env={}):
|
||||
if not self._socket:
|
||||
raise SessionError("Session has been closed.")
|
||||
seq = self._next_sequence()
|
||||
env.update({"seq": 0}) # fixed here
|
||||
que = Queue(msg=msg, env=env)
|
||||
self.message_queue.append(que)
|
||||
if self.verbose:
|
||||
sys.stdout.write("[Session] enqueue: " + str(que.dump()) + "\n")
|
||||
return seq
|
||||
|
||||
def dequeue(self, seq=0):
|
||||
if not self._socket:
|
||||
raise SessionError("Session has been closed.")
|
||||
que = None
|
||||
try:
|
||||
que = self.message_queue.pop(seq)
|
||||
self.old_message_queue.append(que)
|
||||
except IndexError:
|
||||
que = Queue()
|
||||
if self.verbose:
|
||||
sys.stdout.write("[Session] dequeue: " + str(que.dump()) + "\n")
|
||||
return que
|
||||
|
||||
def get_queue(self, seq=None):
|
||||
if not self._socket:
|
||||
raise SessionError("Session has been closed.")
|
||||
if seq is None:
|
||||
seq = len(self.message_queue) - 1
|
||||
que = None
|
||||
try:
|
||||
que = self.message_queue[seq]
|
||||
except IndexError:
|
||||
raise IndexError
|
||||
que = Queue()
|
||||
if self.verbose:
|
||||
sys.stdout.write("[Session] get_queue: " + str(que.dump()) + "\n")
|
||||
return que
|
||||
|
||||
def group_sendmsg(self, msg, group, instance="*", to="*"):
|
||||
return self.enqueue(msg=msg, env={
|
||||
"type": "send",
|
||||
"from": self._lname,
|
||||
"to": to,
|
||||
"group": group,
|
||||
"instance": instance })
|
||||
|
||||
def group_recvmsg(self, nonblock=True, seq=0):
|
||||
que = self.dequeue(seq)
|
||||
return que.msg, que.env
|
||||
|
||||
def group_reply(self, routing, msg):
|
||||
return self.enqueue(msg=msg, env={
|
||||
"type": "send",
|
||||
"from": self._lname,
|
||||
"to": routing["from"],
|
||||
"group": routing["group"],
|
||||
"instance": routing["instance"],
|
||||
"reply": routing["seq"] })
|
||||
|
||||
def get_message(self, group, to='*'):
|
||||
if not self._socket:
|
||||
raise SessionError("Session has been closed.")
|
||||
que = Queue()
|
||||
for q in self.message_queue:
|
||||
if q.env['group'] == group:
|
||||
self.message_queue.remove(q)
|
||||
self.old_message_queue.append(q)
|
||||
que = q
|
||||
if self.verbose:
|
||||
sys.stdout.write("[Session] get_message: " + str(que.dump()) + "\n")
|
||||
return q.msg
|
||||
|
1
src/bin/stats/tests/isc/config/__init__.py
Normal file
1
src/bin/stats/tests/isc/config/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from isc.config.ccsession import *
|
114
src/bin/stats/tests/isc/config/ccsession.py
Normal file
114
src/bin/stats/tests/isc/config/ccsession.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
# This module is a mock-up class of isc.cc.session
|
||||
|
||||
__version__ = "$Revision$"
|
||||
|
||||
import json
|
||||
from isc.cc.session import Session
|
||||
|
||||
COMMAND_CONFIG_UPDATE = "config_update"
|
||||
|
||||
def parse_answer(msg):
|
||||
try:
|
||||
return msg['result'][0], msg['result'][1]
|
||||
except IndexError:
|
||||
return msg['result'][0], None
|
||||
|
||||
def create_answer(rcode, arg = None):
|
||||
if arg is None:
|
||||
return { 'result': [ rcode ] }
|
||||
else:
|
||||
return { 'result': [ rcode, arg ] }
|
||||
|
||||
def parse_command(msg):
|
||||
try:
|
||||
return msg['command'][0], msg['command'][1]
|
||||
except IndexError:
|
||||
return msg['command'][0], None
|
||||
|
||||
def create_command(command_name, params = None):
|
||||
if params is None:
|
||||
return {"command": [command_name]}
|
||||
else:
|
||||
return {"command": [command_name, params]}
|
||||
|
||||
def module_spec_from_file(spec_file, check = True):
|
||||
file = open(spec_file)
|
||||
module_spec = json.loads(file.read())
|
||||
return ModuleSpec(module_spec['module_spec'], check)
|
||||
|
||||
class ModuleSpec:
|
||||
def __init__(self, module_spec, check = True):
|
||||
self._module_spec = module_spec
|
||||
|
||||
def get_config_spec(self):
|
||||
return self._module_spec['config_data']
|
||||
|
||||
def get_commands_spec(self):
|
||||
return self._module_spec['commands']
|
||||
|
||||
def get_module_name(self):
|
||||
return self._module_spec['module_name']
|
||||
|
||||
class ModuleCCSessionError(Exception):
|
||||
pass
|
||||
|
||||
class ConfigData:
|
||||
def __init__(self, specification):
|
||||
self.specification = specification
|
||||
|
||||
class ModuleCCSession(ConfigData):
|
||||
def __init__(self, spec_file_name, config_handler, command_handler, cc_session = None):
|
||||
module_spec = module_spec_from_file(spec_file_name)
|
||||
ConfigData.__init__(self, module_spec)
|
||||
self._module_name = module_spec.get_module_name()
|
||||
self.set_config_handler(config_handler)
|
||||
self.set_command_handler(command_handler)
|
||||
if not cc_session:
|
||||
self._session = Session(verbose=True)
|
||||
else:
|
||||
self._session = cc_session
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
self._session.close()
|
||||
|
||||
def check_command(self):
|
||||
msg, env = self._session.group_recvmsg(False)
|
||||
if not msg or 'result' in msg:
|
||||
return
|
||||
cmd, arg = parse_command(msg)
|
||||
answer = None
|
||||
if cmd == COMMAND_CONFIG_UPDATE and self._config_handler:
|
||||
answer = self._config_handler(arg)
|
||||
elif env['group'] == self._module_name and self._command_handler:
|
||||
answer = self._command_handler(cmd, arg)
|
||||
if answer:
|
||||
self._session.group_reply(env, answer)
|
||||
|
||||
def set_config_handler(self, config_handler):
|
||||
self._config_handler = config_handler
|
||||
# should we run this right now since we've changed the handler?
|
||||
|
||||
def set_command_handler(self, command_handler):
|
||||
self._command_handler = command_handler
|
||||
|
||||
def get_module_spec(self):
|
||||
return self.specification
|
0
src/bin/stats/tests/isc/utils/__init__.py
Normal file
0
src/bin/stats/tests/isc/utils/__init__.py
Normal file
20
src/bin/stats/tests/isc/utils/process.py
Normal file
20
src/bin/stats/tests/isc/utils/process.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id$
|
||||
|
||||
# A dummy function of isc.utils.process.rename()
|
||||
def rename(name=None):
|
||||
pass
|
31
src/bin/stats/tests/stats_test.in
Normal file
31
src/bin/stats/tests/stats_test.in
Normal file
@@ -0,0 +1,31 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2010 Internet Systems Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
|
||||
export PYTHON_EXEC
|
||||
|
||||
PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/bin/stats
|
||||
export PYTHONPATH
|
||||
|
||||
B10_FROM_BUILD=@abs_top_builddir@
|
||||
export B10_FROM_BUILD
|
||||
|
||||
TEST_PATH=@abs_top_srcdir@/src/bin/stats/tests
|
||||
|
||||
cd ${TEST_PATH}
|
||||
${PYTHON_EXEC} -O b10-stats_test.py $*
|
||||
${PYTHON_EXEC} -O b10-stats_stub_test.py $*
|
19
src/bin/stats/tests/testdata/stats_test.spec
vendored
Normal file
19
src/bin/stats/tests/testdata/stats_test.spec
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"module_spec": {
|
||||
"module_name": "Stats",
|
||||
"module_description": "Stats daemon",
|
||||
"config_data": [],
|
||||
"commands": [
|
||||
{
|
||||
"command_name": "status",
|
||||
"command_description": "identify whether stats module is alive or not",
|
||||
"command_args": []
|
||||
},
|
||||
{
|
||||
"command_name": "the_dummy",
|
||||
"command_description": "this is for testing",
|
||||
"command_args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -316,7 +316,9 @@ def _validate_spec(spec, full, data, errors):
|
||||
item_name = spec['item_name']
|
||||
item_optional = spec['item_optional']
|
||||
|
||||
if item_name in data:
|
||||
if not data and item_optional:
|
||||
return True
|
||||
elif item_name in data:
|
||||
return _validate_item(spec, full, data[item_name], errors)
|
||||
elif full and not item_optional:
|
||||
if errors != None:
|
||||
|
Reference in New Issue
Block a user