diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/hooks/dhcp/pgsql_cb | |
parent | Initial commit. (diff) | |
download | isc-kea-upstream.tar.xz isc-kea-upstream.zip |
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/hooks/dhcp/pgsql_cb')
28 files changed, 21931 insertions, 0 deletions
diff --git a/src/hooks/dhcp/pgsql_cb/Makefile.am b/src/hooks/dhcp/pgsql_cb/Makefile.am new file mode 100644 index 0000000..2bb8eae --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/Makefile.am @@ -0,0 +1,92 @@ +SUBDIRS = . tests libloadtests + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) $(PGSQL_CPPFLAGS) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +# Ensure that the message file is included in the distribution +EXTRA_DIST = pgsql_cb_messages.mes + +CLEANFILES = *.gcno *.gcda + +# convenience archive + +noinst_LTLIBRARIES = libpgsqlcb.la + +libpgsqlcb_la_SOURCES = pgsql_cb_callouts.cc + +# Commented out for now - see kea#95 +libpgsqlcb_la_SOURCES += pgsql_cb_dhcp4.cc pgsql_cb_dhcp4.h + +# Commented out for now - to be added back in #96 +libpgsqlcb_la_SOURCES += pgsql_cb_dhcp6.cc pgsql_cb_dhcp6.h + +libpgsqlcb_la_SOURCES += pgsql_cb_impl.cc pgsql_cb_impl.h +libpgsqlcb_la_SOURCES += pgsql_cb_messages.cc pgsql_cb_messages.h +libpgsqlcb_la_SOURCES += pgsql_cb_log.cc pgsql_cb_log.h +libpgsqlcb_la_SOURCES += pgsql_query_macros_dhcp.h +libpgsqlcb_la_SOURCES += version.cc + +libpgsqlcb_la_CXXFLAGS = $(AM_CXXFLAGS) +libpgsqlcb_la_CPPFLAGS = $(AM_CPPFLAGS) + +# install the shared object into $(libdir)/kea/hooks +lib_hooksdir = $(libdir)/kea/hooks +lib_hooks_LTLIBRARIES = libdhcp_pgsql_cb.la + +libdhcp_pgsql_cb_la_SOURCES = +libdhcp_pgsql_cb_la_LDFLAGS = $(AM_LDFLAGS) $(pgsql_LIBS) +libdhcp_pgsql_cb_la_LDFLAGS += -avoid-version -export-dynamic -module + +libdhcp_pgsql_cb_la_LIBADD = libpgsqlcb.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/eval/libkea-eval.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/pgsql/libkea-pgsql.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la +libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la + +# If we want to get rid of all generated messages files, we need to use +# make maintainer-clean. The proper way to introduce custom commands for +# that operation is to define maintainer-clean-local target. However, +# make maintainer-clean also removes Makefile, so running configure script +# is required. To make it easy to rebuild messages without going through +# reconfigure, a new target messages-clean has been added. +maintainer-clean-local: + rm -f pgsql_cb_messages.h pgsql_cb_messages.cc + +# To regenerate messages files, one can do: +# +# make messages-clean +# make messages +# +# This is needed only when a .mes file is modified. +messages-clean: maintainer-clean-local + +if GENERATE_MESSAGES + +# Define rule to build logging source files from message file +messages: pgsql_cb_messages.h pgsql_cb_messages.cc + @echo Message files regenerated + +pgsql_cb_messages.h pgsql_cb_messages.cc: pgsql_cb_messages.mes + $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes + +else + +messages pgsql_cb_messages.h pgsql_cb_messages.cc: + @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. + +endif diff --git a/src/hooks/dhcp/pgsql_cb/Makefile.in b/src/hooks/dhcp/pgsql_cb/Makefile.in new file mode 100644 index 0000000..50c0c9d --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/Makefile.in @@ -0,0 +1,1089 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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 = src/hooks/dhcp/pgsql_cb +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp11.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.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)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(lib_hooksdir)" +LTLIBRARIES = $(lib_hooks_LTLIBRARIES) $(noinst_LTLIBRARIES) +libdhcp_pgsql_cb_la_DEPENDENCIES = libpgsqlcb.la \ + $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ + $(top_builddir)/src/lib/process/libkea-process.la \ + $(top_builddir)/src/lib/eval/libkea-eval.la \ + $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ + $(top_builddir)/src/lib/stats/libkea-stats.la \ + $(top_builddir)/src/lib/config/libkea-cfgclient.la \ + $(top_builddir)/src/lib/http/libkea-http.la \ + $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ + $(top_builddir)/src/lib/hooks/libkea-hooks.la \ + $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \ + $(top_builddir)/src/lib/database/libkea-database.la \ + $(top_builddir)/src/lib/cc/libkea-cc.la \ + $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ + $(top_builddir)/src/lib/dns/libkea-dns++.la \ + $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ + $(top_builddir)/src/lib/log/libkea-log.la \ + $(top_builddir)/src/lib/util/libkea-util.la \ + $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +am_libdhcp_pgsql_cb_la_OBJECTS = +libdhcp_pgsql_cb_la_OBJECTS = $(am_libdhcp_pgsql_cb_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libdhcp_pgsql_cb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libdhcp_pgsql_cb_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +libpgsqlcb_la_LIBADD = +am_libpgsqlcb_la_OBJECTS = libpgsqlcb_la-pgsql_cb_callouts.lo \ + libpgsqlcb_la-pgsql_cb_dhcp4.lo \ + libpgsqlcb_la-pgsql_cb_dhcp6.lo libpgsqlcb_la-pgsql_cb_impl.lo \ + libpgsqlcb_la-pgsql_cb_messages.lo \ + libpgsqlcb_la-pgsql_cb_log.lo libpgsqlcb_la-version.lo +libpgsqlcb_la_OBJECTS = $(am_libpgsqlcb_la_OBJECTS) +libpgsqlcb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +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 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo \ + ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo \ + ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo \ + ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo \ + ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo \ + ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo \ + ./$(DEPDIR)/libpgsqlcb_la-version.Plo +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libdhcp_pgsql_cb_la_SOURCES) $(libpgsqlcb_la_SOURCES) +DIST_SOURCES = $(libdhcp_pgsql_cb_la_SOURCES) $(libpgsqlcb_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +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@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +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@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +YACC = @YACC@ +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_CXX = @ac_ct_CXX@ +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@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +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@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . tests libloadtests +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + $(BOOST_INCLUDES) $(PGSQL_CPPFLAGS) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +# Ensure that the message file is included in the distribution +EXTRA_DIST = pgsql_cb_messages.mes +CLEANFILES = *.gcno *.gcda + +# convenience archive +noinst_LTLIBRARIES = libpgsqlcb.la + +# Commented out for now - see kea#95 + +# Commented out for now - to be added back in #96 +libpgsqlcb_la_SOURCES = pgsql_cb_callouts.cc pgsql_cb_dhcp4.cc \ + pgsql_cb_dhcp4.h pgsql_cb_dhcp6.cc pgsql_cb_dhcp6.h \ + pgsql_cb_impl.cc pgsql_cb_impl.h pgsql_cb_messages.cc \ + pgsql_cb_messages.h pgsql_cb_log.cc pgsql_cb_log.h \ + pgsql_query_macros_dhcp.h version.cc +libpgsqlcb_la_CXXFLAGS = $(AM_CXXFLAGS) +libpgsqlcb_la_CPPFLAGS = $(AM_CPPFLAGS) + +# install the shared object into $(libdir)/kea/hooks +lib_hooksdir = $(libdir)/kea/hooks +lib_hooks_LTLIBRARIES = libdhcp_pgsql_cb.la +libdhcp_pgsql_cb_la_SOURCES = +libdhcp_pgsql_cb_la_LDFLAGS = $(AM_LDFLAGS) $(pgsql_LIBS) \ + -avoid-version -export-dynamic -module +libdhcp_pgsql_cb_la_LIBADD = libpgsqlcb.la \ + $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ + $(top_builddir)/src/lib/process/libkea-process.la \ + $(top_builddir)/src/lib/eval/libkea-eval.la \ + $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ + $(top_builddir)/src/lib/stats/libkea-stats.la \ + $(top_builddir)/src/lib/config/libkea-cfgclient.la \ + $(top_builddir)/src/lib/http/libkea-http.la \ + $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ + $(top_builddir)/src/lib/hooks/libkea-hooks.la \ + $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \ + $(top_builddir)/src/lib/database/libkea-database.la \ + $(top_builddir)/src/lib/cc/libkea-cc.la \ + $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ + $(top_builddir)/src/lib/dns/libkea-dns++.la \ + $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ + $(top_builddir)/src/lib/log/libkea-log.la \ + $(top_builddir)/src/lib/util/libkea-util.la \ + $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(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 src/hooks/dhcp/pgsql_cb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + 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): + +install-lib_hooksLTLIBRARIES: $(lib_hooks_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_hooks_LTLIBRARIES)'; test -n "$(lib_hooksdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(lib_hooksdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(lib_hooksdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(lib_hooksdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(lib_hooksdir)"; \ + } + +uninstall-lib_hooksLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_hooks_LTLIBRARIES)'; test -n "$(lib_hooksdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(lib_hooksdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(lib_hooksdir)/$$f"; \ + done + +clean-lib_hooksLTLIBRARIES: + -test -z "$(lib_hooks_LTLIBRARIES)" || rm -f $(lib_hooks_LTLIBRARIES) + @list='$(lib_hooks_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libdhcp_pgsql_cb.la: $(libdhcp_pgsql_cb_la_OBJECTS) $(libdhcp_pgsql_cb_la_DEPENDENCIES) $(EXTRA_libdhcp_pgsql_cb_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdhcp_pgsql_cb_la_LINK) -rpath $(lib_hooksdir) $(libdhcp_pgsql_cb_la_OBJECTS) $(libdhcp_pgsql_cb_la_LIBADD) $(LIBS) + +libpgsqlcb.la: $(libpgsqlcb_la_OBJECTS) $(libpgsqlcb_la_DEPENDENCIES) $(EXTRA_libpgsqlcb_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libpgsqlcb_la_LINK) $(libpgsqlcb_la_OBJECTS) $(libpgsqlcb_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-version.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +libpgsqlcb_la-pgsql_cb_callouts.lo: pgsql_cb_callouts.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_callouts.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Tpo -c -o libpgsqlcb_la-pgsql_cb_callouts.lo `test -f 'pgsql_cb_callouts.cc' || echo '$(srcdir)/'`pgsql_cb_callouts.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_callouts.cc' object='libpgsqlcb_la-pgsql_cb_callouts.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_callouts.lo `test -f 'pgsql_cb_callouts.cc' || echo '$(srcdir)/'`pgsql_cb_callouts.cc + +libpgsqlcb_la-pgsql_cb_dhcp4.lo: pgsql_cb_dhcp4.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_dhcp4.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Tpo -c -o libpgsqlcb_la-pgsql_cb_dhcp4.lo `test -f 'pgsql_cb_dhcp4.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4.cc' object='libpgsqlcb_la-pgsql_cb_dhcp4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_dhcp4.lo `test -f 'pgsql_cb_dhcp4.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4.cc + +libpgsqlcb_la-pgsql_cb_dhcp6.lo: pgsql_cb_dhcp6.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_dhcp6.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Tpo -c -o libpgsqlcb_la-pgsql_cb_dhcp6.lo `test -f 'pgsql_cb_dhcp6.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6.cc' object='libpgsqlcb_la-pgsql_cb_dhcp6.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_dhcp6.lo `test -f 'pgsql_cb_dhcp6.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6.cc + +libpgsqlcb_la-pgsql_cb_impl.lo: pgsql_cb_impl.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_impl.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Tpo -c -o libpgsqlcb_la-pgsql_cb_impl.lo `test -f 'pgsql_cb_impl.cc' || echo '$(srcdir)/'`pgsql_cb_impl.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_impl.cc' object='libpgsqlcb_la-pgsql_cb_impl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_impl.lo `test -f 'pgsql_cb_impl.cc' || echo '$(srcdir)/'`pgsql_cb_impl.cc + +libpgsqlcb_la-pgsql_cb_messages.lo: pgsql_cb_messages.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_messages.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Tpo -c -o libpgsqlcb_la-pgsql_cb_messages.lo `test -f 'pgsql_cb_messages.cc' || echo '$(srcdir)/'`pgsql_cb_messages.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_messages.cc' object='libpgsqlcb_la-pgsql_cb_messages.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_messages.lo `test -f 'pgsql_cb_messages.cc' || echo '$(srcdir)/'`pgsql_cb_messages.cc + +libpgsqlcb_la-pgsql_cb_log.lo: pgsql_cb_log.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_log.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Tpo -c -o libpgsqlcb_la-pgsql_cb_log.lo `test -f 'pgsql_cb_log.cc' || echo '$(srcdir)/'`pgsql_cb_log.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_log.cc' object='libpgsqlcb_la-pgsql_cb_log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_log.lo `test -f 'pgsql_cb_log.cc' || echo '$(srcdir)/'`pgsql_cb_log.cc + +libpgsqlcb_la-version.lo: version.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-version.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-version.Tpo -c -o libpgsqlcb_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-version.Tpo $(DEPDIR)/libpgsqlcb_la-version.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='version.cc' object='libpgsqlcb_la-version.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(lib_hooksdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +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-recursive + +clean-am: clean-generic clean-lib_hooksLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-version.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-lib_hooksLTLIBRARIES + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo + -rm -f ./$(DEPDIR)/libpgsqlcb_la-version.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic \ + maintainer-clean-local + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-lib_hooksLTLIBRARIES + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic \ + clean-lib_hooksLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags 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-lib_hooksLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-local mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-lib_hooksLTLIBRARIES + +.PRECIOUS: Makefile + + +# If we want to get rid of all generated messages files, we need to use +# make maintainer-clean. The proper way to introduce custom commands for +# that operation is to define maintainer-clean-local target. However, +# make maintainer-clean also removes Makefile, so running configure script +# is required. To make it easy to rebuild messages without going through +# reconfigure, a new target messages-clean has been added. +maintainer-clean-local: + rm -f pgsql_cb_messages.h pgsql_cb_messages.cc + +# To regenerate messages files, one can do: +# +# make messages-clean +# make messages +# +# This is needed only when a .mes file is modified. +messages-clean: maintainer-clean-local + +# Define rule to build logging source files from message file +@GENERATE_MESSAGES_TRUE@messages: pgsql_cb_messages.h pgsql_cb_messages.cc +@GENERATE_MESSAGES_TRUE@ @echo Message files regenerated + +@GENERATE_MESSAGES_TRUE@pgsql_cb_messages.h pgsql_cb_messages.cc: pgsql_cb_messages.mes +@GENERATE_MESSAGES_TRUE@ $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes + +@GENERATE_MESSAGES_FALSE@messages pgsql_cb_messages.h pgsql_cb_messages.cc: +@GENERATE_MESSAGES_FALSE@ @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. + +# 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/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am new file mode 100644 index 0000000..1d6f178 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am @@ -0,0 +1,56 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/pgsql_cb -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -DLIBDHCP_PGSQL_CB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/pgsql_cb/.libs/libdhcp_pgsql_cb.so\" +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +EXTRA_DIST = + +CLEANFILES = *.gcno *.gcda + +TESTS_ENVIRONMENT = \ + $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +if HAVE_GTEST + +TESTS = hook_load_unittests + +hook_load_unittests_SOURCES = +hook_load_unittests_SOURCES += load_unload_unittests.cc +hook_load_unittests_SOURCES += run_unittests.cc +hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS) +hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) + +hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/pgsql/libkea-pgsql.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +hook_load_unittests_LDADD += $(LOG4CPLUS_LIBS) +hook_load_unittests_LDADD += $(CRYPTO_LIBS) +hook_load_unittests_LDADD += $(BOOST_LIBS) +hook_load_unittests_LDADD += $(GTEST_LDADD) + +noinst_PROGRAMS = $(TESTS) + +endif diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in new file mode 100644 index 0000000..8bf1824 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in @@ -0,0 +1,1032 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +@HAVE_GTEST_TRUE@TESTS = hook_load_unittests$(EXEEXT) +@HAVE_GTEST_TRUE@noinst_PROGRAMS = $(am__EXEEXT_1) +subdir = src/hooks/dhcp/pgsql_cb/libloadtests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp11.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.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)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_GTEST_TRUE@am__EXEEXT_1 = hook_load_unittests$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am__hook_load_unittests_SOURCES_DIST = load_unload_unittests.cc \ + run_unittests.cc +@HAVE_GTEST_TRUE@am_hook_load_unittests_OBJECTS = hook_load_unittests-load_unload_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ hook_load_unittests-run_unittests.$(OBJEXT) +hook_load_unittests_OBJECTS = $(am_hook_load_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@hook_load_unittests_DEPENDENCIES = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +hook_load_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) \ + $(hook_load_unittests_LDFLAGS) $(LDFLAGS) -o $@ +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 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = \ + ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po \ + ./$(DEPDIR)/hook_load_unittests-run_unittests.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(hook_load_unittests_SOURCES) +DIST_SOURCES = $(am__hook_load_unittests_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +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@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +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@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +YACC = @YACC@ +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_CXX = @ac_ct_CXX@ +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@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +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@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + -I$(top_builddir)/src/hooks/dhcp/pgsql_cb \ + -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb $(BOOST_INCLUDES) \ + -DLIBDHCP_PGSQL_CB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/pgsql_cb/.libs/libdhcp_pgsql_cb.so\" +AM_CXXFLAGS = $(KEA_CXXFLAGS) +@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static +EXTRA_DIST = +CLEANFILES = *.gcno *.gcda +TESTS_ENVIRONMENT = \ + $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +@HAVE_GTEST_TRUE@hook_load_unittests_SOURCES = \ +@HAVE_GTEST_TRUE@ load_unload_unittests.cc run_unittests.cc +@HAVE_GTEST_TRUE@hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +@HAVE_GTEST_TRUE@hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS) +@HAVE_GTEST_TRUE@hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) +@HAVE_GTEST_TRUE@hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \ +@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(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 src/hooks/dhcp/pgsql_cb/libloadtests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/libloadtests/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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + 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): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +hook_load_unittests$(EXEEXT): $(hook_load_unittests_OBJECTS) $(hook_load_unittests_DEPENDENCIES) $(EXTRA_hook_load_unittests_DEPENDENCIES) + @rm -f hook_load_unittests$(EXEEXT) + $(AM_V_CXXLD)$(hook_load_unittests_LINK) $(hook_load_unittests_OBJECTS) $(hook_load_unittests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook_load_unittests-run_unittests.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +hook_load_unittests-load_unload_unittests.o: load_unload_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-load_unload_unittests.o -MD -MP -MF $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo -c -o hook_load_unittests-load_unload_unittests.o `test -f 'load_unload_unittests.cc' || echo '$(srcdir)/'`load_unload_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo $(DEPDIR)/hook_load_unittests-load_unload_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_unload_unittests.cc' object='hook_load_unittests-load_unload_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-load_unload_unittests.o `test -f 'load_unload_unittests.cc' || echo '$(srcdir)/'`load_unload_unittests.cc + +hook_load_unittests-load_unload_unittests.obj: load_unload_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-load_unload_unittests.obj -MD -MP -MF $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo -c -o hook_load_unittests-load_unload_unittests.obj `if test -f 'load_unload_unittests.cc'; then $(CYGPATH_W) 'load_unload_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/load_unload_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo $(DEPDIR)/hook_load_unittests-load_unload_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_unload_unittests.cc' object='hook_load_unittests-load_unload_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-load_unload_unittests.obj `if test -f 'load_unload_unittests.cc'; then $(CYGPATH_W) 'load_unload_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/load_unload_unittests.cc'; fi` + +hook_load_unittests-run_unittests.o: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/hook_load_unittests-run_unittests.Tpo -c -o hook_load_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-run_unittests.Tpo $(DEPDIR)/hook_load_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='hook_load_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc + +hook_load_unittests-run_unittests.obj: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/hook_load_unittests-run_unittests.Tpo -c -o hook_load_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-run_unittests.Tpo $(DEPDIR)/hook_load_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='hook_load_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +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-recursive + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po + -rm -f ./$(DEPDIR)/hook_load_unittests-run_unittests.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po + -rm -f ./$(DEPDIR)/hook_load_unittests-run_unittests.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-TESTS check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags 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 installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc new file mode 100644 index 0000000..2791c3d --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// @file This file contains tests which exercise the load and unload +/// functions in the ddns tuning hook library. In order to test the load +/// function, one must be able to pass it hook library parameters. The +/// the only way to populate these parameters is by actually loading the +/// library via HooksManager::loadLibraries(). + +#include <config.h> + +#include <cc/data.h> +#include <dhcpsrv/cfgmgr.h> +#include <hooks/hooks_manager.h> +#include <process/daemon.h> +#include <testutils/gtest_utils.h> +#include <testutils/lib_load_test_fixture.h> + +#include <gtest/gtest.h> +#include <errno.h> + +using namespace std; +using namespace isc; +using namespace isc::hooks; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::process; + +namespace { + +/// @brief Test fixture for testing loading and unloading the PgSQL cb library +class PgSqlCbLibLoadTest : public isc::test::LibLoadTest { +public: + /// @brief Constructor + PgSqlCbLibLoadTest() : LibLoadTest(LIBDHCP_PGSQL_CB_SO) { + } + + /// @brief Destructor + virtual ~PgSqlCbLibLoadTest() { + unloadLibraries(); + } +}; + +// Simple V4 test that checks the library can be loaded and unloaded several times. +TEST_F(PgSqlCbLibLoadTest, validLoad4) { + validDaemonTest("kea-dhcp4"); +} + +// Simple V6 test that checks the library can be loaded and unloaded several times. +TEST_F(PgSqlCbLibLoadTest, validLoad6) { + validDaemonTest("kea-dhcp6", AF_INET6); +} + +// Simple V6 test that checks the library cannot by loaded by invalid daemons. +TEST_F(PgSqlCbLibLoadTest, invalidDaemonLoad) { + invalidDaemonTest("kea-ctrl-agent"); + invalidDaemonTest("kea-dhcp-ddns"); + invalidDaemonTest("bogus"); +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc b/src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc new file mode 100644 index 0000000..d9e195d --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc @@ -0,0 +1,20 @@ +// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the End User License +// Agreement. See COPYING file in the premium/ directory. + +#include <config.h> + +#include <log/logger_support.h> + +#include <gtest/gtest.h> + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + isc::log::initLogger(); + + int result = RUN_ALL_TESTS(); + + return (result); +} diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc new file mode 100644 index 0000000..06727e1 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc @@ -0,0 +1,122 @@ +// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Functions accessed by the hooks framework use C linkage to avoid the name +// mangling that accompanies use of the C++ compiler as well as to avoid +// issues related to namespaces. + +#include <config.h> + +#include <dhcpsrv/cfgmgr.h> +#include <hooks/hooks.h> +#include <process/daemon.h> +#include <pgsql_cb_impl.h> + +#include <pgsql_cb_dhcp4.h> +#include <pgsql_cb_dhcp6.h> +#include <pgsql_cb_log.h> + +#include <sstream> +#include <string> + +using namespace isc::cb; +using namespace isc::dhcp; +using namespace isc::hooks; +using namespace isc::log; +using namespace isc::process; +using namespace std; + +extern "C" { + +/// @brief This function is called when the library is loaded. +/// +/// @param handle library handle +/// @return 0 when initialization is successful, 1 otherwise + +int load(LibraryHandle& /* handle */) { + // Make the hook library not loadable by d2 or ca. + uint16_t family = CfgMgr::instance().getFamily(); + const std::string& proc_name = Daemon::getProcName(); + if (family == AF_INET) { + if (proc_name != "kea-dhcp4") { + isc_throw(isc::Unexpected, "Bad process name: " << proc_name + << ", expected kea-dhcp4"); + } + } else { + if (proc_name != "kea-dhcp6") { + isc_throw(isc::Unexpected, "Bad process name: " << proc_name + << ", expected kea-dhcp6"); + } + } + + LOG_INFO(pgsql_cb_logger, PGSQL_CB_INIT_OK); + // Register PostgreSQL CB factories with CB Managers + isc::dhcp::PgSqlConfigBackendDHCPv4::registerBackendType(); + isc::dhcp::PgSqlConfigBackendDHCPv6::registerBackendType(); + + return (0); +} + +/// @brief This function is called by the DHCPv4 server when it is configured. +/// +/// The only purpose of this callout is to retrieve io_service_ reference. +/// +/// @param handle callout handle passed to the callout. +/// @return 0 on success, 1 otherwise. +int dhcp4_srv_configured(CalloutHandle& handle) { + isc::asiolink::IOServicePtr io_service; + handle.getArgument("io_context", io_service); + if (!io_service) { + const string error("Error: io_context is null"); + handle.setArgument("error", error); + handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); + return (1); + } + isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); + return (0); +} + +/// @brief This function is called by the DHCPv6 server when it is configured. +/// +/// The only purpose of this callout is to retrieve io_service_ reference. +/// +/// @param handle callout handle passed to the callout. +/// @return 0 on success, 1 otherwise. +int dhcp6_srv_configured(CalloutHandle& handle) { + isc::asiolink::IOServicePtr io_service; + handle.getArgument("io_context", io_service); + if (!io_service) { + const string error("Error: io_context is null"); + handle.setArgument("error", error); + handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); + return (1); + } + isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); + return (0); +} + +/// @brief This function is called when the library is unloaded. +/// +/// @return 0 if deregistration was successful, 1 otherwise +int unload() { + LOG_INFO(pgsql_cb_logger, PGSQL_CB_DEINIT_OK); + // Unregister the factories and remove PostgreSQL backends + isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType(); + isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType(); + return (0); +} + +/// @brief This function is called to retrieve the multi-threading compatibility. +/// +/// @note: the compatibility is based on the assumption this hook library +/// is always called from the main thread. +/// +/// @return 1 which means compatible with multi-threading. +int multi_threading_compatible() { + return (1); +} + +} // end extern "C" diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc new file mode 100644 index 0000000..9dcac75 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc @@ -0,0 +1,5238 @@ +// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <pgsql_cb_dhcp4.h> +#include <pgsql_cb_impl.h> +#include <pgsql_query_macros_dhcp.h> +#include <cc/data.h> +#include <config_backend/constants.h> +#include <database/database_connection.h> +#include <database/db_exceptions.h> +#include <dhcp/classify.h> +#include <dhcp/dhcp6.h> +#include <dhcp/libdhcp++.h> +#include <dhcp/option_data_types.h> +#include <dhcp/option_space.h> +#include <dhcpsrv/cfgmgr.h> +#include <dhcpsrv/config_backend_dhcp4_mgr.h> +#include <dhcpsrv/network.h> +#include <dhcpsrv/pool.h> +#include <dhcpsrv/lease.h> +#include <dhcpsrv/timer_mgr.h> +#include <dhcpsrv/parsers/client_class_def_parser.h> +#include <util/buffer.h> +#include <util/boost_time_utils.h> +#include <util/multi_threading_mgr.h> +#include <pgsql/pgsql_connection.h> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/pointer_cast.hpp> +#include <boost/scoped_ptr.hpp> + +using namespace isc::cb; +using namespace isc::db; +using namespace isc::data; +using namespace isc::asiolink; +using namespace isc::log; +using namespace isc::util; + +namespace isc { +namespace dhcp { + +/// @brief Implementation of the PostgreSQL Configuration Backend. +class PgSqlConfigBackendDHCPv4Impl : public PgSqlConfigBackendImpl { +public: + + /// @brief Statement tags. + /// + /// The contents of the enum are indexes into the list of SQL statements. + /// It is assumed that the order is such that the indices of statements + /// reading the database are less than those of statements modifying the + /// database. + enum StatementIndex { + CREATE_AUDIT_REVISION, + CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + GET_GLOBAL_PARAMETER4, + GET_ALL_GLOBAL_PARAMETERS4, + GET_MODIFIED_GLOBAL_PARAMETERS4, + GET_SUBNET4_ID_NO_TAG, + GET_SUBNET4_ID_ANY, + GET_SUBNET4_ID_UNASSIGNED, + GET_SUBNET4_PREFIX_NO_TAG, + GET_SUBNET4_PREFIX_ANY, + GET_SUBNET4_PREFIX_UNASSIGNED, + GET_ALL_SUBNETS4, + GET_ALL_SUBNETS4_UNASSIGNED, + GET_MODIFIED_SUBNETS4, + GET_MODIFIED_SUBNETS4_UNASSIGNED, + GET_SHARED_NETWORK_SUBNETS4, + GET_POOL4_RANGE, + GET_POOL4_RANGE_ANY, + GET_SHARED_NETWORK4_NAME_NO_TAG, + GET_SHARED_NETWORK4_NAME_ANY, + GET_SHARED_NETWORK4_NAME_UNASSIGNED, + GET_ALL_SHARED_NETWORKS4, + GET_ALL_SHARED_NETWORKS4_UNASSIGNED, + GET_MODIFIED_SHARED_NETWORKS4, + GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED, + GET_OPTION_DEF4_CODE_SPACE, + GET_ALL_OPTION_DEFS4, + GET_MODIFIED_OPTION_DEFS4, + GET_OPTION4_CODE_SPACE, + GET_ALL_OPTIONS4, + GET_MODIFIED_OPTIONS4, + GET_OPTION4_SUBNET_ID_CODE_SPACE, + GET_OPTION4_POOL_ID_CODE_SPACE, + GET_OPTION4_SHARED_NETWORK_CODE_SPACE, + GET_CLIENT_CLASS4_NAME, + GET_ALL_CLIENT_CLASSES4, + GET_ALL_CLIENT_CLASSES4_UNASSIGNED, + GET_MODIFIED_CLIENT_CLASSES4, + GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED, + GET_AUDIT_ENTRIES4_TIME, + GET_SERVER4, + GET_ALL_SERVERS4, + INSERT_GLOBAL_PARAMETER4, + INSERT_GLOBAL_PARAMETER4_SERVER, + INSERT_SUBNET4, + INSERT_SUBNET4_SERVER, + INSERT_POOL4, + INSERT_SHARED_NETWORK4, + INSERT_SHARED_NETWORK4_SERVER, + INSERT_OPTION_DEF4, + INSERT_OPTION_DEF4_CLIENT_CLASS, + INSERT_OPTION_DEF4_SERVER, + INSERT_OPTION4, + INSERT_OPTION4_SERVER, + INSERT_CLIENT_CLASS4, + INSERT_CLIENT_CLASS4_SERVER, + INSERT_CLIENT_CLASS4_DEPENDENCY, + INSERT_SERVER4, + UPDATE_GLOBAL_PARAMETER4, + UPDATE_SUBNET4, + UPDATE_SHARED_NETWORK4, + UPDATE_OPTION_DEF4, + UPDATE_OPTION_DEF4_CLIENT_CLASS, + UPDATE_OPTION4, + UPDATE_OPTION4_SUBNET_ID, + UPDATE_OPTION4_POOL_ID, + UPDATE_OPTION4_SHARED_NETWORK, + UPDATE_OPTION4_CLIENT_CLASS, + UPDATE_CLIENT_CLASS4, + UPDATE_CLIENT_CLASS4_SAME_POSITION, + UPDATE_SERVER4, + DELETE_GLOBAL_PARAMETER4, + DELETE_ALL_GLOBAL_PARAMETERS4, + DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED, + DELETE_SUBNET4_ID_WITH_TAG, + DELETE_SUBNET4_ID_ANY, + DELETE_SUBNET4_PREFIX_WITH_TAG, + DELETE_SUBNET4_PREFIX_ANY, + DELETE_ALL_SUBNETS4, + DELETE_ALL_SUBNETS4_UNASSIGNED, + DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME, + DELETE_SUBNET4_SERVER, + DELETE_POOLS4, + DELETE_SHARED_NETWORK4_NAME_WITH_TAG, + DELETE_SHARED_NETWORK4_NAME_ANY, + DELETE_ALL_SHARED_NETWORKS4, + DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED, + DELETE_SHARED_NETWORK4_SERVER, + DELETE_OPTION_DEF4_CODE_NAME, + DELETE_ALL_OPTION_DEFS4, + DELETE_ALL_OPTION_DEFS4_UNASSIGNED, + DELETE_OPTION_DEFS4_CLIENT_CLASS, + DELETE_OPTION4, + DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED, + DELETE_OPTION4_SUBNET_ID, + DELETE_OPTION4_POOL_RANGE, + DELETE_OPTION4_SHARED_NETWORK, + DELETE_OPTIONS4_SUBNET_ID_PREFIX, + DELETE_OPTIONS4_SHARED_NETWORK, + DELETE_OPTIONS4_CLIENT_CLASS, + DELETE_CLIENT_CLASS4_DEPENDENCY, + DELETE_CLIENT_CLASS4_SERVER, + DELETE_ALL_CLIENT_CLASSES4, + DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED, + DELETE_CLIENT_CLASS4, + DELETE_CLIENT_CLASS4_ANY, + DELETE_SERVER4, + DELETE_ALL_SERVERS4, + GET_LAST_INSERT_ID4, + NUM_STATEMENTS + }; + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit PgSqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& + parameters); + + /// @brief Destructor. + ~PgSqlConfigBackendDHCPv4Impl(); + + /// @brief Fetches the SQL statement for a given statement index. + /// + /// @param index index of the desired statement. + /// @throw BadValue if there is no statement corresponding to + /// the index. + virtual PgSqlTaggedStatement& getStatement(size_t index) const; + + /// @brief Sends query to retrieve global parameter. + /// + /// @param server_selector Server selector. + /// @param name Name of the parameter to be retrieved. + /// + /// @return Pointer to the retrieved value or null if such parameter + /// doesn't exist. + StampedValuePtr getGlobalParameter4(const ServerSelector& server_selector, + const std::string& name) { + StampedValueCollection parameters; + + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.add(name); + + getGlobalParameters(GET_GLOBAL_PARAMETER4, in_bindings, parameters); + } + + return (parameters.empty() ? StampedValuePtr() : *parameters.begin()); + } + + /// @brief Sends query to insert or update global parameter. + /// + /// @param server_selector Server selector. + /// @param value StampedValue describing the parameter to create/update. + void createUpdateGlobalParameter4(const db::ServerSelector& server_selector, + const StampedValuePtr& value) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "creating or updating global parameter"); + + PsqlBindArray in_bindings; + in_bindings.addTempString(value->getName()); + in_bindings.addTempString(value->getValue()); + in_bindings.add(value->getType()), + in_bindings.addTimestamp(value->getModificationTime()), + in_bindings.addTempString(tag); + in_bindings.addTempString(value->getName()); + + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "global parameter set", + false); + + // Try to update the existing row. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4, + in_bindings) == 0) { + // No such parameter found, so let's insert it. We have to adjust the + // bindings collection to match the prepared statement for insert. + in_bindings.popBack(); + in_bindings.popBack(); + + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4, + in_bindings); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + PsqlBindArray attach_bindings; + uint64_t pid = getLastInsertId("dhcp4_global_parameter", "id"); + attach_bindings.add(pid); // id of newly inserted global. + attach_bindings.addTimestamp(value->getModificationTime()); + attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER, + server_selector, attach_bindings); + } + + transaction.commit(); + } + + /// @brief Sends query to the database to retrieve multiple subnets. + /// + /// Query should order subnets by subnet_id. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] subnets Reference to the container where fetched subnets + /// will be inserted. + void getSubnets4(const StatementIndex& index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + Subnet4Collection& subnets) { + uint64_t last_pool_id = 0; + uint64_t last_pool_option_id = 0; + uint64_t last_option_id = 0; + Pool4Ptr last_pool; + std::string last_tag; + + // Execute actual query. + selectQuery(index, in_bindings, + [this, &subnets, &last_pool, &last_pool_id, + &last_pool_option_id, &last_option_id, &last_tag](PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get pointer to the last subnet in the collection. + Subnet4Ptr last_subnet; + if (!subnets.empty()) { + last_subnet = *subnets.rbegin(); + } + // Subnet_id is column 0. + SubnetID subnet_id = worker.getInt(0) ; + + // Subnet has been returned. Assuming that subnets are ordered by + // subnet identifier, if the subnet identifier of the current row + // is different than the subnet identifier of the previously returned + // row, it means that we have to construct new subnet object. + if (!last_subnet || (last_subnet->getID() != subnet_id)) { + // Reset per subnet component tracking and server tag because + // we're now starting to process a new subnet. + last_pool_id = 0; + last_pool_option_id = 0; + last_option_id = 0; + last_pool.reset(); + last_tag.clear(); + + // Get subnet parameters required by the constructor first. + + // subnet_prefix at 1. + std::string subnet_prefix = worker.getString(1); + auto prefix_pair = Subnet4::parsePrefix(subnet_prefix); + + // renew_timer at 13. + auto renew_timer = worker.getTriplet(13); + + // rebind_timer at 11. + auto rebind_timer = worker.getTriplet(11); + + // valid_lifetime at 19. + // min_valid_lifetime at 55. + // max_valid_lifetime at 56. + auto valid_lifetime = worker.getTriplet(19, 55, 56); + + // Create subnet with basic settings. + last_subnet = Subnet4::create(prefix_pair.first, prefix_pair.second, + renew_timer, rebind_timer, + valid_lifetime, subnet_id); + + // Get other subnet parameters. + // 4o6_interface at 2. + if (!worker.isColumnNull(2)) { + last_subnet->get4o6().setIface4o6(worker.getString(2)); + } + + // 4o6_interface_id at 3. + if (!worker.isColumnNull(3)) { + std::string dhcp4o6_interface_id = worker.getString(3); + OptionBuffer dhcp4o6_interface_id_buf(dhcp4o6_interface_id.begin(), + dhcp4o6_interface_id.end()); + OptionPtr option_dhcp4o6_interface_id = + Option::create(Option::V6, D6O_INTERFACE_ID, dhcp4o6_interface_id_buf); + last_subnet->get4o6().setInterfaceId(option_dhcp4o6_interface_id); + } + + // 4o6_subnet at 4. + if (!worker.isColumnNull(4)) { + std::pair<IOAddress, uint8_t> dhcp4o6_subnet_prefix_pair = + Subnet6::parsePrefix(worker.getString(4)); + last_subnet->get4o6().setSubnet4o6(dhcp4o6_subnet_prefix_pair.first, + dhcp4o6_subnet_prefix_pair.second); + } + + // boot_file_name at 5. + if (!worker.isColumnNull(5)) { + last_subnet->setFilename(worker.getString(5)); + } + + // client_class at 6. + if (!worker.isColumnNull(6)) { + last_subnet->allowClientClass(worker.getString(6)); + } + + // interface at 7. + if (!worker.isColumnNull(7)) { + last_subnet->setIface(worker.getString(7)); + } + + // match_client_id at 8. + if (!worker.isColumnNull(8)) { + last_subnet->setMatchClientId(worker.getBool(8)); + } + + // modification_ts at 9. + last_subnet->setModificationTime(worker.getTimestamp(9)); + + // next_server at 10. + if (!worker.isColumnNull(10)) { + last_subnet->setSiaddr(worker.getInet4(10)); + } + + // rebind_timer at 11 (fetched before subnet create). + + // Relay addresses at 12. + setRelays(worker, 12, *last_subnet); + + // renew_timer at 13 (fetched before subnet create). + + // require_client_classes at 14. + setRequiredClasses(worker, 14, [&last_subnet](const std::string& class_name) { + last_subnet->requireClientClass(class_name); + }); + + // reservations_global at 15. + if (!worker.isColumnNull(15)) { + last_subnet->setReservationsGlobal(worker.getBool(15)); + } + + // server_hostname at 16. + if (!worker.isColumnNull(16)) { + last_subnet->setSname(worker.getString(16)); + } + + // shared_network_name at 17. + if (!worker.isColumnNull(17)) { + last_subnet->setSharedNetworkName(worker.getString(17)); + } + + // user_context at 18. + if (!worker.isColumnNull(18)) { + ElementPtr user_context = worker.getJSON(18); + if (user_context) { + last_subnet->setContext(user_context); + } + } + + // valid_lifetime at 19 (fetched before subnet create). + + // pool and options from 20 to 50. + + // calculate_tee_times at 51. + if (!worker.isColumnNull(51)) { + last_subnet->setCalculateTeeTimes(worker.getBool(51)); + } + + // t1_percent at 52. + if (!worker.isColumnNull(52)) { + last_subnet->setT1Percent(worker.getDouble(52)); + } + + // t2_percent at 53. + if (!worker.isColumnNull(53)) { + last_subnet->setT2Percent(worker.getDouble(53)); + } + + // authoritative at 54. + if (!worker.isColumnNull(54)) { + last_subnet->setAuthoritative(worker.getBool(54)); + } + + // min_valid_lifetime at 55 (fetched as part of triplet). + // max_valid_lifetime at 56 (fetched as part of triplet). + + // pool client_class, require_client_classes and user_context + // from 57 to 59. + + // ddns_send_updates at 60. + if (!worker.isColumnNull(60)) { + last_subnet->setDdnsSendUpdates(worker.getBool(60)); + } + + // ddns_override_no_update at 61. + if (!worker.isColumnNull(61)) { + last_subnet->setDdnsOverrideNoUpdate(worker.getBool(61)); + } + + // ddns_override_client_update at 62. + if (!worker.isColumnNull(62)) { + last_subnet->setDdnsOverrideClientUpdate(worker.getBool(62)); + } + + // ddns_replace_client_name at 63. + if (!worker.isColumnNull(63)) { + last_subnet->setDdnsReplaceClientNameMode( + static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(63))); + } + + // ddns_generated_prefix at 64. + if (!worker.isColumnNull(64)) { + last_subnet->setDdnsGeneratedPrefix(worker.getString(64)); + } + + // ddns_qualifying_suffix at 65. + if (!worker.isColumnNull(65)) { + last_subnet->setDdnsQualifyingSuffix(worker.getString(65)); + } + + // reservations_in_subnet at 66. + if (!worker.isColumnNull(66)) { + last_subnet->setReservationsInSubnet(worker.getBool(66)); + } + + // reservations_out_of_pool at 67. + if (!worker.isColumnNull(67)) { + last_subnet->setReservationsOutOfPool(worker.getBool(67)); + } + + // cache_threshold at 68. + if (!worker.isColumnNull(68)) { + last_subnet->setCacheThreshold(worker.getDouble(68)); + } + + // cache_max_age at 69. + if (!worker.isColumnNull(69)) { + last_subnet->setCacheMaxAge(worker.getInt(69)); + } + + // offer_lifetime at 70. + if (!worker.isColumnNull(70)) { + last_subnet->setOfferLft(worker.getInt(70)); + } + + // allocator at 71. + if (!worker.isColumnNull(71)) { + last_subnet->setAllocatorType(worker.getString(71)); + } + + // server_tag at 72. + + // Subnet ready. Add it to the list. + auto ret = subnets.insert(last_subnet); + + // subnets is a multi index container with unique indexes + // but these indexes are unique too in the database, + // so this is for sanity only. + if (!ret.second) { + isc_throw(Unexpected, "add subnet failed"); + } + } + + // Check for new server tags at 71. + if (!worker.isColumnNull(72)) { + std::string new_tag = worker.getString(72); + if (last_tag != new_tag) { + if (!new_tag.empty() && !last_subnet->hasServerTag(ServerTag(new_tag))) { + last_subnet->setServerTag(new_tag); + } + + last_tag = new_tag; + } + } + + // If the row contains information about the pool and it appears to be + // new pool entry (checked by comparing pool id), let's create the new + // pool and add it to the subnet. + // pool id at 20. + // pool start_address at 21. + // pool end_address at 22. + // pool subnet_id at 23 (ignored) + // pool modification_ts at 24 (ignored) + if (!worker.isColumnNull(20) && + (worker.getInet4(21) != 0) && + (worker.getInet4(22) != 0) && + (worker.getBigInt(20) > last_pool_id)) { + last_pool_id = worker.getBigInt(20); + last_pool = Pool4::create(IOAddress(worker.getInet4(21)), + IOAddress(worker.getInet4(22))); + + // pool client_class at 57. + if (!worker.isColumnNull(57)) { + last_pool->allowClientClass(worker.getString(57)); + } + + // pool require_client_classes at 58. + setRequiredClasses(worker, 58, [&last_pool](const std::string& class_name) { + last_pool->requireClientClass(class_name); + }); + + // pool user_context at 59. + if (!worker.isColumnNull(59)) { + ElementPtr user_context = worker.getJSON(59); + if (user_context) { + last_pool->setContext(user_context); + } + } + + last_subnet->addPool(last_pool); + } + + // Parse pool-specific option from 25 to 37. + if (last_pool && !worker.isColumnNull(25) && + (last_pool_option_id < worker.getBigInt(25))) { + last_pool_option_id = worker.getBigInt(25); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 25); + if (desc) { + last_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + + // Parse subnet-specific option from 38 to 50. + if (!worker.isColumnNull(38) && + (last_option_id < worker.getBigInt(38))) { + last_option_id = worker.getBigInt(38); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 38); + if (desc) { + last_subnet->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + + // Now that we're done fetching the whole subnet, we have to + // check if it has matching server tags and toss it if it + // doesn't. We skip matching the server tags if we're asking + // for ANY subnet. + auto& subnet_index = subnets.get<SubnetSubnetIdIndexTag>(); + tossNonMatchingElements(server_selector, subnet_index); + } + + /// @brief Sends query to retrieve single subnet by id. + /// + /// @param server_selector Server selector. + /// @param subnet_id Subnet identifier. + /// + /// @return Pointer to the returned subnet or NULL if such subnet + /// doesn't exist. + Subnet4Ptr getSubnet4(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + if (server_selector.hasMultipleTags()) { + isc_throw(InvalidOperation, "expected one server tag to be specified" + " while fetching a subnet. Got: " + << getServerTagsAsText(server_selector)); + } + + PsqlBindArray in_bindings; + in_bindings.add(subnet_id); + + auto index = GET_SUBNET4_ID_NO_TAG; + if (server_selector.amUnassigned()) { + index = GET_SUBNET4_ID_UNASSIGNED; + } else if (server_selector.amAny()) { + index = GET_SUBNET4_ID_ANY; + } + + Subnet4Collection subnets; + getSubnets4(index, server_selector, in_bindings, subnets); + + return (subnets.empty() ? Subnet4Ptr() : *subnets.begin()); + } + + /// @brief Sends query to retrieve single subnet by prefix. + /// + /// The prefix should be in the following format: "192.0.2.0/24". + /// + /// @param server_selector Server selector. + /// @param subnet_id Subnet identifier. + /// + /// @return Pointer to the returned subnet or NULL if such subnet + /// doesn't exist. + Subnet4Ptr getSubnet4(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + if (server_selector.hasMultipleTags()) { + isc_throw(InvalidOperation, "expected one server tag to be specified" + " while fetching a subnet. Got: " + << getServerTagsAsText(server_selector)); + } + + PsqlBindArray in_bindings; + in_bindings.add(subnet_prefix); + + auto index = GET_SUBNET4_PREFIX_NO_TAG; + if (server_selector.amUnassigned()) { + index = GET_SUBNET4_PREFIX_UNASSIGNED; + } else if (server_selector.amAny()) { + index = GET_SUBNET4_PREFIX_ANY; + } + + Subnet4Collection subnets; + getSubnets4(index, server_selector, in_bindings, subnets); + + return (subnets.empty() ? Subnet4Ptr() : *subnets.begin()); + } + + /// @brief Sends query to retrieve all subnets. + /// + /// @param server_selector Server selector. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getAllSubnets4(const ServerSelector& server_selector, + Subnet4Collection& subnets) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching all subnets for ANY " + "server is not supported"); + } + + auto index = (server_selector.amUnassigned() ? GET_ALL_SUBNETS4_UNASSIGNED : + GET_ALL_SUBNETS4); + PsqlBindArray in_bindings; + getSubnets4(index, server_selector, in_bindings, subnets); + } + + /// @brief Sends query to retrieve modified subnets. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getModifiedSubnets4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + Subnet4Collection& subnets) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching modified subnets for ANY " + "server is not supported"); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(modification_ts); + + auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SUBNETS4_UNASSIGNED : + GET_MODIFIED_SUBNETS4); + getSubnets4(index, server_selector, in_bindings, subnets); + } + + /// @brief Sends query to retrieve all subnets belonging to a shared network. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network for which the + /// subnets should be retrieved. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getSharedNetworkSubnets4(const ServerSelector& server_selector, + const std::string& shared_network_name, + Subnet4Collection& subnets) { + PsqlBindArray in_bindings; + in_bindings.add(shared_network_name); + getSubnets4(GET_SHARED_NETWORK_SUBNETS4, server_selector, in_bindings, subnets); + } + + /// @brief Sends query to retrieve multiple pools. + /// + /// Query should order pools by id. + /// + /// @param index Index of the query to be used. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] pools Reference to the container where fetched pools + /// will be inserted. + /// @param [out] pool_ids Identifiers of the pools returned in @c pools + /// argument. + void getPools(const StatementIndex& index, + const PsqlBindArray& in_bindings, + PoolCollection& pools, + std::vector<uint64_t>& pool_ids) { + uint64_t last_pool_id = 0; + uint64_t last_pool_option_id = 0; + Pool4Ptr last_pool; + + selectQuery(index, in_bindings, + [this, &last_pool_id, &last_pool_option_id, &last_pool, &pools, &pool_ids] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Pool id is column 0. + auto id = worker.getBigInt(0) ; + if (id > last_pool_id) { + // pool start_address (1) + // pool end_address (2) + last_pool_id = id; + + last_pool = Pool4::create(worker.getInet4(1), worker.getInet4(2)); + + // pool subnet_id (3) (ignored) + + // pool client_class (4) + if (!worker.isColumnNull(4)) { + last_pool->allowClientClass(worker.getString(4)); + } + + // pool require_client_classes (5) + setRequiredClasses(worker, 5, [&last_pool](const std::string& class_name) { + last_pool->requireClientClass(class_name); + }); + + // pool user_context (6) + if (!worker.isColumnNull(6)) { + ElementPtr user_context = worker.getJSON(6); + if (user_context) { + last_pool->setContext(user_context); + } + } + + // pool: modification_ts (7) (ignored) + + pools.push_back(last_pool); + pool_ids.push_back(last_pool_id); + } + + // Parse pool specific option (8). + if (last_pool && !worker.isColumnNull(8) && + (last_pool_option_id < worker.getBigInt(8))) { + last_pool_option_id = worker.getBigInt(8); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 8); + if (desc) { + last_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + } + + /// @brief Sends query to retrieve single pool by address range. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound pool address. + /// @param pool_end_address Upper bound pool address. + /// @param pool_id Pool identifier for the returned pool. + /// @return Pointer to the pool or null if no such pool found. + Pool4Ptr getPool4(const ServerSelector& server_selector, + const IOAddress& pool_start_address, + const IOAddress& pool_end_address, + uint64_t& pool_id) { + PoolCollection pools; + std::vector<uint64_t> pool_ids; + + if (server_selector.amAny()) { + PsqlBindArray in_bindings; + in_bindings.addInet4(pool_start_address); + in_bindings.addInet4(pool_end_address); + getPools(GET_POOL4_RANGE_ANY, in_bindings, pools, pool_ids); + } else { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addInet4(pool_start_address); + in_bindings.addInet4(pool_end_address); + + getPools(GET_POOL4_RANGE, in_bindings, pools, pool_ids); + // Break if something is found? + } + } + + // Return upon the first pool found. + if (!pools.empty()) { + pool_id = pool_ids[0]; + return (boost::dynamic_pointer_cast<Pool4>(*pools.begin())); + } + + pool_id = 0; + + return (Pool4Ptr()); + } + + /// @brief Sends query to insert or update subnet. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the subnet to be inserted or updated. + void createUpdateSubnet4(const ServerSelector& server_selector, + const Subnet4Ptr& subnet) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "creating or updating a subnet for ANY" + " server is not supported"); + + } else if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + in_bindings.addOptional(subnet->get4o6().getIface4o6()); + + // Convert DHCPv4o6 interface id to text. + OptionPtr dhcp4o6_interface_id = subnet->get4o6().getInterfaceId(); + if (dhcp4o6_interface_id) { + in_bindings.addTempString(std::string(dhcp4o6_interface_id->getData().begin(), + dhcp4o6_interface_id->getData().end())); + + } else { + in_bindings.addNull(); + } + + // Convert DHCPv4o6 subnet to text. + Optional<std::string> dhcp4o6_subnet; + if (!subnet->get4o6().getSubnet4o6().unspecified() && + (!subnet->get4o6().getSubnet4o6().get().first.isV6Zero() || + (subnet->get4o6().getSubnet4o6().get().second != 128u))) { + std::ostringstream s; + s << subnet->get4o6().getSubnet4o6().get().first << "/" + << static_cast<int>(subnet->get4o6().getSubnet4o6().get().second); + dhcp4o6_subnet = s.str(); + } + + in_bindings.addOptional(dhcp4o6_subnet); + + in_bindings.addOptional(subnet->getFilename(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getClientClass(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getIface(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getMatchClientId(Network::Inheritance::NONE)); + in_bindings.addTimestamp(subnet->getModificationTime()); + in_bindings.addOptionalInet4(subnet->getSiaddr(Network::Inheritance::NONE)); + in_bindings.add(subnet->getT2(Network::Inheritance::NONE)); + addRelayBinding(in_bindings, subnet); + in_bindings.add(subnet->getT1(Network::Inheritance::NONE)); + addRequiredClassesBinding(in_bindings, subnet); + in_bindings.addOptional(subnet->getReservationsGlobal(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getSname(Network::Inheritance::NONE)); + + // Add shared network. + SharedNetwork4Ptr shared_network; + subnet->getSharedNetwork(shared_network); + + // Check if the subnet is associated with a shared network instance. + // If it is, create the binding using the name of the shared network. + if (shared_network) { + in_bindings.addTempString(shared_network->getName()); + + // If the subnet is associated with a shared network by name (no + // shared network instance), use this name to create the binding. + // This may be the case if the subnet is added as a result of + // receiving a control command that merely specifies shared + // network name. In that case, it is expected that the shared + // network data is already stored in the database. + } else if (!subnet->getSharedNetworkName().empty()) { + in_bindings.addTempString(subnet->getSharedNetworkName()); + + // If the subnet is not associated with a shared network, create + // null binding. + } else { + in_bindings.addNull(); + } + + in_bindings.add(subnet->getContext()); + in_bindings.add(subnet->getValid(Network::Inheritance::NONE)); + in_bindings.addMin(subnet->getValid(Network::Inheritance::NONE)); + in_bindings.addMax(subnet->getValid(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getCalculateTeeTimes(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getT1Percent(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getT2Percent(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getAuthoritative(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsSendUpdates(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)); + addDdnsReplaceClientNameBinding(in_bindings, subnet); + in_bindings.addOptional(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getReservationsInSubnet(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getReservationsOutOfPool(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getCacheThreshold(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getCacheMaxAge(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getOfferLft(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getAllocatorType(Network::Inheritance::NONE)); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateSubnet4"); + + try { + + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, in_bindings); + + } catch (const DuplicateEntry&) { + // It already exists, rollback to the savepoint to preserve + // any prior work. + conn_.rollbackToSavepoint("createUpdateSubnet4"); + + // We're updating, so we need to remove any existing pools and options. + deletePools4(subnet); + deleteOptions4(ServerSelector::ANY(), subnet); + + // Now we need to add two more bindings for WHERE clause. + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Attempt the update. + auto cnt = updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4, + in_bindings); + if (!cnt) { + // Possible only if someone deleted it since we tried to insert it + // or the query is broken. + isc_throw(Unexpected, "Update subnet failed to find subnet id: " + << subnet->getID() << ", prefix: " << subnet->toText()); + } + + // Remove existing server association. + PsqlBindArray server_bindings; + server_bindings.add(subnet->getID()); + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_SERVER, + server_bindings); + } + + // Subnet was successfully created/updated. + + // Insert associations with the servers. + PsqlBindArray attach_bindings; + attach_bindings.add(subnet->getID()); + attach_bindings.addTimestamp(subnet->getModificationTime()); + attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, + server_selector, attach_bindings); + + // (Re)create pools. + for (auto pool : subnet->getPools(Lease::TYPE_V4)) { + createPool4(server_selector, boost::dynamic_pointer_cast<Pool4>(pool), + subnet); + } + + // (Re)create options. + auto option_spaces = subnet->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = subnet->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption4(server_selector, subnet->getID(), desc_copy, + true); + } + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Inserts new IPv4 pool to the database. + /// + /// @param server_selector Server selector. + /// @param pool Pointer to the pool to be inserted. + /// @param subnet Pointer to the subnet that this pool belongs to. + void createPool4(const ServerSelector& server_selector, + const Pool4Ptr& pool, + const Subnet4Ptr& subnet) { + // Create the input bindings. + PsqlBindArray in_bindings; + in_bindings.addInet4(pool->getFirstAddress()); + in_bindings.addInet4(pool->getLastAddress()); + in_bindings.add(subnet->getID()); + in_bindings.addOptional(pool->getClientClass()); + addRequiredClassesBinding(in_bindings, pool); + in_bindings.add(pool->getContext()); + in_bindings.addTimestamp(subnet->getModificationTime()); + + // Attempt to INSERT the pool. + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_POOL4, in_bindings); + + // Get the id of the newly inserted pool. + uint64_t pool_id = getLastInsertId("dhcp4_pool", "id"); + + // Add the pool's options. + auto option_spaces = pool->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = pool->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption4(server_selector, pool_id, desc_copy, true); + } + } + } + + /// @brief Sends a query to delete data from a table. + /// + /// If creates a new audit revision for this change if such audit + /// revision doesn't exist yet (using ScopedAuditRevision mechanism). + /// + /// @tparam Args type of the arguments to be passed to one of the existing + /// @c deleteFromTable methods. + /// @param server_selector server selector. + /// @param operation operation which results in calling this function. This is + /// used for logging purposes. + /// @param log_message log message to be associated with the audit revision. + /// @param cascade_delete boolean flag indicating if we're performing + /// cascade delete. If set to true, the audit entries for the child + /// objects (e.g. DHCPoptions) won't be created. + /// @param keys arguments to be passed to one of the existing + /// @c deleteFromTable methods. + /// + /// @return Number of deleted entries. + template<typename... Args> + uint64_t deleteTransactional(const int index, + const db::ServerSelector& server_selector, + const std::string& operation, + const std::string& log_message, + const bool cascade_delete, + Args&&... keys) { + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, log_message, cascade_delete); + + auto count = deleteFromTable(index, server_selector, operation, keys...); + + transaction.commit(); + + return (count); + } + + /// @brief Sends query to delete subnet by id. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to be deleted. + /// @return Number of deleted subnets. + uint64_t deleteSubnet4(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + int index = (server_selector.amAny() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_ANY : + PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_WITH_TAG); + return (deleteTransactional(index, server_selector, + "deleting a subnet", "subnet deleted", + true, static_cast<uint32_t>(subnet_id))); + } + + /// @brief Sends query to delete subnet by id. + /// + /// @param server_selector Server selector. + /// @param subnet_prefix Prefix of the subnet to be deleted. + /// @return Number of deleted subnets. + uint64_t deleteSubnet4(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + int index = (server_selector.amAny() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_ANY : + PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_WITH_TAG); + return (deleteTransactional(index, server_selector, + "deleting a subnet", "subnet deleted", + true, subnet_prefix)); + } + + /// @brief Deletes pools belonging to a subnet from the database. + /// + /// The query deletes all pools associated with the subnet's + /// identifier or prefix. + /// @param subnet Pointer to the subnet for which pools should be + /// deleted. + uint64_t deletePools4(const Subnet4Ptr& subnet) { + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Run DELETE. + return (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_POOLS4, + in_bindings)); + } + + /// @brief Sends query to the database to retrieve multiple shared + /// networks. + /// + /// Query should order shared networks by id. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] shared_networks Reference to the container where fetched + /// shared networks will be inserted. + void getSharedNetworks4(const StatementIndex& index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + SharedNetwork4Collection& shared_networks) { + uint64_t last_network_id = 0; + uint64_t last_option_id = 0; + std::string last_tag; + + selectQuery(index, in_bindings, + [this, &shared_networks, &last_network_id, &last_option_id, &last_tag] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + SharedNetwork4Ptr last_network; + if (!shared_networks.empty()) { + last_network = *shared_networks.rbegin(); + } + + // Network id is column 0. + auto network_id = worker.getBigInt(0) ; + + // If this is the first shared network or the shared network id in this + // row points to the next shared network we use the data in the + // row to create the new shared network instance. + if (last_network_id != network_id) { + last_network_id = network_id; + + // Reset per shared network component tracking and server tag because + // we're now starting to process a new shared network. + last_option_id = 0; + last_tag.clear(); + + // name at 1. + last_network = SharedNetwork4::create(worker.getString(1)); + last_network->setId(last_network_id); + + // client_class at 2. + if (!worker.isColumnNull(2)) { + last_network->allowClientClass(worker.getString(2)); + } + + // interface at 3. + if (!worker.isColumnNull(3)) { + last_network->setIface(worker.getString(3)); + } + + // match_client_id at 4. + if (!worker.isColumnNull(4)) { + last_network->setMatchClientId(worker.getBool(4)); + } + + // modification_ts at 5. + last_network->setModificationTime(worker.getTimestamp(5)); + + // rebind_timer at 6. + if (!worker.isColumnNull(6)) { + last_network->setT2(worker.getTriplet(6)); + } + + // Relay addresses at 7. + setRelays(worker, 7, *last_network); + + // renew_timer at 8. + if (!worker.isColumnNull(8)) { + last_network->setT1(worker.getTriplet(8)); + } + + // require_client_classes at 9. + setRequiredClasses(worker, 9, [&last_network](const std::string& class_name) { + last_network->requireClientClass(class_name); + }); + + // reservations_global at 10. + if (!worker.isColumnNull(10)) { + last_network->setReservationsGlobal(worker.getBool(10)); + } + + // user_context at 11. + if (!worker.isColumnNull(11)) { + ElementPtr user_context = worker.getJSON(11); + if (user_context) { + last_network->setContext(user_context); + } + } + + // valid_lifetime at 12. + // min_valid_lifetime at 33. + // max_valid_lifetime at 34. + if (!worker.isColumnNull(12)) { + last_network->setValid(worker.getTriplet(12, 33, 34)); + } + + // option from 13 to 25. + + // calculate_tee_times at 26. + if (!worker.isColumnNull(26)) { + last_network->setCalculateTeeTimes(worker.getBool(26)); + } + + // t1_percent at 27. + if (!worker.isColumnNull(27)) { + last_network->setT1Percent(worker.getDouble(27)); + } + + // t2_percent at 28. + if (!worker.isColumnNull(28)) { + last_network->setT2Percent(worker.getDouble(28)); + } + + // authoritative at 29. + if (!worker.isColumnNull(29)) { + last_network->setAuthoritative(worker.getBool(29)); + } + + // boot_file_name at 30. + if (!worker.isColumnNull(30)) { + last_network->setFilename(worker.getString(30)); + } + + // next_server at 31. + if (!worker.isColumnNull(31)) { + last_network->setSiaddr(worker.getInet4(31)); + } + + // server_hostname at 32. + if (!worker.isColumnNull(32)) { + last_network->setSname(worker.getString(32)); + } + + // min_valid_lifetime at 33. + // max_valid_lifetime at 34. + + // ddns_send_updates at 35. + if (!worker.isColumnNull(35)) { + last_network->setDdnsSendUpdates(worker.getBool(35)); + } + + // ddns_override_no_update at 36. + if (!worker.isColumnNull(36)) { + last_network->setDdnsOverrideNoUpdate(worker.getBool(36)); + } + + // ddns_override_client_update at 37. + if (!worker.isColumnNull(37)) { + last_network->setDdnsOverrideClientUpdate(worker.getBool(37)); + } + + // ddns_replace_client_name at 38. + if (!worker.isColumnNull(38)) { + last_network->setDdnsReplaceClientNameMode( + static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(38))); + } + + // ddns_generated_prefix at 39. + if (!worker.isColumnNull(39)) { + last_network->setDdnsGeneratedPrefix(worker.getString(39)); + } + + // ddns_qualifying_suffix at 40. + if (!worker.isColumnNull(40)) { + last_network->setDdnsQualifyingSuffix(worker.getString(40)); + } + + // reservations_in_subnet at 41. + if (!worker.isColumnNull(41)) { + last_network->setReservationsInSubnet(worker.getBool(41)); + } + + // reservations_in_subnet at 42. + if (!worker.isColumnNull(42)) { + last_network->setReservationsOutOfPool(worker.getBool(42)); + } + + // cache_threshold at 43. + if (!worker.isColumnNull(43)) { + last_network->setCacheThreshold(worker.getDouble(43)); + } + + // cache_max_age at 44. + if (!worker.isColumnNull(44)) { + last_network->setCacheMaxAge(worker.getInt(44)); + } + + // offer_lifetime at 45. + if (!worker.isColumnNull(45)) { + last_network->setOfferLft(worker.getInt(45)); + } + + // allocator at 46. + if (!worker.isColumnNull(46)) { + last_network->setAllocatorType(worker.getString(46)); + } + + // server_tag at 47. + + // Add the shared network. + auto ret = shared_networks.push_back(last_network); + + // shared_networks is a multi index container with an unique + // index but this index is unique too in the database, + // so this is for sanity only. + if (!ret.second) { + isc_throw(Unexpected, "add shared network failed"); + } + } + + // Check for new server tags. + if (!worker.isColumnNull(47)) { + std::string new_tag = worker.getString(47); + if (last_tag != new_tag) { + if (!new_tag.empty() && !last_network->hasServerTag(ServerTag(new_tag))) { + last_network->setServerTag(new_tag); + } + + last_tag = new_tag; + } + } + + // Parse network-specific option from 13 to 25. + if (!worker.isColumnNull(13) && + (last_option_id < worker.getBigInt(13))) { + last_option_id = worker.getBigInt(13); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 13); + if (desc) { + last_network->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + + // Now that we're done fetching the whole network, we have to + // check if it has matching server tags and toss it if it + // doesn't. We skip matching the server tags if we're asking + // for ANY shared network. + auto& sn_index = shared_networks.get<SharedNetworkRandomAccessIndexTag>(); + tossNonMatchingElements(server_selector, sn_index); + } + + /// @brief Sends query to retrieve single shared network by name. + /// + /// @param server_selector Server selector. + /// @param name Shared network name. + /// + /// @return Pointer to the returned shared network or NULL if such shared + /// network doesn't exist. + SharedNetwork4Ptr getSharedNetwork4(const ServerSelector& server_selector, + const std::string& name) { + if (server_selector.hasMultipleTags()) { + isc_throw(InvalidOperation, "expected one server tag to be specified" + " while fetching a shared network. Got: " + << getServerTagsAsText(server_selector)); + } + + PsqlBindArray in_bindings; + in_bindings.add(name); + + auto index = PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_NO_TAG; + if (server_selector.amUnassigned()) { + index = PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_UNASSIGNED; + } else if (server_selector.amAny()) { + index = PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_ANY; + } + + SharedNetwork4Collection shared_networks; + getSharedNetworks4(index, server_selector, in_bindings, shared_networks); + + return (shared_networks.empty() ? SharedNetwork4Ptr() : *shared_networks.begin()); + } + + /// @brief Sends query to retrieve all shared networks. + /// + /// @param server_selector Server selector. + /// @param [out] shared_networks Reference to the shared networks collection + /// structure where shared networks should be inserted. + void getAllSharedNetworks4(const ServerSelector& server_selector, + SharedNetwork4Collection& shared_networks) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching all shared networks for ANY " + "server is not supported"); + } + + auto index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4); + + PsqlBindArray in_bindings; + getSharedNetworks4(index, server_selector, in_bindings, shared_networks); + } + + /// @brief Sends query to retrieve modified shared networks. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] shared_networks Reference to the shared networks collection + /// structure where shared networks should be inserted. + void getModifiedSharedNetworks4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + SharedNetwork4Collection& shared_networks) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching modified shared networks for ANY " + "server is not supported"); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(modification_ts); + + auto index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4); + getSharedNetworks4(index, server_selector, in_bindings, shared_networks); + } + + /// @brief Sends query to insert or update shared network. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the shared network to be inserted or updated. + void createUpdateSharedNetwork4(const ServerSelector& server_selector, + const SharedNetwork4Ptr& shared_network) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "creating or updating a shared network for ANY" + " server is not supported"); + + } else if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + PsqlBindArray in_bindings; + in_bindings.addTempString(shared_network->getName()); + in_bindings.addOptional(shared_network->getClientClass(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getIface(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getMatchClientId(Network::Inheritance::NONE)); + in_bindings.addTimestamp(shared_network->getModificationTime()), + in_bindings.add(shared_network->getT2(Network::Inheritance::NONE)); + addRelayBinding(in_bindings, shared_network); + in_bindings.add(shared_network->getT1(Network::Inheritance::NONE)); + addRequiredClassesBinding(in_bindings, shared_network); + in_bindings.addOptional(shared_network->getReservationsGlobal(Network::Inheritance::NONE)); + in_bindings.add(shared_network->getContext()); + in_bindings.add(shared_network->getValid(Network::Inheritance::NONE)); + in_bindings.addMin(shared_network->getValid(Network::Inheritance::NONE)); + in_bindings.addMax(shared_network->getValid(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getT1Percent(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getT2Percent(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getAuthoritative(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getFilename(Network::Inheritance::NONE)); + in_bindings.addOptionalInet4(shared_network->getSiaddr(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getSname(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsSendUpdates(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)); + addDdnsReplaceClientNameBinding(in_bindings, shared_network); + in_bindings.addOptional(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getReservationsInSubnet(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getCacheThreshold(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getCacheMaxAge(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getOfferLft(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getAllocatorType(Network::Inheritance::NONE)); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateSharedNetwork4"); + + try { + + // Try to insert shared network. The shared network name must be unique, + // so if inserting fails with DuplicateEntry exception we'll need to + // update existing shared network entry. + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4, + in_bindings); + + } catch (const DuplicateEntry&) { + // It already exists, rollback to the savepoint to preserve + // any prior work. + conn_.rollbackToSavepoint("createUpdateSharedNetwork4"); + + // We're updating, so we need to remove any options. + deleteOptions4(ServerSelector::ANY(), shared_network); + + // Need to add one more binding for WHERE clause. + in_bindings.addTempString(shared_network->getName()); + + // Try the update. + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4, + in_bindings); + + // Remove existing server association. + PsqlBindArray server_bindings; + server_bindings.addTempString(shared_network->getName()); + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER, + server_bindings); + } + + // Associate the shared network with the servers. + PsqlBindArray attach_bindings; + attach_bindings.addTempString(shared_network->getName()); + attach_bindings.addTimestamp(shared_network->getModificationTime()); + attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER, + server_selector, attach_bindings); + + // (Re)create options. + auto option_spaces = shared_network->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = shared_network->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption4(server_selector, shared_network->getName(), + desc_copy, true); + } + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert DHCP option. + /// + /// This method expects that the server selector contains exactly one + /// server tag. It is intended to be used within a transaction. + /// + /// @param server_selector Server selector. + /// @param in_bindings Collection of bindings representing an option. + /// @param modification_ts option's modification timestamp + void insertOption4(const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + const boost::posix_time::ptime& modification_ts) { + // Attempt the insert. + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4, in_bindings); + + // Fetch primary key value of the inserted option. We will use it in the + // next INSERT statement to associate this option with the server. + auto option_id = getLastInsertId("dhcp4_options", "option_id"); + + PsqlBindArray attach_bindings; + attach_bindings.add(option_id); // id of newly inserted global. + attach_bindings.addTimestamp(modification_ts); + + // Associate the option with the servers. + attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER, + server_selector, attach_bindings); + } + + /// @brief Sends query to insert or update global DHCP option. + /// + /// @param server_selector Server selector. + /// @param option Pointer to the option descriptor encapsulating the option. + void createUpdateOption4(const ServerSelector& server_selector, + const OptionDescriptorPtr& option) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "creating or updating global option"); + + // Create the input parameter bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.add(0); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(tag); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "global option set", false); + + // Try to update the option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption4(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a subnet. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet the option belongs to. + /// @param option Pointer to the option descriptor encapsulating the option. + /// @param cascade_update Boolean value indicating whether the update is + /// performed as part of the owning element, e.g. subnet. + void createUpdateOption4(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option, + const bool cascade_update) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.add(subnet_id); + in_bindings.add(1); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(subnet_id); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet specific option set", + cascade_update); + + // Try to update the subnet option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption4(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a pool. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the pool. + /// @param pool_end_address Upper bound address of the pool. + /// @param option Pointer to the option descriptor encapsulating the option. + void createUpdateOption4(const ServerSelector& server_selector, + const IOAddress& pool_start_address, + const IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + uint64_t pool_id = 0; + Pool4Ptr pool = getPool4(server_selector, pool_start_address, pool_end_address, + pool_id); + if (!pool) { + isc_throw(BadValue, "no pool found for range of " + << pool_start_address << " : " + << pool_end_address); + } + + createUpdateOption4(server_selector, pool_id, option, false); + } + + /// @brief Sends query to insert or update DHCP option in a pool. + /// + /// @param selector Server selector. + /// @param pool_id Identifier of the pool the option belongs to. + /// @param option Pointer to the option descriptor encapsulating the option. + /// @param cascade_update Boolean value indicating whether the update is + /// performed as part of the owning element, e.g. subnet. + void createUpdateOption4(const ServerSelector& server_selector, + const uint64_t pool_id, + const OptionDescriptorPtr& option, + const bool cascade_update) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.add(5); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.add(pool_id); + in_bindings.addTimestamp(option->getModificationTime()); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(pool_id); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "pool specific option set", + cascade_update); + + // Try to update the option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption4(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a shared network. + /// + /// @param selector Server selector. + /// @param shared_network_name Name of the shared network the option + /// belongs to. + /// @param option Pointer to the option descriptor encapsulating the option. + /// @param cascade_update Boolean value indicating whether the update is + /// performed as part of the owning element, e.g. shared network. + void createUpdateOption4(const ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option, + const bool cascade_update) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.add(4); + in_bindings.add(option->getContext()); + in_bindings.add(shared_network_name); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(shared_network_name); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network specific option set", + cascade_update); + + // Try to update the option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption4(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a client class. + /// + /// @param selector Server selector. + /// @param client_class Pointer to the client_class the option belongs to. + /// @param option Pointer to the option descriptor encapsulating the option.. + void createUpdateOption4(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const OptionDescriptorPtr& option) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + PsqlBindArray in_bindings; + std::string class_name = client_class->getName(); + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.add(class_name); + in_bindings.addNull(); + in_bindings.add(2); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(class_name); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "client class specific option set", + true); + + if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_CLIENT_CLASS, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + insertOption4(server_selector, in_bindings, + option->getModificationTime()); + } + } + + /// @brief Sends query to insert or update option definition. + /// + /// @param server_selector Server selector. + /// @param option_def Pointer to the option definition to be inserted or updated. + void createUpdateOptionDef4(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def) { + createUpdateOptionDef(server_selector, Option::V4, option_def, DHCP4_OPTION_SPACE, + PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4, + PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER); + } + + /// @brief Sends query to insert or update option definition + /// for a client class. + /// + /// @param server_selector Server selector. + /// @param option_def Pointer to the option definition to be inserted or updated. + /// @param client_class Client class name. + void createUpdateOptionDef4(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def, + const std::string& client_class_name) { + createUpdateOptionDef(server_selector, Option::V4, option_def, DHCP4_OPTION_SPACE, + PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_CLIENT_CLASS, + PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4_CLIENT_CLASS, + PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER, + client_class_name); + } + + /// @brief Sends query to delete option definition by code and + /// option space name. + /// + /// @param server_selector Server selector. + /// @param code Option code. + /// @param name Option name. + /// @return Number of deleted option definitions. + uint64_t deleteOptionDef4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEF4_CODE_NAME, + server_selector, + "deleting option definition", + "option definition deleted", + false, + in_bindings)); + } + + /// @brief Sends query to delete option definitions for a client class. + /// + /// @param server_selector Server selector. + /// @param client_class Pointer to the client class for which option + /// definitions should be deleted. + /// @return Number of deleted option definitions. + uint64_t deleteOptionDefs4(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class) { + PsqlBindArray in_bindings; + in_bindings.addTempString(client_class->getName()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEFS4_CLIENT_CLASS, + server_selector, + "deleting option definition for a client class", + "option definition deleted", + true, + in_bindings)); + } + + /// @brief Deletes global option. + /// + /// @param server_selector Server selector. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4, + server_selector, + "deleting global option", + "global option deleted", + false, + in_bindings)); + } + + /// @brief Deletes subnet level option. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to which deleted option + /// belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption4(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(subnet_id); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID, + server_selector, + "deleting option for a subnet", + "subnet specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound pool address. + /// @param pool_end_address Upper bound pool address. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption4(const db::ServerSelector& server_selector, + const IOAddress& pool_start_address, + const IOAddress& pool_end_address, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.addInet4(pool_start_address); + in_bindings.addInet4(pool_end_address); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_POOL_RANGE, + server_selector, + "deleting option for a pool", + "pool specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes shared network level option. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network which deleted + /// option belongs to + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption4(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(shared_network_name); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SHARED_NETWORK, + server_selector, + "deleting option for a shared network", + "shared network specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes options belonging to a subnet from the database. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the subnet for which options should be + /// deleted. + /// @return Number of deleted options. + uint64_t deleteOptions4(const ServerSelector& server_selector, + const Subnet4Ptr& subnet) { + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SUBNET_ID_PREFIX, + server_selector, + "deleting options for a subnet", + "subnet specific options deleted", + true, in_bindings)); + } + + /// @brief Deletes options belonging to a shared network from the database. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the subnet for which options should be + /// deleted. + /// @return Number of deleted options. + uint64_t deleteOptions4(const ServerSelector& server_selector, + const SharedNetwork4Ptr& shared_network) { + PsqlBindArray in_bindings; + in_bindings.addTempString(shared_network->getName()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl:: + DELETE_OPTIONS4_SHARED_NETWORK, server_selector, + "deleting options for a shared network", + "shared network specific options deleted", + true, in_bindings)); + } + + /// @brief Deletes options belonging to a client class from the database. + /// + /// @param server_selector Server selector. + /// @param client_class Pointer to the client class for which options + /// should be deleted. + /// @return Number of deleted options. + uint64_t deleteOptions4(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class) { + PsqlBindArray in_bindings; + in_bindings.addTempString(client_class->getName()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl:: + DELETE_OPTIONS4_CLIENT_CLASS, server_selector, + "deleting options for a client class", + "client class specific options deleted", + true, in_bindings)); + } + + /// @brief Common function to retrieve client classes. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] client_classes Reference to a container where fetched client + /// classes will be inserted. + void getClientClasses4(const StatementIndex& index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + ClientClassDictionary& client_classes) { + std::list<ClientClassDefPtr> class_list; + uint64_t last_option_id = 0; + uint64_t last_option_def_id = 0; + std::string last_tag; + + selectQuery(index, in_bindings, + [this, &class_list, &last_option_id, &last_option_def_id, &last_tag] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + ClientClassDefPtr last_client_class; + if (!class_list.empty()) { + last_client_class = *class_list.rbegin(); + } + + // Class ID is column 0. + uint64_t id = worker.getBigInt(0) ; + + if (!last_client_class || (last_client_class->getId() != id)) { + last_option_id = 0; + last_option_def_id = 0; + last_tag.clear(); + + auto options = boost::make_shared<CfgOption>(); + auto option_defs = boost::make_shared<CfgOptionDef>(); + + last_client_class = boost::make_shared<ClientClassDef>(worker.getString(1), + ExpressionPtr(), options); + last_client_class->setCfgOptionDef(option_defs); + + // id + last_client_class->setId(id); + + // name + last_client_class->setName(worker.getString(1)); + + // test + if (!worker.isColumnNull(2)) { + last_client_class->setTest(worker.getString(2)); + } + + // next server + if (!worker.isColumnNull(3)) { + last_client_class->setNextServer(worker.getInet4(3)); + } + + // sname + if (!worker.isColumnNull(4)) { + last_client_class->setSname(worker.getString(4)); + } + + // filename + if (!worker.isColumnNull(5)) { + last_client_class->setFilename(worker.getString(5)); + } + + // required + if (!worker.isColumnNull(6)) { + last_client_class->setRequired(worker.getBool(6)); + } + + // valid lifetime: default, min, max + last_client_class->setValid(worker.getTriplet(7, 8, 9)); + + // depend on known directly or indirectly + last_client_class->setDependOnKnown(worker.getBool(10) || worker.getBool(11)); + + // modification_ts + last_client_class->setModificationTime(worker.getTimestamp(12)); + + // user_context at 13. + if (!worker.isColumnNull(13)) { + ElementPtr user_context = worker.getJSON(13); + if (user_context) { + last_client_class->setContext(user_context); + } + } + + // offer_lifetime at 14. + if (!worker.isColumnNull(14)) { + last_client_class->setOfferLft(worker.getInt(14)); + } + + class_list.push_back(last_client_class); + } + + // Check for new server tags at 38. + if (!worker.isColumnNull(38)) { + std::string new_tag = worker.getString(38); + if (last_tag != new_tag) { + if (!new_tag.empty() && !last_client_class->hasServerTag(ServerTag(new_tag))) { + last_client_class->setServerTag(new_tag); + } + + last_tag = new_tag; + } + } + + // Parse client class specific option definition from 15 to 24. + if (!worker.isColumnNull(15) && + (last_option_def_id < worker.getBigInt(15))) { + last_option_def_id = worker.getBigInt(15); + + auto def = processOptionDefRow(worker, 15); + if (def) { + last_client_class->getCfgOptionDef()->add(def); + } + } + + // Parse client class specific option from 25 to 37. + if (!worker.isColumnNull(25) && + (last_option_id < worker.getBigInt(25))) { + last_option_id = worker.getBigInt(25); + OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 25); + if (desc) { + last_client_class->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + + tossNonMatchingElements(server_selector, class_list); + + for (auto c : class_list) { + client_classes.addClass(c); + } + } + + /// @brief Sends query to retrieve a client class by name. + /// + /// @param server_selector Server selector. + /// @param name Name of the class to be retrieved. + /// @return Pointer to the client class or null if the class is not found. + ClientClassDefPtr getClientClass4(const ServerSelector& server_selector, + const std::string& name) { + PsqlBindArray in_bindings; + in_bindings.add(name); + + ClientClassDictionary client_classes; + getClientClasses4(PgSqlConfigBackendDHCPv4Impl::GET_CLIENT_CLASS4_NAME, + server_selector, in_bindings, client_classes); + return (client_classes.getClasses()->empty() ? ClientClassDefPtr() : + (*client_classes.getClasses()->begin())); + } + + /// @brief Sends query to retrieve all client classes. + /// + /// @param server_selector Server selector. + /// @param [out] client_classes Reference to the client classes collection + /// where retrieved classes will be stored. + void getAllClientClasses4(const ServerSelector& server_selector, + ClientClassDictionary& client_classes) { + PsqlBindArray in_bindings; + getClientClasses4(server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4, + server_selector, in_bindings, client_classes); + } + + /// @brief Sends query to retrieve modified client classes. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] client_classes Reference to the client classes collection + /// where retrieved classes will be stored. + void getModifiedClientClasses4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + ClientClassDictionary& client_classes) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching modified client classes for ANY " + "server is not supported"); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(modification_ts); + getClientClasses4(server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4, + server_selector, in_bindings, client_classes); + } + + /// @brief Upserts client class. + /// + /// @param server_selector Server selector. + /// @param client_class Pointer to the upserted client class. + /// @param follow_class_name name of the class after which the + /// new or updated class should be positioned. An empty value + /// causes the class to be appended at the end of the class + /// hierarchy. + void createUpdateClientClass4(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name) { + // We need to evaluate class expression to see if it references any + // other classes (dependencies). As part of this evaluation we will + // also check if the client class depends on KNOWN/UNKNOWN built-in + // classes. + std::list<std::string> dependencies; + auto depend_on_known = false; + if (!client_class->getTest().empty()) { + ExpressionPtr expression; + ExpressionParser parser; + // Parse the test expression. The callback function is normally used to + // interrupt config file parsing when one of the classes refers to a + // non-existing client class. It returns false in this case. Here, + // we use the callback to capture client classes referenced by the + // upserted client class and record whether this class depends on + // KNOWN/UNKNOWN built-ins. The callback always returns true to avoid + // reporting the parsing error. The dependency check is performed later + // at the database level. + parser.parse(expression, Element::create(client_class->getTest()), AF_INET, + [&dependencies, &depend_on_known](const ClientClass& client_class) -> bool { + if (isClientClassBuiltIn(client_class)) { + if ((client_class == "KNOWN") || (client_class == "UNKNOWN")) { + depend_on_known = true; + } + } else { + dependencies.push_back(client_class); + } + return (true); + }); + } + + PsqlBindArray in_bindings; + std::string class_name = client_class->getName(); + in_bindings.add(class_name); + in_bindings.addTempString(client_class->getTest()); + in_bindings.addInet4(client_class->getNextServer()); + in_bindings.addTempString(client_class->getSname()); + in_bindings.addTempString(client_class->getFilename()); + in_bindings.add(client_class->getRequired()); + in_bindings.add(client_class->getValid()); + in_bindings.add(client_class->getValid().getMin()); + in_bindings.add(client_class->getValid().getMax()); + in_bindings.add(depend_on_known); + + // follow-class-name (11) + if (follow_class_name.empty()) { + in_bindings.addNull(); + } else { + in_bindings.add(follow_class_name); + } + + in_bindings.addTimestamp(client_class->getModificationTime()); + in_bindings.add(client_class->getContext()); + in_bindings.addOptional(client_class->getOfferLft()); + + PgSqlTransaction transaction(conn_); + + ScopedAuditRevision audit_revision(this, PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "client class set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateClass4"); + + // Keeps track of whether the client class is inserted or updated. + auto update = false; + try { + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4, in_bindings); + + } catch (const DuplicateEntry&) { + // It already exists, rollback to the savepoint to preserve + // any prior work. + conn_.rollbackToSavepoint("createUpdateClass4"); + + // Delete options and option definitions. They will be re-created from the new class + // instance. + deleteOptions4(ServerSelector::ANY(), client_class); + deleteOptionDefs4(ServerSelector::ANY(), client_class); + + // Note: follow_class_name is left in the bindings even though it is + // not needed in both cases. This allows us to use one base query. + + // Add the class name for the where clause. + in_bindings.add(class_name); + if (follow_class_name.empty()) { + // If position is not specified, leave the class at the same position. + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4_SAME_POSITION, + in_bindings); + } else { + // Update with follow_class_name specifying the position. + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4, + in_bindings); + } + + // Delete class associations with the servers and dependencies. We will re-create + // them according to the new class specification. + PsqlBindArray in_assoc_bindings; + in_assoc_bindings.add(class_name); + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_DEPENDENCY, + in_assoc_bindings); + updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_SERVER, + in_assoc_bindings); + update = true; + } + + // Associate client class with the servers. + PsqlBindArray attach_bindings; + attach_bindings.add(class_name); + attach_bindings.addTimestamp(client_class->getModificationTime()); + + attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_SERVER, + server_selector, attach_bindings); + + // Iterate over the captured dependencies and try to insert them into the database. + for (auto dependency : dependencies) { + try { + PsqlBindArray in_dependency_bindings; + in_dependency_bindings.add(class_name); + in_dependency_bindings.add(dependency); + + // We deleted earlier dependencies, so we can simply insert new ones. + insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_DEPENDENCY, + in_dependency_bindings); + } catch (const std::exception& ex) { + isc_throw(InvalidOperation, "unmet dependency on client class: " << dependency); + } + } + + // If we performed client class update we also have to verify that its dependency + // on KNOWN/UNKNOWN client classes hasn't changed. + if (update) { + PsqlBindArray in_check_bindings; + insertQuery(PgSqlConfigBackendDHCPv4Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + in_check_bindings); + } + + // (Re)create option definitions. + if (client_class->getCfgOptionDef()) { + auto option_defs = client_class->getCfgOptionDef()->getContainer(); + auto option_spaces = option_defs.getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionDefContainerPtr defs = option_defs.getItems(option_space); + for (auto def = defs->begin(); def != defs->end(); ++def) { + createUpdateOptionDef4(server_selector, *def, client_class->getName()); + } + } + } + + // (Re)create options. + auto option_spaces = client_class->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = client_class->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption4(server_selector, client_class, desc_copy); + } + } + + // All ok. Commit the transaction. + transaction.commit(); + } + + /// @brief Removes client class by name. + /// + /// @param server_selector Server selector. + /// @param name Removed client class name. + /// @return Number of deleted client classes. + uint64_t deleteClientClass4(const ServerSelector& server_selector, + const std::string& name) { + int index = server_selector.amAny() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_ANY : + PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4; + + uint64_t result = deleteTransactional(index, server_selector, + "deleting client class", + "client class deleted", + true, + name); + return (result); + } + + /// @brief Removes unassigned global parameters, global options and + /// option definitions. + /// + /// This function is called when one or more servers are deleted and + /// it is likely that there are some orphaned configuration elements + /// left in the database. This method removes those elements. + void purgeUnassignedConfig() { + multipleUpdateDeleteQueries(DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED, + DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED, + DELETE_ALL_OPTION_DEFS4_UNASSIGNED); + } + + /// @brief Attempts to delete a server having a given tag. + /// + /// @param server_tag Tag of the server to be deleted. + /// @return Number of deleted servers. + /// @throw isc::InvalidOperation when trying to delete the logical + /// server 'all'. + uint64_t deleteServer4(const data::ServerTag& server_tag) { + // It is not allowed to delete 'all' logical server. + if (server_tag.amAll()) { + isc_throw(InvalidOperation, "'all' is a name reserved for the server tag which" + " associates the configuration elements with all servers connecting" + " to the database and may not be deleted"); + } + + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting a server", false); + + // Specify which server should be deleted. + PsqlBindArray in_bindings; + in_bindings.addTempString(server_tag.get()); + + // Attempt to delete the server. + auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_SERVER4, + in_bindings); + + // If we have deleted any servers we have to remove any dangling global + // parameters, options and option definitions. + if (count > 0) { + purgeUnassignedConfig(); + } + + transaction.commit(); + + return (count); + } + + /// @brief Attempts to delete all servers. + /// + /// This method deletes all servers added by the user. It does not + /// delete the logical server 'all'. + /// + /// @return Number of deleted servers. + uint64_t deleteAllServers4() { + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting all servers", + false); + + // No arguments, hence empty input bindings. + PsqlBindArray in_bindings; + + // Attempt to delete the servers. + auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SERVERS4, + in_bindings); + + // If we have deleted any servers we have to remove any dangling global + // parameters, options and option definitions. + if (count > 0) { + purgeUnassignedConfig(); + } + + // Commit the transaction. + transaction.commit(); + + return (count); + } + + /// @brief Attempts to reconnect the server to the config DB backend manager. + /// + /// This is a self-rescheduling function that attempts to reconnect to the + /// server's config DB backends after connectivity to one or more have been + /// lost. Upon entry it will attempt to reconnect via + /// @ref ConfigBackendDHCPv4Mgr.addBackend. + /// If this is successful, DHCP servicing is re-enabled and server returns + /// to normal operation. + /// + /// If reconnection fails and the maximum number of retries has not been + /// exhausted, it will schedule a call to itself to occur at the + /// configured retry interval. DHCP service remains disabled. + /// + /// If the maximum number of retries has been exhausted an error is logged + /// and the server shuts down. + /// + /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the + /// configured reconnect parameters. + /// @return true if connection has been recovered, false otherwise. + static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl) { + MultiThreadingCriticalSection cs; + + // Invoke application layer connection lost callback. + if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) { + return (false); + } + + bool reopened = false; + + const std::string timer_name = db_reconnect_ctl->timerName(); + + // At least one connection was lost. + try { + auto srv_cfg = CfgMgr::instance().getCurrentCfg(); + auto config_ctl = srv_cfg->getConfigControlInfo(); + // Iterate over the configured DBs and instantiate them. + for (auto db : config_ctl->getConfigDatabases()) { + const std::string& access = db.getAccessString(); + auto parameters = db.getParameters(); + if (ConfigBackendDHCPv4Mgr::instance().delBackend(parameters["type"], access, true)) { + ConfigBackendDHCPv4Mgr::instance().addBackend(db.getAccessString()); + } + } + + reopened = true; + } catch (const std::exception& ex) { + LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_FAILED4) + .arg(ex.what()); + } + + if (reopened) { + // Cancel the timer. + if (TimerMgr::instance()->isTimerRegistered(timer_name)) { + TimerMgr::instance()->unregisterTimer(timer_name); + } + + // Invoke application layer connection recovered callback. + if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) { + return (false); + } + } else { + if (!db_reconnect_ctl->checkRetries()) { + // We're out of retries, log it and initiate shutdown. + LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_FAILED4) + .arg(db_reconnect_ctl->maxRetries()); + + // Cancel the timer. + if (TimerMgr::instance()->isTimerRegistered(timer_name)) { + TimerMgr::instance()->unregisterTimer(timer_name); + } + + // Invoke application layer connection failed callback. + DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl); + + return (false); + } + + LOG_INFO(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4) + .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1) + .arg(db_reconnect_ctl->maxRetries()) + .arg(db_reconnect_ctl->retryInterval()); + + // Start the timer. + if (!TimerMgr::instance()->isTimerRegistered(timer_name)) { + TimerMgr::instance()->registerTimer(timer_name, + std::bind(&PgSqlConfigBackendDHCPv4Impl::dbReconnect, db_reconnect_ctl), + db_reconnect_ctl->retryInterval(), + asiolink::IntervalTimer::ONE_SHOT); + } + TimerMgr::instance()->setup(timer_name); + } + + return (true); + } + +}; + +namespace { + +/// @brief Array of tagged statements. +typedef std::array<PgSqlTaggedStatement, PgSqlConfigBackendDHCPv4Impl::NUM_STATEMENTS> +TaggedStatementArray; + +/// @brief Prepared PgSQL statements used by the backend to insert and +/// retrieve data from the database. They must be in the same order as +/// PgSqlConfigBackendDHCPv4Impl::StatementIndex. The statement is +/// the corresponding enum name. +TaggedStatementArray tagged_statements = { { + { + // PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + 4, + { + OID_TIMESTAMP, // 1 audit_ts + OID_VARCHAR, // 2 server_tag + OID_TEXT, // 3 audit_log_message + OID_BOOL // 4 cascade_transaction + }, + "CREATE_AUDIT_REVISION", + "select createAuditRevisionDHCP4($1, $2, $3, $4)" + }, + + // Verify that dependency on KNOWN/UNKNOWN class has not changed. + { + // PgSqlConfigBackendDHCPv4Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + 0, + { + OID_NONE + }, + "CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE", + "select checkDHCPv4ClientClassKnownDependencyChange()" + }, + + // Select global parameter by name. + { + // PgSqlConfigBackendDHCPv4Impl::GET_GLOBAL_PARAMETER4, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 name + }, + "GET_GLOBAL_PARAMETER4", + PGSQL_GET_GLOBAL_PARAMETER(dhcp4, AND g.name = $2) + }, + + // Select all global parameters. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_ALL_GLOBAL_PARAMETERS4", + PGSQL_GET_GLOBAL_PARAMETER(dhcp4) + }, + + // Select modified global parameters. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP // 2 modification_ts + }, + "GET_MODIFIED_GLOBAL_PARAMETERS4", + PGSQL_GET_GLOBAL_PARAMETER(dhcp4, AND g.modification_ts >= $2) + }, + + // Select subnet by id. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_NO_TAG, + 1, + { + OID_INT8 // 1 subnet_id + }, + "GET_SUBNET4_ID_NO_TAG", + PGSQL_GET_SUBNET4_NO_TAG(WHERE s.subnet_id = $1) + }, + + // Select subnet by id without specifying server tags. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_ANY, + 1, + { + OID_INT8 // 1 subnet_id + }, + "GET_SUBNET4_ID_ANY", + PGSQL_GET_SUBNET4_ANY(WHERE s.subnet_id = $1) + }, + + // Select unassigned subnet by id. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_UNASSIGNED, + 1, + { + OID_INT8 // 1 subnet_id + }, + "GET_SUBNET4_ID_UNASSIGNED", + PGSQL_GET_SUBNET4_UNASSIGNED(AND s.subnet_id = $1) + }, + + // Select subnet by prefix. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_NO_TAG, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "GET_SUBNET4_PREFIX_NO_TAG", + PGSQL_GET_SUBNET4_NO_TAG(WHERE s.subnet_prefix = $1) + }, + + // Select subnet by prefix without specifying server tags. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_ANY, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "GET_SUBNET4_PREFIX_ANY", + PGSQL_GET_SUBNET4_ANY(WHERE s.subnet_prefix = $1) + }, + + // Select unassigned subnet by prefix. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_UNASSIGNED, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "GET_SUBNET4_PREFIX_UNASSIGNED", + PGSQL_GET_SUBNET4_UNASSIGNED(AND s.subnet_prefix = $1) + }, + + // Select all subnets. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4, + 0, + { + OID_NONE + }, + "GET_ALL_SUBNETS4", + PGSQL_GET_SUBNET4_NO_TAG() + }, + + // Select all unassigned subnets. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "GET_ALL_SUBNETS4_UNASSIGNED", + PGSQL_GET_SUBNET4_UNASSIGNED() + }, + + // Select subnets having modification time later than X. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SUBNETS4", + PGSQL_GET_SUBNET4_NO_TAG(WHERE s.modification_ts >= $1) + }, + + // Select modified and unassigned subnets. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4_UNASSIGNED, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SUBNETS4_UNASSIGNED", + PGSQL_GET_SUBNET4_UNASSIGNED(AND s.modification_ts >= $1) + }, + + // Select subnets belonging to a shared network. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK_SUBNETS4, + 1, + { + OID_VARCHAR // 1 share_network_name + }, + "GET_SHARED_NETWORK_SUBNETS4", + PGSQL_GET_SUBNET4_ANY(WHERE s.shared_network_name = $1) + }, + + // Select pool by address range for a server. + { + // PgSqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_TEXT, // 2 start_address - cast as inet + OID_TEXT // 3 end_address - cast as inet + }, + "GET_POOL4_RANGE", + PGSQL_GET_POOL4_RANGE_WITH_TAG(WHERE (srv.tag = $1 OR srv.id = 1) \ + AND (p.start_address = cast($2 as inet)) \ + AND (p.end_address = cast($3 as inet))) + }, + + // Select pool by address range for any server. + { + // PgSqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE_ANY, + 2, + { + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT // 2 end_address - cast as inet + }, + "GET_POOL4_RANGE_ANY", + PGSQL_GET_POOL4_RANGE_NO_TAG(WHERE (p.start_address = cast($1 as inet)) AND \ + (p.end_address = cast($2 as inet))) + }, + + // Select shared network by name. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_NO_TAG, + 1, + { + OID_VARCHAR // name of network + }, + "GET_SHARED_NETWORK4_NAME_NO_TAG", + PGSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.name = $1) + }, + + // Select shared network by name without specifying server tags. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_ANY, + 1, + { + OID_VARCHAR // name of network + }, + "GET_SHARED_NETWORK4_NAME_ANY", + PGSQL_GET_SHARED_NETWORK4_ANY(WHERE n.name = $1) + }, + + // Select unassigned shared network by name. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_UNASSIGNED, + 1, + { + OID_VARCHAR // name of network + }, + "GET_SHARED_NETWORK4_NAME_UNASSIGNED", + PGSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.name = $1) + }, + + // Select all shared networks. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4, + 0, + { + OID_NONE + }, + "GET_ALL_SHARED_NETWORKS4", + PGSQL_GET_SHARED_NETWORK4_NO_TAG() + }, + + // Select all unassigned shared networks. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "GET_ALL_SHARED_NETWORKS4_UNASSIGNED", + PGSQL_GET_SHARED_NETWORK4_UNASSIGNED() + }, + + // Select modified shared networks. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SHARED_NETWORKS4", + PGSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.modification_ts >= $1) + }, + + // Select modified and unassigned shared networks. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED", + PGSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.modification_ts >= $1) + }, + + // Retrieves option definition by code and space. + { + // PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "GET_OPTION_DEF4_CODE_SPACE", + PGSQL_GET_OPTION_DEF(dhcp4, AND d.code = $2 AND d.space = $3) + }, + + // Retrieves all option definitions. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_ALL_OPTION_DEFS4", + PGSQL_GET_OPTION_DEF(dhcp4) + }, + + // Retrieves modified option definitions. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP // 2 modification_ts + }, + "GET_MODIFIED_OPTION_DEFS4", + PGSQL_GET_OPTION_DEF(dhcp4, AND d.modification_ts >= $2) + }, + + // Retrieves global option by code and space. + { + // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_CODE_SPACE, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "GET_OPTION4_CODE_SPACE", + PGSQL_GET_OPTION4(AND o.scope_id = 0 AND o.code = $2 AND o.space = $3) + }, + + // Retrieves all global options. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_ALL_OPTIONS4", + PGSQL_GET_OPTION4(AND o.scope_id = 0) + }, + + // Retrieves modified options. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTIONS4, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP // 2 modification_ts + }, + "GET_MODIFIED_OPTIONS4", + PGSQL_GET_OPTION4(AND o.scope_id = 0 AND o.modification_ts >= $2) + }, + + // Retrieves an option for a given subnet, option code and space. + { + // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_SUBNET_ID_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_INT8, // 2 subnet_id + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION4_SUBNET_ID_CODE_SPACE", + PGSQL_GET_OPTION4(AND o.scope_id = 1 AND o.dhcp4_subnet_id = $2 AND o.code = $3 AND o.space = $4) + }, + + // Retrieves an option for a given pool, option code and space. + { + // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_POOL_ID_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_INT8, // 2 pool_id + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION4_POOL_ID_CODE_SPACE", + PGSQL_GET_OPTION4(AND o.scope_id = 5 AND o.pool_id = $2 AND o.code = $3 AND o.space = $4) + }, + + // Retrieves an option for a given shared network, option code and space. + { + // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_SHARED_NETWORK_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR, // 2 shared_network_name + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION4_SHARED_NETWORK_CODE_SPACE", + PGSQL_GET_OPTION4(AND o.scope_id = 4 AND o.shared_network_name = $2 AND o.code = $3 AND o.space = $4) + }, + + // Select a client class by name. + { + // PgSqlConfigBackendDHCPv4Impl::GET_CLIENT_CLASS4_NAME, + 1, + { + OID_VARCHAR // name of class + }, + "GET_CLIENT_CLASS4_NAME", + PGSQL_GET_CLIENT_CLASS4_WITH_TAG(WHERE c.name = $1) + }, + + // Select all client classes. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4, + 0, + { + OID_NONE + }, + "GET_ALL_CLIENT_CLASSES4", + PGSQL_GET_CLIENT_CLASS4_WITH_TAG() + }, + + // Select all unassigned client classes. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4_UNASSIGNED, + 0, + { + OID_NONE + }, + "GET_ALL_CLIENT_CLASSES4_UNASSIGNED", + PGSQL_GET_CLIENT_CLASS4_UNASSIGNED() + }, + + // Select modified client classes. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_CLIENT_CLASSES4", + PGSQL_GET_CLIENT_CLASS4_WITH_TAG(WHERE c.modification_ts >= $1) + }, + + // Select modified client classes. + { + // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED", + PGSQL_GET_CLIENT_CLASS4_UNASSIGNED(AND c.modification_ts >= $1) + }, + + // Retrieves the most recent audit entries. + { + // PgSqlConfigBackendDHCPv4Impl::GET_AUDIT_ENTRIES4_TIME, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP, // 2 modification_ts + OID_INT8 // 3 revision id + }, + "GET_AUDIT_ENTRIES4_TIME", + PGSQL_GET_AUDIT_ENTRIES_TIME(dhcp4) + }, + + // Retrieves a server by tag. + { + // PgSqlConfigBackendDHCPv4Impl::GET_SERVER4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_SERVER4", + PGSQL_GET_SERVER(dhcp4) + }, + + // Retrieves all servers. + { + // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SERVERS4, + 0, + { + OID_NONE + }, + "GET_ALL_SERVERS4", + PGSQL_GET_ALL_SERVERS(dhcp4) + }, + + // Insert global parameter. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4, + 4, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 value + OID_INT2, // 3 parameter_type + OID_TIMESTAMP // 4 modification_ts + }, + "INSERT_GLOBAL_PARAMETER4", + PGSQL_INSERT_GLOBAL_PARAMETER(dhcp4) + }, + + // Insert association of the global parameter with a server. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER, + 3, + { + OID_INT8, // 1 parameter_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_GLOBAL_PARAMETER4_SERVER", + PGSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp4) + }, + + // Insert a subnet. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, + 38, + { + OID_INT8, // 1 subnet_id, + OID_VARCHAR, // 2 subnet_prefix + OID_VARCHAR, // 3 interface_4o6 + OID_VARCHAR, // 4 interface_id_4o6 + OID_VARCHAR, // 5 subnet_4o6 + OID_VARCHAR, // 6 boot_file_name + OID_VARCHAR, // 7 client_class + OID_VARCHAR, // 8 interface + OID_BOOL, // 9 match_client_id + OID_TIMESTAMP, // 10 modification_ts + OID_TEXT, // 11 next_server - cast as inet + OID_INT8, // 12 rebind_timer + OID_TEXT, // 13 relay + OID_INT8, // 14 renew_timer + OID_TEXT, // 15 require_client_classes + OID_BOOL, // 16 reservations_global + OID_VARCHAR, // 17 server_hostname + OID_VARCHAR, // 18 shared_network_name + OID_TEXT, // 19 user_context + OID_INT8, // 20 valid_lifetime + OID_INT8, // 21 min_valid_lifetime + OID_INT8, // 22 max_valid_lifetime + OID_BOOL, // 23 calculate_tee_times + OID_TEXT, // 24 t1_percent - cast as float + OID_TEXT, // 25 t2_percent - cast as float + OID_BOOL, // 26 authoritative + OID_BOOL, // 27 ddns_send_updates + OID_BOOL, // 28 ddns_override_no_update + OID_BOOL, // 29 ddns_override_client_update + OID_INT8, // 30 ddns_replace_client_name + OID_VARCHAR, // 31 ddns_generated_prefix + OID_VARCHAR, // 32 ddns_qualifying_suffix + OID_BOOL, // 33 reservations_in_subnet + OID_BOOL, // 34 reservations_out_of_pool + OID_TEXT, // 35 cache_threshold - cast as float + OID_INT8, // 36 cache_max_age + OID_INT8, // 37 offer_lifetime + OID_VARCHAR // 38 allocator + }, + "INSERT_SUBNET4", + "INSERT INTO dhcp4_subnet(" + " subnet_id," + " subnet_prefix," + " interface_4o6," + " interface_id_4o6," + " subnet_4o6," + " boot_file_name," + " client_class," + " interface," + " match_client_id," + " modification_ts," + " next_server," + " rebind_timer," + " relay," + " renew_timer," + " require_client_classes," + " reservations_global," + " server_hostname," + " shared_network_name," + " user_context," + " valid_lifetime," + " min_valid_lifetime," + " max_valid_lifetime," + " calculate_tee_times," + " t1_percent," + " t2_percent," + " authoritative," + " ddns_send_updates," + " ddns_override_no_update," + " ddns_override_client_update," + " ddns_replace_client_name," + " ddns_generated_prefix," + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool," + " cache_threshold," + " cache_max_age," + " offer_lifetime," + " allocator" + ") VALUES (" + "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, " + "cast($11 as inet), $12, $13, $14, $15, $16, $17, $18, cast($19 as json), $20, " + "$21, $22, $23, cast($24 as float), cast($25 as float), $26, $27, $28, $29, $30, " + "$31, $32, $33, $34, cast($35 as float), $36, $37, $38" + ")" + }, + + // Insert association of the subnet with a server. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, + 3, + { + OID_INT8, // 1 subnet_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_SUBNET4_SERVER", + PGSQL_INSERT_SUBNET_SERVER(dhcp4) + }, + + // Insert pool for a subnet. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_POOL4, + 7, + { + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT, // 2 end_address - cast as inet + OID_INT8, // 3 subnet_id + OID_VARCHAR, // 4 client_class + OID_TEXT, // 5 require_client_classes + OID_TEXT, // 6 user_context - cast as json + OID_TIMESTAMP // 7 modification_ts + }, + "INSERT_POOL4", + PGSQL_INSERT_POOL(dhcp4) + }, + + // Insert a shared network. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4, + 33, + { + OID_VARCHAR, // 1 name, + OID_VARCHAR, // 2 client_class, + OID_VARCHAR, // 3 interface, + OID_BOOL, // 4 match_client_id, + OID_TIMESTAMP, // 5 modification_ts, + OID_INT8, // 6 rebind_timer, + OID_TEXT, // 7 relay, + OID_INT8, // 8 renew_timer, + OID_TEXT, // 9 require_client_classes, + OID_BOOL, // 10 reservations_global, + OID_TEXT, // 11 user_context, + OID_INT8, // 12 valid_lifetime, + OID_INT8, // 13 min_valid_lifetime, + OID_INT8, // 14 max_valid_lifetime, + OID_BOOL, // 15 calculate_tee_times, + OID_TEXT, // 16 t1_percent - cast as float + OID_TEXT, // 17 t2_percent - cast as float + OID_BOOL, // 18 authoritative, + OID_VARCHAR, // 19 boot_file_name, + OID_TEXT, // 20 next_server - cast as inet + OID_VARCHAR, // 21 server_hostname, + OID_BOOL, // 22 ddns_send_updates, + OID_BOOL, // 23 ddns_override_no_update, + OID_BOOL, // 24 ddns_override_client_update, + OID_INT8, // 25 ddns_replace_client_name, + OID_VARCHAR, // 26 ddns_generated_prefix, + OID_VARCHAR, // 27 ddns_qualifying_suffix, + OID_BOOL, // 28 reservations_in_subnet, + OID_BOOL, // 29 reservations_out_of_pool, + OID_TEXT, // 30 cache_threshold - cast as float + OID_INT8, // 31 cache_max_age + OID_INT8, // 32 offer_lifetime + OID_VARCHAR // 33 allocator + }, + "INSERT_SHARED_NETWORK4", + "INSERT INTO dhcp4_shared_network(" + " name," + " client_class," + " interface," + " match_client_id," + " modification_ts," + " rebind_timer," + " relay," + " renew_timer," + " require_client_classes," + " reservations_global," + " user_context," + " valid_lifetime," + " min_valid_lifetime," + " max_valid_lifetime," + " calculate_tee_times," + " t1_percent," + " t2_percent," + " authoritative," + " boot_file_name," + " next_server," + " server_hostname," + " ddns_send_updates," + " ddns_override_no_update," + " ddns_override_client_update," + " ddns_replace_client_name," + " ddns_generated_prefix," + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool," + " cache_threshold," + " cache_max_age," + " offer_lifetime," + " allocator" + ") VALUES (" + "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10," + "cast($11 as json), $12, $13, $14, $15, " + "cast($16 as float), cast($17 as float), $18, $19, cast($20 as inet), " + "$21, $22, $23, $24, $25, $26, $27, $28, $29, cast($30 as float), $31, $32, $33" + ")" + }, + + // Insert association of the shared network with a server. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER, + 3, + { + OID_VARCHAR, // 1 shared_network_name + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_SHARED_NETWORK4_SERVER", + PGSQL_INSERT_SHARED_NETWORK_SERVER(dhcp4) + }, + + // Insert option definition. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4, + 10, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_VARCHAR, // 9 user_context + OID_INT8 // 10 class_id + }, + "INSERT_OPTION_DEF4", + PGSQL_INSERT_OPTION_DEF(dhcp4) + }, + + // Insert option definition for client class. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_CLIENT_CLASS, + 10, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_VARCHAR, // 9 user_context + OID_VARCHAR // 10 class name for where clause + }, + "INSERT_OPTION_DEF4_CLIENT_CLASS", + PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp4) + }, + + // Insert association of the option definition with a server. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER, + 3, + { + OID_INT8, // 1 option_def_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_OPTION_DEF4_SERVER", + PGSQL_INSERT_OPTION_DEF_SERVER(dhcp4) + }, + + // Insert subnet specific option. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4, + 13, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp4_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP // 13 modification_ts + }, + "INSERT_OPTION4", + PGSQL_INSERT_OPTION4() + }, + + // Insert association of the DHCP option with a server. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER, + 3, + { + OID_INT8, // 1 option_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_OPTION4_SERVER", + PGSQL_INSERT_OPTION_SERVER(dhcp4) + }, + + // Insert client class. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4, + 14, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 test + OID_TEXT, // 3 next_server - cast as inet + OID_VARCHAR, // 4 server_hostname + OID_VARCHAR, // 5 boot_file_name + OID_BOOL, // 6 only_if_required + OID_INT8, // 7 valid_lifetime + OID_INT8, // 8 min_valid_lifetime + OID_INT8, // 9 max_valid_lifetime + OID_BOOL, // 10 depend_on_known_directly + OID_VARCHAR, // 11 follow_class_name + OID_TIMESTAMP, // 12 modification_ts + OID_TEXT, // 13 user_context cast as JSON + OID_INT8 // 14 offer_lifetime + }, + "INSERT_CLIENT_CLASS4", + "INSERT INTO dhcp4_client_class(" + " name," + " test," + " next_server," + " server_hostname," + " boot_file_name," + " only_if_required," + " valid_lifetime," + " min_valid_lifetime," + " max_valid_lifetime," + " depend_on_known_directly," + " follow_class_name," + " modification_ts, " + " user_context, " + " offer_lifetime " + ") VALUES (" + "$1, $2, cast($3 as inet), $4, $5, $6, $7, $8, $9, $10, $11, $12, cast($13 as JSON), $14" + ")" + }, + + // Insert association of a client class with a server. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_SERVER, + 3, + { + OID_VARCHAR, // 1 class_name + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_CLIENT_CLASS4_SERVER", + PGSQL_INSERT_CLIENT_CLASS_SERVER(dhcp4) + }, + + // Insert client class dependency. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_DEPENDENCY, + 2, + { + OID_VARCHAR, // class name + OID_VARCHAR // dependency class name + }, + "INSERT_CLIENT_CLASS4_DEPENDENCY", + PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp4) + }, + + // Insert server with server tag and description. + { + // PgSqlConfigBackendDHCPv4Impl::INSERT_SERVER4, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR, // 2 description + OID_TIMESTAMP // 3 modification_ts + }, + "INSERT_SERVER4", + PGSQL_INSERT_SERVER(dhcp4) + }, + + // Update existing global parameter. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4, + 6, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 value + OID_INT2, // 3 parameter_type + OID_TIMESTAMP, // 4 modification_ts + OID_VARCHAR, // 5 server_tag + OID_VARCHAR, // 6 name (of global to update) + }, + "UPDATE_GLOBAL_PARAMETER4", + PGSQL_UPDATE_GLOBAL_PARAMETER(dhcp4) + }, + + // Update existing subnet. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4, + 40, + { + OID_INT8, // 1 subnet_id, + OID_VARCHAR, // 2 subnet_prefix + OID_VARCHAR, // 3 interface_4o6 + OID_VARCHAR, // 4 interface_id_4o6 + OID_VARCHAR, // 5 subnet_4o6 + OID_VARCHAR, // 6 boot_file_name + OID_VARCHAR, // 7 client_class + OID_VARCHAR, // 8 interface + OID_BOOL, // 9 match_client_id + OID_TIMESTAMP, // 10 modification_ts + OID_TEXT, // 11 next_server - cast as inet + OID_INT8, // 12 rebind_timer + OID_TEXT, // 13 relay + OID_INT8, // 14 renew_timer + OID_TEXT, // 15 require_client_classes + OID_BOOL, // 16 reservations_global + OID_VARCHAR, // 17 server_hostname + OID_VARCHAR, // 18 shared_network_name + OID_TEXT, // 19 user_context + OID_INT8, // 20 valid_lifetime + OID_INT8, // 21 min_valid_lifetime + OID_INT8, // 22 max_valid_lifetime + OID_BOOL, // 23 calculate_tee_times + OID_TEXT, // 24 t1_percent - cast as float + OID_TEXT, // 25 t2_percent - cast as float + OID_BOOL, // 26 authoritative + OID_BOOL, // 27 ddns_send_updates + OID_BOOL, // 28 ddns_override_no_update + OID_BOOL, // 29 ddns_override_client_update + OID_INT8, // 30 ddns_replace_client_name + OID_VARCHAR, // 31 ddns_generated_prefix + OID_VARCHAR, // 32 ddns_qualifying_suffix + OID_BOOL, // 33 reservations_in_subnet + OID_BOOL, // 34 reservations_out_of_pool + OID_TEXT, // 35 cache_threshold - cast as float + OID_INT8, // 36 cache_max_age" + OID_INT8, // 37 offer_lifetime" + OID_VARCHAR, // 38 allocator + OID_INT8, // 39 subnet_id (of subnet to update) + OID_VARCHAR, // 40 subnet_prefix (of subnet to update) + }, + "UPDATE_SUBNET4,", + "UPDATE dhcp4_subnet SET" + " subnet_id = $1," + " subnet_prefix = $2," + " interface_4o6 = $3," + " interface_id_4o6 = $4," + " subnet_4o6 = $5," + " boot_file_name = $6," + " client_class = $7," + " interface = $8," + " match_client_id = $9," + " modification_ts = $10," + " next_server = cast($11 as inet)," + " rebind_timer = $12," + " relay = $13," + " renew_timer = $14," + " require_client_classes = $15," + " reservations_global = $16," + " server_hostname = $17," + " shared_network_name = $18," + " user_context = cast($19 as json)," + " valid_lifetime = $20," + " min_valid_lifetime = $21," + " max_valid_lifetime = $22," + " calculate_tee_times = $23," + " t1_percent = cast($24 as float)," + " t2_percent = cast($25 as float)," + " authoritative = $26," + " ddns_send_updates = $27," + " ddns_override_no_update = $28," + " ddns_override_client_update = $29," + " ddns_replace_client_name = $30," + " ddns_generated_prefix = $31," + " ddns_qualifying_suffix = $32," + " reservations_in_subnet = $33," + " reservations_out_of_pool = $34," + " cache_threshold = cast($35 as float)," + " cache_max_age = $36," + " offer_lifetime = $37," + " allocator = $38 " + "WHERE subnet_id = $39 OR subnet_prefix = $40" + }, + + // Update existing shared network. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4, + 34, + { + OID_VARCHAR, // 1 name, + OID_VARCHAR, // 2 client_class, + OID_VARCHAR, // 3 interface, + OID_BOOL, // 4 match_client_id, + OID_TIMESTAMP, // 5 modification_ts, + OID_INT8, // 6 rebind_timer, + OID_TEXT, // 7 relay, + OID_INT8, // 8 renew_timer, + OID_TEXT, // 9 require_client_classes, + OID_BOOL, // 10 reservations_global, + OID_TEXT, // 11 user_context, + OID_INT8, // 12 valid_lifetime, + OID_INT8, // 13 min_valid_lifetime, + OID_INT8, // 14 max_valid_lifetime, + OID_BOOL, // 15 calculate_tee_times, + OID_TEXT, // 16 t1_percent - cast as float + OID_TEXT, // 17 t2_percent - cast as float + OID_BOOL, // 18 authoritative, + OID_VARCHAR, // 19 boot_file_name, + OID_TEXT, // 20 next_server - cast as inet + OID_VARCHAR, // 21 server_hostname, + OID_BOOL, // 22 ddns_send_updates, + OID_BOOL, // 23 ddns_override_no_update, + OID_BOOL, // 24 ddns_override_client_update, + OID_INT8, // 25 ddns_replace_client_name, + OID_VARCHAR, // 26 ddns_generated_prefix, + OID_VARCHAR, // 27 ddns_qualifying_suffix, + OID_BOOL, // 28 reservations_in_subnet, + OID_BOOL, // 29 reservations_out_of_pool, + OID_TEXT, // 30 cache_threshold - cast as float + OID_INT8, // 31 cache_max_age + OID_INT8, // 32 offer_lifetime + OID_VARCHAR, // 33 name (of network to update) + OID_VARCHAR // 34 allocator + }, + "UPDATE_SHARED_NETWORK4", + "UPDATE dhcp4_shared_network SET" + " name = $1," + " client_class = $2," + " interface = $3," + " match_client_id = $4," + " modification_ts = $5," + " rebind_timer = $6," + " relay = $7," + " renew_timer = $8," + " require_client_classes = $9," + " reservations_global = $10," + " user_context = cast($11 as json)," + " valid_lifetime = $12," + " min_valid_lifetime = $13," + " max_valid_lifetime = $14," + " calculate_tee_times = $15," + " t1_percent = cast($16 as float)," + " t2_percent = cast($17 as float)," + " authoritative = $18," + " boot_file_name = $19," + " next_server = cast($20 as inet)," + " server_hostname = $21," + " ddns_send_updates = $22," + " ddns_override_no_update = $23," + " ddns_override_client_update = $24," + " ddns_replace_client_name = $25," + " ddns_generated_prefix = $26," + " ddns_qualifying_suffix = $27," + " reservations_in_subnet = $28," + " reservations_out_of_pool = $29," + " cache_threshold = cast($30 as float)," + " cache_max_age = $31," + " offer_lifetime = $32," + " allocator = $33 " + "WHERE name = $34" + }, + + // Update existing option definition. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4, + 13, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_TEXT, // 9 user_context + OID_INT2, // 10 class_id + OID_VARCHAR, // 11 server_tag + OID_INT2, // 12 code (of option to update) + OID_VARCHAR, // 13 space (of option to update) + }, + "UPDATE_OPTION_DEF4", + PGSQL_UPDATE_OPTION_DEF(dhcp4) + }, + + // Update existing client class option definition. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4_CLIENT_CLASS, + 13, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_TEXT, // 9 user_context + OID_VARCHAR, // 10 name (of class option belongs to) + OID_VARCHAR, // 11 server_tag + OID_INT2, // 12 code (of option to update) + OID_VARCHAR, // 13 space (of option to update) + }, + "UPDATE_OPTION_DEF4_CLIENT_CLASS", + PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp4) + }, + + // Update existing global option. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4, + 16, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp4_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_VARCHAR, // 14 server_tag + OID_INT2, // 15 code (of option to update) + OID_VARCHAR, // 16 space (of option to update) + }, + "UPDATE_OPTION4", + PGSQL_UPDATE_OPTION4_WITH_TAG(AND o.scope_id = 0 AND o.code = $15 AND o.space = $16) + }, + + // Update existing subnet level option. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID, + 16, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp4_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 subnet_id (of option to update) + OID_INT2, // 15 code (of option to update) + OID_VARCHAR // 16 space (of option to update) + }, + "UPDATE_OPTION4_SUBNET_ID", + PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 1 AND o.dhcp4_subnet_id = $14 AND o.code = $15 AND o.space = $16) + }, + + // Update existing pool level option. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID, + 16, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp4_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pool_id (of option to update) + OID_INT2, // 15 code (of option to update) + OID_VARCHAR // 16 space (of option to update) + }, + "UPDATE_OPTION4_POOL_ID", + PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 5 AND o.pool_id = $14 AND o.code = $15 AND o.space = $16) + }, + + // Update existing shared network level option. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK, + 16, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp4_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_VARCHAR, // 14 shared_network_name (of option to update) + OID_INT2, // 15 code (of option to update) + OID_VARCHAR // 16 space (of option to update) + }, + "UPDATE_OPTION4_SHARED_NETWORK", + PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $14 AND o.code = $15 AND o.space = $16) + }, + + // Update existing client class level option. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_CLIENT_CLASS, + 16, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp4_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_VARCHAR, // 14 dhcp_client_class (of option to update) + OID_INT2, // 15 code (of option to update) + OID_VARCHAR, // 16 space (of option to update) + }, + "UPDATE_OPTION4_CLIENT_CLASS", + PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $14 AND o.code = $15 AND o.space = $16) + }, + + // Update existing client class with specifying its position. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4, + 15, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 test + OID_TEXT, // 3 next_server - cast as inet + OID_VARCHAR, // 4 server_hostname + OID_VARCHAR, // 5 boot_file_name + OID_BOOL, // 6 only_if_required + OID_INT8, // 7 valid_lifetime + OID_INT8, // 8 min_valid_lifetime + OID_INT8, // 9 max_valid_lifetime + OID_BOOL, // 10 depend_on_known_directly + OID_VARCHAR, // 11 follow_class_name + OID_TIMESTAMP, // 12 modification_ts + OID_TEXT, // 13 user_context cast as JSON + OID_INT8, // 14 offer_lifetime + OID_VARCHAR // 15 name (of class to update) + }, + "UPDATE_CLIENT_CLASS4", + PGSQL_UPDATE_CLIENT_CLASS4("follow_class_name = $11,") + }, + + // Update existing client class without specifying its position. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4_SAME_POSITION, + 15, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 test + OID_TEXT, // 3 next_server - cast as inet + OID_VARCHAR, // 4 server_hostname + OID_VARCHAR, // 5 boot_file_name + OID_BOOL, // 6 only_if_required + OID_INT8, // 7 valid_lifetime + OID_INT8, // 8 min_valid_lifetime + OID_INT8, // 9 max_valid_lifetime + OID_BOOL, // 10 depend_on_known_directly + OID_VARCHAR, // 11 follow_class_name + OID_TIMESTAMP, // 12 modification_ts + OID_TEXT, // 13 user_context cast as JSON + OID_INT8, // 14 offer_lifetime + OID_VARCHAR // 15 name (of class to update) + }, + "UPDATE_CLIENT_CLASS4_SAME_POSITION", + PGSQL_UPDATE_CLIENT_CLASS4("") + }, + + // Update existing server, e.g. server description. + { + // PgSqlConfigBackendDHCPv4Impl::UPDATE_SERVER4, + 4, + { + OID_VARCHAR, // 1 tag + OID_VARCHAR, // 2 description + OID_TIMESTAMP, // 3 modification_ts + OID_VARCHAR // 4 tag (of server to update) + }, + "UPDATE_SERVER4", + PGSQL_UPDATE_SERVER(dhcp4) + }, + + // Delete global parameter by name. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 name of parameter + }, + "DELETE_GLOBAL_PARAMETER4", + PGSQL_DELETE_GLOBAL_PARAMETER(dhcp4, AND g.name = $2) + }, + + // Delete all global parameters. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_GLOBAL_PARAMETERS4", + PGSQL_DELETE_GLOBAL_PARAMETER(dhcp4) + }, + + // Delete all global parameters which are unassigned to any servers. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED", + PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp4) + }, + + // Delete subnet by id with specifying server tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_WITH_TAG, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_INT8 // 2 subnet_id + }, + "DELETE_SUBNET4_ID_WITH_TAG", + PGSQL_DELETE_SUBNET_WITH_TAG(dhcp4, AND s.subnet_id = $2) + }, + + // Delete subnet by id without specifying server tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_ANY, + 1, + { + OID_INT8 // 1 subnet_id + }, + "DELETE_SUBNET4_ID_ANY", + PGSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.subnet_id = $1) + }, + + // Delete subnet by prefix with specifying server tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_WITH_TAG, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_SUBNET4_PREFIX_WITH_TAG", + PGSQL_DELETE_SUBNET_WITH_TAG(dhcp4, AND s.subnet_prefix = $2) + }, + + // Delete subnet by prefix without specifying server tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_ANY, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "DELETE_SUBNET4_PREFIX_ANY", + PGSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.subnet_prefix = $1) + }, + + // Delete all subnets. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_SUBNETS4", + PGSQL_DELETE_SUBNET_WITH_TAG(dhcp4) + }, + + // Delete all unassigned subnets. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_SUBNETS4_UNASSIGNED", + PGSQL_DELETE_SUBNET_UNASSIGNED(dhcp4) + }, + + // Delete all subnets for a shared network. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME, + 1, + { + OID_VARCHAR // 1 shared_network_name + }, + "DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME", + PGSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.shared_network_name = $1) + }, + + // Delete associations of a subnet with server. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_SERVER, + 1, + { + OID_INT8 // 1 subnet_id + }, + "DELETE_SUBNET4_SERVER", + PGSQL_DELETE_SUBNET_SERVER(dhcp4), + }, + + // Delete pools for a subnet. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_POOLS4, + 2, + { + OID_INT8, // 1 subnet_id + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_POOLS4", + PGSQL_DELETE_POOLS(dhcp4) + }, + + // Delete shared network by name with specifying server tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_WITH_TAG, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 shared_network_name + }, + "DELETE_SHARED_NETWORK4_NAME_WITH_TAG", + PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4, AND n.name = $2) + }, + + // Delete shared network by name without specifying server tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY, + 1, + { + OID_VARCHAR // 1 shared_network_name + }, + "DELETE_SHARED_NETWORK4_NAME_ANY", + PGSQL_DELETE_SHARED_NETWORK_ANY(dhcp4, WHERE n.name = $1) + }, + + // Delete all shared networks. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_SHARED_NETWORKS4", + PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4) + }, + + // Delete all unassigned shared networks. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED", + PGSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp4) + }, + + // Delete associations of a shared network with server. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER, + 1, + { + OID_VARCHAR // 1 shared_network_name + }, + "DELETE_SHARED_NETWORK4_SERVER", + PGSQL_DELETE_SHARED_NETWORK_SERVER(dhcp4) + }, + + // Delete option definition. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEF4_CODE_NAME, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION_DEF4_CODE_NAME", + PGSQL_DELETE_OPTION_DEF(dhcp4, AND code = $2 AND space = $3) + }, + + // Delete all option definitions. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_OPTION_DEFS4", + PGSQL_DELETE_OPTION_DEF(dhcp4) + }, + + // Delete all option definitions which are assigned to no servers. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_OPTION_DEFS4_UNASSIGNED", + PGSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp4) + }, + + // Delete client class specific option definitions. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEFS4_CLIENT_CLASS, + 1, + { + OID_VARCHAR // 1 class name + }, + "DELETE_OPTION_DEFS4_CLIENT_CLASS", + PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp4) + }, + + // Delete single global option. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION4", + PGSQL_DELETE_OPTION_WITH_TAG(dhcp4, AND o.scope_id = 0 AND o.code = $2 AND o.space = $3) + }, + + // Delete all global options which are unassigned to any servers. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED", + PGSQL_DELETE_OPTION_UNASSIGNED(dhcp4, AND o.scope_id = 0) + }, + + // Delete single option from a subnet. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID, + 3, + { + OID_INT8, // 1 subnet_id + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION4_SUBNET_ID", + PGSQL_DELETE_OPTION_NO_TAG(dhcp4, + WHERE o.scope_id = 1 AND o.dhcp4_subnet_id = $1 AND o.code = $2 AND o.space = $3) + }, + + // Delete single option from a pool. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_POOL_RANGE, + 4, + { + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT, // 2 start_address - cast as inet + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "DELETE_OPTION4_POOL_RANGE", + PGSQL_DELETE_OPTION_POOL_RANGE(dhcp4, o.scope_id = 5 AND o.code = $3 AND o.space = $4) + }, + + // Delete single option from a shared network. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SHARED_NETWORK, + 3, + { + OID_VARCHAR, // 1 shared_network_name + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION4_SHARED_NETWORK", + PGSQL_DELETE_OPTION_NO_TAG(dhcp4, + WHERE o.scope_id = 4 AND o.shared_network_name = $1 AND o.code = $2 AND o.space = $3) + }, + + // Delete options belonging to a subnet. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SUBNET_ID_PREFIX, + 2, + { + OID_INT8, // 1 subnet_id + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_OPTIONS4_SUBNET_ID_PREFIX", + PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX(dhcp4) + }, + + // Delete options belonging to a shared_network. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SHARED_NETWORK, + 1, + { + OID_VARCHAR // shared_network_name + }, + "DELETE_OPTIONS4_SHARED_NETWORK", + PGSQL_DELETE_OPTION_NO_TAG(dhcp4, WHERE o.scope_id = 4 AND o.shared_network_name = $1) + }, + + // Delete options belonging to a client class. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_CLIENT_CLASS, + 1, + { + OID_VARCHAR // dhcp_client_class + }, + "DELETE_OPTIONS4_CLIENT_CLASS", + PGSQL_DELETE_OPTION_NO_TAG(dhcp4, WHERE o.scope_id = 2 AND o.dhcp_client_class = $1) + }, + + // Delete all dependencies of a client class. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_DEPENDENCY, + 1, + { + OID_VARCHAR, // 1 class name + }, + "DELETE_CLIENT_CLASS4_DEPENDENCY", + PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp4) + }, + + // Delete associations of a client class with server. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_SERVER, + 1, + { + OID_VARCHAR // 1 class name + }, + "DELETE_CLIENT_CLASS4_SERVER", + PGSQL_DELETE_CLIENT_CLASS_SERVER(dhcp4), + }, + + // Delete all client classes. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_CLIENT_CLASSES4", + PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp4) + }, + + // Delete all unassigned client classes. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED", + PGSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp4) + }, + + // Delete specified client class. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 name + }, + "DELETE_CLIENT_CLASS4", + PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp4, AND name = $2) + }, + + // Delete any client class with a given name. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_ANY, + 1, + { + OID_VARCHAR // 1 name + }, + "DELETE_CLIENT_CLASS4_ANY", + PGSQL_DELETE_CLIENT_CLASS_ANY(dhcp4, AND name = $1) + }, + + // Delete a server by tag. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_SERVER4, + 1, + { + OID_VARCHAR // server_tag + }, + "DELETE_SERVER4", + PGSQL_DELETE_SERVER(dhcp4) + }, + + // Deletes all servers except logical server 'all'. + { + // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SERVERS4, + 0, + { + OID_NONE + }, + "DELETE_ALL_SERVERS4", + PGSQL_DELETE_ALL_SERVERS(dhcp4) + }, + + // Fetches the last sequence id for the given table and column. + { + // PgSqlConfigBackendDHCPv4Impl::GET_LAST_INSERT_ID4, + // args are: table name, sequence column name + 2, + { + OID_VARCHAR, + OID_VARCHAR + }, + "GET_LAST_INSERT_ID4", + "SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE($1, $2))" + } +} +}; + +} // end anonymous namespace + +PgSqlConfigBackendDHCPv4Impl::PgSqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters) + : PgSqlConfigBackendImpl(parameters, &PgSqlConfigBackendDHCPv4Impl::dbReconnect, + PgSqlConfigBackendDHCPv4Impl::GET_LAST_INSERT_ID4) { + // Prepare query statements. Those are will be only used to retrieve + // information from the database, so they can be used even if the + // database is read only for the current user. + conn_.prepareStatements(tagged_statements.begin(), + tagged_statements.end()); +// @todo As part of enabling read-only CB access, statements need to +// be limited: +// tagged_statements.begin() + WRITE_STMTS_BEGIN); + + // Create unique timer name per instance. + timer_name_ = "PgSqlConfigBackend4["; + timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this)); + timer_name_ += "]DbReconnectTimer"; + + // Create ReconnectCtl for this connection. + conn_.makeReconnectCtl(timer_name_); +} + +PgSqlConfigBackendDHCPv4Impl::~PgSqlConfigBackendDHCPv4Impl() { +} + +PgSqlTaggedStatement& +PgSqlConfigBackendDHCPv4Impl::getStatement(size_t index) const { + if (index >= tagged_statements.size()) { + isc_throw(BadValue, "PgSqlConfigBackendDHCPv4Impl::getStatement index: " + << index << ", is invalid"); + } + + return(tagged_statements[index]); +} + +PgSqlConfigBackendDHCPv4::PgSqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters) + : impl_(new PgSqlConfigBackendDHCPv4Impl(parameters)), base_impl_(impl_) { +} + +bool +PgSqlConfigBackendDHCPv4::isUnusable() { + return (impl_->conn_.isUnusable()); +} + +DatabaseConnection::ParameterMap +PgSqlConfigBackendDHCPv4::getParameters() const { + return (impl_->getParameters()); +} + +Subnet4Ptr +PgSqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector, + const std::string& subnet_prefix) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET4_BY_PREFIX) + .arg(subnet_prefix); + return (impl_->getSubnet4(server_selector, subnet_prefix)); +} + +Subnet4Ptr +PgSqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector, + const SubnetID& subnet_id) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID) + .arg(subnet_id); + return (impl_->getSubnet4(server_selector, subnet_id)); +} + +Subnet4Collection +PgSqlConfigBackendDHCPv4::getAllSubnets4(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS4); + Subnet4Collection subnets; + impl_->getAllSubnets4(server_selector, subnets); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS4_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet4Collection +PgSqlConfigBackendDHCPv4::getModifiedSubnets4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS4) + .arg(util::ptimeToText(modification_time)); + Subnet4Collection subnets; + impl_->getModifiedSubnets4(server_selector, modification_time, subnets); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet4Collection +PgSqlConfigBackendDHCPv4::getSharedNetworkSubnets4(const ServerSelector& /* server_selector */, + const std::string& shared_network_name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4) + .arg(shared_network_name); + Subnet4Collection subnets; + impl_->getSharedNetworkSubnets4(ServerSelector::ANY(), shared_network_name, subnets); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT) + .arg(subnets.size()); + return (subnets); +} + +SharedNetwork4Ptr +PgSqlConfigBackendDHCPv4::getSharedNetwork4(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK4) + .arg(name); + return (impl_->getSharedNetwork4(server_selector, name)); +} + +SharedNetwork4Collection +PgSqlConfigBackendDHCPv4::getAllSharedNetworks4(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS4); + SharedNetwork4Collection shared_networks; + impl_->getAllSharedNetworks4(server_selector, shared_networks); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +SharedNetwork4Collection +PgSqlConfigBackendDHCPv4::getModifiedSharedNetworks4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4) + .arg(util::ptimeToText(modification_time)); + SharedNetwork4Collection shared_networks; + impl_->getModifiedSharedNetworks4(server_selector, modification_time, shared_networks); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +OptionDefinitionPtr +PgSqlConfigBackendDHCPv4::getOptionDef4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION_DEF4) + .arg(code).arg(space); + return (impl_->getOptionDef(PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + server_selector, code, space)); +} + +OptionDefContainer +PgSqlConfigBackendDHCPv4::getAllOptionDefs4(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS4); + OptionDefContainer option_defs; + impl_->getAllOptionDefs(PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4, + server_selector, option_defs); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDefContainer +PgSqlConfigBackendDHCPv4::getModifiedOptionDefs4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS4) + .arg(util::ptimeToText(modification_time)); + OptionDefContainer option_defs; + impl_->getModifiedOptionDefs(PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4, + server_selector, modification_time, option_defs); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDescriptorPtr +PgSqlConfigBackendDHCPv4::getOption4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION4) + .arg(code).arg(space); + return (impl_->getOption(PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_CODE_SPACE, + Option::V4, server_selector, code, space)); +} + +OptionContainer +PgSqlConfigBackendDHCPv4::getAllOptions4(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS4); + OptionContainer options = impl_->getAllOptions(PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4, + Option::V4, server_selector); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS4_RESULT) + .arg(options.size()); + return (options); +} + +OptionContainer +PgSqlConfigBackendDHCPv4::getModifiedOptions4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS4) + .arg(util::ptimeToText(modification_time)); + OptionContainer options = impl_->getModifiedOptions(PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTIONS4, + Option::V4, server_selector, modification_time); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT) + .arg(options.size()); + return (options); +} + +StampedValuePtr +PgSqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_GLOBAL_PARAMETER4) + .arg(name); + return (impl_->getGlobalParameter4(server_selector, name)); +} + +StampedValueCollection +PgSqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + impl_->getGlobalParameters(PgSqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, + in_bindings, parameters); + } + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT) + .arg(parameters.size()); + return (parameters); +} + +StampedValueCollection +PgSqlConfigBackendDHCPv4::getModifiedGlobalParameters4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4) + .arg(util::ptimeToText(modification_time)); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addTimestamp(modification_time); + + impl_->getGlobalParameters(PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, + in_bindings, parameters); + } + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT) + .arg(parameters.size()); + return (parameters); +} + +ClientClassDefPtr +PgSqlConfigBackendDHCPv4::getClientClass4(const db::ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_CLIENT_CLASS4) + .arg(name); + return (impl_->getClientClass4(server_selector, name)); +} + +ClientClassDictionary +PgSqlConfigBackendDHCPv4::getAllClientClasses4(const db::ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES4); + ClientClassDictionary client_classes; + impl_->getAllClientClasses4(server_selector, client_classes); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +ClientClassDictionary +PgSqlConfigBackendDHCPv4::getModifiedClientClasses4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4) + .arg(util::ptimeToText(modification_time)); + ClientClassDictionary client_classes; + impl_->getModifiedClientClasses4(server_selector, modification_time, client_classes); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +AuditEntryCollection +PgSqlConfigBackendDHCPv4::getRecentAuditEntries(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4) + .arg(util::ptimeToText(modification_time)) + .arg(modification_id); + AuditEntryCollection audit_entries; + impl_->getRecentAuditEntries(PgSqlConfigBackendDHCPv4Impl::GET_AUDIT_ENTRIES4_TIME, + server_selector, modification_time, + modification_id, audit_entries); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT) + .arg(audit_entries.size()); + return (audit_entries); +} + +ServerCollection +PgSqlConfigBackendDHCPv4::getAllServers4() const { + ServerCollection servers; + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS4); + impl_->getAllServers(PgSqlConfigBackendDHCPv4Impl::GET_ALL_SERVERS4, + servers); + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS4_RESULT) + .arg(servers.size()); + return (servers); +} + +ServerPtr +PgSqlConfigBackendDHCPv4::getServer4(const data::ServerTag& server_tag) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SERVER4) + .arg(server_tag.get()); + return (impl_->getServer(PgSqlConfigBackendDHCPv4Impl::GET_SERVER4, server_tag)); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateSubnet4(const ServerSelector& server_selector, + const Subnet4Ptr& subnet) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SUBNET4) + .arg(subnet); + impl_->createUpdateSubnet4(server_selector, subnet); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateSharedNetwork4(const ServerSelector& server_selector, + const SharedNetwork4Ptr& shared_network) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4) + .arg(shared_network->getName()); + impl_->createUpdateSharedNetwork4(server_selector, shared_network); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateOptionDef4(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION_DEF4) + .arg(option_def->getName()).arg(option_def->getCode()); + impl_->createUpdateOptionDef4(server_selector, option_def); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION4); + impl_->createUpdateOption4(server_selector, option); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4) + .arg(shared_network_name); + impl_->createUpdateOption4(server_selector, shared_network_name, option, false); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4) + .arg(subnet_id); + impl_->createUpdateOption4(server_selector, subnet_id, option, false); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4) + .arg(pool_start_address.toText()).arg(pool_end_address.toText()); + impl_->createUpdateOption4(server_selector, pool_start_address, pool_end_address, + option); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateGlobalParameter4(const ServerSelector& server_selector, + const StampedValuePtr& value) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4) + .arg(value->getName()); + impl_->createUpdateGlobalParameter4(server_selector, value); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateClientClass4(const db::ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4) + .arg(client_class->getName()); + impl_->createUpdateClientClass4(server_selector, client_class, follow_class_name); +} + +void +PgSqlConfigBackendDHCPv4::createUpdateServer4(const ServerPtr& server) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SERVER4) + .arg(server->getServerTagAsText()); + impl_->createUpdateServer(PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + PgSqlConfigBackendDHCPv4Impl::INSERT_SERVER4, + PgSqlConfigBackendDHCPv4Impl::UPDATE_SERVER4, + server); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET4) + .arg(subnet_prefix); + uint64_t result = impl_->deleteSubnet4(server_selector, subnet_prefix); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4) + .arg(subnet_id); + uint64_t result = impl_->deleteSubnet4(server_selector, subnet_id); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteAllSubnets4(const ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS4); + + int index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets", + "deleted all subnets", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteSharedNetworkSubnets4(const db::ServerSelector& server_selector, + const std::string& shared_network_name) { + if (!server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting all subnets from a shared " + "network requires using ANY server selector"); + } + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4) + .arg(shared_network_name); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME, + server_selector, + "deleting all subnets for a shared network", + "deleted all subnets for a shared network", + true, shared_network_name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteSharedNetwork4(const ServerSelector& server_selector, + const std::string& name) { + /// @todo Using UNASSIGNED selector is allowed by the CB API but we don't have + /// dedicated query for this at the moment. The user should use ANY to delete + /// the shared network by name. + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "deleting an unassigned shared network requires " + "an explicit server tag or using ANY server. The UNASSIGNED server " + "selector is currently not supported"); + } + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK4) + .arg(name); + + int index = (server_selector.amAny() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY : + PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_WITH_TAG); + uint64_t result = impl_->deleteTransactional(index, server_selector, + "deleting a shared network", + "shared network deleted", true, name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteAllSharedNetworks4(const ServerSelector& server_selector) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not" + " supported"); + } + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4); + + int index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks", + "deleted all shared networks", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteOptionDef4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF4) + .arg(code).arg(space); + uint64_t result = impl_->deleteOptionDef4(server_selector, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteAllOptionDefs4(const ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS4); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4, + server_selector, "deleting all option definitions", + "deleted all option definitions", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION4) + .arg(code).arg(space); + uint64_t result = impl_->deleteOption4(server_selector, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space) { + /// @todo In the future we might use the server selector to make sure that the + /// option is only deleted if the pool belongs to a given server. For now, we + /// just delete it when there is a match with the parent object. + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4) + .arg(shared_network_name).arg(code).arg(space); + uint64_t result = impl_->deleteOption4(ServerSelector::ANY(), shared_network_name, + code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space) { + /// @todo In the future we might use the server selector to make sure that the + /// option is only deleted if the pool belongs to a given server. For now, we + /// just delete it when there is a match with the parent object. + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4) + .arg(subnet_id).arg(code).arg(space); + uint64_t result = impl_->deleteOption4(ServerSelector::ANY(), subnet_id, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const uint16_t code, + const std::string& space) { + /// @todo In the future we might use the server selector to make sure that the + /// option is only deleted if the pool belongs to a given server. For now, we + /// just delete it when there is a match with the parent object. + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION4) + .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space); + uint64_t result = impl_->deleteOption4(ServerSelector::ANY(), pool_start_address, + pool_end_address, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteGlobalParameter4(const ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER4) + .arg(name); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4, + server_selector, "deleting global parameter", + "global parameter deleted", false, name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteAllGlobalParameters4(const ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4, + server_selector, "deleting all global parameters", + "all global parameters deleted", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteClientClass4(const db::ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS4) + .arg(name); + auto result = impl_->deleteClientClass4(server_selector, name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteAllClientClasses4(const db::ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4); + + int index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED : + PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes", + "deleted all client classes", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteServer4(const ServerTag& server_tag) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER4) + .arg(server_tag.get()); + uint64_t result = impl_->deleteServer4(server_tag); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER4_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv4::deleteAllServers4() { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS4); + uint64_t result = impl_->deleteAllServers4(); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS4_RESULT) + .arg(result); + return (result); +} + +std::string +PgSqlConfigBackendDHCPv4::getType() const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_TYPE4); + return (impl_->getType()); +} + +std::string +PgSqlConfigBackendDHCPv4::getHost() const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_HOST4); + return (impl_->getHost()); +} + +uint16_t +PgSqlConfigBackendDHCPv4::getPort() const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_PORT4); + return (impl_->getPort()); +} + +bool +PgSqlConfigBackendDHCPv4::registerBackendType() { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_REGISTER_BACKEND_TYPE4); + return ( + dhcp::ConfigBackendDHCPv4Mgr::instance().registerBackendFactory("postgresql", + [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv4Ptr { + return (dhcp::PgSqlConfigBackendDHCPv4Ptr(new dhcp::PgSqlConfigBackendDHCPv4(params))); + }) + ); +} + +void +PgSqlConfigBackendDHCPv4::unregisterBackendType() { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_UNREGISTER_BACKEND_TYPE4); + dhcp::ConfigBackendDHCPv4Mgr::instance().unregisterBackendFactory("postgresql"); +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h new file mode 100644 index 0000000..d78698a --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h @@ -0,0 +1,631 @@ +// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PGSQL_CONFIG_BACKEND_DHCP4_H +#define PGSQL_CONFIG_BACKEND_DHCP4_H + +#include <pgsql_cb_impl.h> +#include <database/database_connection.h> +#include <dhcpsrv/client_class_def.h> +#include <dhcpsrv/config_backend_dhcp4.h> +#include <pgsql_cb_log.h> +#include <boost/shared_ptr.hpp> + +namespace isc { +namespace dhcp { + +class PgSqlConfigBackendDHCPv4Impl; + +/// @brief Implementation of the PgSql Configuration Backend for +/// Kea DHCPv4 server. +/// +/// All POSIX times specified in the methods belonging to this +/// class must be local times. +/// +/// The server selection mechanisms used by this backend generally adhere +/// to the rules described for @c ConfigBackendDHCPv4, but support for +/// some of the selectors is not implemented. Whenever this is the case, +/// the methods throw @c isc::NotImplemented exception. +class PgSqlConfigBackendDHCPv4 : public ConfigBackendDHCPv4 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit PgSqlConfigBackendDHCPv4(const db::DatabaseConnection::ParameterMap& parameters); + + /// @brief Retrieves a single subnet by subnet_prefix. + /// + /// @param server_selector Server selector. + /// @param subnet_prefix Prefix of the subnet to be retrieved. + /// @return Pointer to the retrieved subnet or NULL if not found. + virtual Subnet4Ptr + getSubnet4(const db::ServerSelector& server_selector, + const std::string& subnet_prefix) const; + + /// @brief Retrieves a single subnet by subnet identifier. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of a subnet to be retrieved. + /// @return Pointer to the retrieved subnet or NULL if not found. + virtual Subnet4Ptr + getSubnet4(const db::ServerSelector& server_selector, const SubnetID& subnet_id) const; + + /// @brief Retrieves all subnets. + /// + /// @param server_selector Server selector. + /// @return Collection of subnets or empty collection if no subnet found. + virtual Subnet4Collection + getAllSubnets4(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves subnets modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound subnet modification time. + /// @return Collection of subnets or empty collection if no subnet found. + virtual Subnet4Collection + getModifiedSubnets4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves all subnets belonging to a specified shared network. + /// + /// The server selector is currently ignored by this method. All subnets + /// for the given shared network are returned regardless of their + /// associations with the servers. + /// + /// @param server_selector Server selector (currently ignored). + /// @param shared_network_name Name of the shared network for which the + /// subnets should be retrieved. + /// @return Collection of subnets or empty collection if no subnet found. + virtual Subnet4Collection + getSharedNetworkSubnets4(const db::ServerSelector& server_selector, + const std::string& shared_network_name) const; + + /// @brief Retrieves shared network by name. + /// + /// @param server_selector Server selector. + /// @param name Name of the shared network to be retrieved. + /// @return Pointer to the shared network or NULL if not found. + /// @throw NotImplemented if server selector is "unassigned". + virtual SharedNetwork4Ptr + getSharedNetwork4(const db::ServerSelector& server_selector, + const std::string& name) const; + + /// @brief Retrieves all shared networks. + /// + /// @param server_selector Server selector. + /// @return Collection of shared network or empty collection if + /// no shared network found. + virtual SharedNetwork4Collection + getAllSharedNetworks4(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves shared networks modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound shared network modification time. + /// @return Collection of shared network or empty collection if + /// no shared network found. + virtual SharedNetwork4Collection + getModifiedSharedNetworks4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves single option definition by code and space. + /// + /// @param server_selector Server selector. + /// @param code Code of the option to be retrieved. + /// @param space Option space of the option to be retrieved. + /// @return Pointer to the option definition or NULL if not found. + /// @throw NotImplemented if server selector is "unassigned". + virtual OptionDefinitionPtr + getOptionDef4(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space) const; + + /// @brief Retrieves all option definitions. + /// + /// @param server_selector Server selector. + /// @return Collection of option definitions or empty collection if + /// no option definition found. + virtual OptionDefContainer + getAllOptionDefs4(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves option definitions modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound option definition modification + /// time. + /// @return Collection of option definitions or empty collection if + /// no option definition found. + virtual OptionDefContainer + getModifiedOptionDefs4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves single option by code and space. + /// + /// @param server_selector Server selector. + /// @return Pointer to the retrieved option descriptor or null if + /// no option was found. + /// @throw NotImplemented if server selector is "unassigned". + virtual OptionDescriptorPtr + getOption4(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space) const; + + /// @brief Retrieves all global options. + /// + /// @param server_selector Server selector. + /// @return Collection of global options or empty collection if no + /// option found. + virtual OptionContainer + getAllOptions4(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves option modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound option modification time. + /// @return Collection of global options or empty collection if no + /// option found. + virtual OptionContainer + getModifiedOptions4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves global parameter value. + /// + /// Typically, the server selector used for this query should be set to + /// ONE. It is possible to use the MULTIPLE server selector but in that + /// case only the first found parameter is returned. + /// + /// @param server_selector Server selector. + /// @param name Name of the global parameter to be retrieved. + /// @return Value of the global parameter. + /// @throw NotImplemented if server selector is "unassigned". + virtual data::StampedValuePtr + getGlobalParameter4(const db::ServerSelector& server_selector, + const std::string& name) const; + + /// @brief Retrieves all global parameters. + /// + /// Using the server selector it is possible to fetch the parameters for + /// one or more servers. The following list describes what parameters are + /// returned depending on the server selector specified: + /// - ALL: only common parameters are returned which are associated with + /// the logical server 'all'. No parameters associated with the explicit + /// server tags are returned. + /// + /// - ONE: parameters used by the particular sever are returned. This includes + /// parameters associated with the particular server (identified by tag) + /// and parameters associated with the logical server 'all' when server + /// specific parameters are not given. For example, if there is a + /// renew-timer specified for 'server1' tag, different value of the + /// renew-timer specified for 'all' servers and a rebind-timer specified + /// for 'all' servers, the caller will receive renew-timer value associated + /// with the server1 and the rebind-timer value associated with all servers, + /// because there is no explicit rebind-timer specified for server1. + /// + /// - MULTIPLE: parameters used by multiple servers, but those associated + /// with specific server tags take precedence over the values specified for + /// 'all' servers. This is similar to the case of ONE server described + /// above. The effect of querying for parameters belonging to multiple + /// servers is the same as issuing multiple queries with ONE server + /// being selected multiple times. + /// + /// - UNASSIGNED: parameters not associated with any servers. + /// + /// + /// @param server_selector Server selector. + virtual data::StampedValueCollection + getAllGlobalParameters4(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves global parameters modified after specified time. + /// + /// @param modification_time Lower bound modification time. + /// @return Collection of modified global parameters. + virtual data::StampedValueCollection + getModifiedGlobalParameters4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves a client class by name. + /// + /// @param server_selector Server selector. + /// @param name Client class name. + /// @return Pointer to the retrieved client class. + virtual ClientClassDefPtr + getClientClass4(const db::ServerSelector& selector, const std::string& name) const; + + /// @brief Retrieves all client classes. + /// + /// @param selector Server selector. + /// @return Collection of client classes. + virtual ClientClassDictionary + getAllClientClasses4(const db::ServerSelector& selector) const; + + /// @brief Retrieves client classes modified after specified time. + /// + /// @param selector Server selector. + /// @param modification_time Modification time. + /// @return Collection of client classes. + virtual ClientClassDictionary + getModifiedClientClasses4(const db::ServerSelector& selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves the most recent audit entries. + /// + /// @param selector Server selector. + /// @param modification_time Timestamp being a lower limit for the returned + /// result set, i.e. entries later than specified time are returned. + /// @param modification_id Identifier being a lower limit for the returned + /// result set, used when two (or more) entries have the same + /// modification_time. + /// @return Collection of audit entries. + virtual db::AuditEntryCollection + getRecentAuditEntries(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id) const; + + /// @brief Retrieves all servers. + /// + /// This method returns the list of servers excluding the logical server + /// 'all'. + /// + /// @return Collection of servers from the backend. + virtual db::ServerCollection + getAllServers4() const; + + /// @brief Retrieves a server. + /// + /// @param server_tag Tag of the server to be retrieved. + /// @return Pointer to the server instance or null pointer if no server + /// with the particular tag was found. + virtual db::ServerPtr + getServer4(const data::ServerTag& server_tag) const; + + /// @brief Creates or updates a subnet. + /// + /// @param server_selector Server selector. + /// @param subnet Subnet to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateSubnet4(const db::ServerSelector& server_selector, + const Subnet4Ptr& subnet); + + /// @brief Creates or updates a shared network. + /// + /// @param server_selector Server selector. + /// @param shared_network Shared network to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateSharedNetwork4(const db::ServerSelector& server_selector, + const SharedNetwork4Ptr& shared_network); + + /// @brief Creates or updates an option definition. + /// + /// @param server_selector Server selector. + /// @param option_def Option definition to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOptionDef4(const db::ServerSelector& server_selector, + const OptionDefinitionPtr& option_def); + + /// @brief Creates or updates global option. + /// + /// @param server_selector Server selector. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption4(const db::ServerSelector& server_selector, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates shared network level option. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of a shared network to which option + /// belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption4(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates subnet level option. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of a subnet to which option belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption4(const db::ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the pool to which + /// the option belongs. + /// @param pool_end_address Upper bound address of the pool to which the + /// option belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption4(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates global parameter. + /// + /// @param server_selector Server selector. + /// @param name Name of the global parameter. + /// @param value Value of the global parameter. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateGlobalParameter4(const db::ServerSelector& server_selector, + const data::StampedValuePtr& value); + + /// @brief Creates or updates DHCPv4 client class. + /// + /// @param server_selector Server selector. + /// @param client_class Client class to be added or updated. + /// @param follow_class_name name of the class after which the + /// new or updated class should be positioned. An empty value + /// causes the class to be appended at the end of the class + /// hierarchy. + virtual void + createUpdateClientClass4(const db::ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name); + + /// @brief Creates or updates a server. + /// + /// @param server Instance of the server to be stored. + /// @throw InvalidOperation when trying to create a duplicate or + /// update the logical server 'all'. + virtual void + createUpdateServer4(const db::ServerPtr& server); + + /// @brief Deletes subnet by prefix. + /// + /// @param server_selector Server selector. + /// @param subnet_prefix Prefix of the subnet to be deleted. + /// @return Number of deleted subnets. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteSubnet4(const db::ServerSelector& server_selector, + const std::string& subnet_prefix); + + /// @brief Deletes subnet by identifier. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to be deleted. + /// @return Number of deleted subnets. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteSubnet4(const db::ServerSelector& server_selector, const SubnetID& subnet_id); + + /// @brief Deletes all subnets. + /// + /// @param server_selector Server selector. + /// @return Number of deleted subnets. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteAllSubnets4(const db::ServerSelector& server_selector); + + /// @brief Deletes all subnets belonging to a specified shared network. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network for which the + /// subnets should be deleted. + /// @return Number of deleted subnets. + virtual uint64_t + deleteSharedNetworkSubnets4(const db::ServerSelector& server_selector, + const std::string& shared_network_name); + + /// @brief Deletes shared network by name. + /// + /// @param server_selector Server selector. + /// @param name Name of the shared network to be deleted. + /// @return Number of deleted shared networks. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteSharedNetwork4(const db::ServerSelector& server_selector, + const std::string& name); + + /// @brief Deletes all shared networks. + /// + /// @param server_selector Server selector. + /// @return Number of deleted shared networks. + virtual uint64_t + deleteAllSharedNetworks4(const db::ServerSelector& server_selector); + + /// @brief Deletes option definition. + /// + /// @param server_selector Server selector. + /// @param code Code of the option to be deleted. + /// @param space Option space of the option to be deleted. + /// @return Number of deleted option definitions. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOptionDef4(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space); + + /// @brief Deletes all option definitions. + /// + /// @param server_selector Server selector. + /// @return Number of deleted option definitions. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteAllOptionDefs4(const db::ServerSelector& server_selector); + + /// @brief Deletes global option. + /// + /// @param server_selector Server selector. + /// @param code Code of the option to be deleted. + /// @param space Option space of the option to be deleted. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption4(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space); + + /// @brief Deletes shared network level option. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network which deleted + /// option belongs to + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption4(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space); + + /// @brief Deletes subnet level option. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to which deleted option + /// belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption4(const db::ServerSelector& server_selector, const SubnetID& subnet_id, + const uint16_t code, const std::string& space); + + /// @brief Deletes pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the pool to which + /// deleted option belongs. + /// @param pool_end_address Upper bound address of the pool to which the + /// deleted option belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption4(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const uint16_t code, + const std::string& space); + + /// @brief Deletes global parameter. + /// + /// @param server_selector Server selector. + /// @param name Name of the global parameter to be deleted. + /// @return Number of deleted global parameters. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteGlobalParameter4(const db::ServerSelector& server_selector, + const std::string& name); + + /// @brief Deletes all global parameters. + /// + /// @param server_selector Server selector. + /// @return Number of deleted global parameters. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteAllGlobalParameters4(const db::ServerSelector& server_selector); + + /// @brief Deletes DHCPv4 client class. + /// + /// @param server_selector Server selector. + /// @param name Name of the class to be deleted. + /// @return Number of deleted client classes. + virtual uint64_t + deleteClientClass4(const db::ServerSelector& server_selector, + const std::string& name); + + /// @brief Deletes all client classes. + /// + /// @param server_selector Server selector. + /// @return Number of deleted client classes. + virtual uint64_t + deleteAllClientClasses4(const db::ServerSelector& server_selector); + + /// @brief Deletes a server from the backend. + /// + /// @param server_tag Tag of the server to be deleted. + /// @return Number of deleted servers. + /// @throw isc::InvalidOperation when trying to delete the logical + /// server 'all'. + virtual uint64_t + deleteServer4(const data::ServerTag& server_tag); + + /// @brief Deletes all servers from the backend except the logical + /// server 'all'. + /// + /// @return Number of deleted servers. + virtual uint64_t + deleteAllServers4(); + + /// @brief Returns backend type in the textual format. + /// + /// @return "postgresql". + virtual std::string getType() const; + + /// @brief Returns backend host. + /// + /// This is used by the @c BaseConfigBackendPool to select backend + /// when @c BackendSelector is specified. + /// + /// @return host on which the database is located. + virtual std::string getHost() const; + + /// @brief Returns backend port number. + /// + /// This is used by the @c BaseConfigBackendPool to select backend + /// when @c BackendSelector is specified. + /// + /// @return Port number on which database service is available. + virtual uint16_t getPort() const; + + /// @brief Registers the PgSQL backend factory with backend config manager + /// + /// This should be called by the hook lib load() function. + /// @return True if the factory was registered successfully, false otherwise. + static bool registerBackendType(); + + /// @brief Unregisters the PgSQL backend factory and discards PgSQL backends + /// + /// This should be called by the hook lib unload() function. + static void unregisterBackendType(); + + /// @brief Flag which indicates if the config backend has an unusable + /// connection. + /// + /// @return true if there is at least one unusable connection, false + /// otherwise + virtual bool isUnusable(); + + /// @brief Return backend parameters + /// + /// Returns the backend parameters + /// + /// @return Parameters of the backend. + isc::db::DatabaseConnection::ParameterMap getParameters() const; + +protected: + + /// @brief Pointer to the implementation of the @c PgSqlConfigBackendDHCPv4 + /// class. + boost::shared_ptr<PgSqlConfigBackendDHCPv4Impl> impl_; + + /// @brief Pointer to the base implementation of the backend shared by + /// DHCPv4 and DHCPv6 servers. + boost::shared_ptr<PgSqlConfigBackendImpl> base_impl_; +}; + +/// @brief Pointer to the @c PgSqlConfigBackendDHCPv4 class. +typedef boost::shared_ptr<PgSqlConfigBackendDHCPv4> PgSqlConfigBackendDHCPv4Ptr; + +} // end of namespace isc::cb +} // end of namespace isc + +#endif // PGSQL_CONFIG_BACKEND_DHCP4_H diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc new file mode 100644 index 0000000..20d5617 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc @@ -0,0 +1,5725 @@ +// Copyright (C) 2022-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <asiolink/addr_utilities.h> +#include <pgsql_cb_dhcp6.h> +#include <pgsql_cb_impl.h> +#include <pgsql_query_macros_dhcp.h> +#include <cc/data.h> +#include <config_backend/constants.h> +#include <database/database_connection.h> +#include <database/db_exceptions.h> +#include <dhcp/classify.h> +#include <dhcp/dhcp6.h> +#include <dhcp/libdhcp++.h> +#include <dhcp/option_data_types.h> +#include <dhcp/option_space.h> +#include <dhcpsrv/cfgmgr.h> +#include <dhcpsrv/config_backend_dhcp6_mgr.h> +#include <dhcpsrv/network.h> +#include <dhcpsrv/pool.h> +#include <dhcpsrv/lease.h> +#include <dhcpsrv/timer_mgr.h> +#include <dhcpsrv/parsers/client_class_def_parser.h> +#include <util/buffer.h> +#include <util/boost_time_utils.h> +#include <util/multi_threading_mgr.h> +#include <util/triplet.h> +#include <pgsql/pgsql_connection.h> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/pointer_cast.hpp> +#include <boost/scoped_ptr.hpp> + +using namespace isc::cb; +using namespace isc::db; +using namespace isc::data; +using namespace isc::asiolink; +using namespace isc::log; +using namespace isc::util; + +namespace isc { +namespace dhcp { + +/// @brief Implementation of the PostgreSQL Configuration Backend. +class PgSqlConfigBackendDHCPv6Impl : public PgSqlConfigBackendImpl { +public: + + /// @brief Statement tags. + /// + /// The contents of the enum are indexes into the list of SQL statements. + /// It is assumed that the order is such that the indices of statements + /// reading the database are less than those of statements modifying the + /// database. + enum StatementIndex { + CREATE_AUDIT_REVISION, + CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + GET_GLOBAL_PARAMETER6, + GET_ALL_GLOBAL_PARAMETERS6, + GET_MODIFIED_GLOBAL_PARAMETERS6, + GET_SUBNET6_ID_NO_TAG, + GET_SUBNET6_ID_ANY, + GET_SUBNET6_ID_UNASSIGNED, + GET_SUBNET6_PREFIX_NO_TAG, + GET_SUBNET6_PREFIX_ANY, + GET_SUBNET6_PREFIX_UNASSIGNED, + GET_ALL_SUBNETS6, + GET_ALL_SUBNETS6_UNASSIGNED, + GET_MODIFIED_SUBNETS6, + GET_MODIFIED_SUBNETS6_UNASSIGNED, + GET_SHARED_NETWORK_SUBNETS6, + GET_POOL6_RANGE, + GET_POOL6_RANGE_ANY, + GET_PD_POOL, + GET_PD_POOL_ANY, + GET_SHARED_NETWORK6_NAME_NO_TAG, + GET_SHARED_NETWORK6_NAME_ANY, + GET_SHARED_NETWORK6_NAME_UNASSIGNED, + GET_ALL_SHARED_NETWORKS6, + GET_ALL_SHARED_NETWORKS6_UNASSIGNED, + GET_MODIFIED_SHARED_NETWORKS6, + GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED, + GET_OPTION_DEF6_CODE_SPACE, + GET_ALL_OPTION_DEFS6, + GET_MODIFIED_OPTION_DEFS6, + GET_OPTION6_CODE_SPACE, + GET_ALL_OPTIONS6, + GET_MODIFIED_OPTIONS6, + GET_OPTION6_SUBNET_ID_CODE_SPACE, + GET_OPTION6_POOL_ID_CODE_SPACE, + GET_OPTION6_PD_POOL_ID_CODE_SPACE, + GET_OPTION6_SHARED_NETWORK_CODE_SPACE, + GET_CLIENT_CLASS6_NAME, + GET_ALL_CLIENT_CLASSES6, + GET_ALL_CLIENT_CLASSES6_UNASSIGNED, + GET_MODIFIED_CLIENT_CLASSES6, + GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED, + GET_AUDIT_ENTRIES6_TIME, + GET_SERVER6, + GET_ALL_SERVERS6, + INSERT_GLOBAL_PARAMETER6, + INSERT_GLOBAL_PARAMETER6_SERVER, + INSERT_SUBNET6, + INSERT_SUBNET6_SERVER, + INSERT_POOL6, + INSERT_PD_POOL, + INSERT_SHARED_NETWORK6, + INSERT_SHARED_NETWORK6_SERVER, + INSERT_OPTION_DEF6, + INSERT_OPTION_DEF6_CLIENT_CLASS, + INSERT_OPTION_DEF6_SERVER, + INSERT_OPTION6, + INSERT_OPTION6_SERVER, + INSERT_CLIENT_CLASS6, + INSERT_CLIENT_CLASS6_SERVER, + INSERT_CLIENT_CLASS6_DEPENDENCY, + INSERT_SERVER6, + UPDATE_GLOBAL_PARAMETER6, + UPDATE_SUBNET6, + UPDATE_SHARED_NETWORK6, + UPDATE_OPTION_DEF6, + UPDATE_OPTION_DEF6_CLIENT_CLASS, + UPDATE_OPTION6, + UPDATE_OPTION6_SUBNET_ID, + UPDATE_OPTION6_POOL_ID, + UPDATE_OPTION6_PD_POOL_ID, + UPDATE_OPTION6_SHARED_NETWORK, + UPDATE_OPTION6_CLIENT_CLASS, + UPDATE_CLIENT_CLASS6, + UPDATE_CLIENT_CLASS6_SAME_POSITION, + UPDATE_SERVER6, + DELETE_GLOBAL_PARAMETER6, + DELETE_ALL_GLOBAL_PARAMETERS6, + DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED, + DELETE_SUBNET6_ID_WITH_TAG, + DELETE_SUBNET6_ID_ANY, + DELETE_SUBNET6_PREFIX_WITH_TAG, + DELETE_SUBNET6_PREFIX_ANY, + DELETE_ALL_SUBNETS6, + DELETE_ALL_SUBNETS6_UNASSIGNED, + DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME, + DELETE_SUBNET6_SERVER, + DELETE_POOLS6, + DELETE_PD_POOLS, + DELETE_SHARED_NETWORK6_NAME_WITH_TAG, + DELETE_SHARED_NETWORK6_NAME_ANY, + DELETE_ALL_SHARED_NETWORKS6, + DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED, + DELETE_SHARED_NETWORK6_SERVER, + DELETE_OPTION_DEF6_CODE_NAME, + DELETE_ALL_OPTION_DEFS6, + DELETE_ALL_OPTION_DEFS6_UNASSIGNED, + DELETE_OPTION_DEFS6_CLIENT_CLASS, + DELETE_OPTION6, + DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED, + DELETE_OPTION6_SUBNET_ID, + DELETE_OPTION6_POOL_RANGE, + DELETE_OPTION6_PD_POOL, + DELETE_OPTION6_SHARED_NETWORK, + DELETE_OPTIONS6_SUBNET_ID_PREFIX, + DELETE_OPTIONS6_SHARED_NETWORK, + DELETE_OPTIONS6_CLIENT_CLASS, + DELETE_CLIENT_CLASS6_DEPENDENCY, + DELETE_CLIENT_CLASS6_SERVER, + DELETE_ALL_CLIENT_CLASSES6, + DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED, + DELETE_CLIENT_CLASS6, + DELETE_CLIENT_CLASS6_ANY, + DELETE_SERVER6, + DELETE_ALL_SERVERS6, + GET_LAST_INSERT_ID6, + NUM_STATEMENTS + }; + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit PgSqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap& + parameters); + + /// @brief Destructor. + ~PgSqlConfigBackendDHCPv6Impl(); + + /// @brief Fetches the SQL statement for a given statement index. + /// + /// @param index index of the desired statement. + /// @throw BadValue if there is no statement corresponding to + /// the index. + virtual PgSqlTaggedStatement& getStatement(size_t index) const; + + /// @brief Sends query to retrieve global parameter. + /// + /// @param server_selector Server selector. + /// @param name Name of the parameter to be retrieved. + /// + /// @return Pointer to the retrieved value or null if such parameter + /// doesn't exist. + StampedValuePtr getGlobalParameter6(const ServerSelector& server_selector, + const std::string& name) { + StampedValueCollection parameters; + + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.add(name); + + getGlobalParameters(GET_GLOBAL_PARAMETER6, in_bindings, parameters); + } + + return (parameters.empty() ? StampedValuePtr() : *parameters.begin()); + } + + /// @brief Sends query to insert or update global parameter. + /// + /// @param server_selector Server selector. + /// @param value StampedValue describing the parameter to create/update. + void createUpdateGlobalParameter6(const db::ServerSelector& server_selector, + const StampedValuePtr& value) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "creating or updating global parameter"); + + PsqlBindArray in_bindings; + in_bindings.addTempString(value->getName()); + in_bindings.addTempString(value->getValue()); + in_bindings.add(value->getType()), + in_bindings.addTimestamp(value->getModificationTime()), + in_bindings.addTempString(tag); + in_bindings.addTempString(value->getName()); + + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "global parameter set", + false); + + // Try to update the existing row. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6, + in_bindings) == 0) { + // No such parameter found, so let's insert it. We have to adjust the + // bindings collection to match the prepared statement for insert. + in_bindings.popBack(); + in_bindings.popBack(); + + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6, + in_bindings); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + PsqlBindArray attach_bindings; + uint64_t pid = getLastInsertId("dhcp6_global_parameter", "id"); + attach_bindings.add(pid); // id of newly inserted global. + attach_bindings.addTimestamp(value->getModificationTime()); + attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER, + server_selector, attach_bindings); + } + + transaction.commit(); + } + + /// @brief Sends query to the database to retrieve multiple subnets. + /// + /// Query should order subnets by subnet_id. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] subnets Reference to the container where fetched subnets + /// will be inserted. + void getSubnets6(const StatementIndex& index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + Subnet6Collection& subnets) { + uint64_t last_pool_id = 0; + uint64_t last_pd_pool_id = 0; + uint64_t last_pool_option_id = 0; + uint64_t last_pd_pool_option_id = 0; + uint64_t last_option_id = 0; + Pool6Ptr last_pool; + Pool6Ptr last_pd_pool; + std::string last_tag; + + // Execute actual query. + selectQuery(index, in_bindings, + [this, &subnets, &last_pool, &last_pd_pool, + &last_pool_id, &last_pd_pool_id, + &last_pool_option_id, &last_pd_pool_option_id, + &last_option_id, &last_tag](PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get pointer to the last subnet in the collection. + Subnet6Ptr last_subnet; + if (!subnets.empty()) { + last_subnet = *subnets.rbegin(); + } + // Subnet_id is column 0. + SubnetID subnet_id = worker.getInt(0) ; + + // Subnet has been returned. Assuming that subnets are ordered by + // subnet identifier, if the subnet identifier of the current row + // is different than the subnet identifier of the previously returned + // row, it means that we have to construct new subnet object. + if (!last_subnet || (last_subnet->getID() != subnet_id)) { + // Reset per subnet component tracking and server tag because + // we're now starting to process a new subnet. + last_pool_id = 0; + last_pd_pool_id = 0; + last_pool_option_id = 0; + last_pd_pool_option_id = 0; + last_option_id = 0; + last_pool.reset(); + last_pd_pool.reset(); + last_tag.clear(); + + // Get subnet parameters required by the constructor first. + + // subnet_prefix at 1. + std::string subnet_prefix = worker.getString(1); + auto prefix_pair = Subnet6::parsePrefix(subnet_prefix); + + // preferred_lifetime (5) + // min_preferred_lifetime (72) + // max_preferred_lifetime (73) + auto preferred_lifetime = worker.getTriplet(5, 72, 73); + + // renew_timer at 9. + auto renew_timer = worker.getTriplet(9); + + // rebind_timer at 7. + auto rebind_timer = worker.getTriplet(7); + + // valid_lifetime at 14. + // min_valid_lifetime at 74. + // max_valid_lifetime at 75. + auto valid_lifetime = worker.getTriplet(14, 74, 75); + + // Create subnet with basic settings. + last_subnet = Subnet6::create(prefix_pair.first, prefix_pair.second, + renew_timer, rebind_timer, + preferred_lifetime, + valid_lifetime, subnet_id); + + // 0 and 1 are subnet_id and subnet_prefix + + // client_class at 2. + if (!worker.isColumnNull(2)) { + last_subnet->allowClientClass(worker.getString(2)); + } + + // interface at 3. + if (!worker.isColumnNull(3)) { + last_subnet->setIface(worker.getString(3)); + } + + // modification_ts at 4. + last_subnet->setModificationTime(worker.getTimestamp(4)); + + // preferred_lifetime is 5. + + if (!worker.isColumnNull(6)) { + last_subnet->setRapidCommit(worker.getBool(6)); + } + + // rebind_timer is 7. + + // Relay addresses at 8. + setRelays(worker, 8, *last_subnet); + + // renew_timer is 9. + + // require_client_classes at 10. + setRequiredClasses(worker, 10, [&last_subnet](const std::string& class_name) { + last_subnet->requireClientClass(class_name); + }); + + // reservations_global at 11. + if (!worker.isColumnNull(11)) { + last_subnet->setReservationsGlobal(worker.getBool(11)); + } + + // shared_network_name at 12. + if (!worker.isColumnNull(12)) { + last_subnet->setSharedNetworkName(worker.getString(12)); + } + + // user_context at 13. + if (!worker.isColumnNull(13)) { + ElementPtr user_context = worker.getJSON(13); + if (user_context) { + last_subnet->setContext(user_context); + } + } + + // valid_lifetime at 14. + + // 15 to 19 are pool + // 20 to 25 are pd pool + // 26 to 39 are pool option + // 40 to 53 are pd pool option + // 54 to 67 are option + + // calculate_tee_times at 68. + if (!worker.isColumnNull(68)) { + last_subnet->setCalculateTeeTimes(worker.getBool(68)); + } + + // t1_percent at 69. + if (!worker.isColumnNull(69)) { + last_subnet->setT1Percent(worker.getDouble(69)); + } + + // t2_percent at 70. + if (!worker.isColumnNull(70)) { + last_subnet->setT2Percent(worker.getDouble(70)); + } + + // interface_id at 71. + setInterfaceId(*last_subnet, worker, 71); + + // 72 and 73 are {min,max}_preferred_lifetime + + // 74 and 75 are {min,max}_valid_lifetime + + // 76 is pool client_class + // 77 is pool require_client_classes + // 78 is pool user_context + // 79 is pd pool excluded_prefix + // 80 is pd pool excluded_prefix_length + // 81 is pd pool client_class + // 82 is pd pool require_client_classes + // 83 is pd pool user_context + + // ddns_send_updates at 84. + if (!worker.isColumnNull(84)) { + last_subnet->setDdnsSendUpdates(worker.getBool(84)); + } + + // ddns_override_no_update at 85. + if (!worker.isColumnNull(85)) { + last_subnet->setDdnsOverrideNoUpdate(worker.getBool(85)); + } + + // ddns_override_client_update at 86. + if (!worker.isColumnNull(86)) { + last_subnet->setDdnsOverrideClientUpdate(worker.getBool(86)); + } + + // ddns_replace_client_name at 87. + if (!worker.isColumnNull(87)) { + last_subnet->setDdnsReplaceClientNameMode( + static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(87))); + } + + // ddns_generated_prefix at 88. + if (!worker.isColumnNull(88)) { + last_subnet->setDdnsGeneratedPrefix(worker.getString(88)); + } + + // ddns_qualifying_suffix at 89. + if (!worker.isColumnNull(89)) { + last_subnet->setDdnsQualifyingSuffix(worker.getString(89)); + } + + // reservations_in_subnet at 90. + if (!worker.isColumnNull(90)) { + last_subnet->setReservationsInSubnet(worker.getBool(90)); + } + + // reservations_out_of_pool at 91. + if (!worker.isColumnNull(91)) { + last_subnet->setReservationsOutOfPool(worker.getBool(91)); + } + + // cache_threshold at 92. + if (!worker.isColumnNull(92)) { + last_subnet->setCacheThreshold(worker.getDouble(92)); + } + + // cache_max_age at 93. + if (!worker.isColumnNull(93)) { + last_subnet->setCacheMaxAge(worker.getInt(93)); + } + + // allocator at 94. + if (!worker.isColumnNull(94)) { + last_subnet->setAllocatorType(worker.getString(94)); + } + + // pd_allocator at 95. + if (!worker.isColumnNull(95)) { + last_subnet->setPdAllocatorType(worker.getString(95)); + } + + // server_tag at 96. + + // Subnet ready. Add it to the list. + auto ret = subnets.insert(last_subnet); + + // subnets is a multi index container with unique indexes + // but these indexes are unique too in the database, + // so this is for sanity only. + if (!ret.second) { + isc_throw(Unexpected, "add subnet failed"); + } + } + + // Check for new server tags at 96. + if (!worker.isColumnNull(96)) { + std::string new_tag = worker.getString(96); + if (last_tag != new_tag) { + if (!new_tag.empty() && !last_subnet->hasServerTag(ServerTag(new_tag))) { + last_subnet->setServerTag(new_tag); + } + + last_tag = new_tag; + } + } + + // Pool is between 15 and 19 with extra between 76 and 78 + + // If the row contains information about the pool and it + // appears to be new pool entry (checked by comparing pool + // id), let's create the new pool and add it to the + // subnet. + // pool id (15) + // pool start_address (16) + // pool end_address (17) + if (!worker.isColumnNull(15) && + (worker.getInet6(16) != 0) && + (worker.getInet6(17) != 0) && + (worker.getBigInt(15) > last_pool_id)) { + last_pool_id = worker.getBigInt(15); + last_pool = Pool6::create(Lease::TYPE_NA, + IOAddress(worker.getInet6(16)), + IOAddress(worker.getInet6(17))); + + // pool subnet_id at 18 (ignored) + // pool modification_ts at 19 (ignored) + + // pool client_class at 76. + if (!worker.isColumnNull(76)) { + last_pool->allowClientClass(worker.getString(76)); + } + + // pool require_client_classes at 77. + setRequiredClasses(worker, 77, [&last_pool](const std::string& class_name) { + last_pool->requireClientClass(class_name); + }); + + // pool user_context at 78. + if (!worker.isColumnNull(78)) { + ElementPtr user_context = worker.getJSON(78); + if (user_context) { + last_pool->setContext(user_context); + } + } + + last_subnet->addPool(last_pool); + } + + // Pd Pool is between 20 and 25 with extra between 79 and 83 + + // If the row contains information about the pd pool and + // it appears to be new pd pool entry (checked by + // comparing pd pool id), let's create the new pd pool and + // add it to the subnet. + // pd pool id (20) + // pd pool prefix (21) + // pd pool prefix_length (22) + // pd pool delegated_prefix_length (23) + if (!worker.isColumnNull(20) && + (!worker.getString(21).empty()) && + (worker.getSmallInt(22) != 0) && + (worker.getSmallInt(23) != 0) && + (worker.getBigInt(20) > last_pd_pool_id)) { + + // 24 is pd pool subnet_id (ignored) + // 25 is pd pool modification_ts (ignored) + + // excluded_prefix (79) and excluded_prefix_length (80) + IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS(); + if (!worker.isColumnNull(79)) { + excluded_prefix = worker.getInet6(79); + } + + last_pd_pool_id = worker.getBigInt(20); + last_pd_pool = Pool6::create(worker.getInet6(21), + static_cast<uint8_t>(worker.getSmallInt(22)), + static_cast<uint8_t>(worker.getSmallInt(23)), + excluded_prefix, + static_cast<uint8_t>(worker.getSmallInt(80))); + + // pd pool client_class (81) + if (!worker.isColumnNull(81)) { + last_pd_pool->allowClientClass(worker.getString(81)); + } + + // pd pool require_client_classes at 82. + setRequiredClasses(worker, 82, [&last_pd_pool](const std::string& class_name) { + last_pd_pool->requireClientClass(class_name); + }); + + // pd pool user_context at 83. + if (!worker.isColumnNull(83)) { + ElementPtr user_context = worker.getJSON(83); + if (user_context) { + last_pd_pool->setContext(user_context); + } + } + + last_subnet->addPool(last_pd_pool); + } + + // Parse pool-specific option from 26 to 39. + if (last_pool && !worker.isColumnNull(26) && + (last_pool_option_id < worker.getBigInt(26))) { + last_pool_option_id = worker.getBigInt(26); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 26); + if (desc) { + last_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + + // Parse pd pool-specific option from 40 to 53. + if (last_pd_pool && !worker.isColumnNull(40) && + (last_pd_pool_option_id < worker.getBigInt(40))) { + last_pd_pool_option_id = worker.getBigInt(40); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 40); + if (desc) { + last_pd_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + + // Parse subnet-specific option from 54 to 67. + if (!worker.isColumnNull(54) && + (last_option_id < worker.getBigInt(54))) { + last_option_id = worker.getBigInt(54); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 54); + if (desc) { + last_subnet->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + + // Now that we're done fetching the whole subnet, we have to + // check if it has matching server tags and toss it if it + // doesn't. We skip matching the server tags if we're asking + // for ANY subnet. + auto& subnet_index = subnets.get<SubnetSubnetIdIndexTag>(); + tossNonMatchingElements(server_selector, subnet_index); + } + + /// @brief Sends query to retrieve single subnet by id. + /// + /// @param server_selector Server selector. + /// @param subnet_id Subnet identifier. + /// + /// @return Pointer to the returned subnet or NULL if such subnet + /// doesn't exist. + Subnet6Ptr getSubnet6(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + if (server_selector.hasMultipleTags()) { + isc_throw(InvalidOperation, "expected one server tag to be specified" + " while fetching a subnet. Got: " + << getServerTagsAsText(server_selector)); + } + + PsqlBindArray in_bindings; + in_bindings.add(subnet_id); + + auto index = GET_SUBNET6_ID_NO_TAG; + if (server_selector.amUnassigned()) { + index = GET_SUBNET6_ID_UNASSIGNED; + } else if (server_selector.amAny()) { + index = GET_SUBNET6_ID_ANY; + } + + Subnet6Collection subnets; + getSubnets6(index, server_selector, in_bindings, subnets); + + return (subnets.empty() ? Subnet6Ptr() : *subnets.begin()); + } + + /// @brief Sends query to retrieve single subnet by prefix. + /// + /// The prefix should be in the following format: "2001:db8:1::/64". + /// + /// @param server_selector Server selector. + /// @param subnet_id Subnet identifier. + /// + /// @return Pointer to the returned subnet or NULL if such subnet + /// doesn't exist. + Subnet6Ptr getSubnet6(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + if (server_selector.hasMultipleTags()) { + isc_throw(InvalidOperation, "expected one server tag to be specified" + " while fetching a subnet. Got: " + << getServerTagsAsText(server_selector)); + } + + PsqlBindArray in_bindings; + in_bindings.add(subnet_prefix); + + auto index = GET_SUBNET6_PREFIX_NO_TAG; + if (server_selector.amUnassigned()) { + index = GET_SUBNET6_PREFIX_UNASSIGNED; + } else if (server_selector.amAny()) { + index = GET_SUBNET6_PREFIX_ANY; + } + + Subnet6Collection subnets; + getSubnets6(index, server_selector, in_bindings, subnets); + + return (subnets.empty() ? Subnet6Ptr() : *subnets.begin()); + } + + /// @brief Sends query to retrieve all subnets. + /// + /// @param server_selector Server selector. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getAllSubnets6(const ServerSelector& server_selector, + Subnet6Collection& subnets) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching all subnets for ANY " + "server is not supported"); + } + + auto index = (server_selector.amUnassigned() ? GET_ALL_SUBNETS6_UNASSIGNED : + GET_ALL_SUBNETS6); + PsqlBindArray in_bindings; + getSubnets6(index, server_selector, in_bindings, subnets); + } + + /// @brief Sends query to retrieve modified subnets. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getModifiedSubnets6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + Subnet6Collection& subnets) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching modified subnets for ANY " + "server is not supported"); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(modification_ts); + + auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SUBNETS6_UNASSIGNED : + GET_MODIFIED_SUBNETS6); + getSubnets6(index, server_selector, in_bindings, subnets); + } + + /// @brief Sends query to retrieve all subnets belonging to a shared network. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network for which the + /// subnets should be retrieved. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getSharedNetworkSubnets6(const ServerSelector& server_selector, + const std::string& shared_network_name, + Subnet6Collection& subnets) { + PsqlBindArray in_bindings; + in_bindings.add(shared_network_name); + getSubnets6(GET_SHARED_NETWORK_SUBNETS6, server_selector, in_bindings, subnets); + } + + /// @brief Sends query to retrieve multiple pools. + /// + /// Query should order pools by id. + /// + /// @param index Index of the query to be used. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] pools Reference to the container where fetched pools + /// will be inserted. + /// @param [out] pool_ids Identifiers of the pools returned in @c pools + /// argument. + void getPools(const StatementIndex& index, + const PsqlBindArray& in_bindings, + PoolCollection& pools, + std::vector<uint64_t>& pool_ids) { + uint64_t last_pool_id = 0; + uint64_t last_pool_option_id = 0; + Pool6Ptr last_pool; + + selectQuery(index, in_bindings, + [this, &last_pool_id, &last_pool_option_id, &last_pool, &pools, &pool_ids] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Pool id is column 0. + auto id = worker.getBigInt(0) ; + if (id > last_pool_id) { + // pool start_address (1) + // pool end_address (2) + last_pool_id = id; + + last_pool = Pool6::create(Lease::TYPE_NA, worker.getInet6(1), worker.getInet6(2)); + + // pool subnet_id (3) (ignored) + + // pool client_class (4) + if (!worker.isColumnNull(4)) { + last_pool->allowClientClass(worker.getString(4)); + } + + // pool require_client_classes (5) + setRequiredClasses(worker, 5, [&last_pool](const std::string& class_name) { + last_pool->requireClientClass(class_name); + }); + + // pool user_context (6) + if (!worker.isColumnNull(6)) { + ElementPtr user_context = worker.getJSON(6); + if (user_context) { + last_pool->setContext(user_context); + } + } + + // pool: modification_ts (7) (ignored) + + pools.push_back(last_pool); + pool_ids.push_back(last_pool_id); + } + + // Parse pool specific option (8). + if (last_pool && !worker.isColumnNull(8) && + (last_pool_option_id < worker.getBigInt(8))) { + last_pool_option_id = worker.getBigInt(8); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 8); + if (desc) { + last_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + } + + /// @brief Sends query to retrieve multiple pd pools. + /// + /// Query should order pd pools by id. + /// + /// @param index Index of the query to be used. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] pd_pools Reference to the container where fetched pools + /// will be inserted. + /// @param [out] pd_pool_ids Identifiers of the pd pools returned in + /// @c pd_pools argument. + void getPdPools(const StatementIndex& index, + const PsqlBindArray& in_bindings, + PoolCollection& pd_pools, + std::vector<uint64_t>& pd_pool_ids) { + uint64_t last_pd_pool_id = 0; + uint64_t last_pd_pool_option_id = 0; + Pool6Ptr last_pd_pool; + + selectQuery(index, in_bindings, + [this, &last_pd_pool_id, &last_pd_pool_option_id, + &last_pd_pool, &pd_pools, &pd_pool_ids] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Pool id is column 0. + auto id = worker.getBigInt(0) ; + if (id > last_pd_pool_id) { + last_pd_pool_id = id; + + // pd pool prefix (1) + // pd pool prefix_length (2) + // pd pool delegated_prefix_length (3) + + // excluded_prefix (5) and excluded_prefix_length (6) + IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS(); + if (!worker.isColumnNull(5)) { + excluded_prefix = worker.getInet6(5); + } + + last_pd_pool = Pool6::create(worker.getInet6(1), + static_cast<uint8_t>(worker.getSmallInt(2)), + static_cast<uint8_t>(worker.getSmallInt(3)), + excluded_prefix, + static_cast<uint8_t>(worker.getSmallInt(6))); + + // pd pool subnet_id (4) (ignored) + + // pool client_class (7) + if (!worker.isColumnNull(7)) { + last_pd_pool->allowClientClass(worker.getString(7)); + } + + // pool require_client_classes (8) + setRequiredClasses(worker, 8, [&last_pd_pool](const std::string& class_name) { + last_pd_pool->requireClientClass(class_name); + }); + + // pd pool user_context (9) + if (!worker.isColumnNull(9)) { + ElementPtr user_context = worker.getJSON(9); + if (user_context) { + last_pd_pool->setContext(user_context); + } + } + + // pd pool modification_ts (10) (ignored) + + pd_pools.push_back(last_pd_pool); + pd_pool_ids.push_back(last_pd_pool_id); + } + + // Parse pd pool specific option between 11 and 25. + if (last_pd_pool && !worker.isColumnNull(11) && + (last_pd_pool_option_id < worker.getBigInt(11))) { + last_pd_pool_option_id = worker.getBigInt(11); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 11); + if (desc) { + last_pd_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + } + + /// @brief Sends query to retrieve single pool by address range. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound pool address. + /// @param pool_end_address Upper bound pool address. + /// @param pool_id Pool identifier for the returned pool. + /// @return Pointer to the pool or null if no such pool found. + Pool6Ptr getPool6(const ServerSelector& server_selector, + const IOAddress& pool_start_address, + const IOAddress& pool_end_address, + uint64_t& pool_id) { + PoolCollection pools; + std::vector<uint64_t> pool_ids; + + if (server_selector.amAny()) { + PsqlBindArray in_bindings; + in_bindings.addInet6(pool_start_address); + in_bindings.addInet6(pool_end_address); + getPools(GET_POOL6_RANGE_ANY, in_bindings, pools, pool_ids); + } else { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addInet6(pool_start_address); + in_bindings.addInet6(pool_end_address); + + getPools(GET_POOL6_RANGE, in_bindings, pools, pool_ids); + // Break if something is found? + } + } + + // Return upon the first pool found. + if (!pools.empty()) { + pool_id = pool_ids[0]; + return (boost::dynamic_pointer_cast<Pool6>(*pools.begin())); + } + + pool_id = 0; + + return (Pool6Ptr()); + } + + /// @brief Sends query to retrieve single pd pool. + /// + /// @param server_selector Server selector. + /// @param pd_pool_prefix Address part of the pd pool prefix. + /// @param pd_pool_prefix_length Length of the pd pool prefix. + /// @param pd_pool_id Pool identifier for the returned pool. + /// @return Pointer to the pool or null if no such pool found. + Pool6Ptr getPdPool6(const ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + uint64_t& pd_pool_id) { + PoolCollection pd_pools; + std::vector<uint64_t> pd_pool_ids; + + if (server_selector.amAny()) { + PsqlBindArray in_bindings; + in_bindings.addTempString(pd_pool_prefix.toText()); + in_bindings.add(pd_pool_prefix_length); + getPdPools(GET_PD_POOL_ANY, in_bindings, pd_pools, pd_pool_ids); + } else { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addTempString(pd_pool_prefix.toText()); + in_bindings.add(pd_pool_prefix_length); + getPdPools(GET_PD_POOL, in_bindings, pd_pools, pd_pool_ids); + } + } + + if (!pd_pools.empty()) { + pd_pool_id = pd_pool_ids[0]; + return (boost::dynamic_pointer_cast<Pool6>(*pd_pools.begin())); + } + + pd_pool_id = 0; + + return (Pool6Ptr()); + } + + /// @brief Sends query to insert or update subnet. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the subnet to be inserted or updated. + void createUpdateSubnet6(const ServerSelector& server_selector, + const Subnet6Ptr& subnet) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "creating or updating a subnet for ANY" + " server is not supported"); + + } else if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + in_bindings.addOptional(subnet->getClientClass(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getIface(Network::Inheritance::NONE)); + in_bindings.addTimestamp(subnet->getModificationTime()); + in_bindings.add(subnet->getPreferred(Network::Inheritance::NONE)); + in_bindings.addMin(subnet->getPreferred(Network::Inheritance::NONE)); + in_bindings.addMax(subnet->getPreferred(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getRapidCommit(Network::Inheritance::NONE)); + in_bindings.add(subnet->getT2(Network::Inheritance::NONE)); + addRelayBinding(in_bindings, subnet); + in_bindings.add(subnet->getT1(Network::Inheritance::NONE)); + addRequiredClassesBinding(in_bindings, subnet); + in_bindings.addOptional(subnet->getReservationsGlobal(Network::Inheritance::NONE)); + + // Add shared network. + SharedNetwork6Ptr shared_network; + subnet->getSharedNetwork(shared_network); + + // Check if the subnet is associated with a shared network instance. + // If it is, create the binding using the name of the shared network. + if (shared_network) { + in_bindings.addTempString(shared_network->getName()); + + // If the subnet is associated with a shared network by name (no + // shared network instance), use this name to create the binding. + // This may be the case if the subnet is added as a result of + // receiving a control command that merely specifies shared + // network name. In that case, it is expected that the shared + // network data is already stored in the database. + } else if (!subnet->getSharedNetworkName().empty()) { + in_bindings.addTempString(subnet->getSharedNetworkName()); + + // If the subnet is not associated with a shared network, create + // null binding. + } else { + in_bindings.addNull(); + } + + in_bindings.add(subnet->getContext()); + in_bindings.add(subnet->getValid(Network::Inheritance::NONE)); + in_bindings.addMin(subnet->getValid(Network::Inheritance::NONE)); + in_bindings.addMax(subnet->getValid(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getCalculateTeeTimes(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getT1Percent(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getT2Percent(Network::Inheritance::NONE)); + addInterfaceIdBinding(in_bindings, *subnet); + in_bindings.addOptional(subnet->getDdnsSendUpdates(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)); + addDdnsReplaceClientNameBinding(in_bindings, subnet); + in_bindings.addOptional(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getReservationsInSubnet(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getReservationsOutOfPool(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getCacheThreshold(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getCacheMaxAge(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getAllocatorType(Network::Inheritance::NONE)); + in_bindings.addOptional(subnet->getPdAllocatorType(Network::Inheritance::NONE)); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateSubnet6"); + + try { + + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6, in_bindings); + + } catch (const DuplicateEntry&) { + // It already exists, rollback to the savepoint to preserve + // any prior work. + conn_.rollbackToSavepoint("createUpdateSubnet6"); + + // We're updating, so we need to remove any existing pools and options. + deletePools6(subnet); + deletePdPools6(subnet); + deleteOptions6(ServerSelector::ANY(), subnet); + + // Now we need to add two more bindings for WHERE clause. + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Attempt the update. + auto cnt = updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6, + in_bindings); + if (!cnt) { + // Possible only if someone deleted it since we tried to insert it + // or the query is broken. + isc_throw(Unexpected, "Update subnet failed to find subnet id: " + << subnet->getID() << ", prefix: " << subnet->toText()); + } + + // Remove existing server association. + PsqlBindArray server_bindings; + server_bindings.add(subnet->getID()); + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER, + server_bindings); + } + + // Subnet was successfully created/updated. + + // Insert associations with the servers. + PsqlBindArray attach_bindings; + attach_bindings.add(subnet->getID()); + attach_bindings.addTimestamp(subnet->getModificationTime()); + attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER, + server_selector, attach_bindings); + + // (Re)create pools. + for (auto pool : subnet->getPools(Lease::TYPE_NA)) { + createPool6(server_selector, boost::dynamic_pointer_cast<Pool6>(pool), + subnet); + } + + // (Re)create pd pools. + for (auto pd_pool : subnet->getPools(Lease::TYPE_PD)) { + createPdPool6(server_selector, boost::dynamic_pointer_cast<Pool6>(pd_pool), + subnet); + } + + // (Re)create options. + auto option_spaces = subnet->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = subnet->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption6(server_selector, subnet->getID(), desc_copy, + true); + } + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Inserts new IPv6 pool to the database. + /// + /// @param server_selector Server selector. + /// @param pool Pointer to the pool to be inserted. + /// @param subnet Pointer to the subnet that this pool belongs to. + void createPool6(const ServerSelector& server_selector, + const Pool6Ptr& pool, + const Subnet6Ptr& subnet) { + // Create the input bindings. + PsqlBindArray in_bindings; + in_bindings.addInet6(pool->getFirstAddress()); + in_bindings.addInet6(pool->getLastAddress()); + in_bindings.add(subnet->getID()); + in_bindings.addOptional(pool->getClientClass()); + addRequiredClassesBinding(in_bindings, pool); + in_bindings.add(pool->getContext()); + in_bindings.addTimestamp(subnet->getModificationTime()); + + // Attempt to INSERT the pool. + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_POOL6, in_bindings); + + // Get the id of the newly inserted pool. + uint64_t pool_id = getLastInsertId("dhcp6_pool", "id"); + + // Add the pool's options. + auto option_spaces = pool->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = pool->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption6(server_selector, Lease::TYPE_NA, + pool_id, desc_copy, true); + } + } + } + + /// @brief Inserts new IPv6 pd pool to the database. + /// + /// @param server_selector Server selector. + /// @param pd_pool Pointer to the pd pool to be inserted. + /// @param subnet Pointer to the subnet that this pd pool belongs to. + void createPdPool6(const ServerSelector& server_selector, + const Pool6Ptr& pd_pool, + const Subnet6Ptr& subnet) { + int plen = prefixLengthFromRange(pd_pool->getFirstAddress(), + pd_pool->getLastAddress()); + + // Extract excluded prefix components. + Optional<std::string> xprefix_txt; + uint8_t xlen = 0; + const Option6PDExcludePtr& xopt = pd_pool->getPrefixExcludeOption(); + if (xopt) { + const IOAddress& prefix = pd_pool->getFirstAddress(); + const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, pd_pool->getLength()); + xprefix_txt = xprefix.toText(); + xlen = xopt->getExcludedPrefixLength(); + } + + // Create the input bindings. + PsqlBindArray in_bindings; + in_bindings.addInet6(pd_pool->getFirstAddress()); + in_bindings.add(plen); + in_bindings.add(pd_pool->getLength()); + in_bindings.add(subnet->getID()); + in_bindings.addOptional(xprefix_txt); + in_bindings.add(xlen); + in_bindings.addOptional(pd_pool->getClientClass()); + addRequiredClassesBinding(in_bindings, pd_pool); + in_bindings.add(pd_pool->getContext()); + in_bindings.addTimestamp(subnet->getModificationTime()); + + // Attempt to INSERT the pool. + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_PD_POOL, in_bindings); + + // Get the id of the newly inserted pool. + uint64_t pd_pool_id = getLastInsertId("dhcp6_pd_pool", "id"); + + // Add the pool's options. + auto option_spaces = pd_pool->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = pd_pool->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption6(server_selector, Lease::TYPE_PD, + pd_pool_id, desc_copy, true); + } + } + } + + /// @brief Sends a query to delete data from a table. + /// + /// If creates a new audit revision for this change if such audit + /// revision doesn't exist yet (using ScopedAuditRevision mechanism). + /// + /// @tparam Args type of the arguments to be passed to one of the existing + /// @c deleteFromTable methods. + /// @param server_selector server selector. + /// @param operation operation which results in calling this function. This is + /// used for logging purposes. + /// @param log_message log message to be associated with the audit revision. + /// @param cascade_delete boolean flag indicating if we're performing + /// cascade delete. If set to true, the audit entries for the child + /// objects (e.g. DHCPoptions) won't be created. + /// @param keys arguments to be passed to one of the existing + /// @c deleteFromTable methods. + /// + /// @return Number of deleted entries. + template<typename... Args> + uint64_t deleteTransactional(const int index, + const db::ServerSelector& server_selector, + const std::string& operation, + const std::string& log_message, + const bool cascade_delete, + Args&&... keys) { + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, log_message, cascade_delete); + + auto count = deleteFromTable(index, server_selector, operation, keys...); + + transaction.commit(); + + return (count); + } + + /// @brief Sends query to delete subnet by id. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to be deleted. + /// @return Number of deleted subnets. + uint64_t deleteSubnet6(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + int index = (server_selector.amAny() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY : + PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG); + return (deleteTransactional(index, server_selector, + "deleting a subnet", "subnet deleted", + true, static_cast<uint32_t>(subnet_id))); + } + + /// @brief Sends query to delete subnet by id. + /// + /// @param server_selector Server selector. + /// @param subnet_prefix Prefix of the subnet to be deleted. + /// @return Number of deleted subnets. + uint64_t deleteSubnet6(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + int index = (server_selector.amAny() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY : + PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG); + return (deleteTransactional(index, server_selector, + "deleting a subnet", "subnet deleted", + true, subnet_prefix)); + } + + /// @brief Deletes pools belonging to a subnet from the database. + /// + /// The query deletes all pools associated with the subnet's + /// identifier or prefix. + /// @param subnet Pointer to the subnet for which pools should be + /// deleted. + uint64_t deletePools6(const Subnet6Ptr& subnet) { + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Run DELETE. + return (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_POOLS6, + in_bindings)); + } + + /// @brief Deletes prefix delegation pools belonging to a subnet from + /// the database. + /// + /// The query deletes all pd pools associated with the subnet's + /// identifier or prefix. + /// @param subnet Pointer to the subnet for which pd pools should be + /// deleted. + uint64_t deletePdPools6(const Subnet6Ptr& subnet) { + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Run DELETE. + return (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_PD_POOLS, + in_bindings)); + } + + /// @brief Sends query to the database to retrieve multiple shared + /// networks. + /// + /// Query should order shared networks by id. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] shared_networks Reference to the container where fetched + /// shared networks will be inserted. + void getSharedNetworks6(const StatementIndex& index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + SharedNetwork6Collection& shared_networks) { + uint64_t last_network_id = 0; + uint64_t last_option_id = 0; + std::string last_tag; + + selectQuery(index, in_bindings, + [this, &shared_networks, &last_network_id, &last_option_id, &last_tag] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + SharedNetwork6Ptr last_network; + if (!shared_networks.empty()) { + last_network = *shared_networks.rbegin(); + } + + // Network id is column 0. + auto network_id = worker.getBigInt(0) ; + + // If this is the first shared network or the shared network id in this + // row points to the next shared network we use the data in the + // row to create the new shared network instance. + if (last_network_id != network_id) { + last_network_id = network_id; + + // Reset per shared network component tracking and server tag because + // we're now starting to process a new shared network. + last_option_id = 0; + last_tag.clear(); + + // name at 1. + last_network = SharedNetwork6::create(worker.getString(1)); + last_network->setId(last_network_id); + + // client_class at 2. + if (!worker.isColumnNull(2)) { + last_network->allowClientClass(worker.getString(2)); + } + + // interface at 3. + if (!worker.isColumnNull(3)) { + last_network->setIface(worker.getString(3)); + } + + // modification_ts at 4. + last_network->setModificationTime(worker.getTimestamp(4)); + + // preferred_lifetime (5) + // min_preferred_lifetime (32) + // max_preferred_lifetime (33) + last_network->setPreferred(worker.getTriplet(5, 32, 33)); + + // rapid_commit at 6. + if (!worker.isColumnNull(6)) { + last_network->setRapidCommit(worker.getBool(6)); + } + + // rebind_timer at 7. + if (!worker.isColumnNull(7)) { + last_network->setT2(worker.getTriplet(7)); + } + + // Relay addresses at 8. + setRelays(worker, 8, *last_network); + + // renew_timer at 9. + if (!worker.isColumnNull(9)) { + last_network->setT1(worker.getTriplet(9)); + } + + // require_client_classes at 10. + setRequiredClasses(worker, 10, [&last_network](const std::string& class_name) { + last_network->requireClientClass(class_name); + }); + + // reservations_global at 11. + if (!worker.isColumnNull(11)) { + last_network->setReservationsGlobal(worker.getBool(11)); + } + + // user_context at 12. + if (!worker.isColumnNull(12)) { + ElementPtr user_context = worker.getJSON(12); + if (user_context) { + last_network->setContext(user_context); + } + } + + // valid_lifetime at 13. + // min_valid_lifetime at 34. + // max_valid_lifetime at 35. + if (!worker.isColumnNull(13)) { + last_network->setValid(worker.getTriplet(13, 34, 35)); + } + + // option from 14 to 27. + + // calculate_tee_times at 28. + if (!worker.isColumnNull(28)) { + last_network->setCalculateTeeTimes(worker.getBool(28)); + } + + // t1_percent at 29. + if (!worker.isColumnNull(29)) { + last_network->setT1Percent(worker.getDouble(29)); + } + + // t2_percent at 30. + if (!worker.isColumnNull(30)) { + last_network->setT2Percent(worker.getDouble(30)); + } + + // interface_id at 31. + setInterfaceId(*last_network, worker, 31); + + // min_preferred_lifetime at 32. + // max_preferred_lifetime at 33. + // min_valid_lifetime at 34. + // max_valid_lifetime at 35. + + // ddns_send_updates at 36. + if (!worker.isColumnNull(36)) { + last_network->setDdnsSendUpdates(worker.getBool(36)); + } + + // ddns_override_no_update at 37. + if (!worker.isColumnNull(37)) { + last_network->setDdnsOverrideNoUpdate(worker.getBool(37)); + } + + // ddns_override_client_update at 38. + if (!worker.isColumnNull(38)) { + last_network->setDdnsOverrideClientUpdate(worker.getBool(38)); + } + + // ddns_replace_client_name at 39. + if (!worker.isColumnNull(39)) { + last_network->setDdnsReplaceClientNameMode( + static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(39))); + } + + // ddns_generated_prefix at 40. + if (!worker.isColumnNull(40)) { + last_network->setDdnsGeneratedPrefix(worker.getString(40)); + } + + // ddns_qualifying_suffix at 41. + if (!worker.isColumnNull(41)) { + last_network->setDdnsQualifyingSuffix(worker.getString(41)); + } + + // reservations_in_subnet at 42. + if (!worker.isColumnNull(42)) { + last_network->setReservationsInSubnet(worker.getBool(42)); + } + + // reservations_in_subnet at 43. + if (!worker.isColumnNull(43)) { + last_network->setReservationsOutOfPool(worker.getBool(43)); + } + + // cache_threshold at 44. + if (!worker.isColumnNull(44)) { + last_network->setCacheThreshold(worker.getDouble(44)); + } + + // cache_max_age at 45. + if (!worker.isColumnNull(45)) { + last_network->setCacheMaxAge(worker.getInt(45)); + } + + // allocator at 46. + if (!worker.isColumnNull(46)) { + last_network->setAllocatorType(worker.getString(46)); + } + + // pd_allocator at 47. + if (!worker.isColumnNull(47)) { + last_network->setPdAllocatorType(worker.getString(47)); + } + + // server_tag at 48. + + // Add the shared network. + auto ret = shared_networks.push_back(last_network); + + // shared_networks is a multi index container with an unique + // index but this index is unique too in the database, + // so this is for sanity only. + if (!ret.second) { + isc_throw(Unexpected, "add shared network failed"); + } + } + + // Check for new server tags. + if (!worker.isColumnNull(48)) { + std::string new_tag = worker.getString(48); + if (last_tag != new_tag) { + if (!new_tag.empty() && !last_network->hasServerTag(ServerTag(new_tag))) { + last_network->setServerTag(new_tag); + } + + last_tag = new_tag; + } + } + + // Parse network-specific option from 14 to 27. + if (!worker.isColumnNull(14) && + (last_option_id < worker.getBigInt(14))) { + last_option_id = worker.getBigInt(14); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 14); + if (desc) { + last_network->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + + // Now that we're done fetching the whole network, we have to + // check if it has matching server tags and toss it if it + // doesn't. We skip matching the server tags if we're asking + // for ANY shared network. + auto& sn_index = shared_networks.get<SharedNetworkRandomAccessIndexTag>(); + tossNonMatchingElements(server_selector, sn_index); + } + + /// @brief Sends query to retrieve single shared network by name. + /// + /// @param server_selector Server selector. + /// @param name Shared network name. + /// + /// @return Pointer to the returned shared network or NULL if such shared + /// network doesn't exist. + SharedNetwork6Ptr getSharedNetwork6(const ServerSelector& server_selector, + const std::string& name) { + if (server_selector.hasMultipleTags()) { + isc_throw(InvalidOperation, "expected one server tag to be specified" + " while fetching a shared network. Got: " + << getServerTagsAsText(server_selector)); + } + + PsqlBindArray in_bindings; + in_bindings.add(name); + + auto index = PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG; + if (server_selector.amUnassigned()) { + index = PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED; + } else if (server_selector.amAny()) { + index = PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY; + } + + SharedNetwork6Collection shared_networks; + getSharedNetworks6(index, server_selector, in_bindings, shared_networks); + + return (shared_networks.empty() ? SharedNetwork6Ptr() : *shared_networks.begin()); + } + + /// @brief Sends query to retrieve all shared networks. + /// + /// @param server_selector Server selector. + /// @param [out] shared_networks Reference to the shared networks collection + /// structure where shared networks should be inserted. + void getAllSharedNetworks6(const ServerSelector& server_selector, + SharedNetwork6Collection& shared_networks) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching all shared networks for ANY " + "server is not supported"); + } + + auto index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6); + + PsqlBindArray in_bindings; + getSharedNetworks6(index, server_selector, in_bindings, shared_networks); + } + + /// @brief Sends query to retrieve modified shared networks. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] shared_networks Reference to the shared networks collection + /// structure where shared networks should be inserted. + void getModifiedSharedNetworks6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + SharedNetwork6Collection& shared_networks) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching modified shared networks for ANY " + "server is not supported"); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(modification_ts); + + auto index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6); + getSharedNetworks6(index, server_selector, in_bindings, shared_networks); + } + + /// @brief Sends query to insert or update shared network. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the shared network to be inserted or updated. + void createUpdateSharedNetwork6(const ServerSelector& server_selector, + const SharedNetwork6Ptr& shared_network) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "creating or updating a shared network for ANY" + " server is not supported"); + + } else if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + PsqlBindArray in_bindings; + in_bindings.addTempString(shared_network->getName()); + in_bindings.addOptional(shared_network->getClientClass(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getIface(Network::Inheritance::NONE)); + in_bindings.addTimestamp(shared_network->getModificationTime()); + in_bindings.add(shared_network->getPreferred(Network::Inheritance::NONE)); + in_bindings.addMin(shared_network->getPreferred(Network::Inheritance::NONE)); + in_bindings.addMax(shared_network->getPreferred(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getRapidCommit(Network::Inheritance::NONE)); + in_bindings.add(shared_network->getT2(Network::Inheritance::NONE)); + addRelayBinding(in_bindings, shared_network); + in_bindings.add(shared_network->getT1(Network::Inheritance::NONE)); + addRequiredClassesBinding(in_bindings, shared_network); + in_bindings.addOptional(shared_network->getReservationsGlobal(Network::Inheritance::NONE)); + in_bindings.add(shared_network->getContext()); + in_bindings.add(shared_network->getValid(Network::Inheritance::NONE)); + in_bindings.addMin(shared_network->getValid(Network::Inheritance::NONE)); + in_bindings.addMax(shared_network->getValid(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getT1Percent(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getT2Percent(Network::Inheritance::NONE)); + addInterfaceIdBinding(in_bindings, *shared_network); + in_bindings.addOptional(shared_network->getDdnsSendUpdates(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)); + addDdnsReplaceClientNameBinding(in_bindings, shared_network); + in_bindings.addOptional(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getReservationsInSubnet(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getCacheThreshold(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getCacheMaxAge(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getAllocatorType(Network::Inheritance::NONE)); + in_bindings.addOptional(shared_network->getPdAllocatorType(Network::Inheritance::NONE)); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateSharedNetwork6"); + + try { + + // Try to insert shared network. The shared network name must be unique, + // so if inserting fails with DuplicateEntry exception we'll need to + // update existing shared network entry. + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6, + in_bindings); + + } catch (const DuplicateEntry&) { + // It already exists, rollback to the savepoint to preserve + // any prior work. + conn_.rollbackToSavepoint("createUpdateSharedNetwork6"); + + // We're updating, so we need to remove any options. + deleteOptions6(ServerSelector::ANY(), shared_network); + + // Need to add one more binding for WHERE clause. + in_bindings.addTempString(shared_network->getName()); + + // Try the update. + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6, + in_bindings); + + // Remove existing server association. + PsqlBindArray server_bindings; + server_bindings.addTempString(shared_network->getName()); + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER, + server_bindings); + } + + // Associate the shared network with the servers. + PsqlBindArray attach_bindings; + attach_bindings.addTempString(shared_network->getName()); + attach_bindings.addTimestamp(shared_network->getModificationTime()); + attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER, + server_selector, attach_bindings); + + // (Re)create options. + auto option_spaces = shared_network->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = shared_network->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption6(server_selector, shared_network->getName(), + desc_copy, true); + } + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert DHCP option. + /// + /// This method expects that the server selector contains exactly one + /// server tag. It is intended to be used within a transaction. + /// + /// @param server_selector Server selector. + /// @param in_bindings Collection of bindings representing an option. + /// @param modification_ts option's modification timestamp + void insertOption6(const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + const boost::posix_time::ptime& modification_ts) { + // Attempt the insert. + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6, in_bindings); + + // Fetch primary key value of the inserted option. We will use it in the + // next INSERT statement to associate this option with the server. + auto option_id = getLastInsertId("dhcp6_options", "option_id"); + + PsqlBindArray attach_bindings; + attach_bindings.add(option_id); // id of newly inserted global. + attach_bindings.addTimestamp(modification_ts); + + // Associate the option with the servers. + attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER, + server_selector, attach_bindings); + } + + /// @brief Sends query to insert or update global DHCP option. + /// + /// @param server_selector Server selector. + /// @param option Pointer to the option descriptor encapsulating the option. + void createUpdateOption6(const ServerSelector& server_selector, + const OptionDescriptorPtr& option) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "creating or updating global option"); + + // Create the input parameter bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.add(0); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + in_bindings.addNull(); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(tag); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "global option set", false); + + // Try to update the option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption6(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a subnet. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet the option belongs to. + /// @param option Pointer to the option descriptor encapsulating the option. + /// @param cascade_update Boolean value indicating whether the update is + /// performed as part of the owning element, e.g. subnet. + void createUpdateOption6(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option, + const bool cascade_update) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.add(subnet_id); + in_bindings.add(1); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + in_bindings.addNull(); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(subnet_id); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet specific option set", + cascade_update); + + // Try to update the subnet option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption6(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a pool. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the pool. + /// @param pool_end_address Upper bound address of the pool. + /// @param option Pointer to the option descriptor encapsulating the option. + void createUpdateOption6(const ServerSelector& server_selector, + const IOAddress& pool_start_address, + const IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + uint64_t pool_id = 0; + Pool6Ptr pool = getPool6(server_selector, pool_start_address, pool_end_address, + pool_id); + if (!pool) { + isc_throw(BadValue, "no pool found for range of " + << pool_start_address << " : " + << pool_end_address); + } + + createUpdateOption6(server_selector, Lease::TYPE_NA, + pool_id, option, false); + } + + /// @brief Sends query to insert or update DHCP option in a pd pool. + /// + /// @param server_selector Server selector. + /// @param pd_pool_prefix Address part of the pd pool prefix. + /// @param pd_pool_prefix_length Length of the pd pool prefix. + /// @param option Pointer to the option descriptor encapsulating the option. + void createUpdateOption6(const ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const OptionDescriptorPtr& option) { + uint64_t pd_pool_id = 0; + Pool6Ptr pd_pool = getPdPool6(server_selector, + pd_pool_prefix, + pd_pool_prefix_length, + pd_pool_id); + if (!pd_pool) { + isc_throw(BadValue, "no prefix delegation pool found for prefix " + << "of " << pd_pool_prefix << "/" + << static_cast<unsigned>(pd_pool_prefix_length)); + } + + createUpdateOption6(server_selector, Lease::TYPE_PD, + pd_pool_id, option, false); + } + + /// @brief Sends query to insert or update DHCP option in an address + /// or prefix delegation pool. + /// + /// @param selector Server selector. + /// @param pool_type Pool type (Lease::TYPE_NA or Lease::TYPE_PD). + /// @param pool_id Identifier of the address or prefix delegation pool + /// the option belongs to. + /// @param option Pointer to the option descriptor encapsulating the option. + /// @param cascade_update Boolean value indicating whether the update is + /// performed as part of the owning element, e.g. subnet. + void createUpdateOption6(const ServerSelector& server_selector, + const Lease::Type& pool_type, + const uint64_t pool_id, + const OptionDescriptorPtr& option, + const bool cascade_update) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + std::string msg = "creating or updating "; + if (pool_type == Lease::TYPE_PD) { + msg += "prefix delegation"; + } else { + msg += "address"; + } + msg += " pool level option"; + + PsqlBindArray in_bindings; + + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.addNull(); + + // scope_id + if (pool_type == Lease::TYPE_NA) { + in_bindings.add(5); + } else { + in_bindings.add(6); + } + + in_bindings.add(option->getContext()); + in_bindings.addNull(); + + // pool_id + if (pool_type == Lease::TYPE_NA) { + in_bindings.add(pool_id); + } else { + in_bindings.addNull(); + } + + in_bindings.addTimestamp(option->getModificationTime()); + + // pd_pool_id + if (pool_type == Lease::TYPE_PD) { + in_bindings.add(pool_id); + } else { + in_bindings.addNull(); + } + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(pool_id); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + if (pool_type == Lease::TYPE_PD) { + msg = "prefix delegation"; + } else { + msg = "address"; + } + msg += " pool specific option set"; + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, msg, cascade_update); + + auto index = (pool_type == Lease::TYPE_NA ? + PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID : + PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID); + + // Try to update the option. + if (updateDeleteQuery(index, in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption6(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a shared network. + /// + /// @param selector Server selector. + /// @param shared_network_name Name of the shared network the option + /// belongs to. + /// @param option Pointer to the option descriptor encapsulating the option. + /// @param cascade_update Boolean value indicating whether the update is + /// performed as part of the owning element, e.g. shared network. + void createUpdateOption6(const ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option, + const bool cascade_update) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + // Create input bindings. + PsqlBindArray in_bindings; + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.add(4); + in_bindings.add(option->getContext()); + in_bindings.add(shared_network_name); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + in_bindings.addNull(); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(shared_network_name); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network specific option set", + cascade_update); + + // Try to update the option. + if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the option. + insertOption6(server_selector, in_bindings, + option->getModificationTime()); + } + + // Commit the work. + transaction.commit(); + } + + /// @brief Sends query to insert or update DHCP option in a client class. + /// + /// @param selector Server selector. + /// @param client_class Pointer to the client_class the option belongs to. + /// @param option Pointer to the option descriptor encapsulating the option.. + void createUpdateOption6(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const OptionDescriptorPtr& option) { + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + PsqlBindArray in_bindings; + std::string class_name = client_class->getName(); + in_bindings.add(option->option_->getType()); + addOptionValueBinding(in_bindings, option); + in_bindings.addOptional(option->formatted_value_); + in_bindings.addOptional(option->space_name_); + in_bindings.add(option->persistent_); + in_bindings.add(option->cancelled_); + in_bindings.add(class_name); + in_bindings.addNull(); + in_bindings.add(2); + in_bindings.add(option->getContext()); + in_bindings.addNull(); + in_bindings.addNull(); + in_bindings.addTimestamp(option->getModificationTime()); + in_bindings.addNull(); + + // Remember the size before we add where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now we add the update where clause parameters + in_bindings.add(class_name); + in_bindings.add(option->option_->getType()); + in_bindings.addOptional(option->space_name_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "client class specific option set", + true); + + if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS, + in_bindings) == 0) { + // The option doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + insertOption6(server_selector, in_bindings, + option->getModificationTime()); + } + } + + /// @brief Sends query to insert or update option definition. + /// + /// @param server_selector Server selector. + /// @param option_def Pointer to the option definition to be inserted or updated. + void createUpdateOptionDef6(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def) { + createUpdateOptionDef(server_selector, Option::V6, option_def, DHCP6_OPTION_SPACE, + PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6, + PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER); + } + + /// @brief Sends query to insert or update option definition + /// for a client class. + /// + /// @param server_selector Server selector. + /// @param option_def Pointer to the option definition to be inserted or updated. + /// @param client_class Client class name. + void createUpdateOptionDef6(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def, + const std::string& client_class_name) { + createUpdateOptionDef(server_selector, Option::V6, option_def, DHCP6_OPTION_SPACE, + PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS, + PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS, + PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER, + client_class_name); + } + + /// @brief Sends query to delete option definition by code and + /// option space name. + /// + /// @param server_selector Server selector. + /// @param code Option code. + /// @param name Option name. + /// @return Number of deleted option definitions. + uint64_t deleteOptionDef6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEF6_CODE_NAME, + server_selector, + "deleting option definition", + "option definition deleted", + false, + in_bindings)); + } + + /// @brief Sends query to delete option definitions for a client class. + /// + /// @param server_selector Server selector. + /// @param client_class Pointer to the client class for which option + /// definitions should be deleted. + /// @return Number of deleted option definitions. + uint64_t deleteOptionDefs6(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class) { + PsqlBindArray in_bindings; + in_bindings.addTempString(client_class->getName()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEFS6_CLIENT_CLASS, + server_selector, + "deleting option definition for a client class", + "option definition deleted", + true, + in_bindings)); + } + + /// @brief Deletes global option. + /// + /// @param server_selector Server selector. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6, + server_selector, + "deleting global option", + "global option deleted", + false, + in_bindings)); + } + + /// @brief Deletes subnet level option. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to which deleted option + /// belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption6(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(subnet_id); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID, + server_selector, + "deleting option for a subnet", + "subnet specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound pool address. + /// @param pool_end_address Upper bound pool address. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption6(const db::ServerSelector& server_selector, + const IOAddress& pool_start_address, + const IOAddress& pool_end_address, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.addInet6(pool_start_address); + in_bindings.addInet6(pool_end_address); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE, + server_selector, + "deleting option for an address pool", + "address pool specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes pd pool level option. + /// + /// @param server_selector Server selector. + /// @param pd_pool_prefix Address part of the pd pool prefix. + /// @param pd_pool_prefix_length Length of the pd pool prefix. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption6(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.addTempString(pd_pool_prefix.toText()); + in_bindings.add(pd_pool_prefix_length); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL, + server_selector, + "deleting option for a prefix delegation pool", + "prefix delegation pool specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes shared network level option. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network which deleted + /// option belongs to + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + uint64_t deleteOption6(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space) { + PsqlBindArray in_bindings; + in_bindings.add(shared_network_name); + in_bindings.add(code); + in_bindings.add(space); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK, + server_selector, + "deleting option for a shared network", + "shared network specific option deleted", + false, + in_bindings)); + } + + /// @brief Deletes options belonging to a subnet from the database. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the subnet for which options should be + /// deleted. + /// @return Number of deleted options. + uint64_t deleteOptions6(const ServerSelector& server_selector, + const Subnet6Ptr& subnet) { + PsqlBindArray in_bindings; + in_bindings.add(subnet->getID()); + in_bindings.addTempString(subnet->toText()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SUBNET_ID_PREFIX, + server_selector, + "deleting options for a subnet", + "subnet specific options deleted", + true, in_bindings)); + } + + /// @brief Deletes options belonging to a shared network from the database. + /// + /// @param server_selector Server selector. + /// @param subnet Pointer to the subnet for which options should be + /// deleted. + /// @return Number of deleted options. + uint64_t deleteOptions6(const ServerSelector& server_selector, + const SharedNetwork6Ptr& shared_network) { + PsqlBindArray in_bindings; + in_bindings.addTempString(shared_network->getName()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl:: + DELETE_OPTIONS6_SHARED_NETWORK, server_selector, + "deleting options for a shared network", + "shared network specific options deleted", + true, in_bindings)); + } + + /// @brief Deletes options belonging to a client class from the database. + /// + /// @param server_selector Server selector. + /// @param client_class Pointer to the client class for which options + /// should be deleted. + /// @return Number of deleted options. + uint64_t deleteOptions6(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class) { + PsqlBindArray in_bindings; + in_bindings.addTempString(client_class->getName()); + + // Run DELETE. + return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl:: + DELETE_OPTIONS6_CLIENT_CLASS, server_selector, + "deleting options for a client class", + "client class specific options deleted", + true, in_bindings)); + } + + /// @brief Common function to retrieve client classes. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] client_classes Reference to a container where fetched client + /// classes will be inserted. + void getClientClasses6(const StatementIndex& index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings, + ClientClassDictionary& client_classes) { + std::list<ClientClassDefPtr> class_list; + uint64_t last_option_id = 0; + uint64_t last_option_def_id = 0; + std::string last_tag; + + selectQuery(index, in_bindings, + [this, &class_list, &last_option_id, &last_option_def_id, &last_tag] + (PgSqlResult& r, int row) { + // Create a convenience worker for the row. + PgSqlResultRowWorker worker(r, row); + + ClientClassDefPtr last_client_class; + if (!class_list.empty()) { + last_client_class = *class_list.rbegin(); + } + + // Class ID is column 0. + uint64_t id = worker.getBigInt(0) ; + + if (!last_client_class || (last_client_class->getId() != id)) { + last_option_id = 0; + last_option_def_id = 0; + last_tag.clear(); + + auto options = boost::make_shared<CfgOption>(); + auto option_defs = boost::make_shared<CfgOptionDef>(); + + last_client_class = boost::make_shared<ClientClassDef>(worker.getString(1), + ExpressionPtr(), options); + last_client_class->setCfgOptionDef(option_defs); + + // id + last_client_class->setId(id); + + // name + last_client_class->setName(worker.getString(1)); + + // test + if (!worker.isColumnNull(2)) { + last_client_class->setTest(worker.getString(2)); + } + + // required + if (!worker.isColumnNull(3)) { + last_client_class->setRequired(worker.getBool(3)); + } + + // valid lifetime: default, min, max + last_client_class->setValid(worker.getTriplet(4, 5, 6)); + + // depend on known directly or indirectly + last_client_class->setDependOnKnown(worker.getBool(7) || worker.getBool(8)); + + // modification_ts + last_client_class->setModificationTime(worker.getTimestamp(9)); + + // user_context at 10. + if (!worker.isColumnNull(10)) { + ElementPtr user_context = worker.getJSON(10); + if (user_context) { + last_client_class->setContext(user_context); + } + } + + // class specific option definition from 11 to 20. + // class specific option from 21 to 33. + + // preferred lifetime: default, min, max + last_client_class->setPreferred(worker.getTriplet(35, 36, 37)); + + class_list.push_back(last_client_class); + } + + // Check for new server tags at 34. + if (!worker.isColumnNull(34)) { + std::string new_tag = worker.getString(34); + if (last_tag != new_tag) { + if (!new_tag.empty() && !last_client_class->hasServerTag(ServerTag(new_tag))) { + last_client_class->setServerTag(new_tag); + } + + last_tag = new_tag; + } + } + + // Parse client class specific option definition from 11 to 20. + if (!worker.isColumnNull(11) && + (last_option_def_id < worker.getBigInt(11))) { + last_option_def_id = worker.getBigInt(11); + + auto def = processOptionDefRow(worker, 11); + if (def) { + last_client_class->getCfgOptionDef()->add(def); + } + } + + // Parse client class specific option from 21 to 33. + if (!worker.isColumnNull(21) && + (last_option_id < worker.getBigInt(21))) { + last_option_id = worker.getBigInt(21); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 21); + if (desc) { + last_client_class->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); + + tossNonMatchingElements(server_selector, class_list); + + for (auto c : class_list) { + client_classes.addClass(c); + } + } + + /// @brief Sends query to retrieve a client class by name. + /// + /// @param server_selector Server selector. + /// @param name Name of the class to be retrieved. + /// @return Pointer to the client class or null if the class is not found. + ClientClassDefPtr getClientClass6(const ServerSelector& server_selector, + const std::string& name) { + PsqlBindArray in_bindings; + in_bindings.add(name); + + ClientClassDictionary client_classes; + getClientClasses6(PgSqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME, + server_selector, in_bindings, client_classes); + return (client_classes.getClasses()->empty() ? ClientClassDefPtr() : + (*client_classes.getClasses()->begin())); + } + + /// @brief Sends query to retrieve all client classes. + /// + /// @param server_selector Server selector. + /// @param [out] client_classes Reference to the client classes collection + /// where retrieved classes will be stored. + void getAllClientClasses6(const ServerSelector& server_selector, + ClientClassDictionary& client_classes) { + PsqlBindArray in_bindings; + getClientClasses6(server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6, + server_selector, in_bindings, client_classes); + } + + /// @brief Sends query to retrieve modified client classes. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] client_classes Reference to the client classes collection + /// where retrieved classes will be stored. + void getModifiedClientClasses6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + ClientClassDictionary& client_classes) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "fetching modified client classes for ANY " + "server is not supported"); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(modification_ts); + getClientClasses6(server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6, + server_selector, in_bindings, client_classes); + } + + /// @brief Upserts client class. + /// + /// @param server_selector Server selector. + /// @param client_class Pointer to the upserted client class. + /// @param follow_class_name name of the class after which the + /// new or updated class should be positioned. An empty value + /// causes the class to be appended at the end of the class + /// hierarchy. + void createUpdateClientClass6(const ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name) { + // We need to evaluate class expression to see if it references any + // other classes (dependencies). As part of this evaluation we will + // also check if the client class depends on KNOWN/UNKNOWN built-in + // classes. + std::list<std::string> dependencies; + auto depend_on_known = false; + if (!client_class->getTest().empty()) { + ExpressionPtr expression; + ExpressionParser parser; + // Parse the test expression. The callback function is normally used to + // interrupt config file parsing when one of the classes refers to a + // non-existing client class. It returns false in this case. Here, + // we use the callback to capture client classes referenced by the + // upserted client class and record whether this class depends on + // KNOWN/UNKNOWN built-ins. The callback always returns true to avoid + // reporting the parsing error. The dependency check is performed later + // at the database level. + parser.parse(expression, Element::create(client_class->getTest()), AF_INET6, + [&dependencies, &depend_on_known](const ClientClass& client_class) -> bool { + if (isClientClassBuiltIn(client_class)) { + if ((client_class == "KNOWN") || (client_class == "UNKNOWN")) { + depend_on_known = true; + } + } else { + dependencies.push_back(client_class); + } + return (true); + }); + } + + PsqlBindArray in_bindings; + std::string class_name = client_class->getName(); + in_bindings.add(class_name); + in_bindings.addTempString(client_class->getTest()); + in_bindings.add(client_class->getRequired()); + in_bindings.add(client_class->getValid()); + in_bindings.add(client_class->getValid().getMin()); + in_bindings.add(client_class->getValid().getMax()); + in_bindings.add(depend_on_known); + + // follow-class-name (8) + if (follow_class_name.empty()) { + in_bindings.addNull(); + } else { + in_bindings.add(follow_class_name); + } + + in_bindings.add(client_class->getPreferred()); + in_bindings.add(client_class->getPreferred().getMin()); + in_bindings.add(client_class->getPreferred().getMax()); + in_bindings.addTimestamp(client_class->getModificationTime()); + in_bindings.add(client_class->getContext()); + + PgSqlTransaction transaction(conn_); + + ScopedAuditRevision audit_revision(this, PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "client class set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateClass6"); + + // Keeps track of whether the client class is inserted or updated. + auto update = false; + try { + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6, in_bindings); + + } catch (const DuplicateEntry&) { + // It already exists, rollback to the savepoint to preserve + // any prior work. + conn_.rollbackToSavepoint("createUpdateClass6"); + + // Delete options and option definitions. They will be re-created from the new class + // instance. + deleteOptions6(ServerSelector::ANY(), client_class); + deleteOptionDefs6(ServerSelector::ANY(), client_class); + + // Note: follow_class_name is left in the bindings even though it is + // not needed in both cases. This allows us to use one base query. + + // Add the class name for the where clause. + in_bindings.add(class_name); + if (follow_class_name.empty()) { + // If position is not specified, leave the class at the same position. + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6_SAME_POSITION, + in_bindings); + } else { + // Update with follow_class_name specifying the position. + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6, + in_bindings); + } + + // Delete class associations with the servers and dependencies. We will re-create + // them according to the new class specification. + PsqlBindArray in_assoc_bindings; + in_assoc_bindings.add(class_name); + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY, + in_assoc_bindings); + updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER, + in_assoc_bindings); + update = true; + } + + // Associate client class with the servers. + PsqlBindArray attach_bindings; + attach_bindings.add(class_name); + attach_bindings.addTimestamp(client_class->getModificationTime()); + + attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER, + server_selector, attach_bindings); + + // Iterate over the captured dependencies and try to insert them into the database. + for (auto dependency : dependencies) { + try { + PsqlBindArray in_dependency_bindings; + in_dependency_bindings.add(class_name); + in_dependency_bindings.add(dependency); + + // We deleted earlier dependencies, so we can simply insert new ones. + insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY, + in_dependency_bindings); + } catch (const std::exception& ex) { + isc_throw(InvalidOperation, "unmet dependency on client class: " << dependency); + } + } + + // If we performed client class update we also have to verify that its dependency + // on KNOWN/UNKNOWN client classes hasn't changed. + if (update) { + PsqlBindArray in_check_bindings; + insertQuery(PgSqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + in_check_bindings); + } + + // (Re)create option definitions. + if (client_class->getCfgOptionDef()) { + auto option_defs = client_class->getCfgOptionDef()->getContainer(); + auto option_spaces = option_defs.getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionDefContainerPtr defs = option_defs.getItems(option_space); + for (auto def = defs->begin(); def != defs->end(); ++def) { + createUpdateOptionDef6(server_selector, *def, client_class->getName()); + } + } + } + + // (Re)create options. + auto option_spaces = client_class->getCfgOption()->getOptionSpaceNames(); + for (auto option_space : option_spaces) { + OptionContainerPtr options = client_class->getCfgOption()->getAll(option_space); + for (auto desc = options->begin(); desc != options->end(); ++desc) { + OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc); + desc_copy->space_name_ = option_space; + createUpdateOption6(server_selector, client_class, desc_copy); + } + } + + // All ok. Commit the transaction. + transaction.commit(); + } + + /// @brief Removes client class by name. + /// + /// @param server_selector Server selector. + /// @param name Removed client class name. + /// @return Number of deleted client classes. + uint64_t deleteClientClass6(const ServerSelector& server_selector, + const std::string& name) { + int index = server_selector.amAny() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY : + PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6; + + uint64_t result = deleteTransactional(index, server_selector, + "deleting client class", + "client class deleted", + true, + name); + return (result); + } + + /// @brief Removes unassigned global parameters, global options and + /// option definitions. + /// + /// This function is called when one or more servers are deleted and + /// it is likely that there are some orphaned configuration elements + /// left in the database. This method removes those elements. + void purgeUnassignedConfig() { + multipleUpdateDeleteQueries(DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED, + DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED, + DELETE_ALL_OPTION_DEFS6_UNASSIGNED); + } + + /// @brief Attempts to delete a server having a given tag. + /// + /// @param server_tag Tag of the server to be deleted. + /// @return Number of deleted servers. + /// @throw isc::InvalidOperation when trying to delete the logical + /// server 'all'. + uint64_t deleteServer6(const data::ServerTag& server_tag) { + // It is not allowed to delete 'all' logical server. + if (server_tag.amAll()) { + isc_throw(InvalidOperation, "'all' is a name reserved for the server tag which" + " associates the configuration elements with all servers connecting" + " to the database and may not be deleted"); + } + + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting a server", false); + + // Specify which server should be deleted. + PsqlBindArray in_bindings; + in_bindings.addTempString(server_tag.get()); + + // Attempt to delete the server. + auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_SERVER6, + in_bindings); + + // If we have deleted any servers we have to remove any dangling global + // parameters, options and option definitions. + if (count > 0) { + purgeUnassignedConfig(); + } + + transaction.commit(); + + return (count); + } + + /// @brief Attempts to delete all servers. + /// + /// This method deletes all servers added by the user. It does not + /// delete the logical server 'all'. + /// + /// @return Number of deleted servers. + uint64_t deleteAllServers6() { + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision + audit_revision(this, PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting all servers", + false); + + // No arguments, hence empty input bindings. + PsqlBindArray in_bindings; + + // Attempt to delete the servers. + auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6, + in_bindings); + + // If we have deleted any servers we have to remove any dangling global + // parameters, options and option definitions. + if (count > 0) { + purgeUnassignedConfig(); + } + + // Commit the transaction. + transaction.commit(); + + return (count); + } + + /// @brief Attempts to reconnect the server to the config DB backend manager. + /// + /// This is a self-rescheduling function that attempts to reconnect to the + /// server's config DB backends after connectivity to one or more have been + /// lost. Upon entry it will attempt to reconnect via + /// @ref ConfigBackendDHCPv6Mgr.addBackend. + /// If this is successful, DHCP servicing is re-enabled and server returns + /// to normal operation. + /// + /// If reconnection fails and the maximum number of retries has not been + /// exhausted, it will schedule a call to itself to occur at the + /// configured retry interval. DHCP service remains disabled. + /// + /// If the maximum number of retries has been exhausted an error is logged + /// and the server shuts down. + /// + /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the + /// configured reconnect parameters. + /// @return true if connection has been recovered, false otherwise. + static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl) { + MultiThreadingCriticalSection cs; + + // Invoke application layer connection lost callback. + if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) { + return (false); + } + + bool reopened = false; + + const std::string timer_name = db_reconnect_ctl->timerName(); + + // At least one connection was lost. + try { + auto srv_cfg = CfgMgr::instance().getCurrentCfg(); + auto config_ctl = srv_cfg->getConfigControlInfo(); + // Iterate over the configured DBs and instantiate them. + for (auto db : config_ctl->getConfigDatabases()) { + const std::string& access = db.getAccessString(); + auto parameters = db.getParameters(); + if (ConfigBackendDHCPv6Mgr::instance().delBackend(parameters["type"], access, true)) { + ConfigBackendDHCPv6Mgr::instance().addBackend(db.getAccessString()); + } + } + + reopened = true; + } catch (const std::exception& ex) { + LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_FAILED6) + .arg(ex.what()); + } + + if (reopened) { + // Cancel the timer. + if (TimerMgr::instance()->isTimerRegistered(timer_name)) { + TimerMgr::instance()->unregisterTimer(timer_name); + } + + // Invoke application layer connection recovered callback. + if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) { + return (false); + } + } else { + if (!db_reconnect_ctl->checkRetries()) { + // We're out of retries, log it and initiate shutdown. + LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_FAILED6) + .arg(db_reconnect_ctl->maxRetries()); + + // Cancel the timer. + if (TimerMgr::instance()->isTimerRegistered(timer_name)) { + TimerMgr::instance()->unregisterTimer(timer_name); + } + + // Invoke application layer connection failed callback. + DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl); + + return (false); + } + + LOG_INFO(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6) + .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1) + .arg(db_reconnect_ctl->maxRetries()) + .arg(db_reconnect_ctl->retryInterval()); + + // Start the timer. + if (!TimerMgr::instance()->isTimerRegistered(timer_name)) { + TimerMgr::instance()->registerTimer(timer_name, + std::bind(&PgSqlConfigBackendDHCPv6Impl::dbReconnect, db_reconnect_ctl), + db_reconnect_ctl->retryInterval(), + asiolink::IntervalTimer::ONE_SHOT); + } + TimerMgr::instance()->setup(timer_name); + } + + return (true); + } + + /// @brief Sets a Network6 interface ID from result set col. + /// + /// Sets the interface id of the Network6 to the value carried in the + /// given column in a result set row. + /// + /// @param network shared network or subnet to receive the interface ID + /// @param worker result set row worker contain the database row + /// @param col column within the row from which to take the value + void setInterfaceId(Network6& network, PgSqlResultRowWorker& worker, size_t col) { + if (!worker.isColumnNull(col)) { + std::vector<uint8_t> iface_id_data; + worker.getBytes(col, iface_id_data); + if (!iface_id_data.empty()) { + OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID, iface_id_data)); + network.setInterfaceId(opt_iface_id); + } + } + } + + /// @brief Adds network interface ID to a bind array. + /// + /// Adds the interface id to end of the given bind array as a vector of bytes. + /// + /// @param bindings PsqlBindArray to which the ID should be added. + /// @param network Pointer to shared network or subnet for which ID binding + /// should be created. + void addInterfaceIdBinding(PsqlBindArray& bindings, const Network6& network) { + auto opt_iface_id = network.getInterfaceId(Network::Inheritance::NONE); + if (!opt_iface_id) { + bindings.addNull(); + } else { + auto iface_id_data = opt_iface_id->getData(); + if (iface_id_data.empty()) { + bindings.addNull(); + } else { + bindings.addTempBinary(iface_id_data); + } + } + } + +}; + +namespace { + +/// @brief Array of tagged statements. +typedef std::array<PgSqlTaggedStatement, PgSqlConfigBackendDHCPv6Impl::NUM_STATEMENTS> +TaggedStatementArray; + +/// @brief Prepared PgSQL statements used by the backend to insert and +/// retrieve data from the database. They must be in the same order as +/// PgSqlConfigBackendDHCPv6Impl::StatementIndex. The statement is +/// the corresponding enum name. +TaggedStatementArray tagged_statements = { { + { + // PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + 4, + { + OID_TIMESTAMP, // 1 audit_ts + OID_VARCHAR, // 2 server_tag + OID_TEXT, // 3 audit_log_message + OID_BOOL // 4 cascade_transaction + }, + "CREATE_AUDIT_REVISION", + "select createAuditRevisionDHCP6($1, $2, $3, $4)" + }, + + // Verify that dependency on KNOWN/UNKNOWN class has not changed. + { + // PgSqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + 0, + { + OID_NONE + }, + "CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE", + "select checkDHCPv6ClientClassKnownDependencyChange()" + }, + + // Select global parameter by name. + { + // PgSqlConfigBackendDHCPv6Impl::GET_GLOBAL_PARAMETER6, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 name + }, + "GET_GLOBAL_PARAMETER6", + PGSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.name = $2) + }, + + // Select all global parameters. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_ALL_GLOBAL_PARAMETERS6", + PGSQL_GET_GLOBAL_PARAMETER(dhcp6) + }, + + // Select modified global parameters. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP // 2 modification_ts + }, + "GET_MODIFIED_GLOBAL_PARAMETERS6", + PGSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.modification_ts >= $2) + }, + + // Select subnet by id. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_NO_TAG, + 1, + { + OID_INT8 // 1 subnet_id + }, + "GET_SUBNET6_ID_NO_TAG", + PGSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_id = $1) + }, + + // Select subnet by id without specifying server tags. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_ANY, + 1, + { + OID_INT8 // 1 subnet_id + }, + "GET_SUBNET6_ID_ANY", + PGSQL_GET_SUBNET6_ANY(WHERE s.subnet_id = $1) + }, + + // Select unassigned subnet by id. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_UNASSIGNED, + 1, + { + OID_INT8 // 1 subnet_id + }, + "GET_SUBNET6_ID_UNASSIGNED", + PGSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_id = $1) + }, + + // Select subnet by prefix. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_NO_TAG, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "GET_SUBNET6_PREFIX_NO_TAG", + PGSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_prefix = $1) + }, + + // Select subnet by prefix without specifying server tags. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_ANY, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "GET_SUBNET6_PREFIX_ANY", + PGSQL_GET_SUBNET6_ANY(WHERE s.subnet_prefix = $1) + }, + + // Select unassigned subnet by prefix. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_UNASSIGNED, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "GET_SUBNET6_PREFIX_UNASSIGNED", + PGSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_prefix = $1) + }, + + // Select all subnets. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6, + 0, + { + OID_NONE + }, + "GET_ALL_SUBNETS6", + PGSQL_GET_SUBNET6_NO_TAG() + }, + + // Select all unassigned subnets. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "GET_ALL_SUBNETS6_UNASSIGNED", + PGSQL_GET_SUBNET6_UNASSIGNED() + }, + + // Select subnets having modification time later than X. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SUBNETS6", + PGSQL_GET_SUBNET6_NO_TAG(WHERE s.modification_ts >= $1) + }, + + // Select modified and unassigned subnets. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6_UNASSIGNED, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SUBNETS6_UNASSIGNED", + PGSQL_GET_SUBNET6_UNASSIGNED(AND s.modification_ts >= $1) + }, + + // Select subnets belonging to a shared network. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK_SUBNETS6, + 1, + { + OID_VARCHAR // 1 share_network_name + }, + "GET_SHARED_NETWORK_SUBNETS6", + PGSQL_GET_SUBNET6_ANY(WHERE s.shared_network_name = $1) + }, + + // Select pool by address range for a server. + { + // PgSqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_TEXT, // 2 start_address - cast as inet + OID_TEXT // 3 end_address - cast as inet + }, + "GET_POOL6_RANGE", + PGSQL_GET_POOL6_RANGE_WITH_TAG(WHERE (srv.tag = $1 OR srv.id = 1) \ + AND (p.start_address = cast($2 as inet)) \ + AND (p.end_address = cast($3 as inet))) + }, + + // Select pool by address range for any server. + { + // PgSqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE_ANY, + 2, + { + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT // 2 end_address - cast as inet + }, + "GET_POOL6_RANGE_ANY", + PGSQL_GET_POOL6_RANGE_NO_TAG(WHERE (p.start_address = cast($1 as inet)) AND \ + (p.end_address = cast($2 as inet))) + }, + + // Select prefix delegation pool for a server. + { + // PgSqlConfigBackendDHCPv6Impl::GET_PD_POOL, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR, // 2 pd pool prefix + OID_INT2 // 3 prefix length + }, + "GET_PD_POOL", + PGSQL_GET_PD_POOL_WITH_TAG(WHERE (srv.tag = $1 OR srv.id = 1) AND p.prefix = $2 AND p.prefix_length = $3) + }, + + // Select prefix delegation pool for any server. + { + // PgSqlConfigBackendDHCPv6Impl::GET_PD_POOL_ANY, + 2, + { + OID_VARCHAR, // 1 prefix + OID_INT2 // 2 prefix length + }, + "GET_PD_POOL_ANY", + PGSQL_GET_PD_POOL_NO_TAG(WHERE p.prefix = $1 AND p.prefix_length = $2) + }, + + // Select shared network by name. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG, + 1, + { + OID_VARCHAR // name of network + }, + "GET_SHARED_NETWORK6_NAME_NO_TAG", + PGSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.name = $1) + }, + + // Select shared network by name without specifying server tags. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY, + 1, + { + OID_VARCHAR // name of network + }, + "GET_SHARED_NETWORK6_NAME_ANY", + PGSQL_GET_SHARED_NETWORK6_ANY(WHERE n.name = $1) + }, + + // Select unassigned shared network by name. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED, + 1, + { + OID_VARCHAR // name of network + }, + "GET_SHARED_NETWORK6_NAME_UNASSIGNED", + PGSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.name = $1) + }, + + // Select all shared networks. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6, + 0, + { + OID_NONE + }, + "GET_ALL_SHARED_NETWORKS6", + PGSQL_GET_SHARED_NETWORK6_NO_TAG() + }, + + // Select all unassigned shared networks. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "GET_ALL_SHARED_NETWORKS6_UNASSIGNED", + PGSQL_GET_SHARED_NETWORK6_UNASSIGNED() + }, + + // Select modified shared networks. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SHARED_NETWORKS6", + PGSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.modification_ts >= $1) + }, + + // Select modified and unassigned shared networks. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED", + PGSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.modification_ts >= $1) + }, + + // Retrieves option definition by code and space. + { + // PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "GET_OPTION_DEF6_CODE_SPACE", + PGSQL_GET_OPTION_DEF(dhcp6, AND d.code = $2 AND d.space = $3) + }, + + // Retrieves all option definitions. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_ALL_OPTION_DEFS6", + PGSQL_GET_OPTION_DEF(dhcp6) + }, + + // Retrieves modified option definitions. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP // 2 modification_ts + }, + "GET_MODIFIED_OPTION_DEFS6", + PGSQL_GET_OPTION_DEF(dhcp6, AND d.modification_ts >= $2) + }, + + // Retrieves global option by code and space. + { + // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "GET_OPTION6_CODE_SPACE", + PGSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = $2 AND o.space = $3) + }, + + // Retrieves all global options. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_ALL_OPTIONS6", + PGSQL_GET_OPTION6(AND o.scope_id = 0) + }, + + // Retrieves modified options. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP // 2 modification_ts + }, + "GET_MODIFIED_OPTIONS6", + PGSQL_GET_OPTION6(AND o.scope_id = 0 AND o.modification_ts >= $2) + }, + + // Retrieves an option for a given subnet, option code and space. + { + // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_SUBNET_ID_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_INT8, // 2 subnet_id + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION6_SUBNET_ID_CODE_SPACE", + PGSQL_GET_OPTION6(AND o.scope_id = 1 AND o.dhcp6_subnet_id = $2 AND o.code = $3 AND o.space = $4) + }, + + // Retrieves an option for a given pool, option code and space. + { + // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_POOL_ID_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_INT8, // 2 pool_id + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION6_POOL_ID_CODE_SPACE", + PGSQL_GET_OPTION6(AND o.scope_id = 5 AND o.pool_id = $2 AND o.code = $3 AND o.space = $4) + }, + + // Retrieves an option for a given pd pool, option code and space. + { + // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_PD_POOL_ID_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_INT8, // 2 pd_pool_id + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION6_PD_POOL_ID_CODE_SPACE", + PGSQL_GET_OPTION6(AND o.scope_id = 6 AND o.pd_pool_id = $2 AND o.code = $3 AND o.space = $4) + }, + + // Retrieves an option for a given shared network, option code and space. + { + // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_SHARED_NETWORK_CODE_SPACE, + 4, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR, // 2 shared_network_name + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "GET_OPTION6_SHARED_NETWORK_CODE_SPACE", + PGSQL_GET_OPTION6(AND o.scope_id = 4 AND o.shared_network_name = $2 AND o.code = $3 AND o.space = $4) + }, + + // Select a client class by name. + { + // PgSqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME, + 1, + { + OID_VARCHAR // name of class + }, + "GET_CLIENT_CLASS6_NAME", + PGSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.name = $1) + }, + + // Select all client classes. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6, + 0, + { + OID_NONE + }, + "GET_ALL_CLIENT_CLASSES6", + PGSQL_GET_CLIENT_CLASS6_WITH_TAG() + }, + + // Select all unassigned client classes. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED, + 0, + { + OID_NONE + }, + "GET_ALL_CLIENT_CLASSES6_UNASSIGNED", + PGSQL_GET_CLIENT_CLASS6_UNASSIGNED() + }, + + // Select modified client classes. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_CLIENT_CLASSES6", + PGSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.modification_ts >= $1) + }, + + // Select modified client classes. + { + // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED, + 1, + { + OID_TIMESTAMP // 1 modification_ts + }, + "GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED", + PGSQL_GET_CLIENT_CLASS6_UNASSIGNED(AND c.modification_ts >= $1) + }, + + // Retrieves the most recent audit entries. + { + // PgSqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_TIMESTAMP, // 2 modification_ts + OID_INT8 // 3 revision id + }, + "GET_AUDIT_ENTRIES6_TIME", + PGSQL_GET_AUDIT_ENTRIES_TIME(dhcp6) + }, + + // Retrieves a server by tag. + { + // PgSqlConfigBackendDHCPv6Impl::GET_SERVER6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "GET_SERVER6", + PGSQL_GET_SERVER(dhcp6) + }, + + // Retrieves all servers. + { + // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6, + 0, + { + OID_NONE + }, + "GET_ALL_SERVERS6", + PGSQL_GET_ALL_SERVERS(dhcp6) + }, + + // Insert global parameter. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6, + 4, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 value + OID_INT2, // 3 parameter_type + OID_TIMESTAMP // 4 modification_ts + }, + "INSERT_GLOBAL_PARAMETER6", + PGSQL_INSERT_GLOBAL_PARAMETER(dhcp6) + }, + + // Insert association of the global parameter with a server. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER, + 3, + { + OID_INT8, // 1 parameter_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_GLOBAL_PARAMETER6_SERVER", + PGSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp6) + }, + + // Insert a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6, + 35, + { + OID_INT8, // 1 subnet_id, + OID_VARCHAR, // 2 subnet_prefix + OID_VARCHAR, // 3 client_class + OID_VARCHAR, // 4 interface + OID_TIMESTAMP, // 5 modification_ts + OID_INT8, // 6 preferred_lifetime + OID_INT8, // 7 min_preferred_lifetime + OID_INT8, // 8 max_preferred_lifetime + OID_BOOL, // 9 rapid_commit + OID_INT8, // 10 rebind_timer + OID_TEXT, // 11 relay + OID_INT8, // 12 renew_timer + OID_TEXT, // 13 require_client_classes + OID_BOOL, // 14 reservations_global + OID_VARCHAR, // 15 shared_network_name + OID_TEXT, // 16 user_context - cast as json + OID_INT8, // 17 valid_lifetime + OID_INT8, // 18 min_valid_lifetime + OID_INT8, // 19 max_valid_lifetime + OID_BOOL, // 20 calculate_tee_times + OID_TEXT, // 21 t1_percent - cast as float + OID_TEXT, // 22 t2_percent - cast as float + OID_BYTEA, // 23 interface_id + OID_BOOL, // 24 ddns_send_updates + OID_BOOL, // 25 ddns_override_no_update + OID_BOOL, // 26 ddns_override_client_update + OID_INT8, // 27 ddns_replace_client_name + OID_VARCHAR, // 28 ddns_generated_prefix + OID_VARCHAR, // 29 ddns_qualifying_suffix + OID_BOOL, // 30 reservations_in_subnet + OID_BOOL, // 31 reservations_out_of_pool + OID_TEXT, // 32 cache_threshold - cast as float + OID_INT8, // 33 cache_max_age + OID_VARCHAR, // 34 allocator + OID_VARCHAR // 35 pd_allocator + }, + "INSERT_SUBNET6", + "INSERT INTO dhcp6_subnet(" + " subnet_id," + " subnet_prefix," + " client_class," + " interface," + " modification_ts," + " preferred_lifetime," + " min_preferred_lifetime," + " max_preferred_lifetime," + " rapid_commit," + " rebind_timer," + " relay," + " renew_timer," + " require_client_classes," + " reservations_global," + " shared_network_name," + " user_context," + " valid_lifetime," + " min_valid_lifetime," + " max_valid_lifetime," + " calculate_tee_times," + " t1_percent," + " t2_percent," + " interface_id," + " ddns_send_updates," + " ddns_override_no_update," + " ddns_override_client_update," + " ddns_replace_client_name," + " ddns_generated_prefix," + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool," + " cache_threshold," + " cache_max_age," + " allocator," + " pd_allocator" + ") VALUES (" + " $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, " + " $11, $12, $13, $14, $15, cast($16 as json), $17, $18, $19, $20, " + " cast($21 as float), cast($22 as float), $23, $24, $25, $26, $27, $28, $29, $30, " + " $31, cast($32 as float), $33, $34, $35" + ")" + }, + + // Insert association of the subnet with a server. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER, + 3, + { + OID_INT8, // 1 subnet_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_SUBNET6_SERVER", + PGSQL_INSERT_SUBNET_SERVER(dhcp6) + }, + + // Insert pool for a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_POOL6, + 7, + { + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT, // 2 end_address - cast as inet + OID_INT8, // 3 subnet_id + OID_VARCHAR, // 4 client_class + OID_TEXT, // 5 require_client_classes + OID_TEXT, // 6 user_context - cast as json + OID_TIMESTAMP // 7 modification_ts + }, + "INSERT_POOL6", + PGSQL_INSERT_POOL(dhcp6) + }, + + // Insert pd pool for a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_PD_POOL, + 10, + { + OID_VARCHAR, // 1 prefix + OID_INT2, // 2 prefix_length + OID_INT2, // 3 delegated_prefix_length + OID_INT8, // 4 subnet_id + OID_VARCHAR, // 5 excluded_prefix + OID_INT2, // 6 excluded_prefix_length + OID_VARCHAR, // 7 client_class + OID_TEXT, // 8 require_client_classes + OID_TEXT, // 9 user_context - cast as json + OID_TIMESTAMP, // 10 modification_ts + }, + "INSERT_PD_POOL", + PGSQL_INSERT_PD_POOL() + }, + + // Insert a shared network. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6, + 33, + { + OID_VARCHAR, // 1 name + OID_VARCHAR, // 2 client_class + OID_VARCHAR, // 3 interface + OID_TIMESTAMP, // 4 modification_ts + OID_INT8, // 5 preferred_lifetime + OID_INT8, // 6 min_preferred_lifetime + OID_INT8, // 7 max_preferred_lifetime + OID_BOOL, // 8 rapid_commit + OID_INT8, // 9 rebind_timer + OID_TEXT, // 10 relay + OID_INT8, // 11 renew_timer + OID_TEXT, // 12 require_client_classes + OID_BOOL, // 13 reservations_global + OID_TEXT, // 14 user_context - cast as json + OID_INT8, // 15 valid_lifetime + OID_INT8, // 16 min_valid_lifetime + OID_INT8, // 17 max_valid_lifetime + OID_BOOL, // 18 calculate_tee_times + OID_TEXT, // 19 t1_percent - cast as float + OID_TEXT, // 20 t2_percent - cast as float + OID_BYTEA, // 21 interface-id + OID_BOOL, // 22 ddns_send_updates + OID_BOOL, // 23 ddns_override_no_update + OID_BOOL, // 24 ddns_override_client_update + OID_INT8, // 25 ddns_replace_client_name + OID_VARCHAR, // 26 ddns_generated_prefix + OID_VARCHAR, // 27 ddns_qualifying_suffix + OID_BOOL, // 28 reservations_in_subnet + OID_BOOL, // 29 reservations_out_of_pool + OID_TEXT, // 30 cache_threshold - cast as float + OID_INT8, // 31 cache_max_age + OID_VARCHAR, // 32 allocator + OID_VARCHAR // 33 pd_allocator + }, + "INSERT_SHARED_NETWORK6", + "INSERT INTO dhcp6_shared_network(" + " name," + " client_class," + " interface," + " modification_ts," + " preferred_lifetime," + " min_preferred_lifetime," + " max_preferred_lifetime," + " rapid_commit," + " rebind_timer," + " relay," + " renew_timer," + " require_client_classes," + " reservations_global," + " user_context," + " valid_lifetime," + " min_valid_lifetime," + " max_valid_lifetime," + " calculate_tee_times," + " t1_percent," + " t2_percent," + " interface_id," + " ddns_send_updates," + " ddns_override_no_update," + " ddns_override_client_update," + " ddns_replace_client_name," + " ddns_generated_prefix," + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool," + " cache_threshold," + " cache_max_age," + " allocator," + " pd_allocator" + ") VALUES (" + " $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, " + " $11, $12, $13, cast($14 as json), $15, $16, $17, $18," + " cast($19 as float), cast($20 as float), $21, $22, $23," + " $24, $25, $26, $27, $28, $29, cast($30 as float), $31, $32, $33" + ")" + }, + + // Insert association of the shared network with a server. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER, + 3, + { + OID_VARCHAR, // 1 shared_network_name + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_SHARED_NETWORK6_SERVER", + PGSQL_INSERT_SHARED_NETWORK_SERVER(dhcp6) + }, + + // Insert option definition. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6, + 10, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_VARCHAR, // 9 user_context + OID_INT8 // 10 class_id + }, + "INSERT_OPTION_DEF6", + PGSQL_INSERT_OPTION_DEF(dhcp6) + }, + + // Insert option definition for client class. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS, + 10, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_VARCHAR, // 9 user_context + OID_VARCHAR // 10 class name for where clause + }, + "INSERT_OPTION_DEF6_CLIENT_CLASS", + PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp6) + }, + + // Insert association of the option definition with a server. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER, + 3, + { + OID_INT8, // 1 option_def_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_OPTION_DEF6_SERVER", + PGSQL_INSERT_OPTION_DEF_SERVER(dhcp6) + }, + + // Insert subnet specific option. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6, + 14, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8 // 14 pd_pool_id + }, + "INSERT_OPTION6", + PGSQL_INSERT_OPTION6() + }, + + // Insert association of the DHCP option with a server. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER, + 3, + { + OID_INT8, // 1 option_id + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_OPTION6_SERVER", + PGSQL_INSERT_OPTION_SERVER(dhcp6) + }, + + // Insert client class. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6, + 13, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 test + OID_BOOL, // 3 only_if_required + OID_INT8, // 4 valid_lifetime + OID_INT8, // 5 min_valid_lifetime + OID_INT8, // 6 max_valid_lifetime + OID_BOOL, // 7 depend_on_known_directly + OID_VARCHAR, // 8 follow_class_name + OID_INT8, // 9 preferred_lifetime + OID_INT8, // 10 min_preferred_lifetime + OID_INT8, // 11 max_preferred_lifetime + OID_TIMESTAMP, // 12 modification_ts + OID_TEXT // 13 user_context cast as JSON + }, + "INSERT_CLIENT_CLASS6", + "INSERT INTO dhcp6_client_class(" + " name," + " test," + " only_if_required," + " valid_lifetime," + " min_valid_lifetime," + " max_valid_lifetime," + " depend_on_known_directly," + " follow_class_name," + " preferred_lifetime," + " min_preferred_lifetime," + " max_preferred_lifetime," + " modification_ts," + " user_context " + ") VALUES (" + " $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, cast($13 as JSON)" + ")" + }, + + // Insert association of a client class with a server. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER, + 3, + { + OID_VARCHAR, // 1 class_name + OID_TIMESTAMP, // 2 modification_ts + OID_VARCHAR // 3 server_tag + }, + "INSERT_CLIENT_CLASS6_SERVER", + PGSQL_INSERT_CLIENT_CLASS_SERVER(dhcp6) + }, + + // Insert client class dependency. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY, + 2, + { + OID_VARCHAR, // class name + OID_VARCHAR // dependency class name + }, + "INSERT_CLIENT_CLASS6_DEPENDENCY", + PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp6) + }, + + // Insert server with server tag and description. + { + // PgSqlConfigBackendDHCPv6Impl::INSERT_SERVER6, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR, // 2 description + OID_TIMESTAMP // 3 modification_ts + }, + "INSERT_SERVER6", + PGSQL_INSERT_SERVER(dhcp6) + }, + + // Update existing global parameter. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6, + 6, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 value + OID_INT2, // 3 parameter_type + OID_TIMESTAMP, // 4 modification_ts + OID_VARCHAR, // 5 server_tag + OID_VARCHAR, // 6 name (of global to update) + }, + "UPDATE_GLOBAL_PARAMETER6", + PGSQL_UPDATE_GLOBAL_PARAMETER(dhcp6) + }, + + // Update existing subnet. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6, + 37, + { + OID_INT8, // 1 subnet_id, + OID_VARCHAR, // 2 subnet_prefix + OID_VARCHAR, // 3 client_class + OID_VARCHAR, // 4 interface + OID_TIMESTAMP, // 5 modification_ts + OID_INT8, // 6 preferred_lifetime + OID_INT8, // 7 min_preferred_lifetime + OID_INT8, // 8 max_preferred_lifetime + OID_BOOL, // 9 rapid_commit + OID_INT8, // 10 rebind_timer + OID_TEXT, // 11 relay + OID_INT8, // 12 renew_timer + OID_TEXT, // 13 require_client_classes + OID_BOOL, // 14 reservations_global + OID_VARCHAR, // 15 shared_network_name + OID_TEXT, // 16 user_context - cast as json + OID_INT8, // 17 valid_lifetime + OID_INT8, // 18 min_valid_lifetime + OID_INT8, // 19 max_valid_lifetime + OID_BOOL, // 20 calculate_tee_times + OID_TEXT, // 21 t1_percent - cast as float + OID_TEXT, // 22 t2_percent - cast as float + OID_BYTEA, // 23 interface_id + OID_BOOL, // 24 ddns_send_updates + OID_BOOL, // 25 ddns_override_no_update + OID_BOOL, // 26 ddns_override_client_update + OID_INT8, // 27 ddns_replace_client_name + OID_VARCHAR, // 28 ddns_generated_prefix + OID_VARCHAR, // 29 ddns_qualifying_suffix + OID_BOOL, // 30 reservations_in_subnet + OID_BOOL, // 31 reservations_out_of_pool + OID_TEXT, // 32 cache_threshold - cast as float + OID_INT8, // 33 cache_max_age + OID_VARCHAR, // 34 allocator + OID_VARCHAR // 35 pd_allocator + }, + "UPDATE_SUBNET6", + "UPDATE dhcp6_subnet SET" + " subnet_id = $1," + " subnet_prefix = $2," + " client_class = $3," + " interface = $4," + " modification_ts = $5," + " preferred_lifetime = $6," + " min_preferred_lifetime = $7," + " max_preferred_lifetime = $8," + " rapid_commit = $9," + " rebind_timer = $10," + " relay = $11," + " renew_timer = $12," + " require_client_classes = $13," + " reservations_global = $14," + " shared_network_name = $15," + " user_context = cast($16 as json)," + " valid_lifetime = $17," + " min_valid_lifetime = $18," + " max_valid_lifetime = $19," + " calculate_tee_times = $20," + " t1_percent = cast($21 as float)," + " t2_percent = cast($22 as float)," + " interface_id = $23," + " ddns_send_updates = $24," + " ddns_override_no_update = $25," + " ddns_override_client_update = $26," + " ddns_replace_client_name = $27," + " ddns_generated_prefix = $28," + " ddns_qualifying_suffix = $29," + " reservations_in_subnet = $30," + " reservations_out_of_pool = $31," + " cache_threshold = cast($32 as float)," + " cache_max_age = $33," + " allocator = $34," + " pd_allocator = $35 " + "WHERE subnet_id = $36 OR subnet_prefix = $37" + }, + + // Update existing shared network. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6, + 34, + { + OID_VARCHAR, // 1 name + OID_VARCHAR, // 2 client_class + OID_VARCHAR, // 3 interface + OID_TIMESTAMP, // 4 modification_ts + OID_INT8, // 5 preferred_lifetime + OID_INT8, // 6 min_preferred_lifetime + OID_INT8, // 7 max_preferred_lifetime + OID_BOOL, // 8 rapid_commit + OID_INT8, // 9 rebind_timer + OID_TEXT, // 10 relay + OID_INT8, // 11 renew_timer + OID_TEXT, // 12 require_client_classes + OID_BOOL, // 13 reservations_global + OID_TEXT, // 14 user_context - cast as json + OID_INT8, // 15 valid_lifetime + OID_INT8, // 16 min_valid_lifetime + OID_INT8, // 17 max_valid_lifetime + OID_BOOL, // 18 calculate_tee_times + OID_TEXT, // 19 t1_percent - cast as float + OID_TEXT, // 20 t2_percent - cast as float + OID_BYTEA, // 21 interface-id + OID_BOOL, // 22 ddns_send_updates + OID_BOOL, // 23 ddns_override_no_update + OID_BOOL, // 24 ddns_override_client_update + OID_INT8, // 25 ddns_replace_client_name + OID_VARCHAR, // 26 ddns_generated_prefix + OID_VARCHAR, // 27 ddns_qualifying_suffix + OID_BOOL, // 28 reservations_in_subnet + OID_BOOL, // 29 reservations_out_of_pool + OID_TEXT, // 30 cache_threshold - cast as float + OID_INT8, // 31 cache_max_age + OID_VARCHAR, // 32 allocator + OID_VARCHAR // 33 pd_allocator + }, + "UPDATE_SHARED_NETWORK6", + "UPDATE dhcp6_shared_network SET" + " name = $1," + " client_class = $2," + " interface = $3," + " modification_ts = $4," + " preferred_lifetime = $5," + " min_preferred_lifetime = $6," + " max_preferred_lifetime = $7," + " rapid_commit = $8," + " rebind_timer = $9," + " relay = $10," + " renew_timer = $11," + " require_client_classes = $12," + " reservations_global = $13," + " user_context = cast($14 as json)," + " valid_lifetime = $15," + " min_valid_lifetime = $16," + " max_valid_lifetime = $17," + " calculate_tee_times = $18," + " t1_percent = cast($19 as float)," + " t2_percent = cast($20 as float)," + " interface_id = $21," + " ddns_send_updates = $22," + " ddns_override_no_update = $23," + " ddns_override_client_update = $24," + " ddns_replace_client_name = $25," + " ddns_generated_prefix = $26," + " ddns_qualifying_suffix = $27," + " reservations_in_subnet = $28," + " reservations_out_of_pool = $29," + " cache_threshold = cast($30 as float)," + " cache_max_age = $31," + " allocator = $32," + " pd_allocator = $33 " + "WHERE name = $34" + }, + + // Update existing option definition. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6, + 13, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_TEXT, // 9 user_context + OID_INT2, // 10 class_id + OID_VARCHAR, // 11 server_tag + OID_INT2, // 12 code (of option to update) + OID_VARCHAR, // 13 space (of option to update) + }, + "UPDATE_OPTION_DEF6", + PGSQL_UPDATE_OPTION_DEF(dhcp6) + }, + + // Update existing client class option definition. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS, + 13, + { + OID_INT2, // 1 code + OID_VARCHAR, // 2 name + OID_VARCHAR, // 3 space + OID_INT2, // 4 type + OID_TIMESTAMP, // 5 modification_ts + OID_BOOL, // 6 is_array + OID_VARCHAR, // 7 encapsulate + OID_VARCHAR, // 8 record_types + OID_TEXT, // 9 user_context + OID_VARCHAR, // 10 name (of class option belongs to) + OID_VARCHAR, // 11 server_tag + OID_INT2, // 12 code (of option to update) + OID_VARCHAR, // 13 space (of option to update) + }, + "UPDATE_OPTION_DEF6_CLIENT_CLASS", + PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp6) + }, + + // Update existing global option. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, + 17, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pd_pool_id + OID_VARCHAR, // 15 server_tag + OID_INT2, // 16 code (of option to update) + OID_VARCHAR, // 17 space (of option to update) + }, + "UPDATE_OPTION6", + PGSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = $16 AND o.space = $17) + }, + + // Update existing subnet level option. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, + 17, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pd_pool_id + OID_INT8, // 15 subnet_id (of option to update) + OID_INT2, // 16 code (of option to update) + OID_VARCHAR // 17 space (of option to update) + }, + "UPDATE_OPTION6_SUBNET_ID", + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = $15 AND o.code = $16 AND o.space = $17) + }, + + // Update existing pool level option. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID, + 17, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pd_pool_id + OID_INT8, // 15 pool_id (of option to update) + OID_INT2, // 16 code (of option to update) + OID_VARCHAR // 17 space (of option to update) + }, + "UPDATE_OPTION6_POOL_ID", + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = $15 AND o.code = $16 AND o.space = $17) + }, + + // Update existing pd pool level option. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID, + 17, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pd_pool_id + OID_INT8, // 15 pd_pool_id (of option to update) + OID_INT2, // 16 code (of option to update) + OID_VARCHAR // 17 space (of option to update) + }, + "UPDATE_OPTION6_PD_POOL_ID", + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = $15 AND o.code = $16 AND o.space = $17) + }, + + // Update existing shared network level option. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK, + 17, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pd_pool_id + OID_VARCHAR, // 15 shared_network_name (of option to update) + OID_INT2, // 16 code (of option to update) + OID_VARCHAR // 17 space (of option to update) + }, + "UPDATE_OPTION6_SHARED_NETWORK", + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $15 AND o.code = $16 AND o.space = $17) + }, + + // Update existing client class level option. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS, + 17, + { + OID_INT2, // 1 code + OID_BYTEA, // 2 value + OID_TEXT, // 3 formatted_value + OID_VARCHAR, // 4 space + OID_BOOL, // 5 persistent + OID_BOOL, // 6 cancelled + OID_VARCHAR, // 7 dhcp_client_class + OID_INT8, // 8 dhcp6_subnet_id + OID_INT2, // 9 scope_id + OID_TEXT, // 10 user_context + OID_VARCHAR, // 11 shared_network_name + OID_INT8, // 12 pool_id + OID_TIMESTAMP, // 13 modification_ts + OID_INT8, // 14 pd_pool_id + OID_VARCHAR, // 15 client_class (of option to update) + OID_INT2, // 16 code (of option to update) + OID_VARCHAR // 17 space (of option to update) + }, + "UPDATE_OPTION6_CLIENT_CLASS", + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $15 AND o.code = $16 AND o.space = $17) + }, + + // Update existing client class with specifying its position. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6, + 14, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 test + OID_BOOL, // 3 only_if_required + OID_INT8, // 4 valid_lifetime + OID_INT8, // 5 min_valid_lifetime + OID_INT8, // 6 max_valid_lifetime + OID_BOOL, // 7 depend_on_known_directly + OID_VARCHAR, // 8 follow_class_name + OID_INT8, // 9 preferred_lifetime + OID_INT8, // 10 min_preferred_lifetime + OID_INT8, // 11 max_preferred_lifetime + OID_TIMESTAMP, // 12 modification_ts + OID_TEXT, // 13 user_context + OID_VARCHAR // 14 name (of class to update) + }, + "UPDATE_CLIENT_CLASS6", + PGSQL_UPDATE_CLIENT_CLASS6("follow_class_name = $8,") + }, + + // Update existing client class without specifying its position. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6_SAME_POSITION, + 14, + { + OID_VARCHAR, // 1 name + OID_TEXT, // 2 test + OID_BOOL, // 3 only_if_required + OID_INT8, // 4 valid_lifetime + OID_INT8, // 5 min_valid_lifetime + OID_INT8, // 6 max_valid_lifetime + OID_BOOL, // 7 depend_on_known_directly + OID_VARCHAR, // 8 follow_class_name + OID_INT8, // 9 preferred_lifetime + OID_INT8, // 10 min_preferred_lifetime + OID_INT8, // 11 max_preferred_lifetime + OID_TIMESTAMP, // 12 modification_ts + OID_TEXT, // 13 user_context + OID_VARCHAR // 14 name (of class to update) + }, + "UPDATE_CLIENT_CLASS6_SAME_POSITION", + PGSQL_UPDATE_CLIENT_CLASS6("") + }, + + // Update existing server, e.g. server description. + { + // PgSqlConfigBackendDHCPv6Impl::UPDATE_SERVER6, + 4, + { + OID_VARCHAR, // 1 tag + OID_VARCHAR, // 2 description + OID_TIMESTAMP, // 3 modification_ts + OID_VARCHAR // 4 tag (of server to update) + }, + "UPDATE_SERVER6", + PGSQL_UPDATE_SERVER(dhcp6) + }, + + // Delete global parameter by name. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 name of parameter + }, + "DELETE_GLOBAL_PARAMETER6", + PGSQL_DELETE_GLOBAL_PARAMETER(dhcp6, AND g.name = $2) + }, + + // Delete all global parameters. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_GLOBAL_PARAMETERS6", + PGSQL_DELETE_GLOBAL_PARAMETER(dhcp6) + }, + + // Delete all global parameters which are unassigned to any servers. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED", + PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp6) + }, + + // Delete subnet by id with specifying server tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_INT8 // 2 subnet_id + }, + "DELETE_SUBNET6_ID_WITH_TAG", + PGSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_id = $2) + }, + + // Delete subnet by id without specifying server tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY, + 1, + { + OID_INT8 // 1 subnet_id + }, + "DELETE_SUBNET6_ID_ANY", + PGSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_id = $1) + }, + + // Delete subnet by prefix with specifying server tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_SUBNET6_PREFIX_WITH_TAG", + PGSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_prefix = $2) + }, + + // Delete subnet by prefix without specifying server tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY, + 1, + { + OID_VARCHAR // 1 subnet_prefix + }, + "DELETE_SUBNET6_PREFIX_ANY", + PGSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_prefix = $1) + }, + + // Delete all subnets. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_SUBNETS6", + PGSQL_DELETE_SUBNET_WITH_TAG(dhcp6) + }, + + // Delete all unassigned subnets. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_SUBNETS6_UNASSIGNED", + PGSQL_DELETE_SUBNET_UNASSIGNED(dhcp6) + }, + + // Delete all subnets for a shared network. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME, + 1, + { + OID_VARCHAR // 1 shared_network_name + }, + "DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME", + PGSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.shared_network_name = $1) + }, + + // Delete associations of a subnet with server. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER, + 1, + { + OID_INT8 // 1 subnet_id + }, + "DELETE_SUBNET6_SERVER", + PGSQL_DELETE_SUBNET_SERVER(dhcp6), + }, + + // Delete pools for a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_POOLS6, + 2, + { + OID_INT8, // 1 subnet_id + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_POOLS6", + PGSQL_DELETE_POOLS(dhcp6) + }, + + // Delete pd pools for a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_PD_POOLS, + 2, + { + OID_INT8, // 1 subnet_id + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_PD_POOLS", + PGSQL_DELETE_PD_POOLS() + }, + + // Delete shared network by name with specifying server tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 shared_network_name + }, + "DELETE_SHARED_NETWORK6_NAME_WITH_TAG", + PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6, AND n.name = $2) + }, + + // Delete shared network by name without specifying server tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY, + 1, + { + OID_VARCHAR // 1 shared_network_name + }, + "DELETE_SHARED_NETWORK6_NAME_ANY", + PGSQL_DELETE_SHARED_NETWORK_ANY(dhcp6, WHERE n.name = $1) + }, + + // Delete all shared networks. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_SHARED_NETWORKS6", + PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6) + }, + + // Delete all unassigned shared networks. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED", + PGSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp6) + }, + + // Delete associations of a shared network with server. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER, + 1, + { + OID_VARCHAR // 1 shared_network_name + }, + "DELETE_SHARED_NETWORK6_SERVER", + PGSQL_DELETE_SHARED_NETWORK_SERVER(dhcp6) + }, + + // Delete option definition. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEF6_CODE_NAME, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION_DEF6_CODE_NAME", + PGSQL_DELETE_OPTION_DEF(dhcp6, AND code = $2 AND space = $3) + }, + + // Delete all option definitions. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_OPTION_DEFS6", + PGSQL_DELETE_OPTION_DEF(dhcp6) + }, + + // Delete all option definitions which are assigned to no servers. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_OPTION_DEFS6_UNASSIGNED", + PGSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp6) + }, + + // Delete client class specific option definitions. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEFS6_CLIENT_CLASS, + 1, + { + OID_VARCHAR // 1 class name + }, + "DELETE_OPTION_DEFS6_CLIENT_CLASS", + PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp6) + }, + + // Delete single global option. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6, + 3, + { + OID_VARCHAR, // 1 server_tag + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION6", + PGSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = $2 AND o.space = $3) + }, + + // Delete all global options which are unassigned to any servers. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED", + PGSQL_DELETE_OPTION_UNASSIGNED(dhcp6, AND o.scope_id = 0) + }, + + // Delete single option from a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID, + 3, + { + OID_INT8, // 1 subnet_id + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION6_SUBNET_ID", + PGSQL_DELETE_OPTION_NO_TAG(dhcp6, + WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = $1 AND o.code = $2 AND o.space = $3) + }, + + // Delete single option from a pool. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE, + 4, + { + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT, // 2 start_address - cast as inet + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "DELETE_OPTION6_POOL_RANGE", + PGSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = $3 AND o.space = $4) + }, + + // Delete single option from a pd pool. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL, + 4, + { + OID_TEXT, // 1 prefix + OID_INT2, // 2 prefix_length + OID_INT2, // 3 code + OID_VARCHAR // 4 space + }, + "DELETE_OPTION6_PD_POOL", + PGSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = $3 AND o.space = $4) + }, + + // Delete single option from a shared network. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK, + 3, + { + OID_VARCHAR, // 1 shared_network_name + OID_INT2, // 2 code + OID_VARCHAR // 3 space + }, + "DELETE_OPTION6_SHARED_NETWORK", + PGSQL_DELETE_OPTION_NO_TAG(dhcp6, + WHERE o.scope_id = 4 AND o.shared_network_name = $1 AND o.code = $2 AND o.space = $3) + }, + + // Delete options belonging to a subnet. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SUBNET_ID_PREFIX, + 2, + { + OID_INT8, // 1 subnet_id + OID_VARCHAR // 2 subnet_prefix + }, + "DELETE_OPTIONS6_SUBNET_ID_PREFIX", + PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX(dhcp6) + }, + + // Delete options belonging to a shared_network. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SHARED_NETWORK, + 1, + { + OID_VARCHAR // shared_network_name + }, + "DELETE_OPTIONS6_SHARED_NETWORK", + PGSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 4 AND o.shared_network_name = $1) + }, + + // Delete options belonging to a client class. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_CLIENT_CLASS, + 1, + { + OID_VARCHAR // dhcp_client_class + }, + "DELETE_OPTIONS6_CLIENT_CLASS", + PGSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 2 AND o.dhcp_client_class = $1) + }, + + // Delete all dependencies of a client class. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY, + 1, + { + OID_VARCHAR, // 1 class name + }, + "DELETE_CLIENT_CLASS6_DEPENDENCY", + PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp6) + }, + + // Delete associations of a client class with server. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER, + 1, + { + OID_VARCHAR // 1 class name + }, + "DELETE_CLIENT_CLASS6_SERVER", + PGSQL_DELETE_CLIENT_CLASS_SERVER(dhcp6), + }, + + // Delete all client classes. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6, + 1, + { + OID_VARCHAR // 1 server_tag + }, + "DELETE_ALL_CLIENT_CLASSES6", + PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6) + }, + + // Delete all unassigned client classes. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED, + 0, + { + OID_NONE + }, + "DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED", + PGSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp6) + }, + + // Delete specified client class. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6, + 2, + { + OID_VARCHAR, // 1 server_tag + OID_VARCHAR // 2 name + }, + "DELETE_CLIENT_CLASS6", + PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6, AND name = $2) + }, + + // Delete any client class with a given name. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY, + 1, + { + OID_VARCHAR // 1 name + }, + "DELETE_CLIENT_CLASS6_ANY", + PGSQL_DELETE_CLIENT_CLASS_ANY(dhcp6, AND name = $1) + }, + + // Delete a server by tag. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_SERVER6, + 1, + { + OID_VARCHAR // server_tag + }, + "DELETE_SERVER6", + PGSQL_DELETE_SERVER(dhcp6) + }, + + // Deletes all servers except logical server 'all'. + { + // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6, + 0, + { + OID_NONE + }, + "DELETE_ALL_SERVERS6", + PGSQL_DELETE_ALL_SERVERS(dhcp6) + }, + + // Fetches the last sequence id for the given table and column. + { + // PgSqlConfigBackendDHCPv6Impl::GET_LAST_INSERT_ID6, + // args are: table name, sequence column name + 2, + { + OID_VARCHAR, + OID_VARCHAR + }, + "GET_LAST_INSERT_ID6", + "SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE($1, $2))" + } +} +}; + +} // end anonymous namespace + +PgSqlConfigBackendDHCPv6Impl::PgSqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap& parameters) + : PgSqlConfigBackendImpl(parameters, &PgSqlConfigBackendDHCPv6Impl::dbReconnect, + PgSqlConfigBackendDHCPv6Impl::GET_LAST_INSERT_ID6) { + // Prepare query statements. Those are will be only used to retrieve + // information from the database, so they can be used even if the + // database is read only for the current user. + conn_.prepareStatements(tagged_statements.begin(), + tagged_statements.end()); +// @todo As part of enabling read-only CB access, statements need to +// be limited: +// tagged_statements.begin() + WRITE_STMTS_BEGIN); + + // Create unique timer name per instance. + timer_name_ = "PgSqlConfigBackend6["; + timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this)); + timer_name_ += "]DbReconnectTimer"; + + // Create ReconnectCtl for this connection. + conn_.makeReconnectCtl(timer_name_); +} + +PgSqlConfigBackendDHCPv6Impl::~PgSqlConfigBackendDHCPv6Impl() { +} + +PgSqlTaggedStatement& +PgSqlConfigBackendDHCPv6Impl::getStatement(size_t index) const { + if (index >= tagged_statements.size()) { + isc_throw(BadValue, "PgSqlConfigBackendDHCPv6Impl::getStatement index: " + << index << ", is invalid"); + } + + return(tagged_statements[index]); +} + +PgSqlConfigBackendDHCPv6::PgSqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters) + : impl_(new PgSqlConfigBackendDHCPv6Impl(parameters)), base_impl_(impl_) { +} + +bool +PgSqlConfigBackendDHCPv6::isUnusable() { + return (impl_->conn_.isUnusable()); +} + +DatabaseConnection::ParameterMap +PgSqlConfigBackendDHCPv6::getParameters() const { + return (impl_->getParameters()); +} + +Subnet6Ptr +PgSqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector, + const std::string& subnet_prefix) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET6_BY_PREFIX) + .arg(subnet_prefix); + return (impl_->getSubnet6(server_selector, subnet_prefix)); +} + +Subnet6Ptr +PgSqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector, + const SubnetID& subnet_id) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID) + .arg(subnet_id); + return (impl_->getSubnet6(server_selector, subnet_id)); +} + +Subnet6Collection +PgSqlConfigBackendDHCPv6::getAllSubnets6(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS6); + Subnet6Collection subnets; + impl_->getAllSubnets6(server_selector, subnets); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS6_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet6Collection +PgSqlConfigBackendDHCPv6::getModifiedSubnets6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS6) + .arg(util::ptimeToText(modification_time)); + Subnet6Collection subnets; + impl_->getModifiedSubnets6(server_selector, modification_time, subnets); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet6Collection +PgSqlConfigBackendDHCPv6::getSharedNetworkSubnets6(const ServerSelector& /* server_selector */, + const std::string& shared_network_name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6) + .arg(shared_network_name); + Subnet6Collection subnets; + impl_->getSharedNetworkSubnets6(ServerSelector::ANY(), shared_network_name, subnets); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT) + .arg(subnets.size()); + return (subnets); +} + +SharedNetwork6Ptr +PgSqlConfigBackendDHCPv6::getSharedNetwork6(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK6) + .arg(name); + return (impl_->getSharedNetwork6(server_selector, name)); +} + +SharedNetwork6Collection +PgSqlConfigBackendDHCPv6::getAllSharedNetworks6(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS6); + SharedNetwork6Collection shared_networks; + impl_->getAllSharedNetworks6(server_selector, shared_networks); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +SharedNetwork6Collection +PgSqlConfigBackendDHCPv6::getModifiedSharedNetworks6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6) + .arg(util::ptimeToText(modification_time)); + SharedNetwork6Collection shared_networks; + impl_->getModifiedSharedNetworks6(server_selector, modification_time, shared_networks); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +OptionDefinitionPtr +PgSqlConfigBackendDHCPv6::getOptionDef6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION_DEF6) + .arg(code).arg(space); + return (impl_->getOptionDef(PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + server_selector, code, space)); +} + +OptionDefContainer +PgSqlConfigBackendDHCPv6::getAllOptionDefs6(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS6); + OptionDefContainer option_defs; + impl_->getAllOptionDefs(PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6, + server_selector, option_defs); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDefContainer +PgSqlConfigBackendDHCPv6::getModifiedOptionDefs6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS6) + .arg(util::ptimeToText(modification_time)); + OptionDefContainer option_defs; + impl_->getModifiedOptionDefs(PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6, + server_selector, modification_time, option_defs); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDescriptorPtr +PgSqlConfigBackendDHCPv6::getOption6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION6) + .arg(code).arg(space); + return (impl_->getOption(PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, + Option::V6, server_selector, code, space)); +} + +OptionContainer +PgSqlConfigBackendDHCPv6::getAllOptions6(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS6); + OptionContainer options = impl_->getAllOptions(PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6, + Option::V6, server_selector); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS6_RESULT) + .arg(options.size()); + return (options); +} + +OptionContainer +PgSqlConfigBackendDHCPv6::getModifiedOptions6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS6) + .arg(util::ptimeToText(modification_time)); + OptionContainer options = impl_->getModifiedOptions(PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6, + Option::V6, server_selector, modification_time); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT) + .arg(options.size()); + return (options); +} + +StampedValuePtr +PgSqlConfigBackendDHCPv6::getGlobalParameter6(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_GLOBAL_PARAMETER6) + .arg(name); + return (impl_->getGlobalParameter6(server_selector, name)); +} + +StampedValueCollection +PgSqlConfigBackendDHCPv6::getAllGlobalParameters6(const ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + impl_->getGlobalParameters(PgSqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6, + in_bindings, parameters); + } + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT) + .arg(parameters.size()); + return (parameters); +} + +StampedValueCollection +PgSqlConfigBackendDHCPv6::getModifiedGlobalParameters6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6) + .arg(util::ptimeToText(modification_time)); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addTimestamp(modification_time); + + impl_->getGlobalParameters(PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6, + in_bindings, parameters); + } + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT) + .arg(parameters.size()); + return (parameters); +} + +ClientClassDefPtr +PgSqlConfigBackendDHCPv6::getClientClass6(const db::ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_CLIENT_CLASS6) + .arg(name); + return (impl_->getClientClass6(server_selector, name)); +} + +ClientClassDictionary +PgSqlConfigBackendDHCPv6::getAllClientClasses6(const db::ServerSelector& server_selector) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES6); + ClientClassDictionary client_classes; + impl_->getAllClientClasses6(server_selector, client_classes); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +ClientClassDictionary +PgSqlConfigBackendDHCPv6::getModifiedClientClasses6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6) + .arg(util::ptimeToText(modification_time)); + ClientClassDictionary client_classes; + impl_->getModifiedClientClasses6(server_selector, modification_time, client_classes); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +AuditEntryCollection +PgSqlConfigBackendDHCPv6::getRecentAuditEntries(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6) + .arg(util::ptimeToText(modification_time)) + .arg(modification_id); + AuditEntryCollection audit_entries; + impl_->getRecentAuditEntries(PgSqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME, + server_selector, modification_time, + modification_id, audit_entries); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT) + .arg(audit_entries.size()); + return (audit_entries); +} + +ServerCollection +PgSqlConfigBackendDHCPv6::getAllServers6() const { + ServerCollection servers; + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS6); + impl_->getAllServers(PgSqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6, + servers); + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS6_RESULT) + .arg(servers.size()); + return (servers); +} + +ServerPtr +PgSqlConfigBackendDHCPv6::getServer6(const data::ServerTag& server_tag) const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SERVER6) + .arg(server_tag.get()); + return (impl_->getServer(PgSqlConfigBackendDHCPv6Impl::GET_SERVER6, server_tag)); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateSubnet6(const ServerSelector& server_selector, + const Subnet6Ptr& subnet) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SUBNET6) + .arg(subnet); + impl_->createUpdateSubnet6(server_selector, subnet); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateSharedNetwork6(const ServerSelector& server_selector, + const SharedNetwork6Ptr& shared_network) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6) + .arg(shared_network->getName()); + impl_->createUpdateSharedNetwork6(server_selector, shared_network); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateOptionDef6(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION_DEF6) + .arg(option_def->getName()).arg(option_def->getCode()); + impl_->createUpdateOptionDef6(server_selector, option_def); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION6); + impl_->createUpdateOption6(server_selector, option); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6) + .arg(shared_network_name); + impl_->createUpdateOption6(server_selector, shared_network_name, option, false); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6) + .arg(subnet_id); + impl_->createUpdateOption6(server_selector, subnet_id, option, false); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6) + .arg(pool_start_address.toText()).arg(pool_end_address.toText()); + impl_->createUpdateOption6(server_selector, pool_start_address, pool_end_address, + option); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const OptionDescriptorPtr& option) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6) + .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length); + impl_->createUpdateOption6(server_selector, pd_pool_prefix, + pd_pool_prefix_length, option); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateGlobalParameter6(const ServerSelector& server_selector, + const StampedValuePtr& value) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6) + .arg(value->getName()); + impl_->createUpdateGlobalParameter6(server_selector, value); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateClientClass6(const db::ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6) + .arg(client_class->getName()); + impl_->createUpdateClientClass6(server_selector, client_class, follow_class_name); +} + +void +PgSqlConfigBackendDHCPv6::createUpdateServer6(const ServerPtr& server) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SERVER6) + .arg(server->getServerTagAsText()); + impl_->createUpdateServer(PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + PgSqlConfigBackendDHCPv6Impl::INSERT_SERVER6, + PgSqlConfigBackendDHCPv6Impl::UPDATE_SERVER6, + server); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET6) + .arg(subnet_prefix); + uint64_t result = impl_->deleteSubnet6(server_selector, subnet_prefix); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6) + .arg(subnet_id); + uint64_t result = impl_->deleteSubnet6(server_selector, subnet_id); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteAllSubnets6(const ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS6); + + int index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets", + "deleted all subnets", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteSharedNetworkSubnets6(const db::ServerSelector& server_selector, + const std::string& shared_network_name) { + if (!server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting all subnets from a shared " + "network requires using ANY server selector"); + } + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6) + .arg(shared_network_name); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME, + server_selector, + "deleting all subnets for a shared network", + "deleted all subnets for a shared network", + true, shared_network_name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteSharedNetwork6(const ServerSelector& server_selector, + const std::string& name) { + /// @todo Using UNASSIGNED selector is allowed by the CB API but we don't have + /// dedicated query for this at the moment. The user should use ANY to delete + /// the shared network by name. + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "deleting an unassigned shared network requires " + "an explicit server tag or using ANY server. The UNASSIGNED server " + "selector is currently not supported"); + } + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK6) + .arg(name); + + int index = (server_selector.amAny() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY : + PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG); + uint64_t result = impl_->deleteTransactional(index, server_selector, + "deleting a shared network", + "shared network deleted", true, name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteAllSharedNetworks6(const ServerSelector& server_selector) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not" + " supported"); + } + + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6); + + int index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks", + "deleted all shared networks", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteOptionDef6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF6) + .arg(code).arg(space); + uint64_t result = impl_->deleteOptionDef6(server_selector, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteAllOptionDefs6(const ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS6); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6, + server_selector, "deleting all option definitions", + "deleted all option definitions", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION6) + .arg(code).arg(space); + uint64_t result = impl_->deleteOption6(server_selector, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space) { + /// @todo In the future we might use the server selector to make sure that the + /// option is only deleted if the pool belongs to a given server. For now, we + /// just delete it when there is a match with the parent object. + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6) + .arg(shared_network_name).arg(code).arg(space); + uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), shared_network_name, + code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space) { + /// @todo In the future we might use the server selector to make sure that the + /// option is only deleted if the pool belongs to a given server. For now, we + /// just delete it when there is a match with the parent object. + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6) + .arg(subnet_id).arg(code).arg(space); + uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const uint16_t code, + const std::string& space) { + /// @todo In the future we might use the server selector to make sure that the + /// option is only deleted if the pool belongs to a given server. For now, we + /// just delete it when there is a match with the parent object. + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION6) + .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space); + uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pool_start_address, + pool_end_address, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6) + .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length).arg(code).arg(space); + uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pd_pool_prefix, + pd_pool_prefix_length, code, space); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteGlobalParameter6(const ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER6) + .arg(name); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6, + server_selector, "deleting global parameter", + "global parameter deleted", false, name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteAllGlobalParameters6(const ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6); + uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6, + server_selector, "deleting all global parameters", + "all global parameters deleted", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteClientClass6(const db::ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS6) + .arg(name); + auto result = impl_->deleteClientClass6(server_selector, name); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteAllClientClasses6(const db::ServerSelector& server_selector) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6); + + int index = (server_selector.amUnassigned() ? + PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED : + PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes", + "deleted all client classes", true); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteServer6(const ServerTag& server_tag) { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER6) + .arg(server_tag.get()); + uint64_t result = impl_->deleteServer6(server_tag); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER6_RESULT) + .arg(result); + return (result); +} + +uint64_t +PgSqlConfigBackendDHCPv6::deleteAllServers6() { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS6); + uint64_t result = impl_->deleteAllServers6(); + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS6_RESULT) + .arg(result); + return (result); +} + +std::string +PgSqlConfigBackendDHCPv6::getType() const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_TYPE6); + return (impl_->getType()); +} + +std::string +PgSqlConfigBackendDHCPv6::getHost() const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_HOST6); + return (impl_->getHost()); +} + +uint16_t +PgSqlConfigBackendDHCPv6::getPort() const { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_PORT6); + return (impl_->getPort()); +} + +bool +PgSqlConfigBackendDHCPv6::registerBackendType() { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_REGISTER_BACKEND_TYPE6); + return ( + dhcp::ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("postgresql", + [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv6Ptr { + return (dhcp::PgSqlConfigBackendDHCPv6Ptr(new dhcp::PgSqlConfigBackendDHCPv6(params))); + }) + ); +} + +void +PgSqlConfigBackendDHCPv6::unregisterBackendType() { + LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_UNREGISTER_BACKEND_TYPE6); + dhcp::ConfigBackendDHCPv6Mgr::instance().unregisterBackendFactory("postgresql"); +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h new file mode 100644 index 0000000..e3f08f5 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h @@ -0,0 +1,664 @@ +// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PGSQL_CONFIG_BACKEND_DHCP6_H +#define PGSQL_CONFIG_BACKEND_DHCP6_H + +#include <pgsql_cb_impl.h> +#include <database/database_connection.h> +#include <dhcpsrv/client_class_def.h> +#include <dhcpsrv/config_backend_dhcp6.h> +#include <pgsql_cb_log.h> +#include <boost/shared_ptr.hpp> + +namespace isc { +namespace dhcp { + +class PgSqlConfigBackendDHCPv6Impl; + +/// @brief Implementation of the PgSql Configuration Backend for +/// Kea DHCPv6 server. +/// +/// All POSIX times specified in the methods belonging to this +/// class must be local times. +/// +/// The server selection mechanisms used by this backend generally adhere +/// to the rules described for @c ConfigBackendDHCPv6, but support for +/// some of the selectors is not implemented. Whenever this is the case, +/// the methods throw @c isc::NotImplemented exception. +class PgSqlConfigBackendDHCPv6 : public ConfigBackendDHCPv6 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit PgSqlConfigBackendDHCPv6(const db::DatabaseConnection::ParameterMap& parameters); + + /// @brief Retrieves a single subnet by subnet_prefix. + /// + /// @param server_selector Server selector. + /// @param subnet_prefix Prefix of the subnet to be retrieved. + /// @return Pointer to the retrieved subnet or NULL if not found. + virtual Subnet6Ptr + getSubnet6(const db::ServerSelector& server_selector, + const std::string& subnet_prefix) const; + + /// @brief Retrieves a single subnet by subnet identifier. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of a subnet to be retrieved. + /// @return Pointer to the retrieved subnet or NULL if not found. + virtual Subnet6Ptr + getSubnet6(const db::ServerSelector& server_selector, const SubnetID& subnet_id) const; + + /// @brief Retrieves all subnets. + /// + /// @param server_selector Server selector. + /// @return Collection of subnets or empty collection if no subnet found. + virtual Subnet6Collection + getAllSubnets6(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves subnets modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound subnet modification time. + /// @return Collection of subnets or empty collection if no subnet found. + virtual Subnet6Collection + getModifiedSubnets6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves all subnets belonging to a specified shared network. + /// + /// The server selector is currently ignored by this method. All subnets + /// for the given shared network are returned regardless of their + /// associations with the servers. + /// + /// @param server_selector Server selector (currently ignored). + /// @param shared_network_name Name of the shared network for which the + /// subnets should be retrieved. + /// @return Collection of subnets or empty collection if no subnet found. + virtual Subnet6Collection + getSharedNetworkSubnets6(const db::ServerSelector& server_selector, + const std::string& shared_network_name) const; + + /// @brief Retrieves shared network by name. + /// + /// @param server_selector Server selector. + /// @param name Name of the shared network to be retrieved. + /// @return Pointer to the shared network or NULL if not found. + /// @throw NotImplemented if server selector is "unassigned". + virtual SharedNetwork6Ptr + getSharedNetwork6(const db::ServerSelector& server_selector, + const std::string& name) const; + + /// @brief Retrieves all shared networks. + /// + /// @param server_selector Server selector. + /// @return Collection of shared network or empty collection if + /// no shared network found. + virtual SharedNetwork6Collection + getAllSharedNetworks6(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves shared networks modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound shared network modification time. + /// @return Collection of shared network or empty collection if + /// no shared network found. + virtual SharedNetwork6Collection + getModifiedSharedNetworks6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves single option definition by code and space. + /// + /// @param server_selector Server selector. + /// @param code Code of the option to be retrieved. + /// @param space Option space of the option to be retrieved. + /// @return Pointer to the option definition or NULL if not found. + /// @throw NotImplemented if server selector is "unassigned". + virtual OptionDefinitionPtr + getOptionDef6(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space) const; + + /// @brief Retrieves all option definitions. + /// + /// @param server_selector Server selector. + /// @return Collection of option definitions or empty collection if + /// no option definition found. + virtual OptionDefContainer + getAllOptionDefs6(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves option definitions modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound option definition modification + /// time. + /// @return Collection of option definitions or empty collection if + /// no option definition found. + virtual OptionDefContainer + getModifiedOptionDefs6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves single option by code and space. + /// + /// @param server_selector Server selector. + /// @return Pointer to the retrieved option descriptor or null if + /// no option was found. + /// @throw NotImplemented if server selector is "unassigned". + virtual OptionDescriptorPtr + getOption6(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space) const; + + /// @brief Retrieves all global options. + /// + /// @param server_selector Server selector. + /// @return Collection of global options or empty collection if no + /// option found. + virtual OptionContainer + getAllOptions6(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves option modified after specified time. + /// + /// @param server_selector Server selector. + /// @param modification_time Lower bound option modification time. + /// @return Collection of global options or empty collection if no + /// option found. + virtual OptionContainer + getModifiedOptions6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves global parameter value. + /// + /// Typically, the server selector used for this query should be set to + /// ONE. It is possible to use the MULTIPLE server selector but in that + /// case only the first found parameter is returned. + /// + /// @param server_selector Server selector. + /// @param name Name of the global parameter to be retrieved. + /// @return Value of the global parameter. + /// @throw NotImplemented if server selector is "unassigned". + virtual data::StampedValuePtr + getGlobalParameter6(const db::ServerSelector& server_selector, + const std::string& name) const; + + /// @brief Retrieves all global parameters. + /// + /// Using the server selector it is possible to fetch the parameters for + /// one or more servers. The following list describes what parameters are + /// returned depending on the server selector specified: + /// - ALL: only common parameters are returned which are associated with + /// the logical server 'all'. No parameters associated with the explicit + /// server tags are returned. + /// + /// - ONE: parameters used by the particular sever are returned. This includes + /// parameters associated with the particular server (identified by tag) + /// and parameters associated with the logical server 'all' when server + /// specific parameters are not given. For example, if there is a + /// renew-timer specified for 'server1' tag, different value of the + /// renew-timer specified for 'all' servers and a rebind-timer specified + /// for 'all' servers, the caller will receive renew-timer value associated + /// with the server1 and the rebind-timer value associated with all servers, + /// because there is no explicit rebind-timer specified for server1. + /// + /// - MULTIPLE: parameters used by multiple servers, but those associated + /// with specific server tags take precedence over the values specified for + /// 'all' servers. This is similar to the case of ONE server described + /// above. The effect of querying for parameters belonging to multiple + /// servers is the same as issuing multiple queries with ONE server + /// being selected multiple times. + /// + /// - UNASSIGNED: parameters not associated with any servers. + /// + /// + /// @param server_selector Server selector. + virtual data::StampedValueCollection + getAllGlobalParameters6(const db::ServerSelector& server_selector) const; + + /// @brief Retrieves global parameters modified after specified time. + /// + /// @param modification_time Lower bound modification time. + /// @return Collection of modified global parameters. + virtual data::StampedValueCollection + getModifiedGlobalParameters6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves a client class by name. + /// + /// @param server_selector Server selector. + /// @param name Client class name. + /// @return Pointer to the retrieved client class. + virtual ClientClassDefPtr + getClientClass6(const db::ServerSelector& selector, const std::string& name) const; + + /// @brief Retrieves all client classes. + /// + /// @param selector Server selector. + /// @return Collection of client classes. + virtual ClientClassDictionary + getAllClientClasses6(const db::ServerSelector& selector) const; + + /// @brief Retrieves client classes modified after specified time. + /// + /// @param selector Server selector. + /// @param modification_time Modification time. + /// @return Collection of client classes. + virtual ClientClassDictionary + getModifiedClientClasses6(const db::ServerSelector& selector, + const boost::posix_time::ptime& modification_time) const; + + /// @brief Retrieves the most recent audit entries. + /// + /// @param selector Server selector. + /// @param modification_time Timestamp being a lower limit for the returned + /// result set, i.e. entries later than specified time are returned. + /// @param modification_id Identifier being a lower limit for the returned + /// result set, used when two (or more) entries have the same + /// modification_time. + /// @return Collection of audit entries. + virtual db::AuditEntryCollection + getRecentAuditEntries(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id) const; + + /// @brief Retrieves all servers. + /// + /// This method returns the list of servers excluding the logical server + /// 'all'. + /// + /// @return Collection of servers from the backend. + virtual db::ServerCollection + getAllServers6() const; + + /// @brief Retrieves a server. + /// + /// @param server_tag Tag of the server to be retrieved. + /// @return Pointer to the server instance or null pointer if no server + /// with the particular tag was found. + virtual db::ServerPtr + getServer6(const data::ServerTag& server_tag) const; + + /// @brief Creates or updates a subnet. + /// + /// @param server_selector Server selector. + /// @param subnet Subnet to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateSubnet6(const db::ServerSelector& server_selector, + const Subnet6Ptr& subnet); + + /// @brief Creates or updates a shared network. + /// + /// @param server_selector Server selector. + /// @param shared_network Shared network to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateSharedNetwork6(const db::ServerSelector& server_selector, + const SharedNetwork6Ptr& shared_network); + + /// @brief Creates or updates an option definition. + /// + /// @param server_selector Server selector. + /// @param option_def Option definition to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOptionDef6(const db::ServerSelector& server_selector, + const OptionDefinitionPtr& option_def); + + /// @brief Creates or updates global option. + /// + /// @param server_selector Server selector. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption6(const db::ServerSelector& server_selector, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates shared network level option. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of a shared network to which option + /// belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption6(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates subnet level option. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of a subnet to which option belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption6(const db::ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the pool to which + /// the option belongs. + /// @param pool_end_address Upper bound address of the pool to which the + /// option belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption6(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates prefix delegation pool level option. + /// + /// @param server_selector Server selector. + /// @param pd_pool_prefix Address part of the prefix of the prefix + /// delegation pool to which the option belongs. + /// @param pd_pool_prefix_length Prefix length of the prefix + /// delegation pool to which the option belongs. + /// @param option Option to be added or updated. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateOption6(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const OptionDescriptorPtr& option); + + /// @brief Creates or updates global parameter. + /// + /// @param server_selector Server selector. + /// @param name Name of the global parameter. + /// @param value Value of the global parameter. + /// @throw NotImplemented if server selector is "unassigned". + virtual void + createUpdateGlobalParameter6(const db::ServerSelector& server_selector, + const data::StampedValuePtr& value); + + /// @brief Creates or updates DHCPv6 client class. + /// + /// @param server_selector Server selector. + /// @param client_class Client class to be added or updated. + /// @param follow_class_name name of the class after which the + /// new or updated class should be positioned. An empty value + /// causes the class to be appended at the end of the class + /// hierarchy. + virtual void + createUpdateClientClass6(const db::ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name); + + /// @brief Creates or updates a server. + /// + /// @param server Instance of the server to be stored. + /// @throw InvalidOperation when trying to create a duplicate or + /// update the logical server 'all'. + virtual void + createUpdateServer6(const db::ServerPtr& server); + + /// @brief Deletes subnet by prefix. + /// + /// @param server_selector Server selector. + /// @param subnet_prefix Prefix of the subnet to be deleted. + /// @return Number of deleted subnets. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteSubnet6(const db::ServerSelector& server_selector, + const std::string& subnet_prefix); + + /// @brief Deletes subnet by identifier. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to be deleted. + /// @return Number of deleted subnets. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteSubnet6(const db::ServerSelector& server_selector, const SubnetID& subnet_id); + + /// @brief Deletes all subnets. + /// + /// @param server_selector Server selector. + /// @return Number of deleted subnets. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteAllSubnets6(const db::ServerSelector& server_selector); + + /// @brief Deletes all subnets belonging to a specified shared network. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network for which the + /// subnets should be deleted. + /// @return Number of deleted subnets. + virtual uint64_t + deleteSharedNetworkSubnets6(const db::ServerSelector& server_selector, + const std::string& shared_network_name); + + /// @brief Deletes shared network by name. + /// + /// @param server_selector Server selector. + /// @param name Name of the shared network to be deleted. + /// @return Number of deleted shared networks. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteSharedNetwork6(const db::ServerSelector& server_selector, + const std::string& name); + + /// @brief Deletes all shared networks. + /// + /// @param server_selector Server selector. + /// @return Number of deleted shared networks. + virtual uint64_t + deleteAllSharedNetworks6(const db::ServerSelector& server_selector); + + /// @brief Deletes option definition. + /// + /// @param server_selector Server selector. + /// @param code Code of the option to be deleted. + /// @param space Option space of the option to be deleted. + /// @return Number of deleted option definitions. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOptionDef6(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space); + + /// @brief Deletes all option definitions. + /// + /// @param server_selector Server selector. + /// @return Number of deleted option definitions. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteAllOptionDefs6(const db::ServerSelector& server_selector); + + /// @brief Deletes global option. + /// + /// @param server_selector Server selector. + /// @param code Code of the option to be deleted. + /// @param space Option space of the option to be deleted. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption6(const db::ServerSelector& server_selector, const uint16_t code, + const std::string& space); + + /// @brief Deletes shared network level option. + /// + /// @param server_selector Server selector. + /// @param shared_network_name Name of the shared network which deleted + /// option belongs to + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption6(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space); + + /// @brief Deletes subnet level option. + /// + /// @param server_selector Server selector. + /// @param subnet_id Identifier of the subnet to which deleted option + /// belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id, + const uint16_t code, const std::string& space); + + /// @brief Deletes pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the pool to which + /// deleted option belongs. + /// @param pool_end_address Upper bound address of the pool to which the + /// deleted option belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption6(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const uint16_t code, + const std::string& space); + + /// @brief Deletes prefix delegation pool level option. + /// + /// @param server_selector Server selector. + /// @param pool_start_address Lower bound address of the prefix + /// delegation pool to which deleted option belongs. + /// @param pool_end_address Upper bound address of the prefix + /// delegation pool to which the deleted option belongs. + /// @param code Code of the deleted option. + /// @param space Option space of the deleted option. + /// @return Number of deleted options. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteOption6(const db::ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const uint16_t code, + const std::string& space); + + /// @brief Deletes global parameter. + /// + /// @param server_selector Server selector. + /// @param name Name of the global parameter to be deleted. + /// @return Number of deleted global parameters. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteGlobalParameter6(const db::ServerSelector& server_selector, + const std::string& name); + + /// @brief Deletes all global parameters. + /// + /// @param server_selector Server selector. + /// @return Number of deleted global parameters. + /// @throw NotImplemented if server selector is "unassigned". + virtual uint64_t + deleteAllGlobalParameters6(const db::ServerSelector& server_selector); + + /// @brief Deletes DHCPv6 client class. + /// + /// @param server_selector Server selector. + /// @param name Name of the class to be deleted. + /// @return Number of deleted client classes. + virtual uint64_t + deleteClientClass6(const db::ServerSelector& server_selector, + const std::string& name); + + /// @brief Deletes all client classes. + /// + /// @param server_selector Server selector. + /// @return Number of deleted client classes. + virtual uint64_t + deleteAllClientClasses6(const db::ServerSelector& server_selector); + + /// @brief Deletes a server from the backend. + /// + /// @param server_tag Tag of the server to be deleted. + /// @return Number of deleted servers. + /// @throw isc::InvalidOperation when trying to delete the logical + /// server 'all'. + virtual uint64_t + deleteServer6(const data::ServerTag& server_tag); + + /// @brief Deletes all servers from the backend except the logical + /// server 'all'. + /// + /// @return Number of deleted servers. + virtual uint64_t + deleteAllServers6(); + + /// @brief Returns backend type in the textual format. + /// + /// @return "postgresql". + virtual std::string getType() const; + + /// @brief Returns backend host. + /// + /// This is used by the @c BaseConfigBackendPool to select backend + /// when @c BackendSelector is specified. + /// + /// @return host on which the database is located. + virtual std::string getHost() const; + + /// @brief Returns backend port number. + /// + /// This is used by the @c BaseConfigBackendPool to select backend + /// when @c BackendSelector is specified. + /// + /// @return Port number on which database service is available. + virtual uint16_t getPort() const; + + /// @brief Registers the PgSQL backend factory with backend config manager + /// + /// This should be called by the hook lib load() function. + /// @return True if the factory was registered successfully, false otherwise. + static bool registerBackendType(); + + /// @brief Unregisters the PgSQL backend factory and discards PgSQL backends + /// + /// This should be called by the hook lib unload() function. + static void unregisterBackendType(); + + /// @brief Flag which indicates if the config backend has an unusable + /// connection. + /// + /// @return true if there is at least one unusable connection, false + /// otherwise + virtual bool isUnusable(); + + /// @brief Return backend parameters + /// + /// Returns the backend parameters + /// + /// @return Parameters of the backend. + isc::db::DatabaseConnection::ParameterMap getParameters() const; + +protected: + + /// @brief Pointer to the implementation of the @c PgSqlConfigBackendDHCPv6 + /// class. + boost::shared_ptr<PgSqlConfigBackendDHCPv6Impl> impl_; + + /// @brief Pointer to the base implementation of the backend shared by + /// DHCPv4 and DHCPv6 servers. + boost::shared_ptr<PgSqlConfigBackendImpl> base_impl_; +}; + +/// @brief Pointer to the @c PgSqlConfigBackendDHCPv6 class. +typedef boost::shared_ptr<PgSqlConfigBackendDHCPv6> PgSqlConfigBackendDHCPv6Ptr; + +} // end of namespace isc::cb +} // end of namespace isc + +#endif // PGSQL_CONFIG_BACKEND_DHCP6_H diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc new file mode 100644 index 0000000..c8addbf --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc @@ -0,0 +1,1148 @@ +// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <asiolink/io_address.h> +#include <config_backend/constants.h> +#include <dhcp/option_space.h> +#include <database/db_exceptions.h> +#include <pgsql/pgsql_exchange.h> +#include <util/buffer.h> + +#include <pgsql_cb_impl.h> +#include <pgsql_cb_log.h> +#include <cstdint> +#include <utility> + +using namespace isc::asiolink; +using namespace isc::cb; +using namespace isc::data; +using namespace isc::db; +using namespace isc::util; + +namespace isc { +namespace dhcp { + +isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr(); + +PgSqlTaggedStatement& +PgSqlConfigBackendImpl::getStatement(size_t /* index */) const { + isc_throw(NotImplemented, "derivations must override this"); +} + +void +PgSqlConfigBackendImpl::selectQuery(size_t index, + const PsqlBindArray& in_bindings, + PgSqlConnection::ConsumeResultRowFun process_result_row) { + conn_.selectQuery(getStatement(index), in_bindings, process_result_row); +} + +void +PgSqlConfigBackendImpl::insertQuery(size_t index, + const PsqlBindArray& in_bindings) { + conn_.insertQuery(getStatement(index), in_bindings); +} + +uint64_t +PgSqlConfigBackendImpl::updateDeleteQuery(size_t index, + const PsqlBindArray& in_bindings) { + return(conn_.updateDeleteQuery(getStatement(index), in_bindings)); +} + +PgSqlConfigBackendImpl::ScopedAuditRevision::ScopedAuditRevision( + PgSqlConfigBackendImpl* impl, + const int index, + const ServerSelector& server_selector, + const std::string& log_message, + bool cascade_transaction) + : impl_(impl) { + impl_->createAuditRevision(index, server_selector, + boost::posix_time::microsec_clock::local_time(), + log_message, + cascade_transaction); +} + +PgSqlConfigBackendImpl::ScopedAuditRevision::~ScopedAuditRevision() { + impl_->clearAuditRevision(); +} + +PgSqlConfigBackendImpl::PgSqlConfigBackendImpl(const DatabaseConnection::ParameterMap& parameters, + const DbCallback db_reconnect_callback, + size_t last_insert_id_index) + : conn_(parameters, + IOServiceAccessorPtr(new IOServiceAccessor(PgSqlConfigBackendImpl::getIOService)), + db_reconnect_callback), timer_name_(""), + audit_revision_ref_count_(0), parameters_(parameters), + last_insert_id_index_(last_insert_id_index) { + + // Check TLS support. + size_t tls(0); + tls += parameters.count("trust-anchor"); + tls += parameters.count("cert-file"); + tls += parameters.count("key-file"); + tls += parameters.count("cipher-list"); +#ifdef HAVE_PGSQL_SSL + if ((tls > 0) && !PgSqlConnection::warned_about_tls) { + PgSqlConnection::warned_about_tls = true; + LOG_INFO(pgsql_cb_logger, PGSQL_CB_TLS_SUPPORT) + .arg(DatabaseConnection::redactedAccessString(parameters); + PQinitSSL(1); + } +#else + if (tls > 0) { + LOG_ERROR(pgsql_cb_logger, PGSQL_CB_NO_TLS_SUPPORT) + .arg(DatabaseConnection::redactedAccessString(parameters)); + isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL " + << "backend (built with this feature disabled)"); + } +#endif + + // Test schema version first. + std::pair<uint32_t, uint32_t> code_version(PGSQL_SCHEMA_VERSION_MAJOR, PGSQL_SCHEMA_VERSION_MINOR); + std::pair<uint32_t, uint32_t> db_version = PgSqlConnection::getVersion(parameters); + if (code_version != db_version) { + isc_throw(DbOpenError, "PostgreSQL schema version mismatch: need version: " + << code_version.first << "." << code_version.second + << " found version: " << db_version.first << "." + << db_version.second); + } + + // Open the database. + conn_.openDatabase(); +} + +PgSqlConfigBackendImpl::~PgSqlConfigBackendImpl() { + /// nothing to do there. The conn_ connection will be deleted and its dtor + /// will take care of releasing the compiled statements and similar. +} + +void +PgSqlConfigBackendImpl::createAuditRevision(const int index, + const ServerSelector& server_selector, + const boost::posix_time::ptime& audit_ts, + const std::string& log_message, + const bool cascade_transaction) { + // Do not touch existing audit revision in case of the cascade update. + if (++audit_revision_ref_count_ > 1) { + return; + } + + /// @todo The audit trail is not really well prepared to handle multiple server + /// tags or no server tags. Therefore, if the server selector appears to be + /// pointing to multiple servers, no servers or any server we simply associate the + /// audit revision with all servers. The only case when we create a dedicated + /// audit entry is when there is a single server tag, i.e. "all" or explicit + /// server name. In fact, these are the most common two cases. + std::string tag = ServerTag::ALL; + auto const& tags = server_selector.getTags(); + if (tags.size() == 1) { + tag = tags.begin()->get(); + } + + PsqlBindArray in_bindings; + in_bindings.addTimestamp(audit_ts); + in_bindings.add(tag); + in_bindings.add(log_message); + in_bindings.add(cascade_transaction); + + insertQuery(index, in_bindings); +} + +void +PgSqlConfigBackendImpl::clearAuditRevision() { + if (audit_revision_ref_count_ <= 0) { + isc_throw(Unexpected, "attempted to clear audit revision that does not exist - coding error"); + } + --audit_revision_ref_count_; +} + +void +PgSqlConfigBackendImpl::getRecentAuditEntries(const int index, + const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id, + AuditEntryCollection& audit_entries) { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + // Create the input parameters. + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addTimestamp(modification_time); + in_bindings.add(modification_id); + + // Execute select. + selectQuery(index, in_bindings, + [&audit_entries] (PgSqlResult& r, int row) { + // Extract the column values for r[row]. + // Create a worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get the object type. Column 0 is the entry ID which + // we don't need here. + std::string object_type = worker.getString(1); + + // Get the object ID. + uint64_t object_id = worker.getBigInt(2); + + // Get the modification type. + AuditEntry::ModificationType mod_type = + static_cast<AuditEntry::ModificationType>(worker.getSmallInt(3)); + + // Get the modification time. + boost::posix_time::ptime mod_time = worker.getTimestamp(4); + + // Get the revision ID. + uint64_t revision_id = worker.getBigInt(5);; + + // Get the revision log message. + std::string log_message = worker.getString(6); + + // Create new audit entry and add it to the collection of received + // entries. + AuditEntryPtr audit_entry = + AuditEntry::create(object_type, object_id, mod_type, mod_time, + revision_id, log_message); + audit_entries.insert(audit_entry); + }); + } +} + +uint64_t +PgSqlConfigBackendImpl::deleteFromTable(const int index, + const ServerSelector& server_selector, + const std::string& operation) { + // When deleting multiple objects we must not use ANY server. + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting multiple objects for ANY server is not" + " supported"); + } + + PsqlBindArray in_bindings; + return (deleteFromTable(index, server_selector, operation, in_bindings)); +} + +uint64_t +PgSqlConfigBackendImpl::deleteFromTable(const int index, + const db::ServerSelector& server_selector, + const std::string& operation, + db::PsqlBindArray& in_bindings) { + // For ANY server, we use queries that lack server tag, otherwise + // we need to insert the server tag as the first input parameter. + if (!server_selector.amAny() && !server_selector.amUnassigned()) { + std::string tag = getServerTag(server_selector, operation); + in_bindings.insert(tag, 0); + } + + return (updateDeleteQuery(index, in_bindings)); +} + +uint64_t +PgSqlConfigBackendImpl::getLastInsertId(const std::string& table, const std::string& column) { + PsqlBindArray in_bindings; + in_bindings.add(table); + in_bindings.add(column); + uint64_t last_id = 0; + conn_.selectQuery(getStatement(last_insert_id_index_), in_bindings, + [&last_id] (PgSqlResult& r, int row) { + // Get the object type. Column 0 is the entry ID which + PgSqlExchange::getColumnValue(r, row, 0, last_id); + }); + + return (last_id); +} + +void +PgSqlConfigBackendImpl::getGlobalParameters(const int index, + const PsqlBindArray& in_bindings, + StampedValueCollection& parameters) { + // The following parameters from the dhcp[46]_global_parameter table are + // returned per row: + // - id + // - parameter name + // - parameter value + // - parameter type + // - modification timestamp + + StampedValuePtr last_param; + + StampedValueCollection local_parameters; + + selectQuery(index, in_bindings, + [&local_parameters, &last_param](PgSqlResult& r, int row) { + // Extract the column values for r[row]. + // Create a worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get parameter ID. + uint64_t id = worker.getBigInt(0); + + // If we're starting or if this is new parameter being processed... + if (!last_param || (last_param->getId() != id)) { + // Create the parameter instance. + + // Get parameter name. + std::string name = worker.getString(1); + if (!name.empty()) { + // Fetch the value. + std::string value = worker.getString(2); + + // Fetch the type. + Element::types ptype = static_cast<Element::types>(worker.getSmallInt(3)); + + // Create the parameter. + last_param = StampedValue::create(name, value, ptype); + + // Set the id. + last_param->setId(id); + + // Get and set the modification time. + boost::posix_time::ptime mod_time = worker.getTimestamp(4); + last_param->setModificationTime(mod_time); + + // server_tag + std::string server_tag_str = worker.getString(5); + last_param->setServerTag(server_tag_str); + + // If we're fetching parameters for a given server (explicit server + // tag is provided), it takes precedence over the same parameter + // specified for all servers. Therefore, we check if the given + // parameter already exists and belongs to 'all'. + ServerTag last_param_server_tag(server_tag_str); + auto& index = local_parameters.get<StampedValueNameIndexTag>(); + auto existing = index.find(name); + if (existing != index.end()) { + // This parameter was already fetched. Let's check if we should + // replace it or not. + if (!last_param_server_tag.amAll() && (*existing)->hasAllServerTag()) { + // Replace parameter specified for 'all' with the one associated + // with the particular server tag. + local_parameters.replace(existing, last_param); + return; + } + + } + + // If there is no such parameter yet or the existing parameter + // belongs to a different server and the inserted parameter is + // not for all servers. + if ((existing == index.end()) || + (!(*existing)->hasServerTag(last_param_server_tag) && + !last_param_server_tag.amAll())) { + local_parameters.insert(last_param); + } + } + } + }); + + parameters.insert(local_parameters.begin(), local_parameters.end()); +} + +OptionDefinitionPtr +PgSqlConfigBackendImpl::getOptionDef(const int index, + const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "fetching option definition"); + + OptionDefContainer option_defs; + PsqlBindArray in_bindings; + in_bindings.add(tag); + in_bindings.add(code); + in_bindings.add(space); + + getOptionDefs(index, in_bindings, option_defs); + return (option_defs.empty() ? OptionDefinitionPtr() : *option_defs.begin()); +} + +void +PgSqlConfigBackendImpl::getAllOptionDefs(const int index, + const ServerSelector& server_selector, + OptionDefContainer& option_defs) { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + getOptionDefs(index, in_bindings, option_defs); + } +} + +void +PgSqlConfigBackendImpl::getModifiedOptionDefs(const int index, + const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + OptionDefContainer& option_defs) { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + in_bindings.addTimestamp(modification_time); + getOptionDefs(index, in_bindings, option_defs); + } +} + +void +PgSqlConfigBackendImpl::getOptionDefs(const int index, + const PsqlBindArray& in_bindings, + OptionDefContainer& option_defs) { + uint64_t last_def_id = 0; + + OptionDefContainer local_option_defs; + + // Run select query. + selectQuery(index, in_bindings, [this, &local_option_defs, &last_def_id] + (PgSqlResult& r, int row) { + // Extract the column values for r[row]. + // Create a worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get pointer to last fetched option definition. + OptionDefinitionPtr last_def; + if (!local_option_defs.empty()) { + last_def = *local_option_defs.rbegin(); + } + + // Get option def ID. + uint64_t id = worker.getBigInt(0); + + // See if the last fetched definition is the one for which we now got + // the row of data. If not, it means that we need to create new option + // definition. + if ((last_def_id == 0) || (last_def_id != id)) { + last_def_id = id; + last_def = processOptionDefRow(worker, 0); + + // server_tag + ServerTag last_def_server_tag(worker.getString(10)); + last_def->setServerTag(last_def_server_tag.get()); + + // If we're fetching option definitions for a given server + // (explicit server tag is provided), it takes precedence over + // the same option definition specified for all servers. + // Therefore, we check if the given option already exists and + // belongs to 'all'. + auto& index = local_option_defs.get<1>(); + auto existing_it_pair = index.equal_range(last_def->getCode()); + auto existing_it = existing_it_pair.first; + bool found = false; + for ( ; existing_it != existing_it_pair.second; ++existing_it) { + if ((*existing_it)->getOptionSpaceName() == last_def->getOptionSpaceName()) { + found = true; + // This option definition was already fetched. Let's check + // if we should replace it or not. + if (!last_def_server_tag.amAll() && (*existing_it)->hasAllServerTag()) { + index.replace(existing_it, last_def); + return; + } + break; + } + } + + // If there is no such option definition yet or the existing option + // definition belongs to a different server and the inserted option + // definition is not for all servers. + if (!found || + (!(*existing_it)->hasServerTag(last_def_server_tag) && + !last_def_server_tag.amAll())) { + static_cast<void>(local_option_defs.push_back(last_def)); + } + } + }); + + // Append the option definition fetched by this function into the container + // supplied by the caller. The container supplied by the caller may already + // hold some option definitions fetched for other server tags. + option_defs.insert(option_defs.end(), local_option_defs.begin(), + local_option_defs.end()); +} + +void +PgSqlConfigBackendImpl::createUpdateOptionDef(const db::ServerSelector& server_selector, + const Option::Universe& universe, + const OptionDefinitionPtr& option_def, + const std::string& /* space */, + const int& /*get_option_def_code_space*/, + const int& insert_option_def, + const int& update_option_def, + const int& create_audit_revision, + const int& insert_option_def_server, + const std::string& client_class_name) { + + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "creating or updating option definition"); + + // Create input parameter bindings. + PsqlBindArray in_bindings; + in_bindings.add(option_def->getCode()); + in_bindings.addTempString(option_def->getName()); + in_bindings.addTempString(option_def->getOptionSpaceName()); + in_bindings.add(option_def->getType()); + in_bindings.addTimestamp(option_def->getModificationTime()); + in_bindings.add(option_def->getArrayType()); + in_bindings.addTempString(option_def->getEncapsulatedSpace()); + + ElementPtr record_types = Element::createList(); + for (auto field : option_def->getRecordFields()) { + record_types->add(Element::create(static_cast<int>(field))); + } + + if (record_types->empty()) { + in_bindings.addNull(); + } else { + in_bindings.addTempString(record_types->str()); + } + + in_bindings.add(option_def->getContext()); + + if (client_class_name.empty()) { + in_bindings.addNull(); + } else { + in_bindings.add(client_class_name); + } + + // Remember the size before we added where clause arguments. + size_t pre_where_size = in_bindings.size(); + + // Now the add the update where clause parameters + in_bindings.add(tag); + in_bindings.add(option_def->getCode()); + in_bindings.addTempString(option_def->getOptionSpaceName()); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision audit_revision(this, + create_audit_revision, + server_selector, + "option definition set", + true); + + // Try to update the definition. + if (updateDeleteQuery(update_option_def, in_bindings) == 0) { + // It doesn't exist, so we'll try to insert it. + // Remove the update where clause bindings. + while (in_bindings.size() > pre_where_size) { + in_bindings.popBack(); + } + + // Try to insert the definition. + insertQuery(insert_option_def, in_bindings); + + // Successfully inserted the definition. Now, we have to associate it + // with the server tag. + PsqlBindArray attach_bindings; + uint64_t id = getLastInsertId((universe == Option::V4 ? + "dhcp4_option_def" : "dhcp6_option_def"), "id"); + attach_bindings.add(id); + attach_bindings.addTimestamp(option_def->getModificationTime()); + + // Insert associations of the option definition with servers. + attachElementToServers(insert_option_def_server, server_selector, attach_bindings); + } + + // Commit the work. + transaction.commit(); +} + +OptionDescriptorPtr +PgSqlConfigBackendImpl::getOption(const int index, + const Option::Universe& universe, + const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "fetching global option"); + + OptionContainer options; + PsqlBindArray in_bindings; + in_bindings.add(tag); + in_bindings.add(code); + in_bindings.add(space); + + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +OptionContainer +PgSqlConfigBackendImpl::getAllOptions(const int index, + const Option::Universe& universe, + const ServerSelector& server_selector) { + OptionContainer options; + + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + PsqlBindArray in_bindings; + in_bindings.addTempString(tag.get()); + getOptions(index, in_bindings, universe, options); + } + + return (options); +} + +OptionContainer +PgSqlConfigBackendImpl::getModifiedOptions(const int index, + const Option::Universe& universe, + const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) { + OptionContainer options; + + PsqlBindArray in_bindings; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + in_bindings.addTempString(tag.get()); + in_bindings.addTimestamp(modification_time); + getOptions(index, in_bindings, universe, options); + } + + return (options); +} + +OptionDescriptorPtr +PgSqlConfigBackendImpl::getOption(const int index, + const Option::Universe& universe, + const ServerSelector& server_selector, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space) { + + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "fetching subnet level option"); + + PsqlBindArray in_bindings; + in_bindings.add(tag); + in_bindings.add(subnet_id); + in_bindings.add(code); // Postgresql code is same size regardless of universe + in_bindings.add(space); + + OptionContainer options; + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +OptionDescriptorPtr +PgSqlConfigBackendImpl::getOption(const int index, + const ServerSelector& server_selector, + const Lease::Type& pool_type, + const uint64_t pool_id, + const uint16_t code, + const std::string& space) { + + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + std::string msg = "fetching "; + if (pool_type == Lease::TYPE_PD) { + msg += "prefix delegation"; + } else { + msg += "address"; + } + msg += " pool level option"; + auto tag = getServerTag(server_selector, msg); + + PsqlBindArray in_bindings; + in_bindings.add(tag); + in_bindings.add(pool_id); + in_bindings.add(code); // Postgresql code is same size regardless of universe + in_bindings.add(space); + Option::Universe universe = Option::V4; + OptionContainer options; + if (pool_type != Lease::TYPE_V4) { + universe = Option::V6; + } + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +OptionDescriptorPtr +PgSqlConfigBackendImpl::getOption(const int index, + const Option::Universe& universe, + const ServerSelector& server_selector, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space) { + + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "managing configuration for no particular server" + " (unassigned) is unsupported at the moment"); + } + + auto tag = getServerTag(server_selector, "fetching shared network level option"); + + PsqlBindArray in_bindings; + in_bindings.add(tag); + in_bindings.add(shared_network_name); + in_bindings.add(code); // Postgresql code is same size regardless of universe + in_bindings.add(space); + + OptionContainer options; + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +void +PgSqlConfigBackendImpl::getOptions(const int index, + const db::PsqlBindArray& in_bindings, + const Option::Universe& universe, + OptionContainer& options) { + uint64_t last_option_id = 0; + OptionContainer local_options; + selectQuery(index, in_bindings, [this, universe, &local_options, &last_option_id] + (PgSqlResult& r, int row) { + // Extract the column values for r[row]. + // Create a worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get option ID. + uint64_t id = worker.getBigInt(0); + + // Parse option. + if ((last_option_id == 0) || (last_option_id < id)) { + last_option_id = id; + + OptionDescriptorPtr desc = processOptionRow(universe, worker, 0); + if (desc) { + // server_tag for the global option + ServerTag last_option_server_tag(worker.getString(13)); + desc->setServerTag(last_option_server_tag.get()); + + // If we're fetching options for a given server (explicit server + // tag is provided), it takes precedence over the same option + // specified for all servers. Therefore, we check if the given + // option already exists and belongs to 'all'. + auto& index = local_options.get<1>(); + auto existing_it_pair = index.equal_range(desc->option_->getType()); + auto existing_it = existing_it_pair.first; + bool found = false; + for ( ; existing_it != existing_it_pair.second; ++existing_it) { + if (existing_it->space_name_ == desc->space_name_) { + found = true; + // This option was already fetched. Let's check if we should + // replace it or not. + if (!last_option_server_tag.amAll() && existing_it->hasAllServerTag()) { + index.replace(existing_it, *desc); + return; + } + break; + } + } + + // If there is no such global option yet or the existing option + // belongs to a different server and the inserted option is not + // for all servers. + if (!found || + (!existing_it->hasServerTag(last_option_server_tag) && + !last_option_server_tag.amAll())) { + static_cast<void>(local_options.push_back(*desc)); + } + } + } + }); + + // Append the options fetched by this function into the container supplied + // by the caller. The container supplied by the caller may already hold + // some options fetched for other server tags. + options.insert(options.end(), local_options.begin(), local_options.end()); +} + +OptionDescriptorPtr +PgSqlConfigBackendImpl::processOptionRow(const Option::Universe& universe, + PgSqlResultRowWorker& worker, + size_t first_col) { + // Some of the options have standard or custom definitions. + // Depending whether the option has a definition or not a different + // C++ class may be used to represent the option. Therefore, the + // first thing to do is to see if there is a definition for our + // parsed option. The option code and space is needed for it. + std::string space = worker.getString(first_col + 4); + uint16_t code = worker.getSmallInt(first_col + 1); + + OptionPtr option = Option::create(universe, code); + + // Get formatted value if available. + std::string formatted_value; + if (!worker.isColumnNull(first_col + 3)) { + formatted_value = worker.getString(first_col + 3); + } + + // If we don't have a formatted value, check for a blob. Add it to the + // option if it exists. + if (formatted_value.empty() && !worker.isColumnNull(first_col + 2)) { + std::vector<uint8_t> blob; + worker.getBytes(first_col + 2, blob); + option->setData(blob.begin(), blob.end()); + } + + // Check if the option is persistent. + bool persistent = false; + if (!worker.isColumnNull(first_col + 5)) { + persistent = worker.getBool(first_col + 5); + } + + // Check if the option is cancelled. + bool cancelled = false; + if (!worker.isColumnNull(first_col + 6)) { + cancelled = worker.getBool(first_col + 6); + } + + // Create option descriptor which encapsulates our option and adds + // additional information, i.e. whether the option is persistent, + // its option space and timestamp. + OptionDescriptorPtr desc = OptionDescriptor::create(option, + persistent, + cancelled, + formatted_value); + desc->space_name_ = space; + desc->setModificationTime(worker.getTimestamp(first_col + 12)); + + // Set database id for the option. + // @todo Can this actually ever be null and if it is, isn't that an error? + if (!worker.isColumnNull(first_col)) { + desc->setId(worker.getBigInt(first_col)); + } + + return (desc); +} + +OptionDefinitionPtr +PgSqlConfigBackendImpl::processOptionDefRow(PgSqlResultRowWorker& worker, + const size_t first_col) { + OptionDefinitionPtr def; + + // Check array type, because depending on this value we have to use + // different constructor. + std::string name = worker.getString(first_col + 2); + uint16_t code = worker.getSmallInt(first_col + 1); + std::string space = worker.getString(first_col + 3); + OptionDataType type = static_cast<OptionDataType>(worker.getSmallInt(first_col + 4)); + + bool array_type = worker.getBool(first_col + 6); + if (array_type) { + // Create array option. + def = OptionDefinition::create(name, code, space, type, true); + } else { + // Create non-array option. + def = OptionDefinition::create(name, code, space, type, + (worker.isColumnNull(first_col + 7) ? "" + : worker.getString(first_col + 7).c_str())); + } + + // id + def->setId(worker.getBigInt(first_col)); + + // record_types + if (!worker.isColumnNull(first_col + 8)) { + ElementPtr record_types_element = worker.getJSON(first_col + 8); + if (record_types_element->getType() != Element::list) { + isc_throw(BadValue, "invalid record_types value " + << worker.getString(first_col + 8)); + } + + // This element must contain a list of integers specifying + // types of the record fields. + for (auto i = 0; i < record_types_element->size(); ++i) { + auto type_element = record_types_element->get(i); + if (type_element->getType() != Element::integer) { + isc_throw(BadValue, "record type values must be integers"); + } + + def->addRecordField(static_cast<OptionDataType>(type_element->intValue())); + } + } + + // Update modification time. + def->setModificationTime(worker.getTimestamp(first_col + 5)); + + return (def); +} + +void +PgSqlConfigBackendImpl::attachElementToServers(const int index, + const ServerSelector& server_selector, + const PsqlBindArray& in_bindings) { + // Copy the bindings because we're going to modify them. + PsqlBindArray server_bindings = in_bindings; + for (auto const& tag : server_selector.getTags()) { + // Add the server tag to end of the bindings. + std::string server_tag = tag.get(); + server_bindings.add(server_tag); + + // Insert the server association. + // Handles the case where the server does not exists. + try { + insertQuery(index, server_bindings); + } catch (const NullKeyError&) { + // The message should give the tag value. + isc_throw(NullKeyError, + "server '" << tag.get() << "' does not exist"); + } + // Remove the prior server tag. + server_bindings.popBack(); + } +} + +ServerPtr +PgSqlConfigBackendImpl::getServer(const int index, const ServerTag& server_tag) { + ServerCollection servers; + + // Create input parameter bindings. + PsqlBindArray in_bindings; + in_bindings.addTempString(server_tag.get()); + + getServers(index, in_bindings, servers); + + return (servers.empty() ? ServerPtr() : *servers.begin()); +} + +void +PgSqlConfigBackendImpl::getAllServers(const int index, db::ServerCollection& servers) { + PsqlBindArray in_bindings; + getServers(index, in_bindings, servers); +} + +void +PgSqlConfigBackendImpl::getServers(const int index, + const PsqlBindArray& in_bindings, + ServerCollection& servers) { + // Track the last server added to avoid duplicates. This + // assumes the rows are ordered by server ID. + ServerPtr last_server; + selectQuery(index, in_bindings, + [&servers, &last_server](PgSqlResult& r, int row) { + // Extract the column values for r[row]. + // Create a worker for the row. + PgSqlResultRowWorker worker(r, row); + + // Get the server ID. + uint64_t id = worker.getBigInt(0); + + // Get the server tag. + std::string tag = worker.getString(1); + + // Get the description. + std::string description = worker.getString(2); + + // Get the modification time. + boost::posix_time::ptime mod_time = worker.getTimestamp(3); + + if (!last_server || (last_server->getId() != id)) { + // Create the server instance. + last_server = Server::create(ServerTag(tag), description); + + // id + last_server->setId(id); + + // modification_ts + last_server->setModificationTime(mod_time); + + // New server fetched. Let's store it. + servers.insert(last_server); + } + }); +} + +void +PgSqlConfigBackendImpl::createUpdateServer(const int& create_audit_revision, + const int& create_index, + const int& update_index, + const ServerPtr& server) { + // The server tag 'all' is reserved. + if (server->getServerTag().amAll()) { + isc_throw(InvalidOperation, + "'all' is a name reserved for the server tag which" + " associates the configuration elements with all servers connecting" + " to the database and a server with this name may not be created"); + } + + // Populate the input bindings. + PsqlBindArray in_bindings; + std::string tag = server->getServerTagAsText(); + in_bindings.add(tag); + in_bindings.addTempString(server->getDescription()); + in_bindings.addTimestamp(server->getModificationTime()); + + // Start transaction. + PgSqlTransaction transaction(conn_); + + // Create scoped audit revision. As long as this instance exists + // no new audit revisions are created in any subsequent calls. + ScopedAuditRevision audit_revision(this, create_audit_revision, ServerSelector::ALL(), + "server set", true); + + // Create a savepoint in case we are called as part of larger + // transaction. + conn_.createSavepoint("createUpdateServer"); + + try { + // Attempt to insert the server. + insertQuery(create_index, in_bindings); + } catch (const DuplicateEntry&) { + // Rollback to the savepoint to preserve an outer + // transaction work. + conn_.rollbackToSavepoint("createUpdateServer"); + + // Add another instance of tag to the bindings to be used + // as the where clause parameter. PostgreSQL uses + // numbered placeholders so we could use $1 again, but + // doing it this way leaves the SQL more generic. + in_bindings.add(tag); + + // Attempt to update the server. + if (!updateDeleteQuery(update_index, in_bindings)) { + // Possible only if someone deleted it since we tried to insert it, + // the query is broken, or the bindings are nonsense. + isc_throw(Unexpected, "Update server failed to find server tag: " << tag); + } + } + + // Commit the transaction. + transaction.commit(); +} + +std::string +PgSqlConfigBackendImpl::getType() const { + return ("postgresql"); +} + +std::string +PgSqlConfigBackendImpl::getHost() const { + std::string host = "localhost"; + try { + host = conn_.getParameter("host"); + } catch (...) { + // No host parameter. Return localhost as a default. + } + return (host); +} + +uint16_t +PgSqlConfigBackendImpl::getPort() const { + try { + std::string sport = conn_.getParameter("port"); + return (boost::lexical_cast<uint16_t>(sport)); + + } catch (...) { + // No port parameter or parameter invalid. + } + return (0); +} + +void +PgSqlConfigBackendImpl::addDdnsReplaceClientNameBinding(PsqlBindArray& bindings, + const NetworkPtr& network) { + auto ddns_rcn_mode = network->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); + if (!ddns_rcn_mode.unspecified()) { + bindings.add(static_cast<uint8_t>(ddns_rcn_mode.get())); + } else { + bindings.addNull(); + } +} + +void +PgSqlConfigBackendImpl::addRelayBinding(PsqlBindArray& bindings, + const NetworkPtr& network) { + ElementPtr relay_element = Element::createList(); + const auto& addresses = network->getRelayAddresses(); + if (!addresses.empty()) { + for (const auto& address : addresses) { + relay_element->add(Element::create(address.toText())); + } + } + + bindings.add(relay_element); +} + +void +PgSqlConfigBackendImpl::setRelays(PgSqlResultRowWorker& worker, size_t col, Network& network) { + if (worker.isColumnNull(col)) { + return; + } + + ElementPtr relay_element = worker.getJSON(col); + if (relay_element->getType() != Element::list) { + isc_throw(BadValue, "invalid relay list: " << worker.getString(col)); + } + + for (auto i = 0; i < relay_element->size(); ++i) { + auto relay_address_element = relay_element->get(i); + if (relay_address_element->getType() != Element::string) { + isc_throw(BadValue, "elements of relay_addresses list must" + "be valid strings"); + } + + network.addRelayAddress(IOAddress(relay_address_element->stringValue())); + } +} + +void +PgSqlConfigBackendImpl::setRequiredClasses(PgSqlResultRowWorker& worker, size_t col, + std::function<void(const std::string&)> setter) { + if (worker.isColumnNull(col)) { + return; + } + + ElementPtr require_element = worker.getJSON(col); + if (require_element->getType() != Element::list) { + std::ostringstream ss; + require_element->toJSON(ss); + isc_throw(BadValue, "invalid require_client_classes value " << ss.str()); + } + + for (auto i = 0; i < require_element->size(); ++i) { + auto require_item = require_element->get(i); + if (require_item->getType() != Element::string) { + isc_throw(BadValue, "elements of require_client_classes list must" + "be valid strings"); + } + + setter(require_item->stringValue()); + } +} + +void +PgSqlConfigBackendImpl::addOptionValueBinding(PsqlBindArray& bindings, + const OptionDescriptorPtr& option) { + OptionPtr opt = option->option_; + if (option->formatted_value_.empty() && (opt->len() > opt->getHeaderLen())) { + OutputBuffer buf(opt->len()); + opt->pack(buf); + const char* buf_ptr = static_cast<const char*>(buf.getData()); + std::vector<uint8_t> blob(buf_ptr + opt->getHeaderLen(), + buf_ptr + buf.getLength()); + bindings.addTempBinary(blob); + } else { + bindings.addNull(); + } +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h new file mode 100644 index 0000000..68df199 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h @@ -0,0 +1,902 @@ +// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PGSQL_CONFIG_BACKEND_IMPL_H +#define PGSQL_CONFIG_BACKEND_IMPL_H + +#include <cc/stamped_value.h> +#include <database/audit_entry.h> +#include <database/database_connection.h> +#include <database/server.h> +#include <database/server_collection.h> +#include <database/server_selector.h> +#include <dhcp/option.h> +#include <dhcp/option_definition.h> +#include <dhcpsrv/cfg_option.h> +#include <dhcpsrv/lease.h> +#include <dhcpsrv/network.h> +#include <dhcpsrv/subnet_id.h> +#include <exceptions/exceptions.h> +#include <pgsql/pgsql_connection.h> +#include <pgsql/pgsql_exchange.h> + +#include <set> +#include <sstream> +#include <string> +#include <vector> + +namespace isc { +namespace dhcp { + +/// @brief Base class for PostgreSQL Config Backend implementations. +/// +/// This class contains common methods for manipulating data in the +/// PostgreSQL database, used by all servers. +/// +/// All POSIX times specified in the methods belonging to this +/// class must be local times. +class PgSqlConfigBackendImpl { +protected: + + /// @brief RAII object used to protect against creating multiple + /// audit revisions during cascade configuration updates. + /// + /// Audit revision is created per a single database transaction. + /// It includes log message associated with the configuration + /// change. Single command sent over the control API should + /// result in a single audit revision entry in the database. + /// A single configuration update often consists of multiple + /// insertions, updates and/or deletes in the database. For + /// example, a subnet contains pools and DHCP options which are + /// inserted to their respective tables. We refer to such update + /// as a cascade update. Cascade update should result in a single + /// audit revision and an audit entry for a subnet, rather than + /// multiple audit revisions and audit entries for the subnet, + /// pools and child DHCP options. + /// + /// Creating an instance of the @c ScopedAuditRevision guards + /// against creation of multiple audit revisions when child + /// objects are inserted or updated in the database. When the + /// instance of this object goes out of scope the new audit + /// revisions can be created. The caller must ensure that + /// the instance of this object exists throughout the whole + /// transaction with the database. + class ScopedAuditRevision { + public: + + /// @brief Constructor. + /// + /// Creates new audit revision and sets the flag in the + /// PostgreSQL CB implementation object which prevents new audit + /// revisions to be created while this instance exists. + /// + /// @param impl pointer to the PostgreSQL CB implementation. + /// @param index index of the query to set session variables + /// used for creation of the audit revision and the audit + /// entries. + /// @param server_selector Server selector. + /// @param log_message log message associated with the audit + /// revision to be inserted into the database. + /// @param cascade_transaction boolean flag indicating if + /// we're performing cascade transaction. If set to true, + /// the audit entries for the child objects (e.g. DHCP + /// options) won't be created. + ScopedAuditRevision(PgSqlConfigBackendImpl* impl, + const int index, + const db::ServerSelector& server_selector, + const std::string& log_message, + bool cascade_transaction); + + /// @brief Destructor. + /// + /// Clears the flag which is blocking creation of the new + /// audit revisions. + ~ScopedAuditRevision(); + + private: + + /// @brief Pointer to the PostgreSQL CB implementation. + PgSqlConfigBackendImpl* impl_; + }; + +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + /// @param db_reconnect_callback The connection recovery callback. + /// @param last_insert_id_index statement index of the SQL statement to + /// use when fetching the last insert id for a given table. + explicit PgSqlConfigBackendImpl(const db::DatabaseConnection::ParameterMap& parameters, + const db::DbCallback db_reconnect_callback, + const size_t last_insert_id_index); + + /// @brief Destructor. + virtual ~PgSqlConfigBackendImpl(); + + /// @brief Returns server tag associated with the particular selector. + /// + /// This method expects that there is exactly one server tag associated with + /// the server selector. + /// + /// @param server_selector Server selector. + /// @param operation Operation which results in calling this function. This is + /// used for error reporting purposes. + /// @return Server tag. + /// @throw InvalidOperation if the server selector is unassigned or if there + /// is more than one server tag associated with the selector. + std::string getServerTag(const db::ServerSelector& server_selector, + const std::string& operation) const { + auto const& tags = server_selector.getTags(); + if (tags.size() != 1) { + isc_throw(InvalidOperation, "expected exactly one server tag to be specified" + " while " << operation << ". Got: " + << getServerTagsAsText(server_selector)); + } + + return (tags.begin()->get()); + } + + /// @brief Returns server tags associated with the particular selector + /// as text. + /// + /// This method is useful for logging purposes. + std::string getServerTagsAsText(const db::ServerSelector& server_selector) const { + std::ostringstream s; + auto const& server_tags = server_selector.getTags(); + for (auto const& tag : server_tags) { + if (s.tellp() != 0) { + s << ", "; + } + s << tag.get(); + } + + return (s.str()); + } + + /// @brief Invokes the corresponding stored procedure in PgSQL. + /// + /// The @c createAuditRevision stored procedure creates new audit + /// revision and initializes several session variables to be used when + /// the audit entries will be created for the inserted, updated or + /// deleted configuration elements. + /// + /// @param index query index. + /// @param server_selector Server selector. + /// @param audit_ts Timestamp to be associated with the audit + /// revision. + /// @param log_message log message to be used for the audit revision. + /// @param cascade_transaction Boolean value indicating whether the + /// configuration modification is performed as part of the owning + /// element modification, e.g. subnet is modified resulting in + /// modification of the DHCP options it owns. In that case only the + /// audit entry for the owning element should be created. + void createAuditRevision(const int index, + const db::ServerSelector& server_selector, + const boost::posix_time::ptime& audit_ts, + const std::string& log_message, + const bool cascade_transaction); + + /// @brief Clears the flag blocking creation of the new audit revisions. + /// + /// This is used by the @c ScopedAuditRevision object. + void clearAuditRevision(); + + /// @brief Sends query to the database to retrieve most recent audit entries. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param modification_time Timestamp being a lower limit for the returned + /// result set, i.e. entries later than specified time are returned. + /// @param modification_id Identifier being a lower limit for the returned + /// result set, used when two (or more) revisions have the same + /// modification_time. + /// @param [out] audit_entries Reference to the container where fetched audit + /// entries will be inserted. + void getRecentAuditEntries(const int index, + const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id, + db::AuditEntryCollection& audit_entries); + + /// @brief Sends query to delete rows from a table. + /// + /// @param index Index of the statement to be executed. + /// @param server_selector Server selector. + /// @param operation Operation which results in calling this function. This is + /// used for error reporting purposes. + /// @return Number of deleted rows. + uint64_t deleteFromTable(const int index, + const db::ServerSelector& server_selector, + const std::string& operation); + + /// @brief Sends query to delete rows from a table. + /// + /// @param index Index of the statement to be executed. + /// @param server_selector Server selector. + /// @param operation Operation which results in calling this function. This is + /// used for logging purposes. + /// @param in_bindings Reference to the PgSQL input bindings. They are modified + /// as a result of this function - server tag is inserted into the beginning + /// of the bindings collection. + /// @return Number of deleted rows. + uint64_t deleteFromTable(const int index, + const db::ServerSelector& server_selector, + const std::string& operation, + db::PsqlBindArray& bindings); + + /// @brief Sends query to delete rows from a table. + /// + /// @tparam KeyType Type of the key used as the second binding. The + /// server tag is used as first binding. + /// + /// @param index Index of the statement to be executed. + /// @param server_selector Server selector. + /// @param operation Operation which results in calling this function. This is + /// used for error reporting purposes. + /// @param key Value to be used as input binding to the delete + /// statement. The default value is empty which indicates that the + /// key should not be used in the query. + /// @return Number of deleted rows. + /// @throw InvalidOperation if the server selector is unassigned or + /// if there are more than one server tags associated with the + /// server selector. + template<typename KeyType> + uint64_t deleteFromTable(const int index, + const db::ServerSelector& server_selector, + const std::string& operation, + KeyType key) { + // When deleting by some key, we must use ANY. + if (server_selector.amUnassigned()) { + isc_throw(NotImplemented, "deleting an unassigned object requires " + "an explicit server tag or using ANY server. The UNASSIGNED " + "server selector is currently not supported"); + } + + db::PsqlBindArray in_bindings; + in_bindings.add(key); + return (deleteFromTable(index, server_selector, operation, in_bindings)); + } + + /// @brief Returns the last sequence value for the given table and + /// column name. + /// + /// This relies on PostgreSQL's currval() function which will return + /// the last value generated for the sequence within the current session. + /// + /// @param table name of the table + /// @param column name of the sequence column + /// @return returns the most recently modified value for the given + /// sequence + uint64_t getLastInsertId(const std::string& table, const std::string& column); + + /// @brief Sends query to retrieve multiple global parameters. + /// + /// @param index Index of the query to be used. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] parameters Reference to the container where fetched parameters + /// will be inserted. + void getGlobalParameters(const int index, + const db::PsqlBindArray& in_bindings, + data::StampedValueCollection& parameters); + + /// @brief Sends query to retrieve single option definition by code and + /// option space. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param code Option code. + /// @param space Option space name. + /// + /// @return Pointer to the returned option definition or NULL if such + /// option definition doesn't exist. + OptionDefinitionPtr getOptionDef(const int index, + const db::ServerSelector& server_selector, + const uint16_t code, + const std::string& space); + + /// @brief Sends query to retrieve all option definitions. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param [out] option_defs Reference to the container where option + /// definitions are to be stored. + void getAllOptionDefs(const int index, + const db::ServerSelector& server_selector, + OptionDefContainer& option_defs); + + /// @brief Sends query to retrieve option definitions with modification + /// time later than specified timestamp. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param modification_time Lower bound subnet modification time. + /// @param [out] option_defs Reference to the container where option + /// definitions are to be stored. + void getModifiedOptionDefs(const int index, + const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + OptionDefContainer& option_defs); + + /// @brief Sends query to the database to retrieve multiple option + /// definitions. + /// + /// Query should order option definitions by id. + /// + /// @param index Index of the query to be used. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param [out] option_defs Reference to the container where fetched + /// option definitions will be inserted. + void getOptionDefs(const int index, + const db::PsqlBindArray& in_bindings, + OptionDefContainer& option_defs); + + /// @brief Creates or updates an option definition. + /// + /// @param server_selector Server selector. + /// @param universe Option universe, i.e. V4 or V6. + /// @param option_def Option definition to be added or updated. + /// @param space Default option space + /// @param get_option_def_code_space Statement getting option + /// definition by code and space. + /// @param insert_option_def Statement inserting option definition. + /// @param update_option_def Statement updating option definition. + /// @param create_audit_revision Statement creating audit revision. + /// @param insert_option_def_server Statement associating option + /// definition with a server. + /// @param client_class_name Optional client class name to which + /// the option definition belongs. If this value is not specified, + /// it is a global option definition. + /// @throw NotImplemented if server selector is "unassigned". + void createUpdateOptionDef(const db::ServerSelector& server_selector, + const Option::Universe& universe, + const OptionDefinitionPtr& option_def, + const std::string& space, + const int& get_option_def_code_space, + const int& insert_option_def, + const int& update_option_def, + const int& create_audit_revision, + const int& insert_option_def_server, + const std::string& client_class_name = ""); + + /// @brief Sends query to retrieve single global option by code and + /// option space. + /// + /// @param index Index of the query to be used. + /// @param universe Option universe, i.e. V4 or V6. + /// @param server_selector Server selector. + /// @param code Option code. + /// @param space Option space name. + /// + /// @return Pointer to the returned option or NULL if such option + /// doesn't exist. + OptionDescriptorPtr getOption(const int index, + const Option::Universe& universe, + const db::ServerSelector& server_selector, + const uint16_t code, + const std::string& space); + + /// @brief Sends query to retrieve all global options. + /// + /// @param index Index of the query to be used. + /// @param universe Option universe, i.e. V4 or V6. + /// @param server_selector Server selector. + /// @return Container holding returned options. + OptionContainer getAllOptions(const int index, + const Option::Universe& universe, + const db::ServerSelector& server_selector); + + /// @brief Sends query to retrieve global options with modification + /// time later than specified timestamp. + /// + /// @param index Index of the query to be used. + /// @param universe Option universe, i.e. V4 or V6. + /// @param server_selector Server selector. + /// @return Container holding returned options. + OptionContainer getModifiedOptions(const int index, + const Option::Universe& universe, + const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time); + + /// @brief Sends query to retrieve single option by code and option space + /// for a given subnet id. + /// + /// @param index Index of the query to be used. + /// @param universe Option universe, i.e. V4 or V6. + /// @param server_selector Server selector. + /// @param subnet_id Subnet identifier. + /// @param code Option code. + /// @param space Option space name. + /// + /// @return Pointer to the returned option descriptor or NULL if such + /// option doesn't exist. + OptionDescriptorPtr getOption(const int index, + const Option::Universe& universe, + const db::ServerSelector& server_selector, + const dhcp::SubnetID& subnet_id, + const uint16_t code, + const std::string& space); + + /// @brief Sends query to retrieve single option by code and option space + /// for a given address or prefix delegation (v6) pool id. + /// + /// @param index Index of the query to be used. + /// @param server_selector Server selector. + /// @param pool_type Pool type (Lease::TYPE_V4, TYPE_NA or TYPE_PD). + /// @param pool_id Pool identifier in the database. + /// @param code Option code. + /// @param space Option space name. + /// + /// @return Pointer to the returned option descriptor or NULL if such + /// option doesn't exist. + OptionDescriptorPtr getOption(const int index, + const db::ServerSelector& server_selector, + const dhcp::Lease::Type& pool_type, + const uint64_t pool_id, + const uint16_t code, + const std::string& space); + + /// @brief Sends query to retrieve single option by code and option space + /// for a given shared network. + /// + /// @param index Index of the query to be used. + /// @param universe Option universe, i.e. V4 or V6. + /// @param server_selector Server selector. + /// @param shared_network_name Shared network name. + /// @param code Option code. + /// @param space Option space name. + /// + /// @return Pointer to the returned option descriptor or NULL if such + /// option doesn't exist. + OptionDescriptorPtr getOption(const int index, + const Option::Universe& universe, + const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const uint16_t code, + const std::string& space); + + /// @brief Sends query to the database to retrieve multiple options. + /// + /// Query should order by option_id. + /// + /// @note The universe is reused to switch between DHCPv4 and DHCPv6 + /// option layouts. + /// @param family Address family (either AF_INET or AF_INET6). + /// @param index Index of the query to be used. + /// @param in_bindings Input bindings specifying selection criteria. The + /// size of the bindings collection must match the number of placeholders + /// in the prepared statement. The input bindings collection must be empty + /// if the query contains no WHERE clause. + /// @param universe Option universe, i.e. V4 or V6. + /// @param [out] options Reference to the container where fetched options + /// will be inserted. + void getOptions(const int index, + const db::PsqlBindArray& in_bindings, + const Option::Universe& universe, + OptionContainer& options); + + /// @brief Returns DHCP option instance from a set of columns within a + /// result set row. + /// + /// The following is the expected order of columns specified in the SELECT + /// query: + /// - option_id, + /// - code, + /// - value, + /// - formatted_value, + /// - space, + /// - persistent, + /// - cancelled, + /// - dhcp4_subnet_id/dhcp6_subnet_id, + /// - scope_id, + /// - user_context, + /// - shared_network_name, + /// - pool_id, + /// - [pd_pool_id,] + /// - modification_ts + /// + /// @note The universe is reused to switch between DHCPv4 and DHCPv6 + /// option layouts. + /// @param universe V4 or V6. + /// @param worker result set row worker containing the row data + /// @param first_col column index of the first column (i.e. option_id) + /// in the row. + OptionDescriptorPtr processOptionRow(const Option::Universe& universe, + db::PgSqlResultRowWorker& worker, + const size_t first_col); + + /// @brief Returns DHCP option definition instance from output bindings. + /// + /// The following is the expected order of columns specified in the SELECT + /// query: + /// - id, + /// - code, + /// - name, + /// - space, + /// - type, + /// - modification_ts, + /// - is_array, + /// - encapsulate, + /// - record_types, + /// - user_context + /// + /// @param worker result set row worker containing the row data + /// @param first_col column index of the first column (i.e. definition id) + /// in the row. + /// @return Pointer to the option definition. + OptionDefinitionPtr processOptionDefRow(db::PgSqlResultRowWorker& worker, + const size_t first_col); + + /// @brief Associates a configuration element with multiple servers. + /// + /// @param index Query index. + /// @param server_selector Server selector, perhaps with multiple server tags. + /// @param in_bindings Parameter pack holding bindings for the query. The first + /// entry must be the primary key of the element to attach. Note that + /// the server tag (or server id) must be the last binding in the prepared + /// statement. The caller must not include this binding in the parameter pack. + void attachElementToServers(const int index, + const db::ServerSelector& server_selector, + const db::PsqlBindArray& in_bindings); + + /// @brief Adds network ddns-replace-client-name mode to a bind array. + /// + /// If network's value of ddns-replace-client-name mode has been specified + /// it is added to the binding, otherwise a null is added to the binding. + /// + /// @param bindings PsqlBindArray to which the mode should be added. + /// @param network Pointer to shared network or subnet for which mode binding + /// should be created. + void addDdnsReplaceClientNameBinding(db::PsqlBindArray& bindings, + const NetworkPtr& network); + + /// @brief Adds network relays addresses to a bind array. + /// + /// Creates an Element tree of relay addresses add adds that to the end + /// of the given bind array. + /// + /// @param bindings PsqlBindArray to which the relay addresses should be added. + /// @param network Pointer to a shared network or subnet for which binding + /// should be created. + void addRelayBinding(db::PsqlBindArray& bindings, const NetworkPtr& network); + + /// @brief Iterates over the relay addresses in a JSON list element at a + /// given column, adding each to the given Network's relay list. + /// + /// Has no effect if the column is null or is an empty list. + /// + /// @param worker result set row worker containing the row data + /// @param col column index of JSON element column + /// @param network network to update. + /// + /// @throw BadValue if the Element is not a list or if any of the + /// list's elements are not valid IP addresses in string form. + void setRelays(db::PgSqlResultRowWorker& r, size_t col, Network& network); + + /// @brief Adds 'require_client_classes' parameter to a bind array. + /// + /// Creates an Element tree of required class names and adds that to the end + /// of the given bind array. + /// + /// @tparam T of pointer to objects with getRequiredClasses + /// method, e.g. shared network, subnet, pool or prefix delegation pool. + /// @param bindings PsqlBindArray to which the classes should be added. + /// @param object Pointer to an object with getRequiredClasses method + /// @return Pointer to the binding (possibly null binding if there are no + /// required classes specified). + template<typename T> + void addRequiredClassesBinding(db::PsqlBindArray& bindings, const T& object) { + // Create JSON list of required classes. + data::ElementPtr required_classes_element = data::Element::createList(); + const auto& required_classes = object->getRequiredClasses(); + for (auto required_class = required_classes.cbegin(); + required_class != required_classes.cend(); + ++required_class) { + required_classes_element->add(data::Element::create(*required_class)); + } + + bindings.add(required_classes_element); + } + + /// @brief Iterates over the class names in a JSON list element at a + /// given column, invoking a setter function for each one. + /// + /// Has no effect if the column is null or is an empty list. + /// + /// @param worker result set row worker containing the row data + /// @param col column index of JSON element column + /// @param setter function to invoke for each class name in the list + /// + /// @throw BadValue if the Element is not a list or if any of the + /// list's elements are not strings. + void setRequiredClasses(db::PgSqlResultRowWorker& worker, size_t col, + std::function<void(const std::string&)> setter); + + /// @brief Adds an option value to a bind array. + /// + /// @param bindings PsqlBindArray to which the option value should be added. + /// @param option Option descriptor holding the option who's value should + /// added. + void addOptionValueBinding(db::PsqlBindArray& bindings, + const OptionDescriptorPtr& option); + + /// @brief Retrieves a server. + /// + /// @param index Index of the query to be used. + /// @param server_tag Server tag of the server to be retrieved. + /// @return Pointer to the @c Server object representing the server or + /// null if such server doesn't exist. + db::ServerPtr getServer(const int index, const data::ServerTag& server_tag); + + /// @brief Retrieves all servers. + /// + /// @param index Index of the query to be used. + /// @param [out] servers Reference to the container where fetched servers + /// will be inserted. + void getAllServers(const int index, db::ServerCollection& servers); + + /// @brief Sends query to retrieve servers. + /// + /// @param index Index of the query to be used. + /// @param bindings Reference to the PgSQL input bindings. + /// @param [out] servers Reference to the container where fetched servers + /// will be inserted. + void getServers(const int index, + const db::PsqlBindArray& bindings, + db::ServerCollection& servers); + + /// @brief Creates or updates a server. + /// + /// This method attempts to insert a new server into the database using + /// the query identified by @c create_index. If the insertion fails because + /// the server with the given tag already exists in the database, the + /// existing server is updated using the query identified by the + /// @c update_index. + /// + /// @param create_audit_revision Index of the query inserting audit + /// revision. + /// @param create_index Index of the INSERT query to be used. + /// @param update_index Index of the UPDATE query to be used. + /// @param server Pointer to the server to be inserted or updated. + /// @throw InvalidOperation when trying to create a duplicate or + /// update the logical server 'all'. + void createUpdateServer(const int& create_audit_revision, + const int& create_index, + const int& update_index, + const db::ServerPtr& server); + + /// @brief Executes multiple update and/or delete queries with no input + /// bindings. + /// + /// This is a convenience function which takes multiple query indexes as + /// arguments and for each index executes an update or delete query. + /// One of the applications of this function is to remove dangling + /// configuration elements after the server associated with these elements + /// have been deleted. + /// + /// @tparam T type of the indexes, e.g. @c PgSqlConfigBackendDHCPv4Impl::StatementIndex. + /// @tparam R parameter pack holding indexes of type @c T. + /// @param first_index first index. + /// @param other_indexes remaining indexes. + template<typename T, typename... R> + void multipleUpdateDeleteQueries(T first_index, R... other_indexes) { + std::vector<T> indexes({ first_index, other_indexes... }); + db::PsqlBindArray in_bindings; + for (auto index : indexes) { + updateDeleteQuery(index, in_bindings); + } + } + + /// @brief Removes configuration elements from the index which don't match + /// the specified server selector. + /// + /// This is a generic function which removes configuration elements which + /// don't match the specified selector. In order to fetch all server tags + /// for the returned configuration element, the query must not limit the + /// results to the given server tag. Instead, it must post process the + /// result to eliminate those configuration elements for which the desired + /// server tag wasn't found. + /// + /// If the server selector is set to ANY, this method is no-op. + /// + /// @tparam CollectionIndex Type of the collection to be processed. + /// @param server_selector Server selector. + /// @param index Reference to the index holding the returned configuration + /// elements to be processed. + template<typename CollectionIndex> + void tossNonMatchingElements(const db::ServerSelector& server_selector, + CollectionIndex& index) { + // Don't filter the matching server tags if the server selector is + // set to ANY. + if (server_selector.amAny()) { + return; + } + + // Go over the collection of elements. + for (auto elem = index.begin(); elem != index.end();) { + + // If we're asking for shared networks matching all servers, + // we have to make sure that the fetched element has "all" + // server tag. + if (server_selector.amAll()) { + if (!(*elem)->hasAllServerTag()) { + // It doesn't so let's remove it. + elem = index.erase(elem); + continue; + } + + } else if (server_selector.amUnassigned()) { + // Returned element has server tags but we expect that the + // elements are unassigned. + if (!(*elem)->getServerTags().empty()) { + elem = index.erase(elem); + continue; + } + + } else { + // Server selector contains explicit server tags, so + // let's see if the returned elements includes any of + // them. + auto const& tags = server_selector.getTags(); + bool tag_found = false; + for (auto const& tag : tags) { + if ((*elem)->hasServerTag(tag) || + (*elem)->hasAllServerTag()) { + tag_found = true; + break; + } + } + if (!tag_found) { + // Tag not matching, so toss the element. + elem = index.erase(elem); + continue; + } + } + + // Go to the next element if we didn't toss the current one. + // Otherwise, the erase() function should have already taken + // us to the next one. + ++elem; + } + } + + /// @brief Returns backend type in the textual format. + /// + /// @return "postgresql". + std::string getType() const; + + /// @brief Returns backend host. + /// + /// This is used by the @c BaseConfigBackendPool to select backend + /// when @c BackendSelector is specified. + /// + /// @return host on which the database is located. + std::string getHost() const; + + /// @brief Returns backend port number. + /// + /// This is used by the @c BaseConfigBackendPool to select backend + /// when @c BackendSelector is specified. + /// + /// @return Port number on which database service is available. + uint16_t getPort() const; + + /// @brief Return backend parameters + /// + /// Returns the backend parameters + /// + /// @return Parameters of the backend. + const isc::db::DatabaseConnection::ParameterMap& getParameters() { + return (parameters_); + } + + /// @brief Sets IO service to be used by the PostgreSQL config backend. + /// + /// @param IOService object, used for all ASIO operations. + static void setIOService(const isc::asiolink::IOServicePtr& io_service) { + io_service_ = io_service; + } + + /// @brief Returns pointer to the IO service. + static isc::asiolink::IOServicePtr& getIOService() { + return (io_service_); + } + + /// @brief Fetches the SQL statement for a given statement index. + /// + /// Derivations must override the implementation. The reference + /// returned should be non-volatile over the entire lifetime + /// of the derivation instance. + /// + /// @param index index of the desired statement. + /// @throw NotImplemented, always + virtual db::PgSqlTaggedStatement& getStatement(size_t index) const; + + /// @brief Executes SELECT using the prepared statement specified + /// by the given index. + /// + /// The @c index must refer to an existing prepared statement + /// associated with the connection. The @c in_bindings size must match + /// the number of placeholders in the prepared statement. + /// + /// This method executes prepared statement using provided input bindings and + /// calls @c process_result_row function for each returned row. The + /// @c process_result function is implemented by the caller and should + /// gather and store each returned row in an external data structure prior. + /// + /// @param statement reference to the precompiled tagged statement to execute + /// @param in_bindings input bindings holding values to substitue placeholders + /// in the query. + /// @param process_result_row Pointer to the function to be invoked for each + /// retrieved row. This function consumes the retrieved data from the + /// result set. + void selectQuery(size_t index, const db::PsqlBindArray& in_bindings, + db::PgSqlConnection::ConsumeResultRowFun process_result_row); + + /// @brief Executes INSERT using the prepared statement specified + /// by the given index. + /// + /// The @c index must refer to an existing prepared statement + /// associated with the connection. The @c in_bindings size must match + /// the number of placeholders in the prepared statement. + /// + /// This method executes prepared statement using provided bindings to + /// insert data into the database. + /// + /// @param statement reference to the precompiled tagged statement to execute + /// @param in_bindings input bindings holding values to substitue placeholders + /// in the query. + void insertQuery(size_t index, const db::PsqlBindArray& in_bindings); + + /// @brief Executes UPDATE or DELETE using the prepared statement + /// specified by the given index, and returns the number of affected rows. + /// + /// The @c index must refer to an existing prepared statement + /// associated with the connection. The @c in_bindings size must match + /// the number of placeholders in the prepared statement. + /// + /// @param statement reference to the precompiled tagged statement to execute + /// @param in_bindings Input bindings holding values to substitute placeholders + /// in the query. + /// + /// @return Number of affected rows. + uint64_t updateDeleteQuery(size_t index, const db::PsqlBindArray& in_bindings); + + /// @brief Represents connection to the PostgreSQL database. + db::PgSqlConnection conn_; + +protected: + + /// @brief Timer name used to register database reconnect timer. + std::string timer_name_; + +private: + + /// @brief Reference counter for @ScopedAuditRevision instances. + int audit_revision_ref_count_; + + /// @brief Connection parameters + isc::db::DatabaseConnection::ParameterMap parameters_; + + /// @brief The IOService object, used for all ASIO operations. + static isc::asiolink::IOServicePtr io_service_; + + /// @brief Statement index of the SQL statement to use for fetching + /// last inserted id in a given table. + size_t last_insert_id_index_; +}; + +} // end of namespace isc::dhcp +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc new file mode 100644 index 0000000..64522d9 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <pgsql_cb_log.h> + +namespace isc { +namespace dhcp { + +isc::log::Logger pgsql_cb_logger("pgsql-cb-hooks"); + +} // namespace dhcp +} // namespace isc diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h new file mode 100644 index 0000000..6331177 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h @@ -0,0 +1,22 @@ +// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LEASE_CMD_LOG_H +#define LEASE_CMD_LOG_H + +#include <log/logger_support.h> +#include <log/macros.h> +#include <pgsql_cb_messages.h> + +namespace isc { +namespace dhcp { + +extern isc::log::Logger pgsql_cb_logger; + +} // namespace dhcp +} // namespace isc + +#endif diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc new file mode 100644 index 0000000..2baed5c --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc @@ -0,0 +1,405 @@ +// File created from ../../../../src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes + +#include <cstddef> +#include <log/message_types.h> +#include <log/message_initializer.h> + +namespace isc { +namespace cb { + +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4 = "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6 = "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6 = "PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4 = "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6 = "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 = "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 = "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 = "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 = "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION4 = "PGSQL_CB_CREATE_UPDATE_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION6 = "PGSQL_CB_CREATE_UPDATE_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF4 = "PGSQL_CB_CREATE_UPDATE_OPTION_DEF4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF6 = "PGSQL_CB_CREATE_UPDATE_OPTION_DEF6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER4 = "PGSQL_CB_CREATE_UPDATE_SERVER4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER6 = "PGSQL_CB_CREATE_UPDATE_SERVER6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET4 = "PGSQL_CB_CREATE_UPDATE_SUBNET4"; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET6 = "PGSQL_CB_CREATE_UPDATE_SUBNET6"; +extern const isc::log::MessageID PGSQL_CB_DEINIT_OK = "PGSQL_CB_DEINIT_OK"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4 = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6 = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4 = "PGSQL_CB_DELETE_ALL_OPTION_DEFS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT = "PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6 = "PGSQL_CB_DELETE_ALL_OPTION_DEFS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT = "PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4 = "PGSQL_CB_DELETE_ALL_SERVERS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4_RESULT = "PGSQL_CB_DELETE_ALL_SERVERS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6 = "PGSQL_CB_DELETE_ALL_SERVERS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6_RESULT = "PGSQL_CB_DELETE_ALL_SERVERS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4 = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6 = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4 = "PGSQL_CB_DELETE_ALL_SUBNETS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT = "PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6 = "PGSQL_CB_DELETE_ALL_SUBNETS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT = "PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4 = "PGSQL_CB_DELETE_BY_POOL_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT = "PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6 = "PGSQL_CB_DELETE_BY_POOL_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT = "PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6 = "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT = "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4 = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6 = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4 = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6 = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4 = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6 = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4 = "PGSQL_CB_DELETE_CLIENT_CLASS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT = "PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6 = "PGSQL_CB_DELETE_CLIENT_CLASS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT = "PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4 = "PGSQL_CB_DELETE_GLOBAL_PARAMETER4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT = "PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6 = "PGSQL_CB_DELETE_GLOBAL_PARAMETER6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT = "PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4 = "PGSQL_CB_DELETE_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4_RESULT = "PGSQL_CB_DELETE_OPTION4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6 = "PGSQL_CB_DELETE_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6_RESULT = "PGSQL_CB_DELETE_OPTION6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4 = "PGSQL_CB_DELETE_OPTION_DEF4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4_RESULT = "PGSQL_CB_DELETE_OPTION_DEF4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6 = "PGSQL_CB_DELETE_OPTION_DEF6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6_RESULT = "PGSQL_CB_DELETE_OPTION_DEF6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4 = "PGSQL_CB_DELETE_SERVER4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4_RESULT = "PGSQL_CB_DELETE_SERVER4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6 = "PGSQL_CB_DELETE_SERVER6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6_RESULT = "PGSQL_CB_DELETE_SERVER6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4 = "PGSQL_CB_DELETE_SHARED_NETWORK4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6 = "PGSQL_CB_DELETE_SHARED_NETWORK6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4 = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6 = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4 = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6 = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6"; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4 = "PGSQL_CB_GET_ALL_CLIENT_CLASSES4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT = "PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6 = "PGSQL_CB_GET_ALL_CLIENT_CLASSES6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT = "PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4 = "PGSQL_CB_GET_ALL_OPTIONS4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4_RESULT = "PGSQL_CB_GET_ALL_OPTIONS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6 = "PGSQL_CB_GET_ALL_OPTIONS6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6_RESULT = "PGSQL_CB_GET_ALL_OPTIONS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4 = "PGSQL_CB_GET_ALL_OPTION_DEFS4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT = "PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6 = "PGSQL_CB_GET_ALL_OPTION_DEFS6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT = "PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4 = "PGSQL_CB_GET_ALL_SERVERS4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4_RESULT = "PGSQL_CB_GET_ALL_SERVERS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6 = "PGSQL_CB_GET_ALL_SERVERS6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6_RESULT = "PGSQL_CB_GET_ALL_SERVERS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4 = "PGSQL_CB_GET_ALL_SHARED_NETWORKS4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT = "PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6 = "PGSQL_CB_GET_ALL_SHARED_NETWORKS6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT = "PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4 = "PGSQL_CB_GET_ALL_SUBNETS4"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4_RESULT = "PGSQL_CB_GET_ALL_SUBNETS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6 = "PGSQL_CB_GET_ALL_SUBNETS6"; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6_RESULT = "PGSQL_CB_GET_ALL_SUBNETS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS4 = "PGSQL_CB_GET_CLIENT_CLASS4"; +extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS6 = "PGSQL_CB_GET_CLIENT_CLASS6"; +extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER4 = "PGSQL_CB_GET_GLOBAL_PARAMETER4"; +extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER6 = "PGSQL_CB_GET_GLOBAL_PARAMETER6"; +extern const isc::log::MessageID PGSQL_CB_GET_HOST4 = "PGSQL_CB_GET_HOST4"; +extern const isc::log::MessageID PGSQL_CB_GET_HOST6 = "PGSQL_CB_GET_HOST6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4 = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6 = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4 = "PGSQL_CB_GET_MODIFIED_OPTIONS4"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT = "PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6 = "PGSQL_CB_GET_MODIFIED_OPTIONS6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT = "PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4 = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6 = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4 = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6 = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4 = "PGSQL_CB_GET_MODIFIED_SUBNETS4"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT = "PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6 = "PGSQL_CB_GET_MODIFIED_SUBNETS6"; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT = "PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION4 = "PGSQL_CB_GET_OPTION4"; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION6 = "PGSQL_CB_GET_OPTION6"; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF4 = "PGSQL_CB_GET_OPTION_DEF4"; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF6 = "PGSQL_CB_GET_OPTION_DEF6"; +extern const isc::log::MessageID PGSQL_CB_GET_PORT4 = "PGSQL_CB_GET_PORT4"; +extern const isc::log::MessageID PGSQL_CB_GET_PORT6 = "PGSQL_CB_GET_PORT6"; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4 = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4"; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6 = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6"; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_SERVER4 = "PGSQL_CB_GET_SERVER4"; +extern const isc::log::MessageID PGSQL_CB_GET_SERVER6 = "PGSQL_CB_GET_SERVER6"; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK4 = "PGSQL_CB_GET_SHARED_NETWORK4"; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK6 = "PGSQL_CB_GET_SHARED_NETWORK6"; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4 = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4"; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6 = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6"; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT"; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_PREFIX = "PGSQL_CB_GET_SUBNET4_BY_PREFIX"; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID = "PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID"; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_PREFIX = "PGSQL_CB_GET_SUBNET6_BY_PREFIX"; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID = "PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID"; +extern const isc::log::MessageID PGSQL_CB_GET_TYPE4 = "PGSQL_CB_GET_TYPE4"; +extern const isc::log::MessageID PGSQL_CB_GET_TYPE6 = "PGSQL_CB_GET_TYPE6"; +extern const isc::log::MessageID PGSQL_CB_INIT_OK = "PGSQL_CB_INIT_OK"; +extern const isc::log::MessageID PGSQL_CB_NO_TLS_SUPPORT = "PGSQL_CB_NO_TLS_SUPPORT"; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED4 = "PGSQL_CB_RECONNECT_ATTEMPT_FAILED4"; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED6 = "PGSQL_CB_RECONNECT_ATTEMPT_FAILED6"; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4 = "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4"; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6 = "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6"; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED4 = "PGSQL_CB_RECONNECT_FAILED4"; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED6 = "PGSQL_CB_RECONNECT_FAILED6"; +extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE4 = "PGSQL_CB_REGISTER_BACKEND_TYPE4"; +extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE6 = "PGSQL_CB_REGISTER_BACKEND_TYPE6"; +extern const isc::log::MessageID PGSQL_CB_TLS_SUPPORT = "PGSQL_CB_TLS_SUPPORT"; +extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE4 = "PGSQL_CB_UNREGISTER_BACKEND_TYPE4"; +extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE6 = "PGSQL_CB_UNREGISTER_BACKEND_TYPE6"; + +} // namespace cb +} // namespace isc + +namespace { + +const char* values[] = { + "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4", "create or update option pool start: %1 pool end: %2", + "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6", "create or update option pool start: %1 pool end: %2", + "PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6", "create or update option prefix: %1 prefix len: %2", + "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4", "create or update option by subnet id: %1", + "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6", "create or update option by subnet id: %1", + "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4", "create or update client class: %1", + "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6", "create or update client class: %1", + "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4", "create or update global parameter: %1", + "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6", "create or update global parameter: %1", + "PGSQL_CB_CREATE_UPDATE_OPTION4", "create or update option", + "PGSQL_CB_CREATE_UPDATE_OPTION6", "create or update option", + "PGSQL_CB_CREATE_UPDATE_OPTION_DEF4", "create or update option definition: %1 code: %2", + "PGSQL_CB_CREATE_UPDATE_OPTION_DEF6", "create or update option definition: %1 code: %2", + "PGSQL_CB_CREATE_UPDATE_SERVER4", "create or update server: %1", + "PGSQL_CB_CREATE_UPDATE_SERVER6", "create or update server: %1", + "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4", "create or update shared network: %1", + "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6", "create or update shared network: %1", + "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4", "create or update shared network: %1 option", + "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6", "create or update shared network: %1 option", + "PGSQL_CB_CREATE_UPDATE_SUBNET4", "create or update subnet: %1", + "PGSQL_CB_CREATE_UPDATE_SUBNET6", "create or update subnet: %1", + "PGSQL_CB_DEINIT_OK", "unloading Postgres CB hooks library successful", + "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4", "delete all client classes", + "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6", "delete all client classes", + "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4", "delete all global parameters", + "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6", "delete all global parameters", + "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_OPTION_DEFS4", "delete all option definitions", + "PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_OPTION_DEFS6", "delete all option definitions", + "PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_SERVERS4", "delete all DHCPv4 servers", + "PGSQL_CB_DELETE_ALL_SERVERS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_SERVERS6", "delete all DHCPv6 servers", + "PGSQL_CB_DELETE_ALL_SERVERS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4", "delete all shared networks", + "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6", "delete all shared networks", + "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_SUBNETS4", "delete all subnets", + "PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_ALL_SUBNETS6", "delete all subnets", + "PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_POOL_OPTION4", "delete pool start: %1 pool end: %2 option code: %3 space: %4", + "PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_POOL_OPTION6", "delete pool start: %1 pool end: %2 option code: %3 space: %4", + "PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6", "delete prefix: %1 prefix len: %2 option code: %3 space: %4", + "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4", "delete subnet by prefix: %1", + "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6", "delete subnet by prefix: %1", + "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4", "delete by subnet id: %1 option code: %2 space: %3", + "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6", "delete by subnet id: %1 option code: %2 space: %3", + "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4", "delete subnet by subnet id: %1", + "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6", "delete subnet by subnet id: %1", + "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_CLIENT_CLASS4", "delete client class: %1", + "PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_CLIENT_CLASS6", "delete client class: %1", + "PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_GLOBAL_PARAMETER4", "delete global parameter: %1", + "PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_GLOBAL_PARAMETER6", "delete global parameter: %1", + "PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_OPTION4", "delete option code: %1 space: %2", + "PGSQL_CB_DELETE_OPTION4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_OPTION6", "delete option code: %1 space: %2", + "PGSQL_CB_DELETE_OPTION6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_OPTION_DEF4", "delete option definition code: %1 space: %2", + "PGSQL_CB_DELETE_OPTION_DEF4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_OPTION_DEF6", "delete option definition code: %1 space: %2", + "PGSQL_CB_DELETE_OPTION_DEF6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SERVER4", "delete DHCPv4 server: %1", + "PGSQL_CB_DELETE_SERVER4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SERVER6", "delete DHCPv6 server: %1", + "PGSQL_CB_DELETE_SERVER6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SHARED_NETWORK4", "delete shared network: %1", + "PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SHARED_NETWORK6", "delete shared network: %1", + "PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4", "delete shared network: %1 option code: %2 space: %3", + "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6", "delete shared network: %1 option code: %2 space: %3", + "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4", "delete shared network: %1 subnets", + "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT", "deleted: %1 entries", + "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6", "delete shared network: %1 subnets", + "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT", "deleted: %1 entries", + "PGSQL_CB_GET_ALL_CLIENT_CLASSES4", "retrieving all client classes", + "PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_CLIENT_CLASSES6", "retrieving all client classes", + "PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4", "retrieving all global parameters", + "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6", "retrieving all global parameters", + "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_OPTIONS4", "retrieving all options", + "PGSQL_CB_GET_ALL_OPTIONS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_OPTIONS6", "retrieving all options", + "PGSQL_CB_GET_ALL_OPTIONS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_OPTION_DEFS4", "retrieving all option definitions", + "PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_OPTION_DEFS6", "retrieving all option definitions", + "PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_SERVERS4", "retrieving all servers", + "PGSQL_CB_GET_ALL_SERVERS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_SERVERS6", "retrieving all DHCPv6 servers", + "PGSQL_CB_GET_ALL_SERVERS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_SHARED_NETWORKS4", "retrieving all shared networks", + "PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_SHARED_NETWORKS6", "retrieving all shared networks", + "PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_SUBNETS4", "retrieving all subnets", + "PGSQL_CB_GET_ALL_SUBNETS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_ALL_SUBNETS6", "retrieving all subnets", + "PGSQL_CB_GET_ALL_SUBNETS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_CLIENT_CLASS4", "retrieving client class: %1", + "PGSQL_CB_GET_CLIENT_CLASS6", "retrieving client class: %1", + "PGSQL_CB_GET_GLOBAL_PARAMETER4", "retrieving global parameter: %1", + "PGSQL_CB_GET_GLOBAL_PARAMETER6", "retrieving global parameter: %1", + "PGSQL_CB_GET_HOST4", "get host", + "PGSQL_CB_GET_HOST6", "get host", + "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4", "retrieving modified client classes from: %1", + "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6", "retrieving modified client classes from: %1", + "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4", "retrieving modified global parameters from: %1", + "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6", "retrieving modified global parameters from: %1", + "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_OPTIONS4", "retrieving modified options from: %1", + "PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_OPTIONS6", "retrieving modified options from: %1", + "PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4", "retrieving modified option definitions from: %1", + "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6", "retrieving modified option definitions from: %1", + "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4", "retrieving modified shared networks from: %1", + "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6", "retrieving modified shared networks from: %1", + "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_SUBNETS4", "retrieving modified subnets from: %1", + "PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_MODIFIED_SUBNETS6", "retrieving modified subnets from: %1", + "PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_OPTION4", "retrieving option code: %1 space: %2", + "PGSQL_CB_GET_OPTION6", "retrieving option code: %1 space: %2", + "PGSQL_CB_GET_OPTION_DEF4", "retrieving option definition code: %1 space: %2", + "PGSQL_CB_GET_OPTION_DEF6", "retrieving option definition code: %1 space: %2", + "PGSQL_CB_GET_PORT4", "get port", + "PGSQL_CB_GET_PORT6", "get port", + "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4", "retrieving audit entries from: %1 %2", + "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6", "retrieving audit entries from: %1 %2", + "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_SERVER4", "retrieving DHCPv4 server: %1", + "PGSQL_CB_GET_SERVER6", "retrieving DHCPv6 server: %1", + "PGSQL_CB_GET_SHARED_NETWORK4", "retrieving shared network: %1", + "PGSQL_CB_GET_SHARED_NETWORK6", "retrieving shared network: %1", + "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4", "retrieving shared network: %1 subnets", + "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6", "retrieving shared network: %1 subnets", + "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT", "retrieving: %1 elements", + "PGSQL_CB_GET_SUBNET4_BY_PREFIX", "retrieving subnet by prefix: %1", + "PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID", "retrieving subnet by subnet id: %1", + "PGSQL_CB_GET_SUBNET6_BY_PREFIX", "retrieving subnet by prefix: %1", + "PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID", "retrieving subnet by subnet id: %1", + "PGSQL_CB_GET_TYPE4", "get type", + "PGSQL_CB_GET_TYPE6", "get type", + "PGSQL_CB_INIT_OK", "loading Postgres CB hooks library successful", + "PGSQL_CB_NO_TLS_SUPPORT", "Attempt to configure TLS (unsupported for PostgreSQL): %1", + "PGSQL_CB_RECONNECT_ATTEMPT_FAILED4", "database reconnect failed: %1", + "PGSQL_CB_RECONNECT_ATTEMPT_FAILED6", "database reconnect failed: %1", + "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4", "scheduling attempt %1 of %2 in %3 milliseconds", + "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6", "scheduling attempt %1 of %2 in %3 milliseconds", + "PGSQL_CB_RECONNECT_FAILED4", "maximum number of database reconnect attempts: %1, has been exhausted without success", + "PGSQL_CB_RECONNECT_FAILED6", "maximum number of database reconnect attempts: %1, has been exhausted without success", + "PGSQL_CB_REGISTER_BACKEND_TYPE4", "register backend", + "PGSQL_CB_REGISTER_BACKEND_TYPE6", "register backend", + "PGSQL_CB_TLS_SUPPORT", "Attempt to configure TLS: %1", + "PGSQL_CB_UNREGISTER_BACKEND_TYPE4", "unregister backend", + "PGSQL_CB_UNREGISTER_BACKEND_TYPE6", "unregister backend", + NULL +}; + +const isc::log::MessageInitializer initializer(values); + +} // Anonymous namespace + diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h new file mode 100644 index 0000000..57a41d3 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h @@ -0,0 +1,206 @@ +// File created from ../../../../src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes + +#ifndef PGSQL_CB_MESSAGES_H +#define PGSQL_CB_MESSAGES_H + +#include <log/message_types.h> + +namespace isc { +namespace cb { + +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET4; +extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET6; +extern const isc::log::MessageID PGSQL_CB_DEINIT_OK; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6; +extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6; +extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6; +extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6; +extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6; +extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6; +extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS4; +extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS6; +extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER4; +extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER6; +extern const isc::log::MessageID PGSQL_CB_GET_HOST4; +extern const isc::log::MessageID PGSQL_CB_GET_HOST6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6; +extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION4; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION6; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF4; +extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF6; +extern const isc::log::MessageID PGSQL_CB_GET_PORT4; +extern const isc::log::MessageID PGSQL_CB_GET_PORT6; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6; +extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_SERVER4; +extern const isc::log::MessageID PGSQL_CB_GET_SERVER6; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK4; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK6; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6; +extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_PREFIX; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_PREFIX; +extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID; +extern const isc::log::MessageID PGSQL_CB_GET_TYPE4; +extern const isc::log::MessageID PGSQL_CB_GET_TYPE6; +extern const isc::log::MessageID PGSQL_CB_INIT_OK; +extern const isc::log::MessageID PGSQL_CB_NO_TLS_SUPPORT; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED4; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED6; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED4; +extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED6; +extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE4; +extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE6; +extern const isc::log::MessageID PGSQL_CB_TLS_SUPPORT; +extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE4; +extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE6; + +} // namespace cb +} // namespace isc + +#endif // PGSQL_CB_MESSAGES_H diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes new file mode 100644 index 0000000..8855ece --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes @@ -0,0 +1,595 @@ +# Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC") + +$NAMESPACE isc::cb + +% PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4 create or update option pool start: %1 pool end: %2 +Debug message issued when triggered an action to create or update option by pool + +% PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6 create or update option pool start: %1 pool end: %2 +Debug message issued when triggered an action to create or update option by pool + +% PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6 create or update option prefix: %1 prefix len: %2 +Debug message issued when triggered an action to create or update option by prefix + +% PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4 create or update option by subnet id: %1 +Debug message issued when triggered an action to create or update option by subnet id + +% PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6 create or update option by subnet id: %1 +Debug message issued when triggered an action to create or update option by subnet id + +% PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 create or update client class: %1 +Debug message issued when triggered an action to create or update client class + +% PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 create or update client class: %1 +Debug message issued when triggered an action to create or update client class + +% PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 create or update global parameter: %1 +Debug message issued when triggered an action to create or update global parameter + +% PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 create or update global parameter: %1 +Debug message issued when triggered an action to create or update global parameter + +% PGSQL_CB_CREATE_UPDATE_OPTION4 create or update option +Debug message issued when triggered an action to create or update option + +% PGSQL_CB_CREATE_UPDATE_OPTION6 create or update option +Debug message issued when triggered an action to create or update option + +% PGSQL_CB_CREATE_UPDATE_OPTION_DEF4 create or update option definition: %1 code: %2 +Debug message issued when triggered an action to create or update option definition + +% PGSQL_CB_CREATE_UPDATE_OPTION_DEF6 create or update option definition: %1 code: %2 +Debug message issued when triggered an action to create or update option definition + +% PGSQL_CB_CREATE_UPDATE_SERVER4 create or update server: %1 +Debug message issued when triggered an action to create or update a DHCPv4 +server information. + +% PGSQL_CB_CREATE_UPDATE_SERVER6 create or update server: %1 +Debug message issued when triggered an action to create or update a DHCPv6 +server information. + +% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4 create or update shared network: %1 +Debug message issued when triggered an action to create or update shared network + +% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6 create or update shared network: %1 +Debug message issued when triggered an action to create or update shared network + +% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4 create or update shared network: %1 option +Debug message issued when triggered an action to create or update shared network option + +% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6 create or update shared network: %1 option +Debug message issued when triggered an action to create or update shared network option + +% PGSQL_CB_CREATE_UPDATE_SUBNET4 create or update subnet: %1 +Debug message issued when triggered an action to create or update subnet + +% PGSQL_CB_CREATE_UPDATE_SUBNET6 create or update subnet: %1 +Debug message issued when triggered an action to create or update subnet + +% PGSQL_CB_DEINIT_OK unloading Postgres CB hooks library successful +This informational message indicates that the Postgres Configuration Backend hooks +library has been unloaded successfully. + +% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4 delete all client classes +Debug message issued when triggered an action to delete all client classes + +% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all client classes + +% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6 delete all client classes +Debug message issued when triggered an action to delete all client classes + +% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all client classes + +% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 delete all global parameters +Debug message issued when triggered an action to delete all global parameters + +% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all global parameters + +% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 delete all global parameters +Debug message issued when triggered an action to delete all global parameters + +% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all global parameters + +% PGSQL_CB_DELETE_ALL_OPTION_DEFS4 delete all option definitions +Debug message issued when triggered an action to delete all option definitions + +% PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all option definitions + +% PGSQL_CB_DELETE_ALL_OPTION_DEFS6 delete all option definitions +Debug message issued when triggered an action to delete all option definitions + +% PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all option definitions + +% PGSQL_CB_DELETE_ALL_SERVERS4 delete all DHCPv4 servers +Debug message issued when triggered an action to delete all servers. + +% PGSQL_CB_DELETE_ALL_SERVERS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all servers. + +% PGSQL_CB_DELETE_ALL_SERVERS6 delete all DHCPv6 servers +Debug message issued when triggered an action to delete all servers. + +% PGSQL_CB_DELETE_ALL_SERVERS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all servers. + +% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4 delete all shared networks +Debug message issued when triggered an action to delete all shared networks + +% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all shared networks + +% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6 delete all shared networks +Debug message issued when triggered an action to delete all shared networks + +% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all shared networks + +% PGSQL_CB_DELETE_ALL_SUBNETS4 delete all subnets +Debug message issued when triggered an action to delete all subnets + +% PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all subnets + +% PGSQL_CB_DELETE_ALL_SUBNETS6 delete all subnets +Debug message issued when triggered an action to delete all subnets + +% PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all subnets + +% PGSQL_CB_DELETE_BY_POOL_OPTION4 delete pool start: %1 pool end: %2 option code: %3 space: %4 +Debug message issued when triggered an action to delete option by pool + +% PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by pool + +% PGSQL_CB_DELETE_BY_POOL_OPTION6 delete pool start: %1 pool end: %2 option code: %3 space: %4 +Debug message issued when triggered an action to delete option by pool + +% PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by pool + +% PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6 delete prefix: %1 prefix len: %2 option code: %3 space: %4 +Debug message issued when triggered an action to delete option by prefix + +% PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by prefix + +% PGSQL_CB_DELETE_BY_PREFIX_SUBNET4 delete subnet by prefix: %1 +Debug message issued when triggered an action to delete subnet by prefix + +% PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by prefix + +% PGSQL_CB_DELETE_BY_PREFIX_SUBNET6 delete subnet by prefix: %1 +Debug message issued when triggered an action to delete subnet by prefix + +% PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by prefix + +% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4 delete by subnet id: %1 option code: %2 space: %3 +Debug message issued when triggered an action to delete option by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6 delete by subnet id: %1 option code: %2 space: %3 +Debug message issued when triggered an action to delete option by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4 delete subnet by subnet id: %1 +Debug message issued when triggered an action to delete subnet by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6 delete subnet by subnet id: %1 +Debug message issued when triggered an action to delete subnet by subnet id + +% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by subnet id + +% PGSQL_CB_DELETE_CLIENT_CLASS4 delete client class: %1 +Debug message issued when triggered an action to delete client class + +% PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete client class + +% PGSQL_CB_DELETE_CLIENT_CLASS6 delete client class: %1 +Debug message issued when triggered an action to delete client class + +% PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete client class + +% PGSQL_CB_DELETE_GLOBAL_PARAMETER4 delete global parameter: %1 +Debug message issued when triggered an action to delete global parameter + +% PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete global parameter + +% PGSQL_CB_DELETE_GLOBAL_PARAMETER6 delete global parameter: %1 +Debug message issued when triggered an action to delete global parameter + +% PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete global parameter + +% PGSQL_CB_DELETE_OPTION4 delete option code: %1 space: %2 +Debug message issued when triggered an action to delete option + +% PGSQL_CB_DELETE_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option + +% PGSQL_CB_DELETE_OPTION6 delete option code: %1 space: %2 +Debug message issued when triggered an action to delete option + +% PGSQL_CB_DELETE_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option + +% PGSQL_CB_DELETE_OPTION_DEF4 delete option definition code: %1 space: %2 +Debug message issued when triggered an action to delete option definition + +% PGSQL_CB_DELETE_OPTION_DEF4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option definition + +% PGSQL_CB_DELETE_OPTION_DEF6 delete option definition code: %1 space: %2 +Debug message issued when triggered an action to delete option definition + +% PGSQL_CB_DELETE_OPTION_DEF6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option definition + +% PGSQL_CB_DELETE_SERVER4 delete DHCPv4 server: %1 +Debug message issued when triggered an action to delete a server. + +% PGSQL_CB_DELETE_SERVER4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete a server. + +% PGSQL_CB_DELETE_SERVER6 delete DHCPv6 server: %1 +Debug message issued when triggered an action to delete a server. + +% PGSQL_CB_DELETE_SERVER6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete a server. + +% PGSQL_CB_DELETE_SHARED_NETWORK4 delete shared network: %1 +Debug message issued when triggered an action to delete shared network + +% PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network + +% PGSQL_CB_DELETE_SHARED_NETWORK6 delete shared network: %1 +Debug message issued when triggered an action to delete shared network + +% PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network + +% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4 delete shared network: %1 option code: %2 space: %3 +Debug message issued when triggered an action to delete shared network option + +% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network option + +% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6 delete shared network: %1 option code: %2 space: %3 +Debug message issued when triggered an action to delete shared network option + +% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network option + +% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4 delete shared network: %1 subnets +Debug message issued when triggered an action to delete shared network subnets + +% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network subnets + +% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6 delete shared network: %1 subnets +Debug message issued when triggered an action to delete shared network subnets + +% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network subnets + +% PGSQL_CB_GET_ALL_CLIENT_CLASSES4 retrieving all client classes +Debug message issued when triggered an action to retrieve all client classes + +% PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all client classes + +% PGSQL_CB_GET_ALL_CLIENT_CLASSES6 retrieving all client classes +Debug message issued when triggered an action to retrieve all client classes + +% PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all client classes + +% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 retrieving all global parameters +Debug message issued when triggered an action to retrieve all global parameters + +% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all global parameters + +% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 retrieving all global parameters +Debug message issued when triggered an action to retrieve all global parameters + +% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all global parameters + +% PGSQL_CB_GET_ALL_OPTIONS4 retrieving all options +Debug message issued when triggered an action to retrieve all options + +% PGSQL_CB_GET_ALL_OPTIONS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all options + +% PGSQL_CB_GET_ALL_OPTIONS6 retrieving all options +Debug message issued when triggered an action to retrieve all options + +% PGSQL_CB_GET_ALL_OPTIONS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all options + +% PGSQL_CB_GET_ALL_OPTION_DEFS4 retrieving all option definitions +Debug message issued when triggered an action to retrieve all option definitions + +% PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all option definitions + +% PGSQL_CB_GET_ALL_OPTION_DEFS6 retrieving all option definitions +Debug message issued when triggered an action to retrieve all option definitions + +% PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all option definitions + +% PGSQL_CB_GET_ALL_SERVERS4 retrieving all servers +Debug message issued when triggered an action to retrieve all DHCPv4 +servers + +% PGSQL_CB_GET_ALL_SERVERS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all DHCPv4 +servers + +% PGSQL_CB_GET_ALL_SERVERS6 retrieving all DHCPv6 servers +Debug message issued when triggered an action to retrieve all DHCPv6 +servers + +% PGSQL_CB_GET_ALL_SERVERS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all DHCPv6 +servers + +% PGSQL_CB_GET_ALL_SHARED_NETWORKS4 retrieving all shared networks +Debug message issued when triggered an action to retrieve all shared networks + +% PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all shared networks + +% PGSQL_CB_GET_ALL_SHARED_NETWORKS6 retrieving all shared networks +Debug message issued when triggered an action to retrieve all shared networks + +% PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all shared networks + +% PGSQL_CB_GET_ALL_SUBNETS4 retrieving all subnets +Debug message issued when triggered an action to retrieve all subnets + +% PGSQL_CB_GET_ALL_SUBNETS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all subnets + +% PGSQL_CB_GET_ALL_SUBNETS6 retrieving all subnets +Debug message issued when triggered an action to retrieve all subnets + +% PGSQL_CB_GET_ALL_SUBNETS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all subnets + +% PGSQL_CB_GET_CLIENT_CLASS4 retrieving client class: %1 +Debug message issued when triggered an action to retrieve a client class + +% PGSQL_CB_GET_CLIENT_CLASS6 retrieving client class: %1 +Debug message issued when triggered an action to retrieve a client class + +% PGSQL_CB_GET_GLOBAL_PARAMETER4 retrieving global parameter: %1 +Debug message issued when triggered an action to retrieve global parameter + +% PGSQL_CB_GET_GLOBAL_PARAMETER6 retrieving global parameter: %1 +Debug message issued when triggered an action to retrieve global parameter + +% PGSQL_CB_GET_HOST4 get host +Debug message issued when triggered an action to retrieve host + +% PGSQL_CB_GET_HOST6 get host +Debug message issued when triggered an action to retrieve host + +% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4 retrieving modified client classes from: %1 +Debug message issued when triggered an action to retrieve modified client classes from specified time + +% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified client classes from specified time + +% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 retrieving modified client classes from: %1 +Debug message issued when triggered an action to retrieve modified client classes from specified time + +% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified client classes from specified time + +% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 retrieving modified global parameters from: %1 +Debug message issued when triggered an action to retrieve modified global parameters from specified time + +% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified global parameters from specified time + +% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6 retrieving modified global parameters from: %1 +Debug message issued when triggered an action to retrieve modified global parameters from specified time + +% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified global parameters from specified time + +% PGSQL_CB_GET_MODIFIED_OPTIONS4 retrieving modified options from: %1 +Debug message issued when triggered an action to retrieve modified options from specified time + +% PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified options from specified time + +% PGSQL_CB_GET_MODIFIED_OPTIONS6 retrieving modified options from: %1 +Debug message issued when triggered an action to retrieve modified options from specified time + +% PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified options from specified time + +% PGSQL_CB_GET_MODIFIED_OPTION_DEFS4 retrieving modified option definitions from: %1 +Debug message issued when triggered an action to retrieve modified option definitions from specified time + +% PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified option definitions from specified time + +% PGSQL_CB_GET_MODIFIED_OPTION_DEFS6 retrieving modified option definitions from: %1 +Debug message issued when triggered an action to retrieve modified option definitions from specified time + +% PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified option definitions from specified time + +% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4 retrieving modified shared networks from: %1 +Debug message issued when triggered an action to retrieve modified shared networks from specified time + +% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified shared networks from specified time + +% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6 retrieving modified shared networks from: %1 +Debug message issued when triggered an action to retrieve modified shared networks from specified time + +% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified shared networks from specified time + +% PGSQL_CB_GET_MODIFIED_SUBNETS4 retrieving modified subnets from: %1 +Debug message issued when triggered an action to retrieve modified subnets from specified time + +% PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified subnets from specified time + +% PGSQL_CB_GET_MODIFIED_SUBNETS6 retrieving modified subnets from: %1 +Debug message issued when triggered an action to retrieve modified subnets from specified time + +% PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified subnets from specified time + +% PGSQL_CB_GET_OPTION4 retrieving option code: %1 space: %2 +Debug message issued when triggered an action to retrieve option + +% PGSQL_CB_GET_OPTION6 retrieving option code: %1 space: %2 +Debug message issued when triggered an action to retrieve option + +% PGSQL_CB_GET_OPTION_DEF4 retrieving option definition code: %1 space: %2 +Debug message issued when triggered an action to retrieve option definition + +% PGSQL_CB_GET_OPTION_DEF6 retrieving option definition code: %1 space: %2 +Debug message issued when triggered an action to retrieve option definition + +% PGSQL_CB_GET_PORT4 get port +Debug message issued when triggered an action to retrieve port + +% PGSQL_CB_GET_PORT6 get port +Debug message issued when triggered an action to retrieve port + +% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4 retrieving audit entries from: %1 %2 +Debug message issued when triggered an action to retrieve audit entries from specified time and id. + +% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve audit entries from specified time + +% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6 retrieving audit entries from: %1 %2 +Debug message issued when triggered an action to retrieve audit entries from specified time and id + +% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve audit entries from specified time + +% PGSQL_CB_GET_SERVER4 retrieving DHCPv4 server: %1 +Debug message issued when triggered an action to retrieve a DHCPv4 server information. + +% PGSQL_CB_GET_SERVER6 retrieving DHCPv6 server: %1 +Debug message issued when triggered an action to retrieve a DHCPv6 server information. + +% PGSQL_CB_GET_SHARED_NETWORK4 retrieving shared network: %1 +Debug message issued when triggered an action to retrieve shared network + +% PGSQL_CB_GET_SHARED_NETWORK6 retrieving shared network: %1 +Debug message issued when triggered an action to retrieve shared network + +% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4 retrieving shared network: %1 subnets +Debug message issued when triggered an action to retrieve shared network subnets + +% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve shared network subnets + +% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6 retrieving shared network: %1 subnets +Debug message issued when triggered an action to retrieve shared network subnets + +% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve shared network subnets + +% PGSQL_CB_GET_SUBNET4_BY_PREFIX retrieving subnet by prefix: %1 +Debug message issued when triggered an action to retrieve subnet by prefix + +% PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID retrieving subnet by subnet id: %1 +Debug message issued when triggered an action to retrieve subnet by subnet id + +% PGSQL_CB_GET_SUBNET6_BY_PREFIX retrieving subnet by prefix: %1 +Debug message issued when triggered an action to retrieve subnet by prefix + +% PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID retrieving subnet by subnet id: %1 +Debug message issued when triggered an action to retrieve subnet by subnet id + +% PGSQL_CB_GET_TYPE4 get type +Debug message issued when triggered an action to retrieve type + +% PGSQL_CB_GET_TYPE6 get type +Debug message issued when triggered an action to retrieve type + +% PGSQL_CB_INIT_OK loading Postgres CB hooks library successful +This informational message indicates that the Postgres Configuration Backend hooks +library has been loaded successfully. Enjoy! + +% PGSQL_CB_NO_TLS_SUPPORT Attempt to configure TLS (unsupported for PostgreSQL): %1 +This error message is printed when TLS support was required in the Kea +configuration: Kea was built with this feature disabled for PostgreSQL. +The parameters of the connection are logged. + +% PGSQL_CB_RECONNECT_ATTEMPT_FAILED4 database reconnect failed: %1 +Error message issued when an attempt to reconnect has failed. + +% PGSQL_CB_RECONNECT_ATTEMPT_FAILED6 database reconnect failed: %1 +Error message issued when an attempt to reconnect has failed. + +% PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4 scheduling attempt %1 of %2 in %3 milliseconds +Info message issued when the server is scheduling the next attempt to reconnect +to the database. This occurs when the server has lost database connectivity and +is attempting to reconnect automatically. + +% PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6 scheduling attempt %1 of %2 in %3 milliseconds +Info message issued when the server is scheduling the next attempt to reconnect +to the database. This occurs when the server has lost database connectivity and +is attempting to reconnect automatically. + +% PGSQL_CB_RECONNECT_FAILED4 maximum number of database reconnect attempts: %1, has been exhausted without success +Error message issued when the server failed to reconnect. Loss of connectivity +is typically a network or database server issue. + +% PGSQL_CB_RECONNECT_FAILED6 maximum number of database reconnect attempts: %1, has been exhausted without success +Error message issued when the server failed to reconnect. Loss of connectivity +is typically a network or database server issue. + +% PGSQL_CB_REGISTER_BACKEND_TYPE4 register backend +Debug message issued when triggered an action to register backend + +% PGSQL_CB_REGISTER_BACKEND_TYPE6 register backend +Debug message issued when triggered an action to register backend + +% PGSQL_CB_TLS_SUPPORT Attempt to configure TLS: %1 +This informational message is printed when TLS support was required in +the Kea configuration: The TLS support in PostgreSQL will be initialized but +its configuration is fully managed outside the C API. +The parameters of the connection are logged. + +% PGSQL_CB_UNREGISTER_BACKEND_TYPE4 unregister backend +Debug message issued when triggered an action to unregister backend + +% PGSQL_CB_UNREGISTER_BACKEND_TYPE6 unregister backend +Debug message issued when triggered an action to unregister backend diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h b/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h new file mode 100644 index 0000000..f30187c --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h @@ -0,0 +1,1391 @@ +// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PGSQL_QUERY_MACROS_DHCP_H +#define PGSQL_QUERY_MACROS_DHCP_H + +/// @file pgsql_query_macros_dhcp.h +/// Collection of common macros defining PgSQL prepared statements used +/// to manage Kea DHCP configuration in the database. +/// +/// Some of the macros are DHCPv4 specific, other are DHCPv6 specific. +/// Some macros are common for both DHCP server types. The first +/// parameter @c table_prefix should be set to @c dhcp4 or @c dhcp6, +/// depending which DHCP server type it relates to. Provided value +/// is used as a prefix for PgSQL table names. For example, if the +/// prefix is set to @c dhcp4, the table name referred to in the +/// query may be dhcp4_subnet etc. The second argument in the variadic +/// macro is a part of the WHERE clause in the PgSQL query. The fixed +/// part of the WHERE clause is included in the macro. +namespace isc { +namespace dhcp { + +namespace { + +#ifndef PGSQL_GET_GLOBAL_PARAMETER +#define PGSQL_GET_GLOBAL_PARAMETER(table_prefix, ...) \ + "SELECT" \ + " g.id," \ + " g.name," \ + " g.value," \ + " g.parameter_type," \ + " gmt_epoch(g.modification_ts) as modification_ts, " \ + " s.tag " \ + "FROM " #table_prefix "_global_parameter AS g " \ + "INNER JOIN " #table_prefix "_global_parameter_server AS a " \ + " ON g.id = a.parameter_id " \ + "INNER JOIN " #table_prefix "_server AS s " \ + " ON (a.server_id = s.id) " \ + "WHERE (s.tag = $1 OR s.id = 1) " #__VA_ARGS__ \ + " ORDER BY g.id, s.id" +#endif + +#ifndef PGSQL_GET_SUBNET4 +#define PGSQL_GET_SUBNET4_COMMON(server_join, ...) \ + "SELECT" \ + " s.subnet_id," \ + " s.subnet_prefix," \ + " s.interface_4o6," \ + " s.interface_id_4o6," \ + " s.subnet_4o6," \ + " s.boot_file_name," \ + " s.client_class," \ + " s.interface," \ + " s.match_client_id," \ + " gmt_epoch(s.modification_ts) as modification_ts, " \ + " s.next_server," \ + " s.rebind_timer," \ + " s.relay," \ + " s.renew_timer," \ + " s.require_client_classes," \ + " s.reservations_global," \ + " s.server_hostname," \ + " s.shared_network_name," \ + " s.user_context," \ + " s.valid_lifetime," \ + " p.id," \ + " p.start_address," \ + " p.end_address," \ + " p.subnet_id," \ + " gmt_epoch(p.modification_ts) as modification_ts, " \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp4_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts, " \ + " o.option_id," \ + " o.code," \ + " o.value," \ + " o.formatted_value," \ + " o.space," \ + " o.persistent," \ + " o.cancelled," \ + " o.dhcp4_subnet_id," \ + " o.scope_id," \ + " o.user_context," \ + " o.shared_network_name," \ + " o.pool_id," \ + " gmt_epoch(o.modification_ts) as modification_ts, " \ + " s.calculate_tee_times," \ + " s.t1_percent," \ + " s.t2_percent," \ + " s.authoritative," \ + " s.min_valid_lifetime," \ + " s.max_valid_lifetime," \ + " p.client_class," \ + " p.require_client_classes," \ + " p.user_context," \ + " s.ddns_send_updates," \ + " s.ddns_override_no_update," \ + " s.ddns_override_client_update," \ + " s.ddns_replace_client_name," \ + " s.ddns_generated_prefix," \ + " s.ddns_qualifying_suffix," \ + " s.reservations_in_subnet," \ + " s.reservations_out_of_pool," \ + " s.cache_threshold," \ + " s.cache_max_age," \ + " s.offer_lifetime," \ + " s.allocator," \ + " srv.tag " \ + "FROM dhcp4_subnet AS s " \ + server_join \ + "LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id " \ + "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \ + "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id " \ + #__VA_ARGS__ \ + " ORDER BY s.subnet_id, p.id, x.option_id, o.option_id" + +#define PGSQL_GET_SUBNET4_NO_TAG(...) \ + PGSQL_GET_SUBNET4_COMMON( \ + "INNER JOIN dhcp4_subnet_server AS a " \ + " ON s.subnet_id = a.subnet_id " \ + "INNER JOIN dhcp4_server AS srv " \ + " ON (a.server_id = srv.id) ", \ + __VA_ARGS__) + +#define PGSQL_GET_SUBNET4_ANY(...) \ + PGSQL_GET_SUBNET4_COMMON( \ + "LEFT JOIN dhcp4_subnet_server AS a "\ + " ON s.subnet_id = a.subnet_id " \ + "LEFT JOIN dhcp4_server AS srv " \ + " ON a.server_id = srv.id ", \ + __VA_ARGS__) + +#define PGSQL_GET_SUBNET4_UNASSIGNED(...) \ + PGSQL_GET_SUBNET4_COMMON( \ + "LEFT JOIN dhcp4_subnet_server AS a "\ + " ON s.subnet_id = a.subnet_id " \ + "LEFT JOIN dhcp4_server AS srv " \ + " ON a.server_id = srv.id ", \ + WHERE a.subnet_id IS NULL __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_SUBNET6 +#define PGSQL_GET_SUBNET6_COMMON(server_join, ...) \ + "SELECT" \ + " s.subnet_id," \ + " s.subnet_prefix," \ + " s.client_class," \ + " s.interface," \ + " gmt_epoch(s.modification_ts) as modification_ts, " \ + " s.preferred_lifetime," \ + " s.rapid_commit," \ + " s.rebind_timer," \ + " s.relay," \ + " s.renew_timer," \ + " s.require_client_classes," \ + " s.reservations_global," \ + " s.shared_network_name," \ + " s.user_context," \ + " s.valid_lifetime," \ + " p.id," \ + " p.start_address," \ + " p.end_address," \ + " p.subnet_id," \ + " gmt_epoch(p.modification_ts) as modification_ts, " \ + " d.id," \ + " d.prefix," \ + " d.prefix_length," \ + " d.delegated_prefix_length," \ + " d.subnet_id," \ + " gmt_epoch(d.modification_ts) as modification_ts, " \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp6_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts, " \ + " x.pd_pool_id," \ + " y.option_id," \ + " y.code," \ + " y.value," \ + " y.formatted_value," \ + " y.space," \ + " y.persistent," \ + " y.cancelled," \ + " y.dhcp6_subnet_id," \ + " y.scope_id," \ + " y.user_context," \ + " y.shared_network_name," \ + " y.pool_id," \ + " gmt_epoch(y.modification_ts) as modification_ts, " \ + " y.pd_pool_id," \ + " o.option_id," \ + " o.code," \ + " o.value," \ + " o.formatted_value," \ + " o.space," \ + " o.persistent," \ + " o.cancelled," \ + " o.dhcp6_subnet_id," \ + " o.scope_id," \ + " o.user_context," \ + " o.shared_network_name," \ + " o.pool_id," \ + " gmt_epoch(o.modification_ts) as modification_ts, " \ + " o.pd_pool_id, " \ + " s.calculate_tee_times," \ + " s.t1_percent," \ + " s.t2_percent," \ + " s.interface_id," \ + " s.min_preferred_lifetime," \ + " s.max_preferred_lifetime," \ + " s.min_valid_lifetime," \ + " s.max_valid_lifetime," \ + " p.client_class," \ + " p.require_client_classes," \ + " p.user_context," \ + " d.excluded_prefix," \ + " d.excluded_prefix_length," \ + " d.client_class," \ + " d.require_client_classes," \ + " d.user_context," \ + " s.ddns_send_updates," \ + " s.ddns_override_no_update," \ + " s.ddns_override_client_update," \ + " s.ddns_replace_client_name," \ + " s.ddns_generated_prefix," \ + " s.ddns_qualifying_suffix," \ + " s.reservations_in_subnet," \ + " s.reservations_out_of_pool," \ + " s.cache_threshold," \ + " s.cache_max_age," \ + " s.allocator," \ + " s.pd_allocator," \ + " srv.tag " \ + "FROM dhcp6_subnet AS s " \ + server_join \ + "LEFT JOIN dhcp6_pool AS p ON s.subnet_id = p.subnet_id " \ + "LEFT JOIN dhcp6_pd_pool AS d ON s.subnet_id = d.subnet_id " \ + "LEFT JOIN dhcp6_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \ + "LEFT JOIN dhcp6_options AS y ON y.scope_id = 6 AND d.id = y.pd_pool_id " \ + "LEFT JOIN dhcp6_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp6_subnet_id " \ + #__VA_ARGS__ \ + " ORDER BY s.subnet_id, p.id, d.id, x.option_id, y.option_id, o.option_id" + +#define PGSQL_GET_SUBNET6_NO_TAG(...) \ + PGSQL_GET_SUBNET6_COMMON( \ + "INNER JOIN dhcp6_subnet_server AS a " \ + " ON s.subnet_id = a.subnet_id " \ + "INNER JOIN dhcp6_server AS srv " \ + " ON (a.server_id = srv.id) ", \ + __VA_ARGS__) + +#define PGSQL_GET_SUBNET6_ANY(...) \ + PGSQL_GET_SUBNET6_COMMON( \ + "LEFT JOIN dhcp6_subnet_server AS a "\ + " ON s.subnet_id = a.subnet_id " \ + "LEFT JOIN dhcp6_server AS srv " \ + " ON a.server_id = srv.id ", \ + __VA_ARGS__) + +#define PGSQL_GET_SUBNET6_UNASSIGNED(...) \ + PGSQL_GET_SUBNET6_COMMON( \ + "LEFT JOIN dhcp6_subnet_server AS a "\ + " ON s.subnet_id = a.subnet_id " \ + "LEFT JOIN dhcp6_server AS srv " \ + " ON a.server_id = srv.id ", \ + WHERE a.subnet_id IS NULL __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_POOL4_COMMON +#define PGSQL_GET_POOL4_COMMON(server_join, ...) \ + "SELECT" \ + " p.id," \ + " p.start_address," \ + " p.end_address," \ + " p.subnet_id," \ + " p.client_class," \ + " p.require_client_classes," \ + " p.user_context," \ + " gmt_epoch(p.modification_ts) as modification_ts, " \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp4_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts " \ + "FROM dhcp4_pool AS p " \ + server_join \ + "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \ + #__VA_ARGS__ \ + " ORDER BY p.id, x.option_id" + +#define PGSQL_GET_POOL4_RANGE_WITH_TAG(...) \ + PGSQL_GET_POOL4_COMMON( \ + "INNER JOIN dhcp4_subnet_server AS s ON p.subnet_id = s.subnet_id " \ + "INNER JOIN dhcp4_server AS srv " \ + " ON (s.server_id = srv.id) OR (s.server_id = 1) ", \ + __VA_ARGS__) + +#define PGSQL_GET_POOL4_RANGE_NO_TAG(...) \ + PGSQL_GET_POOL4_COMMON("", __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_POOL6_COMMON +#define PGSQL_GET_POOL6_COMMON(server_join, ...) \ + "SELECT" \ + " p.id," \ + " p.start_address," \ + " p.end_address," \ + " p.subnet_id," \ + " p.client_class," \ + " p.require_client_classes," \ + " p.user_context," \ + " gmt_epoch(p.modification_ts) as modification_ts, " \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp6_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts, " \ + " x.pd_pool_id " \ + "FROM dhcp6_pool AS p " \ + server_join \ + "LEFT JOIN dhcp6_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \ + #__VA_ARGS__ \ + " ORDER BY p.id, x.option_id" + +#define PGSQL_GET_POOL6_RANGE_WITH_TAG(...) \ + PGSQL_GET_POOL6_COMMON( \ + "INNER JOIN dhcp6_subnet_server AS s ON p.subnet_id = s.subnet_id " \ + "INNER JOIN dhcp6_server AS srv " \ + " ON (s.server_id = srv.id) OR (s.server_id = 1) ", \ + __VA_ARGS__) + +#define PGSQL_GET_POOL6_RANGE_NO_TAG(...) \ + PGSQL_GET_POOL6_COMMON("", __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_PD_POOL_COMMON +#define PGSQL_GET_PD_POOL_COMMON(server_join, ...) \ + "SELECT" \ + " p.id," \ + " p.prefix," \ + " p.prefix_length," \ + " p.delegated_prefix_length," \ + " p.subnet_id," \ + " p.excluded_prefix," \ + " p.excluded_prefix_length," \ + " p.client_class," \ + " p.require_client_classes," \ + " p.user_context," \ + " gmt_epoch(p.modification_ts) as modification_ts, " \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp6_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts, " \ + " x.pd_pool_id " \ + "FROM dhcp6_pd_pool AS p " \ + server_join \ + "LEFT JOIN dhcp6_options AS x ON x.scope_id = 6 AND p.id = x.pd_pool_id " \ + #__VA_ARGS__ \ + " ORDER BY p.id, x.option_id" \ + +#define PGSQL_GET_PD_POOL_WITH_TAG(...) \ + PGSQL_GET_PD_POOL_COMMON( \ + "INNER JOIN dhcp6_subnet_server AS s ON p.subnet_id = s.subnet_id " \ + "INNER JOIN dhcp6_server AS srv " \ + " ON (s.server_id = srv.id) OR (s.server_id = 1) ", \ + __VA_ARGS__) + +#define PGSQL_GET_PD_POOL_NO_TAG(...) \ + PGSQL_GET_PD_POOL_COMMON("", __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_SHARED_NETWORK4 +#define PGSQL_GET_SHARED_NETWORK4_COMMON(server_join, ...) \ + "SELECT" \ + " n.id," \ + " n.name," \ + " n.client_class," \ + " n.interface," \ + " n.match_client_id," \ + " gmt_epoch(n.modification_ts) as modification_ts, " \ + " n.rebind_timer," \ + " n.relay," \ + " n.renew_timer," \ + " n.require_client_classes," \ + " n.reservations_global," \ + " n.user_context," \ + " n.valid_lifetime," \ + " o.option_id," \ + " o.code," \ + " o.value," \ + " o.formatted_value," \ + " o.space," \ + " o.persistent," \ + " o.cancelled," \ + " o.dhcp4_subnet_id," \ + " o.scope_id," \ + " o.user_context," \ + " o.shared_network_name," \ + " o.pool_id," \ + " gmt_epoch(o.modification_ts) as modification_ts, " \ + " n.calculate_tee_times," \ + " n.t1_percent," \ + " n.t2_percent," \ + " n.authoritative," \ + " n.boot_file_name," \ + " n.next_server," \ + " n.server_hostname," \ + " n.min_valid_lifetime," \ + " n.max_valid_lifetime," \ + " n.ddns_send_updates," \ + " n.ddns_override_no_update," \ + " n.ddns_override_client_update," \ + " n.ddns_replace_client_name," \ + " n.ddns_generated_prefix," \ + " n.ddns_qualifying_suffix," \ + " n.reservations_in_subnet," \ + " n.reservations_out_of_pool," \ + " n.cache_threshold," \ + " n.cache_max_age," \ + " n.offer_lifetime," \ + " n.allocator," \ + " s.tag " \ + "FROM dhcp4_shared_network AS n " \ + server_join \ + "LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name " \ + #__VA_ARGS__ \ + " ORDER BY n.id, s.id, o.option_id" + +#define PGSQL_GET_SHARED_NETWORK4_NO_TAG(...) \ + PGSQL_GET_SHARED_NETWORK4_COMMON( \ + "INNER JOIN dhcp4_shared_network_server AS a " \ + " ON n.id = a.shared_network_id " \ + "INNER JOIN dhcp4_server AS s " \ + " ON (a.server_id = s.id) ", \ + __VA_ARGS__) + +#define PGSQL_GET_SHARED_NETWORK4_ANY(...) \ + PGSQL_GET_SHARED_NETWORK4_COMMON( \ + "LEFT JOIN dhcp4_shared_network_server AS a " \ + " ON n.id = a.shared_network_id " \ + "LEFT JOIN dhcp4_server AS s " \ + " ON a.server_id = s.id ", \ + __VA_ARGS__) + +#define PGSQL_GET_SHARED_NETWORK4_UNASSIGNED(...) \ + PGSQL_GET_SHARED_NETWORK4_COMMON( \ + "LEFT JOIN dhcp4_shared_network_server AS a " \ + " ON n.id = a.shared_network_id " \ + "LEFT JOIN dhcp4_server AS s " \ + " ON a.server_id = s.id ", \ + WHERE a.shared_network_id IS NULL __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_SHARED_NETWORK6 +#define PGSQL_GET_SHARED_NETWORK6_COMMON(server_join, ...) \ + "SELECT" \ + " n.id," \ + " n.name," \ + " n.client_class," \ + " n.interface," \ + " gmt_epoch(n.modification_ts) as modification_ts, " \ + " n.preferred_lifetime," \ + " n.rapid_commit," \ + " n.rebind_timer," \ + " n.relay," \ + " n.renew_timer," \ + " n.require_client_classes," \ + " n.reservations_global," \ + " n.user_context," \ + " n.valid_lifetime," \ + " o.option_id," \ + " o.code," \ + " o.value," \ + " o.formatted_value," \ + " o.space," \ + " o.persistent," \ + " o.cancelled," \ + " o.dhcp6_subnet_id," \ + " o.scope_id," \ + " o.user_context," \ + " o.shared_network_name," \ + " o.pool_id," \ + " gmt_epoch(o.modification_ts) as modification_ts, " \ + " o.pd_pool_id, " \ + " n.calculate_tee_times," \ + " n.t1_percent," \ + " n.t2_percent," \ + " n.interface_id," \ + " n.min_preferred_lifetime," \ + " n.max_preferred_lifetime," \ + " n.min_valid_lifetime," \ + " n.max_valid_lifetime," \ + " n.ddns_send_updates," \ + " n.ddns_override_no_update," \ + " n.ddns_override_client_update," \ + " n.ddns_replace_client_name," \ + " n.ddns_generated_prefix," \ + " n.ddns_qualifying_suffix," \ + " n.reservations_in_subnet," \ + " n.reservations_out_of_pool," \ + " n.cache_threshold," \ + " n.cache_max_age," \ + " n.allocator," \ + " n.pd_allocator," \ + " s.tag " \ + "FROM dhcp6_shared_network AS n " \ + server_join \ + "LEFT JOIN dhcp6_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name " \ + #__VA_ARGS__ \ + " ORDER BY n.id, s.id, o.option_id" + +#define PGSQL_GET_SHARED_NETWORK6_NO_TAG(...) \ + PGSQL_GET_SHARED_NETWORK6_COMMON( \ + "INNER JOIN dhcp6_shared_network_server AS a " \ + " ON n.id = a.shared_network_id " \ + "INNER JOIN dhcp6_server AS s " \ + " ON (a.server_id = s.id) ", \ + __VA_ARGS__) + +#define PGSQL_GET_SHARED_NETWORK6_ANY(...) \ + PGSQL_GET_SHARED_NETWORK6_COMMON( \ + "LEFT JOIN dhcp6_shared_network_server AS a " \ + " ON n.id = a.shared_network_id " \ + "LEFT JOIN dhcp6_server AS s " \ + " ON a.server_id = s.id ", \ + __VA_ARGS__) + +#define PGSQL_GET_SHARED_NETWORK6_UNASSIGNED(...) \ + PGSQL_GET_SHARED_NETWORK6_COMMON( \ + "LEFT JOIN dhcp6_shared_network_server AS a " \ + " ON n.id = a.shared_network_id " \ + "LEFT JOIN dhcp6_server AS s " \ + " ON a.server_id = s.id ", \ + WHERE a.shared_network_id IS NULL __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_OPTION_DEF +#define PGSQL_GET_OPTION_DEF(table_prefix, ...) \ + "SELECT" \ + " d.id," \ + " d.code," \ + " d.name," \ + " d.space," \ + " d.type," \ + " gmt_epoch(d.modification_ts) as modification_ts, " \ + " d.is_array," \ + " d.encapsulate," \ + " d.record_types," \ + " d.user_context," \ + " s.tag " \ + "FROM " #table_prefix "_option_def AS d " \ + "INNER JOIN " #table_prefix "_option_def_server AS a" \ + " ON d.id = a.option_def_id " \ + "INNER JOIN " #table_prefix "_server AS s " \ + " ON a.server_id = s.id " \ + "WHERE (s.tag = $1 OR s.id = 1) " #__VA_ARGS__ \ + " ORDER BY d.id" +#endif + +#ifndef PGSQL_GET_OPTION_COMMON +#define PGSQL_GET_OPTION_COMMON(table_prefix, pd_pool_id, ...) \ + "SELECT" \ + " o.option_id," \ + " o.code," \ + " o.value," \ + " o.formatted_value," \ + " o.space," \ + " o.persistent," \ + " o.cancelled," \ + " o." #table_prefix "_subnet_id," \ + " o.scope_id," \ + " o.user_context," \ + " o.shared_network_name," \ + " o.pool_id," \ + " gmt_epoch(o.modification_ts) as modification_ts, " \ + " s.tag " \ + pd_pool_id \ + "FROM " #table_prefix "_options AS o " \ + "INNER JOIN " #table_prefix "_options_server AS a" \ + " ON o.option_id = a.option_id " \ + "INNER JOIN " #table_prefix "_server AS s" \ + " ON a.server_id = s.id " \ + "WHERE (s.tag = $1 OR s.id = 1) " #__VA_ARGS__ \ + " ORDER BY o.option_id, s.id" + +#define PGSQL_GET_OPTION4(...) \ + PGSQL_GET_OPTION_COMMON(dhcp4, "", __VA_ARGS__) + +#define PGSQL_GET_OPTION6(...) \ + PGSQL_GET_OPTION_COMMON(dhcp6, ", o.pd_pool_id ", __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_AUDIT_ENTRIES_TIME +#define PGSQL_GET_AUDIT_ENTRIES_TIME(table_prefix) \ + "SELECT" \ + " a.id," \ + " a.object_type," \ + " a.object_id," \ + " a.modification_type," \ + " gmt_epoch(r.modification_ts) as modification_ts, " \ + " r.id, " \ + " r.log_message " \ + "FROM " #table_prefix "_audit AS a " \ + "INNER JOIN " #table_prefix "_audit_revision AS r " \ + " ON a.revision_id = r.id " \ + "INNER JOIN " #table_prefix "_server AS s" \ + " ON r.server_id = s.id " \ + "WHERE (s.tag = $1 OR s.id = 1) AND ((r.modification_ts, r.id) > (cast($2 as timestamp), $3))" \ + " ORDER BY r.modification_ts, r.id, a.id" +#endif + +#ifndef PGSQL_GET_SERVERS_COMMON +#define PGSQL_GET_SERVERS_COMMON(table_prefix, ...) \ + "SELECT" \ + " s.id," \ + " s.tag," \ + " s.description," \ + " gmt_epoch(s.modification_ts) as modification_ts " \ + "FROM " #table_prefix "_server AS s " \ + "WHERE s.id > 1 " \ + __VA_ARGS__ \ + " ORDER BY s.id" + +#define PGSQL_GET_ALL_SERVERS(table_prefix) \ + PGSQL_GET_SERVERS_COMMON(table_prefix, "") + +#define PGSQL_GET_SERVER(table_prefix) \ + PGSQL_GET_SERVERS_COMMON(table_prefix, " AND s.tag = $1") +#endif + +#ifndef PGSQL_GET_CLIENT_CLASS4_COMMON +#define PGSQL_GET_CLIENT_CLASS4_COMMON(server_join, ...) \ + "SELECT " \ + " c.id," \ + " c.name," \ + " c.test," \ + " c.next_server," \ + " c.server_hostname," \ + " c.boot_file_name," \ + " c.only_if_required," \ + " c.valid_lifetime," \ + " c.min_valid_lifetime," \ + " c.max_valid_lifetime," \ + " c.depend_on_known_directly," \ + " o.depend_on_known_indirectly, " \ + " gmt_epoch(c.modification_ts) as modification_ts, " \ + " c.user_context," \ + " c.offer_lifetime," \ + " d.id," \ + " d.code," \ + " d.name," \ + " d.space," \ + " d.type," \ + " gmt_epoch(d.modification_ts) as modification_ts, " \ + " d.is_array," \ + " d.encapsulate," \ + " d.record_types," \ + " d.user_context," \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp4_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts, " \ + " s.tag " \ + "FROM dhcp4_client_class AS c " \ + "INNER JOIN dhcp4_client_class_order AS o " \ + " ON c.id = o.class_id " \ + server_join \ + "LEFT JOIN dhcp4_option_def AS d ON c.id = d.class_id " \ + "LEFT JOIN dhcp4_options AS x ON x.scope_id = 2 AND c.name = x.dhcp_client_class " \ + #__VA_ARGS__ \ + " ORDER BY o.order_index, d.id, x.option_id" + +#define PGSQL_GET_CLIENT_CLASS4_WITH_TAG(...) \ + PGSQL_GET_CLIENT_CLASS4_COMMON( \ + "INNER JOIN dhcp4_client_class_server AS a " \ + " ON c.id = a.class_id " \ + "INNER JOIN dhcp4_server AS s " \ + " ON a.server_id = s.id ", \ + __VA_ARGS__) + +#define PGSQL_GET_CLIENT_CLASS4_UNASSIGNED(...) \ + PGSQL_GET_CLIENT_CLASS4_COMMON( \ + "LEFT JOIN dhcp4_client_class_server AS a " \ + " ON c.id = a.class_id " \ + "LEFT JOIN dhcp4_server AS s " \ + " ON a.server_id = s.id ", \ + WHERE a.class_id IS NULL __VA_ARGS__) +#endif + +#ifndef PGSQL_GET_CLIENT_CLASS6_COMMON +#define PGSQL_GET_CLIENT_CLASS6_COMMON(server_join, ...) \ + "SELECT " \ + " c.id," \ + " c.name," \ + " c.test," \ + " c.only_if_required," \ + " c.valid_lifetime," \ + " c.min_valid_lifetime," \ + " c.max_valid_lifetime," \ + " c.depend_on_known_directly," \ + " o.depend_on_known_indirectly, " \ + " gmt_epoch(c.modification_ts) as modification_ts, " \ + " c.user_context, " \ + " d.id," \ + " d.code," \ + " d.name," \ + " d.space," \ + " d.type," \ + " gmt_epoch(d.modification_ts) as modification_ts, " \ + " d.is_array," \ + " d.encapsulate," \ + " d.record_types," \ + " d.user_context," \ + " x.option_id," \ + " x.code," \ + " x.value," \ + " x.formatted_value," \ + " x.space," \ + " x.persistent," \ + " x.cancelled," \ + " x.dhcp6_subnet_id," \ + " x.scope_id," \ + " x.user_context," \ + " x.shared_network_name," \ + " x.pool_id," \ + " gmt_epoch(x.modification_ts) as modification_ts, " \ + " s.tag, " \ + " c.preferred_lifetime," \ + " c.min_preferred_lifetime, " \ + " c.max_preferred_lifetime " \ + "FROM dhcp6_client_class AS c " \ + "INNER JOIN dhcp6_client_class_order AS o " \ + " ON c.id = o.class_id " \ + server_join \ + "LEFT JOIN dhcp6_option_def AS d ON c.id = d.class_id " \ + "LEFT JOIN dhcp6_options AS x ON x.scope_id = 2 AND c.name = x.dhcp_client_class " \ + #__VA_ARGS__ \ + " ORDER BY o.order_index, d.id, x.option_id" + +#define PGSQL_GET_CLIENT_CLASS6_WITH_TAG(...) \ + PGSQL_GET_CLIENT_CLASS6_COMMON( \ + "INNER JOIN dhcp6_client_class_server AS a " \ + " ON c.id = a.class_id " \ + "INNER JOIN dhcp6_server AS s " \ + " ON a.server_id = s.id ", \ + __VA_ARGS__) + +#define PGSQL_GET_CLIENT_CLASS6_UNASSIGNED(...) \ + PGSQL_GET_CLIENT_CLASS6_COMMON( \ + "LEFT JOIN dhcp6_client_class_server AS a " \ + " ON c.id = a.class_id " \ + "LEFT JOIN dhcp6_server AS s " \ + " ON a.server_id = s.id ", \ + WHERE a.class_id IS NULL __VA_ARGS__) +#endif + +#ifndef PGSQL_INSERT_GLOBAL_PARAMETER +#define PGSQL_INSERT_GLOBAL_PARAMETER(table_prefix) \ + "INSERT INTO " #table_prefix "_global_parameter(" \ + " name," \ + " value," \ + " parameter_type," \ + " modification_ts" \ + ") VALUES ($1, $2, $3, $4)" +#endif + +#ifndef PGSQL_INSERT_GLOBAL_PARAMETER_SERVER +#define PGSQL_INSERT_GLOBAL_PARAMETER_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_global_parameter_server(" \ + " parameter_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))" +#endif + +#ifndef PGSQL_INSERT_SUBNET_SERVER +#define PGSQL_INSERT_SUBNET_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_subnet_server(" \ + " subnet_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))" +#endif + +#ifndef PGSQL_INSERT_POOL +#define PGSQL_INSERT_POOL(table_prefix) \ + "INSERT INTO " #table_prefix "_pool(" \ + " start_address," \ + " end_address," \ + " subnet_id," \ + " client_class," \ + " require_client_classes," \ + " user_context," \ + " modification_ts" \ + ") VALUES (cast($1 as inet), cast($2 as inet), $3, $4, $5, cast($6 as json), $7)" +#endif + +#ifndef PGSQL_INSERT_PD_POOL +#define PGSQL_INSERT_PD_POOL() \ + "INSERT INTO dhcp6_pd_pool(" \ + " prefix," \ + " prefix_length," \ + " delegated_prefix_length," \ + " subnet_id," \ + " excluded_prefix," \ + " excluded_prefix_length," \ + " client_class," \ + " require_client_classes," \ + " user_context," \ + " modification_ts" \ + ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), $10)" +#endif + +#ifndef PGSQL_INSERT_SHARED_NETWORK_SERVER +#define PGSQL_INSERT_SHARED_NETWORK_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_shared_network_server(" \ + " shared_network_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES (" \ + " (SELECT id FROM " #table_prefix "_shared_network WHERE name = $1), $2," \ + " (SELECT id FROM " #table_prefix "_server WHERE tag = $3)" \ + ")" +#endif + +#ifndef PGSQL_INSERT_OPTION_DEF +#define PGSQL_INSERT_OPTION_DEF(table_prefix) \ + "INSERT INTO " #table_prefix "_option_def (" \ + " code," \ + " name," \ + " space," \ + " type," \ + " modification_ts," \ + " is_array," \ + " encapsulate," \ + " record_types," \ + " user_context," \ + " class_id" \ + ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), $10)" +#endif + +#ifndef PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS +#define PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS(table_prefix) \ + "INSERT INTO " #table_prefix "_option_def (" \ + " code," \ + " name," \ + " space," \ + " type," \ + " modification_ts," \ + " is_array," \ + " encapsulate," \ + " record_types," \ + " user_context," \ + " class_id" \ + ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), " \ + " (SELECT id FROM " #table_prefix "_client_class WHERE name = $10))" +#endif + +#ifndef PGSQL_INSERT_OPTION_DEF_SERVER +#define PGSQL_INSERT_OPTION_DEF_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_option_def_server(" \ + " option_def_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))" +#endif + +#ifndef PGSQL_INSERT_OPTION_COMMON +#define PGSQL_INSERT_OPTION_COMMON(table_prefix, pd_pool_id, last) \ + "INSERT INTO " #table_prefix "_options (" \ + " code," \ + " value," \ + " formatted_value," \ + " space," \ + " persistent," \ + " cancelled," \ + " dhcp_client_class," \ + " " #table_prefix "_subnet_id," \ + " scope_id," \ + " user_context," \ + " shared_network_name," \ + " pool_id," \ + " modification_ts" \ + pd_pool_id \ + ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, cast($10 as json), $11, $12, $13" last ")" + +#define PGSQL_INSERT_OPTION4() \ + PGSQL_INSERT_OPTION_COMMON(dhcp4, "", "") + +#define PGSQL_INSERT_OPTION6() \ + PGSQL_INSERT_OPTION_COMMON(dhcp6, ", pd_pool_id ", ", $14") +#endif + +#ifndef PGSQL_INSERT_OPTION_SERVER +#define PGSQL_INSERT_OPTION_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_options_server (" \ + " option_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))" +#endif + +#ifndef PGSQL_INSERT_CLIENT_CLASS_SERVER +#define PGSQL_INSERT_CLIENT_CLASS_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_client_class_server (" \ + " class_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES ((SELECT id FROM " #table_prefix "_client_class WHERE name = $1), $2," \ + " (SELECT id FROM " #table_prefix "_server WHERE tag = $3))" +#endif + +#ifndef PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY +#define PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY(table_prefix) \ + "INSERT INTO " #table_prefix "_client_class_dependency (" \ + " class_id," \ + " dependency_id" \ + ") VALUES ((SELECT id FROM " #table_prefix "_client_class WHERE name = $1), " \ + " (SELECT id FROM " #table_prefix "_client_class WHERE name = $2))" +#endif + +#ifndef PGSQL_INSERT_SERVER +#define PGSQL_INSERT_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_server (" \ + " tag," \ + " description," \ + " modification_ts" \ + ") VALUES ($1, $2, $3)" +#endif + +#ifndef PGSQL_UPDATE_GLOBAL_PARAMETER +#define PGSQL_UPDATE_GLOBAL_PARAMETER(table_prefix) \ + "UPDATE " #table_prefix "_global_parameter AS g " \ + "SET " \ + " name = $1, " \ + " value = $2, " \ + " parameter_type = $3, " \ + " modification_ts = $4 " \ + "FROM " #table_prefix "_global_parameter_server as a, " \ + " " #table_prefix "_server as s " \ + "WHERE g.id = a.parameter_id AND " \ + " a.server_id = s.id AND " \ + " s.tag = $5 AND g.name = $6" +#endif + +#ifndef PGSQL_UPDATE_OPTION_DEF +#define PGSQL_UPDATE_OPTION_DEF(table_prefix) \ + "UPDATE " #table_prefix "_option_def AS d " \ + "SET" \ + " code = $1," \ + " name = $2," \ + " space = $3," \ + " type = $4," \ + " modification_ts = $5," \ + " is_array = $6," \ + " encapsulate = $7," \ + " record_types = $8," \ + " user_context = cast($9 as json), " \ + " class_id = $10 " \ + "FROM " #table_prefix "_option_def_server as a, " \ + " " #table_prefix "_server as s " \ + "WHERE d.id = a.option_def_id AND" \ + " a.server_id = s.id AND " \ + " s.tag = $11 AND d.code = $12 AND d.space = $13" +#endif + +#ifndef PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS +#define PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(table_prefix) \ + "UPDATE " #table_prefix "_option_def AS d " \ + "SET" \ + " code = $1," \ + " name = $2," \ + " space = $3," \ + " type = $4," \ + " modification_ts = $5," \ + " is_array = $6," \ + " encapsulate = $7," \ + " record_types = $8," \ + " user_context = cast($9 as json) " \ + "FROM " #table_prefix "_option_def_server as a, " \ + " " #table_prefix "_server as s " \ + "WHERE d.id = a.option_def_id AND " \ + " a.server_id = s.id AND " \ + " d.class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = $10) " \ + " AND s.tag = $11 AND d.code = $12 AND d.space = $13" +#endif + +#ifndef PGSQL_UPDATE_OPTION_NO_TAG +#define PGSQL_UPDATE_OPTION_NO_TAG(table_prefix, pd_pool_id, ...) \ + "UPDATE " #table_prefix "_options AS o " \ + "SET" \ + " code = $1," \ + " value = $2," \ + " formatted_value = $3," \ + " space = $4," \ + " persistent = $5," \ + " cancelled = $6," \ + " dhcp_client_class = $7," \ + " " #table_prefix "_subnet_id = $8," \ + " scope_id = $9," \ + " user_context = cast($10 as json)," \ + " shared_network_name = $11," \ + " pool_id = $12," \ + " modification_ts = $13 " \ + pd_pool_id \ + "WHERE " #__VA_ARGS__ + +#define PGSQL_UPDATE_OPTION4_NO_TAG(...) \ + PGSQL_UPDATE_OPTION_NO_TAG(dhcp4, "", __VA_ARGS__) + +#define PGSQL_UPDATE_OPTION6_NO_TAG(...) \ + PGSQL_UPDATE_OPTION_NO_TAG(dhcp6, ", pd_pool_id = $14 ", __VA_ARGS__) +#endif + +#ifndef PGSQL_UPDATE_OPTION_WITH_TAG +#define PGSQL_UPDATE_OPTION_WITH_TAG(table_prefix, pd_pool_id, ...) \ + "UPDATE " #table_prefix "_options AS o " \ + "SET" \ + " code = $1," \ + " value = $2," \ + " formatted_value = $3," \ + " space = $4," \ + " persistent = $5," \ + " cancelled = $6," \ + " dhcp_client_class = $7," \ + " " #table_prefix "_subnet_id = $8," \ + " scope_id = $9," \ + " user_context = cast($10 as json)," \ + " shared_network_name = $11," \ + " pool_id = $12," \ + " modification_ts = $13 " \ + pd_pool_id \ + "FROM " #table_prefix "_options_server as a, " \ + " " #table_prefix "_server as s " \ + "WHERE o.option_id = a.option_id AND " \ + " a.server_id = s.id " \ + #__VA_ARGS__ + +#define PGSQL_UPDATE_OPTION4_WITH_TAG(...) \ + PGSQL_UPDATE_OPTION_WITH_TAG(dhcp4, "", AND s.tag = $14 __VA_ARGS__) + +#define PGSQL_UPDATE_OPTION6_WITH_TAG(...) \ + PGSQL_UPDATE_OPTION_WITH_TAG(dhcp6, \ + ", pd_pool_id = $14 ", AND s.tag = $15 __VA_ARGS__) +#endif + +#ifndef PGSQL_UPDATE_CLIENT_CLASS4 +#define PGSQL_UPDATE_CLIENT_CLASS4(follow_class_name_set) \ + "UPDATE dhcp4_client_class SET" \ + " name = $1," \ + " test = $2," \ + " next_server = cast($3 as inet)," \ + " server_hostname = $4," \ + " boot_file_name = $5," \ + " only_if_required = $6," \ + " valid_lifetime = $7," \ + " min_valid_lifetime = $8," \ + " max_valid_lifetime = $9," \ + " depend_on_known_directly = $10," \ + follow_class_name_set \ + " modification_ts = $12, " \ + " user_context = cast($13 as json), " \ + " offer_lifetime = $14 " \ + "WHERE name = $15" +#endif + +#ifndef PGSQL_UPDATE_CLIENT_CLASS6 +#define PGSQL_UPDATE_CLIENT_CLASS6(follow_class_name_set) \ + "UPDATE dhcp6_client_class SET" \ + " name = $1," \ + " test = $2," \ + " only_if_required = $3," \ + " valid_lifetime = $4," \ + " min_valid_lifetime = $5," \ + " max_valid_lifetime = $6," \ + " depend_on_known_directly = $7," \ + follow_class_name_set \ + " preferred_lifetime = $9, " \ + " min_preferred_lifetime = $10, " \ + " max_preferred_lifetime = $11, " \ + " modification_ts = $12, " \ + " user_context = cast($13 as json) " \ + "WHERE name = $14" +#endif + +#ifndef PGSQL_UPDATE_SERVER +#define PGSQL_UPDATE_SERVER(table_prefix) \ + "UPDATE " #table_prefix "_server " \ + "SET" \ + " tag = $1," \ + " description = $2," \ + " modification_ts = $3 " \ + "WHERE tag = $4" +#endif + +#ifndef PGSQL_DELETE_GLOBAL_PARAMETER +#define PGSQL_DELETE_GLOBAL_PARAMETER(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_global_parameter AS g " \ + "USING " \ + " " #table_prefix "_global_parameter_server AS a, " \ + " " #table_prefix "_server AS s " \ + "WHERE " \ + " g.id = a.parameter_id AND " \ + " a.server_id = s.id AND " \ + " s.tag = $1 " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED +#define PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_global_parameter AS g " \ + "WHERE g.id in ( " \ + " SELECT g.id FROM " #table_prefix "_global_parameter AS g " \ + " LEFT JOIN " #table_prefix "_global_parameter_server AS a ON g.id = a.parameter_id " \ + " WHERE a.parameter_id IS NULL) " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_SUBNET_COMMON +#define PGSQL_DELETE_SUBNET_COMMON(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_subnet AS s " \ + "USING " \ + " " #table_prefix "_subnet_server AS a, " \ + " " #table_prefix "_server AS srv " \ + "WHERE " \ + " s.subnet_id = a.subnet_id AND " \ + " a.server_id = srv.id " \ + #__VA_ARGS__ + +#define PGSQL_DELETE_SUBNET_WITH_TAG(table_prefix, ...) \ + PGSQL_DELETE_SUBNET_COMMON(table_prefix, AND srv.tag = $1 __VA_ARGS__) + +#define PGSQL_DELETE_SUBNET_ANY(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_subnet AS s " \ + #__VA_ARGS__ + +#define PGSQL_DELETE_SUBNET_UNASSIGNED(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_subnet AS s " \ + "WHERE s.subnet_id in ( " \ + " SELECT s.subnet_id FROM " #table_prefix "_subnet AS s " \ + " LEFT JOIN " #table_prefix "_subnet_server AS a ON s.subnet_id = a.subnet_id " \ + " WHERE a.subnet_id IS NULL) " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_SUBNET_SERVER +#define PGSQL_DELETE_SUBNET_SERVER(table_prefix) \ + "DELETE FROM " #table_prefix "_subnet_server " \ + "WHERE subnet_id = $1" +#endif + +#ifndef PGSQL_DELETE_POOLS +#define PGSQL_DELETE_POOLS(table_prefix) \ + "DELETE FROM " #table_prefix "_pool " \ + "WHERE subnet_id = $1 OR subnet_id = " \ + "(SELECT subnet_id FROM " #table_prefix "_subnet" \ + " WHERE subnet_prefix = $2)" +#endif + +#ifndef PGSQL_DELETE_PD_POOLS +#define PGSQL_DELETE_PD_POOLS() \ + "DELETE FROM dhcp6_pd_pool " \ + "WHERE subnet_id = $1 OR subnet_id = " \ + "(SELECT subnet_id FROM dhcp6_subnet" \ + " WHERE subnet_prefix = $2)" +#endif + +#ifndef PGSQL_DELETE_SHARED_NETWORK_COMMON +#define PGSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_shared_network AS n " \ + "USING " \ + " " #table_prefix "_shared_network_server AS a, " \ + " " #table_prefix "_server AS s " \ + "WHERE " \ + " n.id = a.shared_network_id AND " \ + " a.server_id = s.id " \ + #__VA_ARGS__ + +#define PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(table_prefix, ...) \ + PGSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, AND s.tag = $1 __VA_ARGS__) + +#define PGSQL_DELETE_SHARED_NETWORK_ANY(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_shared_network AS n " \ + #__VA_ARGS__ + +#define PGSQL_DELETE_SHARED_NETWORK_UNASSIGNED(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_shared_network AS n " \ + "WHERE n.id in ( " \ + " SELECT n.id FROM " #table_prefix "_shared_network AS n " \ + " LEFT JOIN " #table_prefix "_shared_network_server AS a ON n.id = a.shared_network_id " \ + " WHERE a.shared_network_id IS NULL) " \ + #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_SHARED_NETWORK_SERVER +#define PGSQL_DELETE_SHARED_NETWORK_SERVER(table_prefix) \ + "DELETE FROM " #table_prefix "_shared_network_server " \ + "WHERE shared_network_id = " \ + "(SELECT id FROM " #table_prefix "_shared_network WHERE name = $1)" +#endif + +#ifndef PGSQL_DELETE_OPTION_DEF +#define PGSQL_DELETE_OPTION_DEF(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_option_def AS d " \ + "USING " \ + " " #table_prefix "_option_def_server AS a, " \ + " " #table_prefix "_server AS s " \ + "WHERE " \ + " d.id = a.option_def_id AND " \ + " a.server_id = s.id AND " \ + " s.tag = $1 " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_OPTION_DEF_UNASSIGNED +#define PGSQL_DELETE_OPTION_DEF_UNASSIGNED(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_option_def AS d " \ + "WHERE d.id in ( " \ + " SELECT d.id FROM " #table_prefix "_option_def AS d " \ + " LEFT JOIN " #table_prefix "_option_def_server AS a ON d.id = a.option_def_id " \ + " WHERE a.option_def_id IS NULL) " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS +#define PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(table_prefix) \ + "DELETE FROM " #table_prefix "_option_def " \ + "WHERE class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = $1)" +#endif + +#ifndef PGSQL_DELETE_OPTION_WITH_TAG +#define PGSQL_DELETE_OPTION_WITH_TAG(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_options AS o " \ + "USING " \ + " " #table_prefix "_options_server AS a, " \ + " " #table_prefix "_server AS s " \ + "WHERE " \ + " o.option_id = a.option_id AND " \ + " a.server_id = s.id AND " \ + " s.tag = $1 " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_OPTION_NO_TAG +#define PGSQL_DELETE_OPTION_NO_TAG(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_options AS o " \ + #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX +#define PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX(table_prefix) \ + "DELETE FROM " #table_prefix "_options AS o " \ + "USING " \ + " " #table_prefix "_subnet AS s " \ + "WHERE " \ + " s.subnet_id = o." #table_prefix "_subnet_id AND " \ + " o.scope_id = 1 AND (s.subnet_id = $1 OR s.subnet_prefix = $2)" +#endif + +#ifndef PGSQL_DELETE_OPTION_UNASSIGNED +#define PGSQL_DELETE_OPTION_UNASSIGNED(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_options AS o " \ + "WHERE o.option_id in ( " \ + " SELECT o.option_id FROM " #table_prefix "_options AS o " \ + " LEFT JOIN " #table_prefix "_options_server AS a ON o.option_id = a.option_id " \ + " WHERE a.option_id IS NULL) " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_OPTION_POOL_RANGE +#define PGSQL_DELETE_OPTION_POOL_RANGE(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_options AS o " \ + "WHERE " #__VA_ARGS__ \ + " AND o.pool_id = " \ + " (SELECT id FROM " #table_prefix "_pool" \ + " WHERE start_address = cast($1 as inet) AND end_address = cast($2 as inet))" +#endif + +#ifndef PGSQL_DELETE_OPTION_PD_POOL +#define PGSQL_DELETE_OPTION_PD_POOL(...) \ + "DELETE FROM dhcp6_options AS o " \ + "WHERE " #__VA_ARGS__ \ + " AND o.pd_pool_id = " \ + " (SELECT id FROM dhcp6_pd_pool" \ + " WHERE prefix = $1 AND prefix_length = $2)" +#endif + +#ifndef PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY +#define PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY(table_prefix) \ + "DELETE FROM " #table_prefix "_client_class_dependency " \ + "WHERE class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = $1)" +#endif + +#ifndef PGSQL_DELETE_CLIENT_CLASS_SERVER +#define PGSQL_DELETE_CLIENT_CLASS_SERVER(table_prefix) \ + "DELETE FROM " #table_prefix "_client_class_server " \ + "WHERE class_id = " \ + "(SELECT id FROM " #table_prefix "_client_class WHERE name = $1)" +#endif + +#ifndef PGSQL_DELETE_CLIENT_CLASS_COMMON +#define PGSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_client_class AS c " \ + "USING " \ + " " #table_prefix "_client_class_server AS a, " \ + " " #table_prefix "_server AS s " \ + "WHERE " \ + " c.id = a.class_id AND " \ + " a.server_id = s.id " \ + #__VA_ARGS__ + +#define PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(table_prefix, ...) \ + PGSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, AND s.tag = $1 __VA_ARGS__) + +#define PGSQL_DELETE_CLIENT_CLASS_ANY(table_prefix, ...) \ + PGSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, __VA_ARGS__) + +#define PGSQL_DELETE_CLIENT_CLASS_UNASSIGNED(table_prefix, ...) \ + "DELETE FROM " #table_prefix "_client_class AS c " \ + "WHERE c.id in (" \ + " SELECT c.id FROM " #table_prefix "_client_class AS c " \ + " LEFT JOIN " #table_prefix "_client_class_server AS a ON c.id = a.class_id " \ + " WHERE a.class_id IS NULL) " #__VA_ARGS__ +#endif + +#ifndef PGSQL_DELETE_SERVER +#define PGSQL_DELETE_SERVER(table_prefix) \ + "DELETE FROM " #table_prefix "_server " \ + "WHERE tag = $1" +#endif + +#ifndef PGSQL_DELETE_ALL_SERVERS +#define PGSQL_DELETE_ALL_SERVERS(table_prefix) \ + "DELETE FROM " #table_prefix "_server " \ + "WHERE id > 1" +#endif + +} // end of anonymous namespace + +} // end of namespace isc::dhcp +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/pgsql_cb/tests/Makefile.am b/src/hooks/dhcp/pgsql_cb/tests/Makefile.am new file mode 100644 index 0000000..f285cfd --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/Makefile.am @@ -0,0 +1,64 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/pgsql_cb -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb +AM_CPPFLAGS += $(BOOST_INCLUDES) $(PGSQL_CPPFLAGS) +AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\" + +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +# Unit test data files need to get installed. +EXTRA_DIST = + +CLEANFILES = *.gcno *.gcda + +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +TESTS = +if HAVE_GTEST +TESTS += pgsql_cb_unittests + +pgsql_cb_unittests_SOURCES = pgsql_cb_impl_unittest.cc +pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp4_unittest.cc +pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp4_mgr_unittest.cc +pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp6_unittest.cc +pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp6_mgr_unittest.cc +pgsql_cb_unittests_SOURCES += run_unittests.cc + +pgsql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) + +pgsql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) + +pgsql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS) + +pgsql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/pgsql_cb/libpgsqlcb.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/pgsql/testutils/libpgsqltest.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/pgsql/libkea-pgsql.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la +pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +pgsql_cb_unittests_LDADD += $(LOG4CPLUS_LIBS) +pgsql_cb_unittests_LDADD += $(CRYPTO_LIBS) +pgsql_cb_unittests_LDADD += $(BOOST_LIBS) +pgsql_cb_unittests_LDADD += $(GTEST_LDADD) +endif +noinst_PROGRAMS = $(TESTS) diff --git a/src/hooks/dhcp/pgsql_cb/tests/Makefile.in b/src/hooks/dhcp/pgsql_cb/tests/Makefile.in new file mode 100644 index 0000000..256f305 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/Makefile.in @@ -0,0 +1,1124 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +TESTS = $(am__EXEEXT_1) +@HAVE_GTEST_TRUE@am__append_1 = pgsql_cb_unittests +noinst_PROGRAMS = $(am__EXEEXT_2) +subdir = src/hooks/dhcp/pgsql_cb/tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp11.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.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)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_GTEST_TRUE@am__EXEEXT_1 = pgsql_cb_unittests$(EXEEXT) +am__EXEEXT_2 = $(am__EXEEXT_1) +PROGRAMS = $(noinst_PROGRAMS) +am__pgsql_cb_unittests_SOURCES_DIST = pgsql_cb_impl_unittest.cc \ + pgsql_cb_dhcp4_unittest.cc pgsql_cb_dhcp4_mgr_unittest.cc \ + pgsql_cb_dhcp6_unittest.cc pgsql_cb_dhcp6_mgr_unittest.cc \ + run_unittests.cc +@HAVE_GTEST_TRUE@am_pgsql_cb_unittests_OBJECTS = pgsql_cb_unittests-pgsql_cb_impl_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ pgsql_cb_unittests-run_unittests.$(OBJEXT) +pgsql_cb_unittests_OBJECTS = $(am_pgsql_cb_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@pgsql_cb_unittests_DEPENDENCIES = $(top_builddir)/src/hooks/dhcp/pgsql_cb/libpgsqlcb.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/testutils/libpgsqltest.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +pgsql_cb_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) \ + $(pgsql_cb_unittests_LDFLAGS) $(LDFLAGS) -o $@ +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 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = \ + ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po \ + ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po \ + ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po \ + ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po \ + ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po \ + ./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(pgsql_cb_unittests_SOURCES) +DIST_SOURCES = $(am__pgsql_cb_unittests_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +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@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +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@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +YACC = @YACC@ +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_CXX = @ac_ct_CXX@ +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@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +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@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + -I$(top_builddir)/src/hooks/dhcp/pgsql_cb \ + -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb $(BOOST_INCLUDES) \ + $(PGSQL_CPPFLAGS) \ + -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\" +AM_CXXFLAGS = $(KEA_CXXFLAGS) +@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static + +# Unit test data files need to get installed. +EXTRA_DIST = +CLEANFILES = *.gcno *.gcda +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) +@HAVE_GTEST_TRUE@pgsql_cb_unittests_SOURCES = \ +@HAVE_GTEST_TRUE@ pgsql_cb_impl_unittest.cc \ +@HAVE_GTEST_TRUE@ pgsql_cb_dhcp4_unittest.cc \ +@HAVE_GTEST_TRUE@ pgsql_cb_dhcp4_mgr_unittest.cc \ +@HAVE_GTEST_TRUE@ pgsql_cb_dhcp6_unittest.cc \ +@HAVE_GTEST_TRUE@ pgsql_cb_dhcp6_mgr_unittest.cc \ +@HAVE_GTEST_TRUE@ run_unittests.cc +@HAVE_GTEST_TRUE@pgsql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +@HAVE_GTEST_TRUE@pgsql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) +@HAVE_GTEST_TRUE@pgsql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS) +@HAVE_GTEST_TRUE@pgsql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/pgsql_cb/libpgsqlcb.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/testutils/libpgsqltest.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \ +@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(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 src/hooks/dhcp/pgsql_cb/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/tests/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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + 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): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +pgsql_cb_unittests$(EXEEXT): $(pgsql_cb_unittests_OBJECTS) $(pgsql_cb_unittests_DEPENDENCIES) $(EXTRA_pgsql_cb_unittests_DEPENDENCIES) + @rm -f pgsql_cb_unittests$(EXEEXT) + $(AM_V_CXXLD)$(pgsql_cb_unittests_LINK) $(pgsql_cb_unittests_OBJECTS) $(pgsql_cb_unittests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +pgsql_cb_unittests-pgsql_cb_impl_unittest.o: pgsql_cb_impl_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_impl_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.o `test -f 'pgsql_cb_impl_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_impl_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_impl_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_impl_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.o `test -f 'pgsql_cb_impl_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_impl_unittest.cc + +pgsql_cb_unittests-pgsql_cb_impl_unittest.obj: pgsql_cb_impl_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_impl_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.obj `if test -f 'pgsql_cb_impl_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_impl_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_impl_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_impl_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_impl_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.obj `if test -f 'pgsql_cb_impl_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_impl_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_impl_unittest.cc'; fi` + +pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o: pgsql_cb_dhcp4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o `test -f 'pgsql_cb_dhcp4_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o `test -f 'pgsql_cb_dhcp4_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_unittest.cc + +pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj: pgsql_cb_dhcp4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj `if test -f 'pgsql_cb_dhcp4_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj `if test -f 'pgsql_cb_dhcp4_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_unittest.cc'; fi` + +pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o: pgsql_cb_dhcp4_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o `test -f 'pgsql_cb_dhcp4_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o `test -f 'pgsql_cb_dhcp4_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_mgr_unittest.cc + +pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj: pgsql_cb_dhcp4_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp4_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_mgr_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp4_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_mgr_unittest.cc'; fi` + +pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o: pgsql_cb_dhcp6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o `test -f 'pgsql_cb_dhcp6_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o `test -f 'pgsql_cb_dhcp6_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_unittest.cc + +pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj: pgsql_cb_dhcp6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj `if test -f 'pgsql_cb_dhcp6_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj `if test -f 'pgsql_cb_dhcp6_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_unittest.cc'; fi` + +pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o: pgsql_cb_dhcp6_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o `test -f 'pgsql_cb_dhcp6_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o `test -f 'pgsql_cb_dhcp6_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_mgr_unittest.cc + +pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj: pgsql_cb_dhcp6_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp6_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_mgr_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp6_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_mgr_unittest.cc'; fi` + +pgsql_cb_unittests-run_unittests.o: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo -c -o pgsql_cb_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo $(DEPDIR)/pgsql_cb_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='pgsql_cb_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc + +pgsql_cb_unittests-run_unittests.obj: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo -c -o pgsql_cb_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo $(DEPDIR)/pgsql_cb_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='pgsql_cb_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +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-recursive + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po + -rm -f ./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-TESTS check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags 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 installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc new file mode 100644 index 0000000..5eb0df5 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <cc/stamped_value.h> +#include <dhcpsrv/config_backend_dhcp4_mgr.h> +#include <pgsql_cb_dhcp4.h> +#include <pgsql/testutils/pgsql_schema.h> +#include <dhcpsrv/testutils/generic_backend_unittest.h> +#include <boost/shared_ptr.hpp> +#include <gtest/gtest.h> + +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::dhcp::test; +using namespace isc::db; +using namespace isc::db::test; + +namespace { + +/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv4Mgr. +class PgSqlConfigBackendDHCPv4MgrTest : public GenericBackendTest { +public: + /// @brief Constructor. + PgSqlConfigBackendDHCPv4MgrTest() { + // Recreate a fresh mgr. + ConfigBackendDHCPv4Mgr::create(); + + // Ensure we have the proper schema with no transient data. + createPgSQLSchema(); + } + + /// @brief Destructor. + virtual ~PgSqlConfigBackendDHCPv4MgrTest() { + // Destroy the mgr. + ConfigBackendDHCPv4Mgr::destroy(); + + // If data wipe enabled, delete transient data otherwise destroy the schema. + destroyPgSQLSchema(); + } +}; + +// This test verifies that PgSQL backend can be registered with and +// unregistered from the Config Backend Manager. +TEST_F(PgSqlConfigBackendDHCPv4MgrTest, factoryRegistration) { + + // Get the mgr singleton. + ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance(); + + // With no factory registered, attempting to add a PgSQL db should fail. + ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType); + + // Now we'll register the PgSQL factory. + ASSERT_NO_THROW(PgSqlConfigBackendDHCPv4::registerBackendType()); + + // With the factory registered, attempting to add a PgSQL db should succeed. + ASSERT_NO_THROW(mgr.addBackend(validPgSQLConnectionString())); + + // Create a PgSQL backend selector for convenience. + BackendSelector pgsql(BackendSelector::Type::POSTGRESQL); + + // Should be able to create a global parameter. + StampedValuePtr server_tag = StampedValue::create("server-tag", "whale"); + ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter4(pgsql, ServerSelector::ALL(), + server_tag)); + // Verify parameter can be fetched. + server_tag.reset(); + ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter4(pgsql, ServerSelector::ALL(), + "server-tag")); + ASSERT_TRUE(server_tag); + EXPECT_EQ("server-tag", server_tag->getName()); + EXPECT_EQ("whale", server_tag->getValue()); + + // Now we'll unregister PgSQL. + ASSERT_NO_THROW(PgSqlConfigBackendDHCPv4::unregisterBackendType()); + + // With no factory registered, attempting to add a PgSQL db should fail. + ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType); + + // Attempting to read the global parameter should fail. + ASSERT_THROW(mgr.getPool()->getGlobalParameter4(pgsql, ServerSelector::ALL(), "server-tag"), + NoSuchDatabase); +} + +} diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc new file mode 100644 index 0000000..fdd11e8 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc @@ -0,0 +1,513 @@ +// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <database/db_exceptions.h> +#include <database/server.h> +#include <dhcpsrv/cfgmgr.h> +#include <dhcpsrv/config_backend_dhcp4_mgr.h> +#include <dhcpsrv/testutils/generic_cb_dhcp4_unittest.h> +#include <dhcpsrv/testutils/generic_cb_recovery_unittest.h> +#include <dhcpsrv/testutils/pgsql_generic_backend_unittest.h> +#include <dhcpsrv/testutils/test_utils.h> +#include <pgsql_cb_dhcp4.h> +#include <pgsql/testutils/pgsql_schema.h> +#include <testutils/multi_threading_utils.h> +#include <testutils/gtest_utils.h> + +#include <boost/make_shared.hpp> +#include <boost/shared_ptr.hpp> +#include <gtest/gtest.h> +#include <map> +#include <sstream> + +using namespace isc; +using namespace isc::asiolink; +using namespace isc::db; +using namespace isc::db::test; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::dhcp::test; +using namespace isc::process; +using namespace isc::test; +using namespace isc::util; +namespace ph = std::placeholders; + +namespace { + +/// @brief Test implementation of the PostgreSQL configuration backend. +/// +/// It exposes protected members of the @c PgSqlConfigBackendDHCPv4. +class TestPgSqlConfigBackendDHCPv4 : public PgSqlConfigBackendDHCPv4 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit TestPgSqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters) + : PgSqlConfigBackendDHCPv4(parameters) { + } + + using PgSqlConfigBackendDHCPv4::base_impl_; +}; + +/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv4. +class PgSqlConfigBackendDHCPv4Test : public GenericConfigBackendDHCPv4Test { +public: + /// @brief Constructor. + PgSqlConfigBackendDHCPv4Test() {} + + /// @brief Destructor. + virtual ~PgSqlConfigBackendDHCPv4Test() {} + + /// @brief Creates the PostgreSQL back end schema + virtual void createSchema() { + createPgSQLSchema(); + } + + /// @brief Destroys the PostgreSQL back end schema + virtual void destroySchema() { + destroyPgSQLSchema(); + } + + /// @brief Returns a valid PostgreSQL back end specific connection + /// string + std::string validConnectionString() { + return (validPgSQLConnectionString()); + } + + /// @brief Instantiates an instance of a PostgreSQL DHCPv4 configuration + /// back end. + /// + /// @params Connection parameters describing the back end to create. + /// + /// @return Pointer to the newly created back end instance. + ConfigBackendDHCPv4Ptr backendFactory(db::DatabaseConnection::ParameterMap& + params) { + + return (ConfigBackendDHCPv4Ptr(new TestPgSqlConfigBackendDHCPv4(params))); + } + + /// @brief Counts rows in a selected table in PostgreSQL database. + /// + /// This method can be used to verify that some configuration elements were + /// deleted from a selected table as a result of cascade delete or a trigger. + /// For example, deleting a subnet should trigger deletion of its address + /// pools and options. By counting the rows on each table we can determine + /// whether the deletion took place on all tables for which it was expected. + /// + /// @param table Table name. + /// @return Number of rows in the specified table. + size_t countRows(const std::string& table) const { + auto p = boost::dynamic_pointer_cast<TestPgSqlConfigBackendDHCPv4>(cbptr_); + if (!p) { + ADD_FAILURE() << "cbptr_ does not cast to TestPgSqlConfigBackendDHCPv4"; + return (0); + } + + // Reuse the existing connection of the backend. + auto impl = boost::dynamic_pointer_cast<PgSqlConfigBackendImpl>(p->base_impl_); + auto& conn = impl->conn_; + + return (PgSqlGenericBackendTest::countRows(conn, table)); + } +}; + +TEST_F(PgSqlConfigBackendDHCPv4Test, getType) { + getTypeTest("postgresql"); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getHost) { + getHostTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getPort) { + getPortTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteServerTest) { + createUpdateDeleteServerTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAndDeleteAllServersTest) { + getAndDeleteAllServersTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4Test) { + createUpdateDeleteGlobalParameter4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, globalParameters4WithServerTagsTest) { + globalParameters4WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllGlobalParameters4Test) { + getAllGlobalParameters4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedGlobalParameters4Test) { + getModifiedGlobalParameters4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, nullKeyErrorTest) { + nullKeyErrorTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateSubnet4SelectorsTest) { + createUpdateSubnet4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4Test) { + getSubnet4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4byIdSelectorsTest) { + getSubnet4byIdSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4WithOptionalUnspecifiedTest) { + getSubnet4WithOptionalUnspecifiedTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4SharedNetworkTest) { + getSubnet4SharedNetworkTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4ByPrefixTest) { + getSubnet4ByPrefixTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4byPrefixSelectorsTest) { + getSubnet4byPrefixSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSubnets4Test) { + getAllSubnets4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSubnets4SelectorsTest) { + getAllSubnets4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSubnets4WithServerTagsTest) { + getAllSubnets4WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSubnets4SelectorsTest) { + getModifiedSubnets4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSubnet4Test) { + deleteSubnet4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSubnet4ByIdSelectorsTest) { + deleteSubnet4ByIdSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSubnet4ByPrefixSelectorsTest) { + deleteSubnet4ByPrefixSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteAllSubnets4SelectorsTest) { + deleteAllSubnets4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, unassignedSubnet4Test) { + unassignedSubnet4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSubnets4Test) { + getModifiedSubnets4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, subnetLifetimeTest) { + subnetLifetimeTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetworkSubnets4Test) { + getSharedNetworkSubnets4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, subnetUpdatePoolsTest) { + subnetUpdatePoolsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, subnetOptionsTest) { + subnetOptionsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetwork4Test) { + getSharedNetwork4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetwork4SelectorsTest) { + getSharedNetwork4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4Test) { + createUpdateSharedNetwork4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4SelectorsTest) { + createUpdateSharedNetwork4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetwork4WithOptionalUnspecifiedTest) { + getSharedNetwork4WithOptionalUnspecifiedTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSharedNetworkSubnets4Test) { + deleteSharedNetworkSubnets4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSharedNetworks4Test) { + getAllSharedNetworks4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSharedNetworks4SelectorsTest) { + getAllSharedNetworks4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSharedNetworks4WithServerTagsTest) { + getAllSharedNetworks4WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4Test) { + getModifiedSharedNetworks4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4SelectorsTest) { + getModifiedSharedNetworks4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSharedNetwork4Test) { + deleteSharedNetwork4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSharedNetwork4SelectorsTest) { + deleteSharedNetwork4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteAllSharedNetworks4SelectorsTest) { + deleteAllSharedNetworks4SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, unassignedSharedNetworkTest) { + unassignedSharedNetworkTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, sharedNetworkLifetimeTest) { + sharedNetworkLifetimeTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, sharedNetworkOptionsTest) { + sharedNetworkOptionsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getOptionDef4Test) { + getOptionDef4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, optionDefs4WithServerTagsTest) { + optionDefs4WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllOptionDefs4Test) { + getAllOptionDefs4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedOptionDefs4Test) { + getModifiedOptionDefs4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteOption4Test) { + createUpdateDeleteOption4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, globalOptions4WithServerTagsTest) { + globalOptions4WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getAllOptions4Test) { + getAllOptions4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedOptions4Test) { + getModifiedOptions4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteSubnetOption4Test) { + createUpdateDeleteSubnetOption4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeletePoolOption4Test) { + createUpdateDeletePoolOption4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteSharedNetworkOption4Test) { + createUpdateDeleteSharedNetworkOption4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, subnetOptionIdOrderTest) { + subnetOptionIdOrderTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, sharedNetworkOptionIdOrderTest) { + sharedNetworkOptionIdOrderTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, setAndGetAllClientClasses4Test) { + setAndGetAllClientClasses4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getClientClass4Test) { + getClientClass4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateClientClass4OptionsTest) { + createUpdateClientClass4OptionsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedClientClasses4Test) { + getModifiedClientClasses4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteClientClass4Test) { + deleteClientClass4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, deleteAllClientClasses4Test) { + deleteAllClientClasses4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, clientClassDependencies4Test) { + clientClassDependencies4Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv4Test, multipleAuditEntriesTest) { + multipleAuditEntriesTest(); +} + +/// @brief Test fixture for verifying database connection loss-recovery +/// behavior. +class PgSqlConfigBackendDHCPv4DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest { +public: + /// @brief Constructor + PgSqlConfigBackendDHCPv4DbLostCallbackTest() {}; + + /// @brief Destructor + virtual ~PgSqlConfigBackendDHCPv4DbLostCallbackTest() {}; + + /// @brief Creates the PostgreSQL CB schema. + virtual void createSchema() { + createPgSQLSchema(); + } + + /// @brief Destroys the PostgreSQL CB schema. + virtual void destroySchema() { + destroyPgSQLSchema(); + } + + /// @brief Method which returns a valid back end specific connection + /// string + virtual std::string validConnectionString() { + return (validPgSQLConnectionString()); + } + + /// @brief Method which returns an invalid back end specific connection + /// string. + virtual std::string invalidConnectionString() { + return (connectionString(PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, + VALID_USER, VALID_PASSWORD)); + } + + /// @brief Registers PostgreSQL as a CB backend type. + virtual void registerBackendType() { + isc::dhcp::PgSqlConfigBackendDHCPv4::registerBackendType(); + } + + /// @brief Unregisters PostgreSQL as a CB backend type. + virtual void unregisterBackendType() { + isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType(); + } + + /// @brief Sets the IOService instance in the CB implementation object. + /// + /// @param io_service pointer to the IOService instance to use. It may be + /// an empty pointer. + virtual void setConfigBackendImplIOService(isc::asiolink::IOServicePtr io_service) { + isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); + } + + /// @brief Attempts to add a backend instance to the CB manager. + /// + /// @param access Connection access string containing the database + /// connection parameters. + virtual void addBackend(const std::string& access) { + ConfigBackendDHCPv4Mgr::instance().addBackend(access); + } + + /// @brief Fetches a collection of all the servers currently in + /// the CB database. This function is used to check the operability + /// of the CB backend. + ServerCollection getAllServers() { + return (ConfigBackendDHCPv4Mgr::instance().getPool()->getAllServers4(BackendSelector())); + } +}; + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testNoCallbackOnOpenFailure) { + MultiThreadingTest mt(false); + testNoCallbackOnOpenFailure(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) { + MultiThreadingTest mt(true); + testNoCallbackOnOpenFailure(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedAfterTimeoutCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedAfterTimeoutCallback(); +} + +} diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc new file mode 100644 index 0000000..cb2b699 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <cc/stamped_value.h> +#include <dhcpsrv/config_backend_dhcp6_mgr.h> +#include <pgsql_cb_dhcp6.h> +#include <pgsql/testutils/pgsql_schema.h> +#include <dhcpsrv/testutils/generic_backend_unittest.h> +#include <boost/shared_ptr.hpp> +#include <gtest/gtest.h> + +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::dhcp::test; +using namespace isc::db; +using namespace isc::db::test; + +namespace { + +/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv6Mgr. +class PgSqlConfigBackendDHCPv6MgrTest : public GenericBackendTest { +public: + /// @brief Constructor. + PgSqlConfigBackendDHCPv6MgrTest() { + // Recreate a fresh mgr. + ConfigBackendDHCPv6Mgr::create(); + + // Ensure we have the proper schema with no transient data. + createPgSQLSchema(); + } + + /// @brief Destructor. + virtual ~PgSqlConfigBackendDHCPv6MgrTest() { + // Destroy the mgr. + ConfigBackendDHCPv6Mgr::destroy(); + + // If data wipe enabled, delete transient data otherwise destroy the schema. + destroyPgSQLSchema(); + } +}; + +// This test verifies that PgSQL backend can be registered with and +// unregistered from the Config Backend Manager. +TEST_F(PgSqlConfigBackendDHCPv6MgrTest, factoryRegistration) { + + // Get the mgr singleton. + ConfigBackendDHCPv6Mgr& mgr = ConfigBackendDHCPv6Mgr::instance(); + + // With no factory registered, attempting to add a PgSQL db should fail. + ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType); + + // Now we'll register the PgSQL factory. + ASSERT_NO_THROW(PgSqlConfigBackendDHCPv6::registerBackendType()); + + // With the factory registered, attempting to add a PgSQL db should succeed. + ASSERT_NO_THROW(mgr.addBackend(validPgSQLConnectionString())); + + // Create a PgSQL backend selector for convenience. + BackendSelector pgsql(BackendSelector::Type::POSTGRESQL); + + // Should be able to create a global parameter. + StampedValuePtr server_tag = StampedValue::create("server-tag", "whale"); + ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(pgsql, ServerSelector::ALL(), + server_tag)); + // Verify parameter can be fetched. + server_tag.reset(); + ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter6(pgsql, ServerSelector::ALL(), + "server-tag")); + ASSERT_TRUE(server_tag); + EXPECT_EQ("server-tag", server_tag->getName()); + EXPECT_EQ("whale", server_tag->getValue()); + + // Now we'll unregister PgSQL. + ASSERT_NO_THROW(PgSqlConfigBackendDHCPv6::unregisterBackendType()); + + // With no factory registered, attempting to add a PgSQL db should fail. + ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType); + + // Attempting to read the global parameter should fail. + ASSERT_THROW(mgr.getPool()->getGlobalParameter6(pgsql, ServerSelector::ALL(), "server-tag"), + NoSuchDatabase); +} + +} diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc new file mode 100644 index 0000000..b6bdacc --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc @@ -0,0 +1,517 @@ +// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <database/db_exceptions.h> +#include <database/server.h> +#include <dhcpsrv/cfgmgr.h> +#include <dhcpsrv/config_backend_dhcp6_mgr.h> +#include <dhcpsrv/testutils/generic_cb_dhcp6_unittest.h> +#include <dhcpsrv/testutils/generic_cb_recovery_unittest.h> +#include <dhcpsrv/testutils/pgsql_generic_backend_unittest.h> +#include <dhcpsrv/testutils/test_utils.h> +#include <pgsql_cb_dhcp6.h> +#include <pgsql/testutils/pgsql_schema.h> +#include <testutils/multi_threading_utils.h> +#include <testutils/gtest_utils.h> + +#include <boost/make_shared.hpp> +#include <boost/shared_ptr.hpp> +#include <gtest/gtest.h> +#include <map> +#include <sstream> + +using namespace isc; +using namespace isc::asiolink; +using namespace isc::db; +using namespace isc::db::test; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::dhcp::test; +using namespace isc::process; +using namespace isc::test; +using namespace isc::util; +namespace ph = std::placeholders; + +namespace { + +/// @brief Test implementation of the PostgreSQL configuration backend. +/// +/// It exposes protected members of the @c PgSqlConfigBackendDHCPv6. +class TestPgSqlConfigBackendDHCPv6 : public PgSqlConfigBackendDHCPv6 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit TestPgSqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters) + : PgSqlConfigBackendDHCPv6(parameters) { + } + + using PgSqlConfigBackendDHCPv6::base_impl_; +}; + +/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv6. +class PgSqlConfigBackendDHCPv6Test : public GenericConfigBackendDHCPv6Test { +public: + /// @brief Constructor. + PgSqlConfigBackendDHCPv6Test() {} + + /// @brief Destructor. + virtual ~PgSqlConfigBackendDHCPv6Test() {} + + /// @brief Creates the PostgreSQL back end schema + virtual void createSchema() { + createPgSQLSchema(); + } + + /// @brief Destroys the PostgreSQL back end schema + virtual void destroySchema() { + destroyPgSQLSchema(); + } + + /// @brief Returns a valid PostgreSQL back end specific connection + /// string + std::string validConnectionString() { + return (validPgSQLConnectionString()); + } + + /// @brief Instantiates an instance of a PostgreSQL DHCPv6 configuration + /// back end. + /// + /// @params Connection parameters describing the back end to create. + /// + /// @return Pointer to the newly created back end instance. + ConfigBackendDHCPv6Ptr backendFactory(db::DatabaseConnection::ParameterMap& + params) { + + return (ConfigBackendDHCPv6Ptr(new TestPgSqlConfigBackendDHCPv6(params))); + } + + /// @brief Counts rows in a selected table in PostgreSQL database. + /// + /// This method can be used to verify that some configuration elements were + /// deleted from a selected table as a result of cascade delete or a trigger. + /// For example, deleting a subnet should trigger deletion of its address + /// pools and options. By counting the rows on each table we can determine + /// whether the deletion took place on all tables for which it was expected. + /// + /// @param table Table name. + /// @return Number of rows in the specified table. + size_t countRows(const std::string& table) const { + auto p = boost::dynamic_pointer_cast<TestPgSqlConfigBackendDHCPv6>(cbptr_); + if (!p) { + ADD_FAILURE() << "cbptr_ does not cast to TestPgSqlConfigBackendDHCPv6"; + return (0); + } + + // Reuse the existing connection of the backend. + auto impl = boost::dynamic_pointer_cast<PgSqlConfigBackendImpl>(p->base_impl_); + auto& conn = impl->conn_; + + return (PgSqlGenericBackendTest::countRows(conn, table)); + } +}; + +TEST_F(PgSqlConfigBackendDHCPv6Test, getType) { + getTypeTest("postgresql"); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getHost) { + getHostTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getPort) { + getPortTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteServerTest) { + createUpdateDeleteServerTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAndDeleteAllServersTest) { + getAndDeleteAllServersTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteGlobalParameter6Test) { + createUpdateDeleteGlobalParameter6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, globalParameters6WithServerTagsTest) { + globalParameters6WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllGlobalParameters6Test) { + getAllGlobalParameters6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedGlobalParameters6Test) { + getModifiedGlobalParameters6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, nullKeyErrorTest) { + nullKeyErrorTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateSubnet6SelectorsTest) { + createUpdateSubnet6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6Test) { + getSubnet6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6byIdSelectorsTest) { + getSubnet6byIdSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6WithOptionalUnspecifiedTest) { + getSubnet6WithOptionalUnspecifiedTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6SharedNetworkTest) { + getSubnet6SharedNetworkTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6ByPrefixTest) { + getSubnet6ByPrefixTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6byPrefixSelectorsTest) { + getSubnet6byPrefixSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSubnets6Test) { + getAllSubnets6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSubnets6SelectorsTest) { + getAllSubnets6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSubnets6WithServerTagsTest) { + getAllSubnets6WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSubnets6SelectorsTest) { + getModifiedSubnets6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSubnet6Test) { + deleteSubnet6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSubnet6ByIdSelectorsTest) { + deleteSubnet6ByIdSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSubnet6ByPrefixSelectorsTest) { + deleteSubnet6ByPrefixSelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteAllSubnets6SelectorsTest) { + deleteAllSubnets6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, unassignedSubnet6Test) { + unassignedSubnet6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSubnets6Test) { + getModifiedSubnets6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, subnetLifetimeTest) { + subnetLifetimeTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetworkSubnets6Test) { + getSharedNetworkSubnets6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, subnetUpdatePoolsTest) { + subnetUpdatePoolsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, subnetOptionsTest) { + subnetOptionsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetwork6Test) { + getSharedNetwork6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetwork6SelectorsTest) { + getSharedNetwork6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6Test) { + createUpdateSharedNetwork6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6SelectorsTest) { + createUpdateSharedNetwork6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetwork6WithOptionalUnspecifiedTest) { + getSharedNetwork6WithOptionalUnspecifiedTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSharedNetworkSubnets6Test) { + deleteSharedNetworkSubnets6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSharedNetworks6Test) { + getAllSharedNetworks6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSharedNetworks6SelectorsTest) { + getAllSharedNetworks6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSharedNetworks6WithServerTagsTest) { + getAllSharedNetworks6WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6Test) { + getModifiedSharedNetworks6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6SelectorsTest) { + getModifiedSharedNetworks6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSharedNetwork6Test) { + deleteSharedNetwork6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSharedNetwork6SelectorsTest) { + deleteSharedNetwork6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteAllSharedNetworks6SelectorsTest) { + deleteAllSharedNetworks6SelectorsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, unassignedSharedNetworkTest) { + unassignedSharedNetworkTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkLifetimeTest) { + sharedNetworkLifetimeTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkOptionsTest) { + sharedNetworkOptionsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getOptionDef6Test) { + getOptionDef6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, optionDefs6WithServerTagsTest) { + optionDefs6WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllOptionDefs6Test) { + getAllOptionDefs6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedOptionDefs6Test) { + getModifiedOptionDefs6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteOption6Test) { + createUpdateDeleteOption6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, globalOptions6WithServerTagsTest) { + globalOptions6WithServerTagsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllOptions6Test) { + getAllOptions6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedOptions6Test) { + getModifiedOptions6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteSubnetOption6Test) { + createUpdateDeleteSubnetOption6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeletePoolOption6Test) { + createUpdateDeletePoolOption6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeletePdPoolOption6Test) { + createUpdateDeletePdPoolOption6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteSharedNetworkOption6Test) { + createUpdateDeleteSharedNetworkOption6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, subnetOptionIdOrderTest) { + subnetOptionIdOrderTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkOptionIdOrderTest) { + sharedNetworkOptionIdOrderTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, setAndGetAllClientClasses6Test) { + setAndGetAllClientClasses6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getClientClass6Test) { + getClientClass6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateClientClass6OptionsTest) { + createUpdateClientClass6OptionsTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedClientClasses6Test) { + getModifiedClientClasses6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteClientClass6Test) { + deleteClientClass6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, deleteAllClientClasses6Test) { + deleteAllClientClasses6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, clientClassDependencies6Test) { + clientClassDependencies6Test(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, multipleAuditEntriesTest) { + multipleAuditEntriesTest(); +} + +/// @brief Test fixture for verifying database connection loss-recovery +/// behavior. +class PgSqlConfigBackendDHCPv6DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest { +public: + /// @brief Constructor + PgSqlConfigBackendDHCPv6DbLostCallbackTest() {}; + + /// @brief Destructor + virtual ~PgSqlConfigBackendDHCPv6DbLostCallbackTest() {}; + + /// @brief Creates the PostgreSQL CB schema. + virtual void createSchema() { + createPgSQLSchema(); + } + + /// @brief Destroys the PostgreSQL CB schema. + virtual void destroySchema() { + destroyPgSQLSchema(); + } + + /// @brief Method which returns a valid back end specific connection + /// string + virtual std::string validConnectionString() { + return (validPgSQLConnectionString()); + } + + /// @brief Method which returns an invalid back end specific connection + /// string. + virtual std::string invalidConnectionString() { + return (connectionString(PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, + VALID_USER, VALID_PASSWORD)); + } + + /// @brief Registers PostgreSQL as a CB backend type. + virtual void registerBackendType() { + isc::dhcp::PgSqlConfigBackendDHCPv6::registerBackendType(); + } + + /// @brief Unregisters PostgreSQL as a CB backend type. + virtual void unregisterBackendType() { + isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType(); + } + + /// @brief Sets the IOService instance in the CB implementation object. + /// + /// @param io_service pointer to the IOService instance to use. It may be + /// an empty pointer. + virtual void setConfigBackendImplIOService(isc::asiolink::IOServicePtr io_service) { + isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); + } + + /// @brief Attempts to add a backend instance to the CB manager. + /// + /// @param access Connection access string containing the database + /// connection parameters. + virtual void addBackend(const std::string& access) { + ConfigBackendDHCPv6Mgr::instance().addBackend(access); + } + + /// @brief Fetches a collection of all the servers currently in + /// the CB database. This function is used to check the operability + /// of the CB backend. + ServerCollection getAllServers() { + return (ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector())); + } +}; + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailure) { + MultiThreadingTest mt(false); + testNoCallbackOnOpenFailure(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) { + MultiThreadingTest mt(true); + testNoCallbackOnOpenFailure(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedAfterTimeoutCallback(); +} + +TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedAfterTimeoutCallback(); +} + +} diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc new file mode 100644 index 0000000..025eb33 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <dhcpsrv/testutils/pgsql_generic_backend_unittest.h> +#include <pgsql/testutils/pgsql_schema.h> +#include <testutils/gtest_utils.h> + +#include <gtest/gtest.h> +#include <pgsql_cb_impl.h> +#include <vector> + +using namespace isc::db; +using namespace isc::dhcp; +using namespace isc::dhcp::test; +using namespace isc::util; + +namespace { + +class PgSqlConfigBackendTest : public PgSqlGenericBackendTest { +public: + PgSqlConfigBackendTest() : PgSqlGenericBackendTest() { + createFullSchema(); + } + + /// @brief Setup for each test. + /// + /// Creates the configuration backend impl. + virtual void SetUp() { + DatabaseConnection::ParameterMap params; + params["name"] = "keatest"; + params["password"] = "keatest"; + params["user"] = "keatest"; + ASSERT_NO_THROW_LOG(cbptr_.reset(new PgSqlConfigBackendImpl(params, 0, 0))); + } + + /// @brief Cleans up after each test. + /// + /// Destroys the configuration backend impl. + virtual void TearDown() { + ASSERT_NO_THROW_LOG(cbptr_.reset()); + } + + ~PgSqlConfigBackendTest() { + destroyFullSchema(); + } + + /// @brief creates full schema (slow!) + /// + /// If possible, use simpler, faster alternative: @ref createDummySchema(); + /// Don't forget to tear it down with @ref destroyFullSchema(); + void createFullSchema() { + // Create the actual full Kea schema. + isc::db::test::createPgSQLSchema(); + } + + /// @brief destroys the full schema (slow!) + /// + /// Don't forget to call this method once you're done, if you used @ref createFullSchema(). + void destroyFullSchema() { + // Clean up after ourselves. + isc::db::test::destroyPgSQLSchema(); + } + + boost::shared_ptr<PgSqlConfigBackendImpl> cbptr_; +}; + +// Let's start with absolute basics. This should construct a backend instance +// connected to the unit test schema. The backend instance is created in +// Setup() and which will ASSERT on failures. +TEST_F(PgSqlConfigBackendTest, constructor) { + // Is this the right config backend type? + EXPECT_EQ("postgresql", cbptr_->getType()); +} + +} // namespace diff --git a/src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc b/src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc new file mode 100644 index 0000000..74904a3 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc @@ -0,0 +1,20 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <log/logger_support.h> + +#include <gtest/gtest.h> + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + isc::log::initLogger(); + int result = RUN_ALL_TESTS(); + + return (result); +} diff --git a/src/hooks/dhcp/pgsql_cb/version.cc b/src/hooks/dhcp/pgsql_cb/version.cc new file mode 100644 index 0000000..f232709 --- /dev/null +++ b/src/hooks/dhcp/pgsql_cb/version.cc @@ -0,0 +1,18 @@ +// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <hooks/hooks.h> + +extern "C" { + +/// @brief returns Kea hooks version. +int version() { + return (KEA_HOOKS_VERSION); +} + +} |