summaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/Makefile.am15
-rw-r--r--python/Makefile.in525
-rw-r--r--python/libknot/__init__.py.in3
-rwxr-xr-xpython/libknot/control.py441
-rw-r--r--python/setup.py.in27
-rwxr-xr-xpython/stats_http.py73
-rwxr-xr-xpython/stats_influxdb.py79
7 files changed, 1163 insertions, 0 deletions
diff --git a/python/Makefile.am b/python/Makefile.am
new file mode 100644
index 0000000..dd76d62
--- /dev/null
+++ b/python/Makefile.am
@@ -0,0 +1,15 @@
+EXTRA_DIST = \
+ libknot/__init__.py.in \
+ libknot/control.py \
+ setup.py.in \
+ stats_http.py \
+ stats_influxdb.py
+
+clean-local:
+ -rm -rf dist *.egg-info
+
+dist: clean-local
+ python3 setup.py sdist
+
+upload:
+ twine upload dist/*
diff --git a/python/Makefile.in b/python/Makefile.in
new file mode 100644
index 0000000..19d328a
--- /dev/null
+++ b/python/Makefile.in
@@ -0,0 +1,525 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = python
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cc_clang.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_compare_version.m4 \
+ $(top_srcdir)/m4/code-coverage.m4 \
+ $(top_srcdir)/m4/knot-lib-version.m4 \
+ $(top_srcdir)/m4/knot-module.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/sanitizer.m4 $(top_srcdir)/m4/visibility.m4 \
+ $(top_srcdir)/m4/knot-version.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES = setup.py
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/setup.py.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_CLANG_VERSION = @CC_CLANG_VERSION@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KNOT_VERSION_MAJOR = @KNOT_VERSION_MAJOR@
+KNOT_VERSION_MINOR = @KNOT_VERSION_MINOR@
+KNOT_VERSION_PATCH = @KNOT_VERSION_PATCH@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAG_EXCLUDE_LIBS = @LDFLAG_EXCLUDE_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cap_ng_CFLAGS = @cap_ng_CFLAGS@
+cap_ng_LIBS = @cap_ng_LIBS@
+conf_mapsize = @conf_mapsize@
+config_dir = @config_dir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dlopen_LIBS = @dlopen_LIBS@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+external_lmdb_LIBS = @external_lmdb_LIBS@
+fuzzer_CFLAGS = @fuzzer_CFLAGS@
+fuzzer_LDFLAGS = @fuzzer_LDFLAGS@
+gnutls_CFLAGS = @gnutls_CFLAGS@
+gnutls_LIBS = @gnutls_LIBS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libdnssec_SONAME = @libdnssec_SONAME@
+libdnssec_SOVERSION = @libdnssec_SOVERSION@
+libdnssec_VERSION_INFO = @libdnssec_VERSION_INFO@
+libedit_CFLAGS = @libedit_CFLAGS@
+libedit_LIBS = @libedit_LIBS@
+libexecdir = @libexecdir@
+libfstrm_CFLAGS = @libfstrm_CFLAGS@
+libfstrm_LIBS = @libfstrm_LIBS@
+libidn2_CFLAGS = @libidn2_CFLAGS@
+libidn2_LIBS = @libidn2_LIBS@
+libidn_CFLAGS = @libidn_CFLAGS@
+libidn_LIBS = @libidn_LIBS@
+libknot_SONAME = @libknot_SONAME@
+libknot_SOVERSION = @libknot_SOVERSION@
+libknot_VERSION_INFO = @libknot_VERSION_INFO@
+libmaxminddb_CFLAGS = @libmaxminddb_CFLAGS@
+libmaxminddb_LIBS = @libmaxminddb_LIBS@
+libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@
+libprotobuf_c_LIBS = @libprotobuf_c_LIBS@
+liburcu_CFLAGS = @liburcu_CFLAGS@
+liburcu_LIBS = @liburcu_LIBS@
+liburcu_PKGCONFIG = @liburcu_PKGCONFIG@
+libzscanner_SONAME = @libzscanner_SONAME@
+libzscanner_SOVERSION = @libzscanner_SOVERSION@
+libzscanner_VERSION_INFO = @libzscanner_VERSION_INFO@
+lmdb_CFLAGS = @lmdb_CFLAGS@
+lmdb_LIBS = @lmdb_LIBS@
+localedir = @localedir@
+localstatedir = @localstatedir@
+malloc_LIBS = @malloc_LIBS@
+mandir = @mandir@
+math_LIBS = @math_LIBS@
+mkdir_p = @mkdir_p@
+module_dir = @module_dir@
+module_instdir = @module_instdir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pthread_LIBS = @pthread_LIBS@
+run_dir = @run_dir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+storage_dir = @storage_dir@
+sysconfdir = @sysconfdir@
+systemd_CFLAGS = @systemd_CFLAGS@
+systemd_LIBS = @systemd_LIBS@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ libknot/__init__.py.in \
+ libknot/control.py \
+ setup.py.in \
+ stats_http.py \
+ stats_influxdb.py
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign python/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign python/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+setup.py: $(top_builddir)/config.status $(srcdir)/setup.py.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ clean-local cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+clean-local:
+ -rm -rf dist *.egg-info
+
+dist: clean-local
+ python3 setup.py sdist
+
+upload:
+ twine upload dist/*
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/python/libknot/__init__.py.in b/python/libknot/__init__.py.in
new file mode 100644
index 0000000..5984340
--- /dev/null
+++ b/python/libknot/__init__.py.in
@@ -0,0 +1,3 @@
+"""Python libknot interface."""
+
+LIBKNOT_VERSION = "@libknot_SOVERSION@"
diff --git a/python/libknot/control.py b/python/libknot/control.py
new file mode 100755
index 0000000..ced1be6
--- /dev/null
+++ b/python/libknot/control.py
@@ -0,0 +1,441 @@
+"""Libknot server control interface wrapper.
+
+Example:
+ import json
+ from libknot.control import *
+
+ #load_lib("/usr/lib/libknot.so")
+
+ ctl = KnotCtl()
+ ctl.connect("/var/run/knot/knot.sock")
+
+ try:
+ ctl.send_block(cmd="conf-begin")
+ resp = ctl.receive_block()
+
+ ctl.send_block(cmd="conf-set", section="zone", item="domain", data="test")
+ resp = ctl.receive_block()
+
+ ctl.send_block(cmd="conf-commit")
+ resp = ctl.receive_block()
+
+ ctl.send_block(cmd="conf-read", section="zone", item="domain")
+ resp = ctl.receive_block()
+ print(json.dumps(resp, indent=4))
+ finally:
+ ctl.send(KnotCtlType.END)
+ ctl.close()
+"""
+
+from ctypes import cdll, c_void_p, c_int, c_char_p, c_uint, byref
+from enum import IntEnum
+import sys
+
+CTL_ALLOC = None
+CTL_FREE = None
+CTL_SET_TIMEOUT = None
+CTL_CONNECT = None
+CTL_CLOSE = None
+CTL_SEND = None
+CTL_RECEIVE = None
+CTL_ERROR = None
+
+
+def load_lib(path=None):
+ """Loads the libknot library."""
+
+ if path is None:
+ version = ""
+ try:
+ from libknot import LIBKNOT_VERSION
+ version = ".%u" % int(LIBKNOT_VERSION)
+ except:
+ pass
+
+ if sys.platform == "darwin":
+ path = "libknot%s.dylib" % version
+ else:
+ path = "libknot.so%s" % version
+ LIB = cdll.LoadLibrary(path)
+
+ global CTL_ALLOC
+ CTL_ALLOC = LIB.knot_ctl_alloc
+ CTL_ALLOC.restype = c_void_p
+
+ global CTL_FREE
+ CTL_FREE = LIB.knot_ctl_free
+ CTL_FREE.argtypes = [c_void_p]
+
+ global CTL_SET_TIMEOUT
+ CTL_SET_TIMEOUT = LIB.knot_ctl_set_timeout
+ CTL_SET_TIMEOUT.argtypes = [c_void_p, c_int]
+
+ global CTL_CONNECT
+ CTL_CONNECT = LIB.knot_ctl_connect
+ CTL_CONNECT.restype = c_int
+ CTL_CONNECT.argtypes = [c_void_p, c_char_p]
+
+ global CTL_CLOSE
+ CTL_CLOSE = LIB.knot_ctl_close
+ CTL_CLOSE.argtypes = [c_void_p]
+
+ global CTL_SEND
+ CTL_SEND = LIB.knot_ctl_send
+ CTL_SEND.restype = c_int
+ CTL_SEND.argtypes = [c_void_p, c_uint, c_void_p]
+
+ global CTL_RECEIVE
+ CTL_RECEIVE = LIB.knot_ctl_receive
+ CTL_RECEIVE.restype = c_int
+ CTL_RECEIVE.argtypes = [c_void_p, c_void_p, c_void_p]
+
+ global CTL_ERROR
+ CTL_ERROR = LIB.knot_strerror
+ CTL_ERROR.restype = c_char_p
+ CTL_ERROR.argtypes = [c_int]
+
+
+class KnotCtlError(Exception):
+ """Libknot server control error."""
+
+ def __init__(self, message, data=None):
+ """
+ @type message: str
+ @type data: KnotCtlData
+ """
+
+ self.message = message
+ self.data = data
+
+ def __str__(self):
+ return "%s (data: %s)" % (self.message, self.data)
+
+
+class KnotCtlType(IntEnum):
+ """Libknot server control data unit types."""
+
+ END = 0
+ DATA = 1
+ EXTRA = 2
+ BLOCK = 3
+
+
+class KnotCtlDataIdx(IntEnum):
+ """Libknot server control data unit indices."""
+
+ COMMAND = 0
+ FLAGS = 1
+ ERROR = 2
+ SECTION = 3
+ ITEM = 4
+ ID = 5
+ ZONE = 6
+ OWNER = 7
+ TTL = 8
+ TYPE = 9
+ DATA = 10
+ FILTER = 11
+
+
+class KnotCtlData(object):
+ """Libknot server control data unit."""
+
+ DataArray = c_char_p * len(KnotCtlDataIdx)
+
+ def __init__(self):
+ self.data = self.DataArray()
+
+ def __str__(self):
+ string = str()
+
+ for idx in KnotCtlDataIdx:
+ if self.data[idx]:
+ if string:
+ string += ", "
+ string += "%s = %s" % (idx.name, self.data[idx])
+
+ return string
+
+ def __getitem__(self, index):
+ """Data unit item getter.
+
+ @type index: KnotCtlDataIdx
+ @rtype: str
+ """
+
+ value = self.data[index]
+ if not value:
+ value = str()
+ return value if isinstance(value, str) else value.decode()
+
+ def __setitem__(self, index, value):
+ """Data unit item setter.
+
+ @type index: KnotCtlDataIdx
+ @type value: str
+ """
+
+ self.data[index] = c_char_p(value.encode()) if value else c_char_p()
+
+class KnotCtl(object):
+ """Libknot server control interface."""
+
+ def __init__(self):
+ if not CTL_ALLOC:
+ load_lib()
+ self.obj = CTL_ALLOC()
+
+ def __del__(self):
+ CTL_FREE(self.obj)
+
+ def set_timeout(self, timeout):
+ """Sets control socket operations timeout in seconds.
+
+ @type timeout: int
+ """
+
+ CTL_SET_TIMEOUT(self.obj, timeout * 1000)
+
+ def connect(self, path):
+ """Connect to a specified control UNIX socket.
+
+ @type path: str
+ """
+
+ ret = CTL_CONNECT(self.obj, path.encode())
+ if ret != 0:
+ err = CTL_ERROR(ret)
+ raise KnotCtlError(err if isinstance(err, str) else err.decode())
+
+ def close(self):
+ """Disconnects from the current control socket."""
+
+ CTL_CLOSE(self.obj)
+
+ def send(self, data_type, data=None):
+ """Sends a data unit to the connected control socket.
+
+ @type data_type: KnotCtlType
+ @type data: KnotCtlData
+ """
+
+ ret = CTL_SEND(self.obj, data_type,
+ data.data if data else c_char_p())
+ if ret != 0:
+ err = CTL_ERROR(ret)
+ raise KnotCtlError(err if isinstance(err, str) else err.decode())
+
+ def receive(self, data=None):
+ """Receives a data unit from the connected control socket.
+
+ @type data: KnotCtlData
+ @rtype: KnotCtlType
+ """
+
+ data_type = c_uint()
+ ret = CTL_RECEIVE(self.obj, byref(data_type),
+ data.data if data else c_char_p())
+ if ret != 0:
+ err = CTL_ERROR(ret)
+ raise KnotCtlError(err if isinstance(err, str) else err.decode())
+ return KnotCtlType(data_type.value)
+
+ def send_block(self, cmd, section=None, item=None, identifier=None, zone=None,
+ owner=None, ttl=None, rtype=None, data=None, flags=None,
+ filter=None):
+ """Sends a control query block.
+
+ @type cmd: str
+ @type section: str
+ @type item: str
+ @type identifier: str
+ @type zone: str
+ @type owner: str
+ @type ttl: str
+ @type rtype: str
+ @type data: str
+ @type filter: str
+ """
+
+ query = KnotCtlData()
+ query[KnotCtlDataIdx.COMMAND] = cmd
+ query[KnotCtlDataIdx.SECTION] = section
+ query[KnotCtlDataIdx.ITEM] = item
+ query[KnotCtlDataIdx.ID] = identifier
+ query[KnotCtlDataIdx.ZONE] = zone
+ query[KnotCtlDataIdx.OWNER] = owner
+ query[KnotCtlDataIdx.TTL] = ttl
+ query[KnotCtlDataIdx.TYPE] = rtype
+ query[KnotCtlDataIdx.DATA] = data
+ query[KnotCtlDataIdx.FLAGS] = flags
+ query[KnotCtlDataIdx.FILTER] = filter
+
+ self.send(KnotCtlType.DATA, query)
+ self.send(KnotCtlType.BLOCK)
+
+ def _receive_conf(self, out, reply):
+
+ section = reply[KnotCtlDataIdx.SECTION]
+ ident = reply[KnotCtlDataIdx.ID]
+ item = reply[KnotCtlDataIdx.ITEM]
+ data = reply[KnotCtlDataIdx.DATA]
+
+ # Add the section if not exists.
+ if section not in out:
+ out[section] = dict()
+
+ # Add the identifier if not exists.
+ if ident and ident not in out[section]:
+ out[section][ident] = dict()
+
+ # Return if no item/value.
+ if not item:
+ return
+
+ item_level = out[section][ident] if ident else out[section]
+
+ # Treat alone identifier item differently.
+ if item in ["id", "domain", "target"]:
+ if data not in out[section]:
+ out[section][data] = dict()
+ else:
+ if item not in item_level:
+ item_level[item] = list()
+
+ if data:
+ item_level[item].append(data)
+
+ def _receive_zone_status(self, out, reply):
+
+ zone = reply[KnotCtlDataIdx.ZONE]
+ rtype = reply[KnotCtlDataIdx.TYPE]
+ data = reply[KnotCtlDataIdx.DATA]
+
+ # Add the zone if not exists.
+ if zone not in out:
+ out[zone] = dict()
+
+ out[zone][rtype] = data
+
+ def _receive_zone(self, out, reply):
+
+ zone = reply[KnotCtlDataIdx.ZONE]
+ owner = reply[KnotCtlDataIdx.OWNER]
+ ttl = reply[KnotCtlDataIdx.TTL]
+ rtype = reply[KnotCtlDataIdx.TYPE]
+ data = reply[KnotCtlDataIdx.DATA]
+
+ # Add the zone if not exists.
+ if zone not in out:
+ out[zone] = dict()
+
+ if owner not in out[zone]:
+ out[zone][owner] = dict()
+
+ if rtype not in out[zone][owner]:
+ out[zone][owner][rtype] = dict()
+
+ # Add the key/value.
+ out[zone][owner][rtype]["ttl"] = ttl
+
+ if not "data" in out[zone][owner][rtype]:
+ out[zone][owner][rtype]["data"] = [data]
+ else:
+ out[zone][owner][rtype]["data"].append(data)
+
+ def _receive_stats(self, out, reply):
+
+ zone = reply[KnotCtlDataIdx.ZONE]
+ section = reply[KnotCtlDataIdx.SECTION]
+ item = reply[KnotCtlDataIdx.ITEM]
+ idx = reply[KnotCtlDataIdx.ID]
+ data = int(reply[KnotCtlDataIdx.DATA])
+
+ # Add the zone if not exists.
+ if zone:
+ if "zone" not in out:
+ out["zone"] = dict()
+
+ if zone not in out["zone"]:
+ out["zone"][zone] = dict()
+
+ section_level = out["zone"][zone] if zone else out
+
+ if section not in section_level:
+ section_level[section] = dict()
+
+ if idx:
+ if item not in section_level[section]:
+ section_level[section][item] = dict()
+
+ section_level[section][item][idx] = data
+ else:
+ section_level[section][item] = data
+
+ def receive_stats(self):
+ """Receives statistics answer and returns it as a structured dictionary.
+
+ @rtype: dict
+ """
+
+ out = dict()
+ err_reply = None
+
+ while True:
+ reply = KnotCtlData()
+ reply_type = self.receive(reply)
+
+ # Stop if not data type.
+ if reply_type not in [KnotCtlType.DATA, KnotCtlType.EXTRA]:
+ break
+
+ # Check for an error.
+ if reply[KnotCtlDataIdx.ERROR]:
+ err_reply = reply
+ continue
+
+ self._receive_stats(out, reply)
+
+ if err_reply:
+ raise KnotCtlError(err_reply[KnotCtlDataIdx.ERROR], err_reply)
+
+ return out
+
+ def receive_block(self):
+ """Receives a control answer and returns it as a structured dictionary.
+
+ @rtype: dict
+ """
+
+ out = dict()
+ err_reply = None
+
+ while True:
+ reply = KnotCtlData()
+ reply_type = self.receive(reply)
+
+ # Stop if not data type.
+ if reply_type not in [KnotCtlType.DATA, KnotCtlType.EXTRA]:
+ break
+
+ # Check for an error.
+ if reply[KnotCtlDataIdx.ERROR]:
+ err_reply = reply
+ continue
+
+ # Check for config data.
+ if reply[KnotCtlDataIdx.SECTION]:
+ self._receive_conf(out, reply)
+ # Check for zone data.
+ elif reply[KnotCtlDataIdx.ZONE]:
+ if reply[KnotCtlDataIdx.OWNER]:
+ self._receive_zone(out, reply)
+ else:
+ self._receive_zone_status(out, reply)
+ else:
+ continue
+
+ if err_reply:
+ raise KnotCtlError(err_reply[KnotCtlDataIdx.ERROR], err_reply)
+
+ return out
diff --git a/python/setup.py.in b/python/setup.py.in
new file mode 100644
index 0000000..8d57bc9
--- /dev/null
+++ b/python/setup.py.in
@@ -0,0 +1,27 @@
+import setuptools
+
+setuptools.setup(
+ name='libknot',
+ version='@PACKAGE_VERSION@',
+ description='Python bindings for libknot',
+ author='Daniel Salzman',
+ author_email='daniel.salzman@nic.cz',
+ url='https://gitlab.labs.nic.cz/knot/knot-dns',
+ license='GPL-3.0',
+ packages=['libknot'],
+ classifiers=[ # See https://pypi.org/classifiers
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
+ 'Topic :: Internet :: Name Service (DNS)',
+ 'Topic :: Software Development :: Libraries',
+ 'Topic :: System :: Systems Administration',
+ ]
+)
diff --git a/python/stats_http.py b/python/stats_http.py
new file mode 100755
index 0000000..a38d5f7
--- /dev/null
+++ b/python/stats_http.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+
+"""Simple program for exposing statistics from Knot DNS over HTTP/HTTPS."""
+
+import http.server
+import libknot.control
+import json
+import ssl
+import time
+
+# Configuration.
+#libknot.control.load_lib("../src/.libs/libknot.so")
+ctl_socket = "/tmp/knot.sock"
+ctl_timeout = 2
+ctl_flags = "" # set "F" for all supported counters.
+http_host = "127.0.0.1"
+http_port = 8080
+ssl_enable = False
+ssl_keyfile = "./mykey.key"
+ssl_certfile = "./mycert.crt"
+
+
+class StatsServer(http.server.BaseHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(200)
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+
+ # Connect to Knot server.
+ ctl = libknot.control.KnotCtl()
+ ctl.connect(ctl_socket)
+ ctl.set_timeout(ctl_timeout)
+
+ # Get global metrics.
+ global_stats = dict()
+ try:
+ ctl.send_block(cmd="stats", flags=ctl_flags)
+ global_stats = ctl.receive_stats()
+ except:
+ pass
+
+ # Get zone metrics.
+ zone_stats = dict()
+ try:
+ ctl.send_block(cmd="zone-stats", flags=ctl_flags)
+ zone_stats = ctl.receive_stats()
+ except:
+ pass
+
+ # Disconnect from the server.
+ ctl.send(libknot.control.KnotCtlType.END)
+ ctl.close()
+
+ # Publish the stats.
+ stats = {**global_stats, **zone_stats}
+ self.wfile.write(bytes(json.dumps(stats, indent=4, sort_keys=True), "utf-8"))
+
+
+httpd = http.server.HTTPServer((http_host, http_port), StatsServer)
+
+if ssl_enable:
+ httpd.socket = ssl.wrap_socket(httpd.socket, keyfile=ssl_keyfile,
+ certfile=ssl_certfile, server_side=True)
+
+print("%s: HTTP%s Server Start - %s:%s" %
+ (time.asctime(), "S" if ssl_enable else "", http_host, http_port))
+
+try:
+ httpd.serve_forever()
+except KeyboardInterrupt:
+ pass
+
+httpd.server_close()
diff --git a/python/stats_influxdb.py b/python/stats_influxdb.py
new file mode 100755
index 0000000..33d3709
--- /dev/null
+++ b/python/stats_influxdb.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+
+"""Simple program for exporting statistics from Knot DNS to influxdb."""
+
+import libknot.control
+import io
+import json
+import os
+import time
+
+# Configuration.
+#libknot.control.load_lib("../src/.libs/libknot.so")
+ctl_socket = "/tmp/knot.sock"
+ctl_timeout = 2
+# InfluxDB parameters.
+host = "217.31.192.164"
+port = "8086"
+db = "KnotDNS"
+instance = "Knot"
+# Send metrics every N seconds.
+send_interval = 5
+
+
+def send():
+ # Connect to Knot server.
+ ctl = libknot.control.KnotCtl()
+ ctl.connect(ctl_socket)
+ ctl.set_timeout(ctl_timeout)
+
+ # Get global metrics.
+ global_stats = dict()
+ try:
+ ctl.send_block(cmd="stats", flags="F")
+ global_stats = ctl.receive_stats()
+ except:
+ pass
+
+ # Get zone metrics.
+ zone_stats = dict()
+ try:
+ ctl.send_block(cmd="zone-stats", flags="F")
+ zone_stats = ctl.receive_stats()
+ except:
+ pass
+
+ # Disconnect from the server.
+ ctl.send(libknot.control.KnotCtlType.END)
+ ctl.close()
+
+ # Prepare the metrics to publish.
+ output = io.StringIO()
+
+ stats = {**global_stats, **zone_stats}
+ timestamp = str(int(time.time()))
+
+ for metric in stats["server"]:
+ print("server,instance=" + instance + ",metric=" + metric + " value=" +
+ stats["server"][metric] + " " + timestamp, file=output)
+
+ for group in stats["mod-stats"]:
+ for metric in stats["mod-stats"][group]:
+ print(group + ",instance=" + instance + ",metric=" + metric +
+ " value=" + stats["mod-stats"][group][metric] + " " + timestamp,
+ file=output)
+
+ # Publish the metrics.
+ os.system("curl -i -XPOST 'http://%s:%s/write?db=%s&precision=s' --data-binary '%s'"
+ % (host, port, db, output.getvalue()))
+
+
+print("%s: Graphite sender - Server Start - %s:%s" %
+ (time.asctime(), host, port))
+
+try:
+ while(True):
+ send()
+ time.sleep(send_interval)
+except KeyboardInterrupt:
+ pass