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/mysql_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/mysql_cb')
28 files changed, 20037 insertions, 0 deletions
diff --git a/src/hooks/dhcp/mysql_cb/Makefile.am b/src/hooks/dhcp/mysql_cb/Makefile.am new file mode 100644 index 0000000..1263a3d --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/Makefile.am @@ -0,0 +1,88 @@ +SUBDIRS = . tests libloadtests + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) $(MYSQL_CPPFLAGS) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +# Ensure that the message file is included in the distribution +EXTRA_DIST = mysql_cb_messages.mes + +CLEANFILES = *.gcno *.gcda + +# convenience archive + +noinst_LTLIBRARIES = libmysqlcb.la + +libmysqlcb_la_SOURCES = mysql_cb_callouts.cc +libmysqlcb_la_SOURCES += mysql_cb_dhcp4.cc mysql_cb_dhcp4.h +libmysqlcb_la_SOURCES += mysql_cb_dhcp6.cc mysql_cb_dhcp6.h +libmysqlcb_la_SOURCES += mysql_cb_impl.cc mysql_cb_impl.h +libmysqlcb_la_SOURCES += mysql_cb_messages.cc mysql_cb_messages.h +libmysqlcb_la_SOURCES += mysql_cb_log.cc mysql_cb_log.h +libmysqlcb_la_SOURCES += mysql_query_macros_dhcp.h +libmysqlcb_la_SOURCES += version.cc + +libmysqlcb_la_CXXFLAGS = $(AM_CXXFLAGS) +libmysqlcb_la_CPPFLAGS = $(AM_CPPFLAGS) + +# install the shared object into $(libdir)/kea/hooks +lib_hooksdir = $(libdir)/kea/hooks +lib_hooks_LTLIBRARIES = libdhcp_mysql_cb.la + +libdhcp_mysql_cb_la_SOURCES = +libdhcp_mysql_cb_la_LDFLAGS = $(AM_LDFLAGS) $(MYSQL_LIBS) +libdhcp_mysql_cb_la_LDFLAGS += -avoid-version -export-dynamic -module + +libdhcp_mysql_cb_la_LIBADD = libmysqlcb.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/eval/libkea-eval.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/mysql/libkea-mysql.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la +libdhcp_mysql_cb_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la +libdhcp_mysql_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 mysql_cb_messages.h mysql_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: mysql_cb_messages.h mysql_cb_messages.cc + @echo Message files regenerated + +mysql_cb_messages.h mysql_cb_messages.cc: mysql_cb_messages.mes + $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes + +else + +messages mysql_cb_messages.h mysql_cb_messages.cc: + @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. + +endif + diff --git a/src/hooks/dhcp/mysql_cb/Makefile.in b/src/hooks/dhcp/mysql_cb/Makefile.in new file mode 100644 index 0000000..733f7ac --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/Makefile.in @@ -0,0 +1,1085 @@ +# 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/mysql_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_mysql_cb_la_DEPENDENCIES = libmysqlcb.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/mysql/libkea-mysql.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_mysql_cb_la_OBJECTS = +libdhcp_mysql_cb_la_OBJECTS = $(am_libdhcp_mysql_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_mysql_cb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libdhcp_mysql_cb_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +libmysqlcb_la_LIBADD = +am_libmysqlcb_la_OBJECTS = libmysqlcb_la-mysql_cb_callouts.lo \ + libmysqlcb_la-mysql_cb_dhcp4.lo \ + libmysqlcb_la-mysql_cb_dhcp6.lo libmysqlcb_la-mysql_cb_impl.lo \ + libmysqlcb_la-mysql_cb_messages.lo \ + libmysqlcb_la-mysql_cb_log.lo libmysqlcb_la-version.lo +libmysqlcb_la_OBJECTS = $(am_libmysqlcb_la_OBJECTS) +libmysqlcb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(libmysqlcb_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)/libmysqlcb_la-mysql_cb_callouts.Plo \ + ./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Plo \ + ./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Plo \ + ./$(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Plo \ + ./$(DEPDIR)/libmysqlcb_la-mysql_cb_log.Plo \ + ./$(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Plo \ + ./$(DEPDIR)/libmysqlcb_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_mysql_cb_la_SOURCES) $(libmysqlcb_la_SOURCES) +DIST_SOURCES = $(libdhcp_mysql_cb_la_SOURCES) $(libmysqlcb_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) $(MYSQL_CPPFLAGS) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +# Ensure that the message file is included in the distribution +EXTRA_DIST = mysql_cb_messages.mes +CLEANFILES = *.gcno *.gcda + +# convenience archive +noinst_LTLIBRARIES = libmysqlcb.la +libmysqlcb_la_SOURCES = mysql_cb_callouts.cc mysql_cb_dhcp4.cc \ + mysql_cb_dhcp4.h mysql_cb_dhcp6.cc mysql_cb_dhcp6.h \ + mysql_cb_impl.cc mysql_cb_impl.h mysql_cb_messages.cc \ + mysql_cb_messages.h mysql_cb_log.cc mysql_cb_log.h \ + mysql_query_macros_dhcp.h version.cc +libmysqlcb_la_CXXFLAGS = $(AM_CXXFLAGS) +libmysqlcb_la_CPPFLAGS = $(AM_CPPFLAGS) + +# install the shared object into $(libdir)/kea/hooks +lib_hooksdir = $(libdir)/kea/hooks +lib_hooks_LTLIBRARIES = libdhcp_mysql_cb.la +libdhcp_mysql_cb_la_SOURCES = +libdhcp_mysql_cb_la_LDFLAGS = $(AM_LDFLAGS) $(MYSQL_LIBS) \ + -avoid-version -export-dynamic -module +libdhcp_mysql_cb_la_LIBADD = libmysqlcb.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/mysql/libkea-mysql.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/mysql_cb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/mysql_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_mysql_cb.la: $(libdhcp_mysql_cb_la_OBJECTS) $(libdhcp_mysql_cb_la_DEPENDENCIES) $(EXTRA_libdhcp_mysql_cb_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdhcp_mysql_cb_la_LINK) -rpath $(lib_hooksdir) $(libdhcp_mysql_cb_la_OBJECTS) $(libdhcp_mysql_cb_la_LIBADD) $(LIBS) + +libmysqlcb.la: $(libmysqlcb_la_OBJECTS) $(libmysqlcb_la_DEPENDENCIES) $(EXTRA_libmysqlcb_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libmysqlcb_la_LINK) $(libmysqlcb_la_OBJECTS) $(libmysqlcb_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_la-mysql_cb_callouts.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_la-mysql_cb_log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmysqlcb_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 $@ $< + +libmysqlcb_la-mysql_cb_callouts.lo: mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-mysql_cb_callouts.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-mysql_cb_callouts.Tpo -c -o libmysqlcb_la-mysql_cb_callouts.lo `test -f 'mysql_cb_callouts.cc' || echo '$(srcdir)/'`mysql_cb_callouts.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-mysql_cb_callouts.Tpo $(DEPDIR)/libmysqlcb_la-mysql_cb_callouts.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_callouts.cc' object='libmysqlcb_la-mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_la-mysql_cb_callouts.lo `test -f 'mysql_cb_callouts.cc' || echo '$(srcdir)/'`mysql_cb_callouts.cc + +libmysqlcb_la-mysql_cb_dhcp4.lo: mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-mysql_cb_dhcp4.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Tpo -c -o libmysqlcb_la-mysql_cb_dhcp4.lo `test -f 'mysql_cb_dhcp4.cc' || echo '$(srcdir)/'`mysql_cb_dhcp4.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Tpo $(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp4.cc' object='libmysqlcb_la-mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_la-mysql_cb_dhcp4.lo `test -f 'mysql_cb_dhcp4.cc' || echo '$(srcdir)/'`mysql_cb_dhcp4.cc + +libmysqlcb_la-mysql_cb_dhcp6.lo: mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-mysql_cb_dhcp6.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Tpo -c -o libmysqlcb_la-mysql_cb_dhcp6.lo `test -f 'mysql_cb_dhcp6.cc' || echo '$(srcdir)/'`mysql_cb_dhcp6.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Tpo $(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp6.cc' object='libmysqlcb_la-mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_la-mysql_cb_dhcp6.lo `test -f 'mysql_cb_dhcp6.cc' || echo '$(srcdir)/'`mysql_cb_dhcp6.cc + +libmysqlcb_la-mysql_cb_impl.lo: mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-mysql_cb_impl.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Tpo -c -o libmysqlcb_la-mysql_cb_impl.lo `test -f 'mysql_cb_impl.cc' || echo '$(srcdir)/'`mysql_cb_impl.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Tpo $(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_impl.cc' object='libmysqlcb_la-mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_la-mysql_cb_impl.lo `test -f 'mysql_cb_impl.cc' || echo '$(srcdir)/'`mysql_cb_impl.cc + +libmysqlcb_la-mysql_cb_messages.lo: mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-mysql_cb_messages.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Tpo -c -o libmysqlcb_la-mysql_cb_messages.lo `test -f 'mysql_cb_messages.cc' || echo '$(srcdir)/'`mysql_cb_messages.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Tpo $(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_messages.cc' object='libmysqlcb_la-mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_la-mysql_cb_messages.lo `test -f 'mysql_cb_messages.cc' || echo '$(srcdir)/'`mysql_cb_messages.cc + +libmysqlcb_la-mysql_cb_log.lo: mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-mysql_cb_log.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-mysql_cb_log.Tpo -c -o libmysqlcb_la-mysql_cb_log.lo `test -f 'mysql_cb_log.cc' || echo '$(srcdir)/'`mysql_cb_log.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-mysql_cb_log.Tpo $(DEPDIR)/libmysqlcb_la-mysql_cb_log.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_log.cc' object='libmysqlcb_la-mysql_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_la-mysql_cb_log.lo `test -f 'mysql_cb_log.cc' || echo '$(srcdir)/'`mysql_cb_log.cc + +libmysqlcb_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libmysqlcb_la-version.lo -MD -MP -MF $(DEPDIR)/libmysqlcb_la-version.Tpo -c -o libmysqlcb_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmysqlcb_la-version.Tpo $(DEPDIR)/libmysqlcb_la-version.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='version.cc' object='libmysqlcb_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) $(libmysqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libmysqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libmysqlcb_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)/libmysqlcb_la-mysql_cb_callouts.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_log.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_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)/libmysqlcb_la-mysql_cb_callouts.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp4.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_dhcp6.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_impl.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_log.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_la-mysql_cb_messages.Plo + -rm -f ./$(DEPDIR)/libmysqlcb_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 mysql_cb_messages.h mysql_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: mysql_cb_messages.h mysql_cb_messages.cc +@GENERATE_MESSAGES_TRUE@ @echo Message files regenerated + +@GENERATE_MESSAGES_TRUE@mysql_cb_messages.h mysql_cb_messages.cc: mysql_cb_messages.mes +@GENERATE_MESSAGES_TRUE@ $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes + +@GENERATE_MESSAGES_FALSE@messages mysql_cb_messages.h mysql_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/mysql_cb/libloadtests/Makefile.am b/src/hooks/dhcp/mysql_cb/libloadtests/Makefile.am new file mode 100644 index 0000000..391c1ec --- /dev/null +++ b/src/hooks/dhcp/mysql_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/mysql_cb -I$(top_srcdir)/src/hooks/dhcp/mysql_cb +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -DLIBDHCP_MYSQL_CB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/mysql_cb/.libs/libdhcp_mysql_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/mysql/libkea-mysql.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/mysql_cb/libloadtests/Makefile.in b/src/hooks/dhcp/mysql_cb/libloadtests/Makefile.in new file mode 100644 index 0000000..5c6177f --- /dev/null +++ b/src/hooks/dhcp/mysql_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/mysql_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/mysql/libkea-mysql.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/mysql_cb \ + -I$(top_srcdir)/src/hooks/dhcp/mysql_cb $(BOOST_INCLUDES) \ + -DLIBDHCP_MYSQL_CB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/mysql_cb/.libs/libdhcp_mysql_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/mysql/libkea-mysql.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/mysql_cb/libloadtests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/mysql_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/mysql_cb/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/mysql_cb/libloadtests/load_unload_unittests.cc new file mode 100644 index 0000000..89102fa --- /dev/null +++ b/src/hooks/dhcp/mysql_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 MySQL cb library +class MySqlCbLibLoadTest : public isc::test::LibLoadTest { +public: + /// @brief Constructor + MySqlCbLibLoadTest() : LibLoadTest(LIBDHCP_MYSQL_CB_SO) { + } + + /// @brief Destructor + virtual ~MySqlCbLibLoadTest() { + unloadLibraries(); + } +}; + +// Simple V4 test that checks the library can be loaded and unloaded several times. +TEST_F(MySqlCbLibLoadTest, validLoad4) { + validDaemonTest("kea-dhcp4"); +} + +// Simple V6 test that checks the library can be loaded and unloaded several times. +TEST_F(MySqlCbLibLoadTest, validLoad6) { + validDaemonTest("kea-dhcp6", AF_INET6); +} + +// Simple V6 test that checks the library cannot by loaded by invalid daemons. +TEST_F(MySqlCbLibLoadTest, invalidDaemonLoad) { + invalidDaemonTest("kea-ctrl-agent"); + invalidDaemonTest("kea-dhcp-ddns"); + invalidDaemonTest("bogus"); +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/mysql_cb/libloadtests/run_unittests.cc b/src/hooks/dhcp/mysql_cb/libloadtests/run_unittests.cc new file mode 100644 index 0000000..d9e195d --- /dev/null +++ b/src/hooks/dhcp/mysql_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/mysql_cb/mysql_cb_callouts.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc new file mode 100644 index 0000000..c047f42 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc @@ -0,0 +1,122 @@ +// Copyright (C) 2018-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 <mysql_cb_impl.h> + +#include <mysql_cb_dhcp4.h> +#include <mysql_cb_dhcp6.h> +#include <mysql_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(mysql_cb_logger, MYSQL_CB_INIT_OK); + // Register MySQL CB factories with CB Managers + isc::dhcp::MySqlConfigBackendDHCPv4::registerBackendType(); + isc::dhcp::MySqlConfigBackendDHCPv6::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::MySqlConfigBackendImpl::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::MySqlConfigBackendImpl::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(mysql_cb_logger, MYSQL_CB_DEINIT_OK); + // Unregister the factories and remove MySQL backends + isc::dhcp::MySqlConfigBackendDHCPv4::unregisterBackendType(); + isc::dhcp::MySqlConfigBackendDHCPv6::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/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc new file mode 100644 index 0000000..76a7fe4 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -0,0 +1,4358 @@ +// Copyright (C) 2018-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 <mysql_cb_dhcp4.h> +#include <mysql_cb_impl.h> +#include <mysql_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 <mysql/mysql_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> +#include <mysql.h> +#include <mysqld_error.h> +#include <array> +#include <sstream> +#include <utility> +#include <vector> + +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 MySQL Configuration Backend. +class MySqlConfigBackendDHCPv4Impl : public MySqlConfigBackendImpl { +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, + NUM_STATEMENTS + }; + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& + parameters); + + /// @brief Destructor. + ~MySqlConfigBackendDHCPv4Impl(); + + /// @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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createString(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 name Name of the global parameter. + /// @param value Value of the global parameter. + 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"); + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(value->getName()), + MySqlBinding::createString(value->getValue()), + MySqlBinding::createInteger<uint8_t>(value->getType()), + MySqlBinding::createTimestamp(value->getModificationTime()), + MySqlBinding::createString(tag), + MySqlBinding::createString(value->getName()) + }; + + MySqlTransaction 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, MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "global parameter set", false); + + // Try to update the existing row. + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::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.pop_back(); + in_bindings.pop_back(); + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4, + in_bindings); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + + // Let's first get the primary key of the global parameter. + uint64_t id = mysql_insert_id(conn_.mysql_); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + attachElementToServers(MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER, + server_selector, + MySqlBinding::createInteger<uint64_t>(id), + MySqlBinding::createTimestamp(value->getModificationTime())); + } + + 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 MySqlBindingCollection& in_bindings, + Subnet4Collection& subnets) { + // Create output bindings. The order must match that in the prepared + // statement. Please put comments only at the end of line so + // line counting and indexing match. + // The server tag must be the last field. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint32_t>(), // subnet_id + MySqlBinding::createString(SUBNET4_PREFIX_BUF_LENGTH), // subnet_prefix + MySqlBinding::createString(DHCP4O6_INTERFACE_BUF_LENGTH), // 4o6_interface + MySqlBinding::createString(DHCP4O6_INTERFACE_ID_BUF_LENGTH), // 4o6_interface_id + MySqlBinding::createString(DHCP4O6_SUBNET_BUF_LENGTH), // 4o6_subnet + MySqlBinding::createString(BOOT_FILE_NAME_BUF_LENGTH), // boot_file_name + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // client_class + MySqlBinding::createString(INTERFACE_BUF_LENGTH), // interface + MySqlBinding::createInteger<uint8_t>(), // match_client_id + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createInteger<uint32_t>(), // next_server + MySqlBinding::createInteger<uint32_t>(), // rebind_timer + MySqlBinding::createString(RELAY_BUF_LENGTH), // relay + MySqlBinding::createInteger<uint32_t>(), // renew_timer + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes + MySqlBinding::createInteger<uint8_t>(), // reservations_global + MySqlBinding::createString(SERVER_HOSTNAME_BUF_LENGTH), // server_hostname + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // shared_network_name + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createInteger<uint32_t>(), // valid_lifetime + MySqlBinding::createInteger<uint64_t>(), // pool: id + MySqlBinding::createInteger<uint32_t>(), // pool: start_address + MySqlBinding::createInteger<uint32_t>(), // pool: end_address + MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id + MySqlBinding::createTimestamp(), // pool: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pool option: option_id + MySqlBinding::createInteger<uint8_t>(), // pool option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pool option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space + MySqlBinding::createInteger<uint8_t>(), // pool option: persistent + MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled + MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp4_subnet_id + MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id + MySqlBinding::createTimestamp(), //pool option: modification_ts + MySqlBinding::createInteger<uint64_t>(), // option: option_id + MySqlBinding::createInteger<uint8_t>(), // option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space + MySqlBinding::createInteger<uint8_t>(), // option: persistent + MySqlBinding::createInteger<uint8_t>(), // option: cancelled + MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id + MySqlBinding::createInteger<uint8_t>(), // option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // option: pool_id + MySqlBinding::createTimestamp(), //option: modification_ts + MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times + MySqlBinding::createInteger<float>(), // t1_percent + MySqlBinding::createInteger<float>(), // t2_percent + MySqlBinding::createInteger<uint8_t>(), // authoritative + MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime + MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context + MySqlBinding::createInteger<uint8_t>(), // ddns_send_updates + MySqlBinding::createInteger<uint8_t>(), // ddns_override_no_update + MySqlBinding::createInteger<uint8_t>(), // ddns_override_client_update + MySqlBinding::createInteger<uint8_t>(), // ddns_replace_client_name + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger<uint8_t>(), // reservations_in_subnet + MySqlBinding::createInteger<uint8_t>(), // reservations_out_of_pool + MySqlBinding::createInteger<float>(), // cache_threshold + MySqlBinding::createInteger<uint32_t>(), // cache_max_age + MySqlBinding::createInteger<uint32_t>(), // offer lifetime + MySqlBinding::createString(ALLOCATOR_TYPE_BUF_LENGTH), // allocator + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag + }; + + 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. + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &subnets, &last_pool, &last_pool_id, + &last_pool_option_id, &last_option_id, + &last_tag] + (MySqlBindingCollection& out_bindings) { + // Get pointer to the last subnet in the collection. + Subnet4Ptr last_subnet; + if (!subnets.empty()) { + last_subnet = *subnets.rbegin(); + } + + // 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() != out_bindings[0]->getInteger<uint32_t>())) { + // 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_id at 0. + SubnetID subnet_id(out_bindings[0]->getInteger<uint32_t>()); + + // subnet_prefix at 1. + std::string subnet_prefix = out_bindings[1]->getString(); + auto prefix_pair = Subnet4::parsePrefix(subnet_prefix); + + // renew_timer at 13. + auto renew_timer = createTriplet(out_bindings[13]); + + // rebind_timer at 11. + auto rebind_timer = createTriplet(out_bindings[11]); + + // valid_lifetime at 19. + // min_valid_lifetime at 55. + // max_valid_lifetime at 56. + auto valid_lifetime = createTriplet(out_bindings[19], + out_bindings[55], + out_bindings[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. + + // subnet_id at 0. + + // subnet_prefix at 1. + + // 4o6_interface at 2. + if (!out_bindings[2]->amNull()) { + last_subnet->get4o6().setIface4o6(out_bindings[2]->getString()); + } + + // 4o6_interface_id at 3. + if (!out_bindings[3]->amNull()) { + std::string dhcp4o6_interface_id = out_bindings[3]->getString(); + 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 (!out_bindings[4]->amNull()) { + std::pair<IOAddress, uint8_t> dhcp4o6_subnet_prefix_pair = + Subnet6::parsePrefix(out_bindings[4]->getString()); + last_subnet->get4o6().setSubnet4o6(dhcp4o6_subnet_prefix_pair.first, + dhcp4o6_subnet_prefix_pair.second); + } + + // boot_file_name at 5. + if (!out_bindings[5]->amNull()) { + last_subnet->setFilename(out_bindings[5]->getString()); + } + + // client_class at 6. + if (!out_bindings[6]->amNull()) { + last_subnet->allowClientClass(out_bindings[6]->getString()); + } + + // interface at 7. + if (!out_bindings[7]->amNull()) { + last_subnet->setIface(out_bindings[7]->getString()); + } + + // match_client_id at 8. + if (!out_bindings[8]->amNull()) { + last_subnet->setMatchClientId(out_bindings[8]->getBool()); + } + + // modification_ts at 9. + last_subnet->setModificationTime(out_bindings[9]->getTimestamp()); + + // next_server at 10. + if (!out_bindings[10]->amNull()) { + last_subnet->setSiaddr(IOAddress(out_bindings[10]->getInteger<uint32_t>())); + } + + // rebind_timer at 11. + + // relay at 12. + ElementPtr relay_element = out_bindings[12]->getJSON(); + if (relay_element) { + if (relay_element->getType() != Element::list) { + isc_throw(BadValue, "invalid relay value " + << out_bindings[12]->getString()); + } + 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, "relay address must be a string"); + } + last_subnet->addRelayAddress(IOAddress(relay_element->get(i)->stringValue())); + } + } + + // renew_timer at 13. + + // require_client_classes at 14. + ElementPtr require_element = out_bindings[14]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid require_client_classes value " + << out_bindings[14]->getString()); + } + 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"); + } + last_subnet->requireClientClass(require_item->stringValue()); + } + } + + // reservations_global at 15. + if (!out_bindings[15]->amNull()) { + last_subnet->setReservationsGlobal(out_bindings[15]->getBool()); + } + + // server_hostname at 16. + if (!out_bindings[16]->amNull()) { + last_subnet->setSname(out_bindings[16]->getString()); + } + + // shared_network_name at 17. + if (!out_bindings[17]->amNull()) { + last_subnet->setSharedNetworkName(out_bindings[17]->getString()); + } + + // user_context at 18. + ElementPtr user_context = out_bindings[18]->getJSON(); + if (user_context) { + last_subnet->setContext(user_context); + } + + // valid_lifetime at 19. + + // pool and option from 20 to 50. + + // calculate_tee_times at 51. + if (!out_bindings[51]->amNull()) { + last_subnet->setCalculateTeeTimes(out_bindings[51]->getBool()); + } + + // t1_percent at 52. + if (!out_bindings[52]->amNull()) { + last_subnet->setT1Percent(out_bindings[52]->getFloat()); + } + + // t2_percent at 53. + if (!out_bindings[53]->amNull()) { + last_subnet->setT2Percent(out_bindings[53]->getFloat()); + } + + // authoritative at 54. + if (!out_bindings[54]->amNull()) { + last_subnet->setAuthoritative(out_bindings[54]->getBool()); + } + + // min_valid_lifetime at 55. + // max_valid_lifetime at 56. + + // pool client_class, require_client_classes and user_context + // from 57 to 59. + + // ddns_send_updates at 60. + if (!out_bindings[60]->amNull()) { + last_subnet->setDdnsSendUpdates(out_bindings[60]->getBool()); + } + + // ddns_override_no_update at 61. + if (!out_bindings[61]->amNull()) { + last_subnet->setDdnsOverrideNoUpdate(out_bindings[61]->getBool()); + } + + // ddns_override_client_update at 62. + if (!out_bindings[62]->amNull()) { + last_subnet->setDdnsOverrideClientUpdate(out_bindings[62]->getBool()); + } + + // ddns_replace_client_name at 63. + if (!out_bindings[63]->amNull()) { + last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode> + (out_bindings[63]->getInteger<uint8_t>())); + } + + // ddns_generated_prefix at 64. + if (!out_bindings[64]->amNull()) { + last_subnet->setDdnsGeneratedPrefix(out_bindings[64]->getString()); + } + + // ddns_qualifying_suffix at 65. + if (!out_bindings[65]->amNull()) { + last_subnet->setDdnsQualifyingSuffix(out_bindings[65]->getString()); + } + + // reservations_in_subnet at 66. + if (!out_bindings[66]->amNull()) { + last_subnet->setReservationsInSubnet(out_bindings[66]->getBool()); + } + + // reservations_out_of_pool at 67. + if (!out_bindings[67]->amNull()) { + last_subnet->setReservationsOutOfPool(out_bindings[67]->getBool()); + } + + // cache_threshold at 68. + if (!out_bindings[68]->amNull()) { + last_subnet->setCacheThreshold(out_bindings[68]->getFloat()); + } + + // cache_max_age at 69. + if (!out_bindings[69]->amNull()) { + last_subnet->setCacheMaxAge(out_bindings[69]->getInteger<uint32_t>()); + } + + // offer lifetime at 70. + if (!out_bindings[70]->amNull()) { + Optional<uint32_t> offer_lft(out_bindings[70]->getInteger<uint32_t>()); + last_subnet->setOfferLft(offer_lft); + } + + // allocator at 71. + if (!out_bindings[71]->amNull()) { + last_subnet->setAllocatorType(out_bindings[71]->getString()); + } + + // 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 (!out_bindings[72]->amNull() && + (last_tag != out_bindings[72]->getString())) { + last_tag = out_bindings[72]->getString(); + if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) { + last_subnet->setServerTag(last_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 (!out_bindings[20]->amNull() && + (out_bindings[21]->getInteger<uint32_t>() != 0) && + (out_bindings[22]->getInteger<uint32_t>() != 0) && + (out_bindings[20]->getInteger<uint64_t>() > last_pool_id)) { + last_pool_id = out_bindings[20]->getInteger<uint64_t>(); + last_pool = Pool4::create(IOAddress(out_bindings[21]->getInteger<uint32_t>()), + IOAddress(out_bindings[22]->getInteger<uint32_t>())); + + // pool client_class at 57. + if (!out_bindings[57]->amNull()) { + last_pool->allowClientClass(out_bindings[57]->getString()); + } + + // pool require_client_classes at 58. + ElementPtr require_element = out_bindings[58]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid pool require_client_classes value " + << out_bindings[58]->getString()); + } + 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 pool require_client_classes list must" + "be valid strings"); + } + last_pool->requireClientClass(require_item->stringValue()); + } + } + + // pool user_context at 59. + ElementPtr user_context = out_bindings[59]->getJSON(); + if (user_context) { + last_pool->setContext(user_context); + } + + last_subnet->addPool(last_pool); + } + + // Parse pool-specific option from 25 to 37. + if (last_pool && !out_bindings[25]->amNull() && + (last_pool_option_id < out_bindings[25]->getInteger<uint64_t>())) { + last_pool_option_id = out_bindings[25]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 25); + if (desc) { + last_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + + // Parse subnet-specific option from 38 to 50. + if (!out_bindings[38]->amNull() && + (last_option_id < out_bindings[38]->getInteger<uint64_t>())) { + last_option_id = out_bindings[38]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 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)); + } + + MySqlBindingCollection in_bindings = { MySqlBinding::createInteger<uint32_t>(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)); + } + + MySqlBindingCollection in_bindings = { MySqlBinding::createString(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); + MySqlBindingCollection 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(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) { + MySqlBindingCollection in_bindings = { MySqlBinding::createString(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 MySqlBindingCollection& in_bindings, + PoolCollection& pools, + std::vector<uint64_t>& pool_ids) { + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // pool: id + MySqlBinding::createInteger<uint32_t>(), // pool: start_address + MySqlBinding::createInteger<uint32_t>(), // pool: end_address + MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context + MySqlBinding::createTimestamp(), // pool: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pool option: option_id + MySqlBinding::createInteger<uint8_t>(), // pool option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pool option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space + MySqlBinding::createInteger<uint8_t>(), // pool option: persistent + MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled + MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp4_subnet_id + MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id + MySqlBinding::createTimestamp(), //pool option: modification_ts + }; + + uint64_t last_pool_id = 0; + uint64_t last_pool_option_id = 0; + Pool4Ptr last_pool; + + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &last_pool_id, &last_pool_option_id, &last_pool, + &pools, &pool_ids] + (MySqlBindingCollection& out_bindings) { + if (out_bindings[0]->getInteger<uint64_t>() > last_pool_id) { + // pool id (0) + last_pool_id = out_bindings[0]->getInteger<uint64_t>(); + + // pool start_address (1) + // pool end_address (2) + + last_pool = Pool4::create(IOAddress(out_bindings[1]->getInteger<uint32_t>()), + IOAddress(out_bindings[2]->getInteger<uint32_t>())); + + // pool subnet_id (3) (ignored) + + // pool client_class (4) + if (!out_bindings[4]->amNull()) { + last_pool->allowClientClass(out_bindings[4]->getString()); + } + + // pool require_client_classes (5) + ElementPtr require_element = out_bindings[5]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid pool require_client_classes value " + << out_bindings[5]->getString()); + } + 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 pool require_client_classes list must" + "be valid strings"); + } + last_pool->requireClientClass(require_item->stringValue()); + } + } + + // pool user_context (6) + ElementPtr user_context = out_bindings[6]->getJSON(); + 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 && !out_bindings[8]->amNull() && + (last_pool_option_id < out_bindings[8]->getInteger<uint64_t>())) { + last_pool_option_id = out_bindings[8]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 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()) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(pool_start_address.toUint32()), + MySqlBinding::createInteger<uint32_t>(pool_end_address.toUint32()) + }; + getPools(GET_POOL4_RANGE_ANY, in_bindings, pools, pool_ids); + } else { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createInteger<uint32_t>(pool_start_address.toUint32()), + MySqlBinding::createInteger<uint32_t>(pool_end_address.toUint32()) + }; + 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"); + } + + // Convert DHCPv4o6 interface id to text. + OptionPtr dhcp4o6_interface_id = subnet->get4o6().getInterfaceId(); + MySqlBindingPtr dhcp4o6_interface_id_binding; + if (dhcp4o6_interface_id) { + std::string dhcp4o6_interface_id_text(dhcp4o6_interface_id->getData().begin(), + dhcp4o6_interface_id->getData().end()); + dhcp4o6_interface_id_binding = MySqlBinding::createString(dhcp4o6_interface_id_text); + + } else { + dhcp4o6_interface_id_binding = MySqlBinding::createNull(); + } + + // 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(); + } + + // Create JSON list of required classes. + ElementPtr required_classes_element = Element::createList(); + const auto& required_classes = subnet->getRequiredClasses(); + for (auto required_class = required_classes.cbegin(); + required_class != required_classes.cend(); + ++required_class) { + required_classes_element->add(Element::create(*required_class)); + } + + // Create binding for DDNS replace client name mode. + MySqlBindingPtr ddns_rcn_mode_binding; + auto ddns_rcn_mode = subnet->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); + if (!ddns_rcn_mode.unspecified()) { + ddns_rcn_mode_binding = MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t> + (ddns_rcn_mode.get())); + } else { + ddns_rcn_mode_binding = MySqlBinding::createNull(); + } + + // Create binding with shared network name if the subnet belongs to a + // shared network. + MySqlBindingPtr shared_network_binding; + + 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) { + shared_network_binding = MySqlBinding::createString(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()) { + shared_network_binding = MySqlBinding::createString(subnet->getSharedNetworkName()); + + // If the subnet is not associated with a shared network, create + // null binding. + } else { + shared_network_binding = MySqlBinding::createNull(); + } + + // Create input bindings. + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()), + MySqlBinding::condCreateString(subnet->get4o6().getIface4o6()), + dhcp4o6_interface_id_binding, + MySqlBinding::condCreateString(dhcp4o6_subnet), + MySqlBinding::condCreateString(subnet->getFilename(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getClientClass(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getIface(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getMatchClientId(Network::Inheritance::NONE)), + MySqlBinding::createTimestamp(subnet->getModificationTime()), + MySqlBinding::condCreateIPv4Address(subnet->getSiaddr(Network::Inheritance::NONE)), + createBinding(subnet->getT2(Network::Inheritance::NONE)), + createInputRelayBinding(subnet), + createBinding(subnet->getT1(Network::Inheritance::NONE)), + createInputRequiredClassesBinding(subnet), + MySqlBinding::condCreateBool(subnet->getReservationsGlobal(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getSname(Network::Inheritance::NONE)), + shared_network_binding, + createInputContextBinding(subnet), + createBinding(subnet->getValid(Network::Inheritance::NONE)), + createMinBinding(subnet->getValid(Network::Inheritance::NONE)), + createMaxBinding(subnet->getValid(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getCalculateTeeTimes(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(subnet->getT1Percent(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(subnet->getT2Percent(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getAuthoritative(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getDdnsSendUpdates(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), + ddns_rcn_mode_binding, + MySqlBinding::condCreateString(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsOutOfPool(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(subnet->getCacheThreshold(Network::Inheritance::NONE)), + condCreateInteger<uint32_t>(subnet->getCacheMaxAge(Network::Inheritance::NONE)), + condCreateInteger<uint32_t>(subnet->getOfferLft(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getAllocatorType(Network::Inheritance::NONE)) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet set", true); + + try { + + // Try to insert subnet. If this duplicates unique key, i.e. this + // subnet already exists it will throw DuplicateEntry exception in + // which case we'll try an update. + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, + in_bindings); + + } catch (const DuplicateEntry&) { + deletePools4(subnet); + deleteOptions4(ServerSelector::ANY(), subnet); + + // Need to add two more bindings for WHERE clause. + in_bindings.push_back(MySqlBinding::createInteger<uint32_t>(subnet->getID())); + in_bindings.push_back(MySqlBinding::createString(subnet->toText())); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4, + in_bindings); + + MySqlBindingCollection in_server_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()) + }; + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_SERVER, + in_server_bindings); + } + + // Insert associations with the servers. + attachElementToServers(MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, + server_selector, + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createTimestamp(subnet->getModificationTime())); + + // (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); + } + } + + 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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(pool->getFirstAddress().toUint32()), + MySqlBinding::createInteger<uint32_t>(pool->getLastAddress().toUint32()), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())), + MySqlBinding::condCreateString(pool->getClientClass()), + createInputRequiredClassesBinding(pool), + createInputContextBinding(pool), + MySqlBinding::createTimestamp(subnet->getModificationTime()) + }; + + // Run INSERT. + conn_.insertQuery(INSERT_POOL4, in_bindings); + + uint64_t pool_id = mysql_insert_id(conn_.mysql_); + 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) { + MySqlTransaction 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, + MySqlConfigBackendDHCPv4Impl::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() ? + MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_ANY : + MySqlConfigBackendDHCPv4Impl::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() ? + MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_ANY : + MySqlConfigBackendDHCPv4Impl::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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()) + }; + + // Run DELETE. + return (conn_.updateDeleteQuery(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 MySqlBindingCollection& in_bindings, + SharedNetwork4Collection& shared_networks) { + // Create output bindings. The order must match that in the prepared + // statement. Please put comments only at the end of line so + // line counting and indexing match. + // The server tag must be the last field. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // name + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // client_class + MySqlBinding::createString(INTERFACE_BUF_LENGTH), // interface + MySqlBinding::createInteger<uint8_t>(), // match_client_id + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createInteger<uint32_t>(), // rebind_timer + MySqlBinding::createString(RELAY_BUF_LENGTH), // relay + MySqlBinding::createInteger<uint32_t>(), // renew_timer + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes + MySqlBinding::createInteger<uint8_t>(), // reservations_global + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createInteger<uint32_t>(), // valid_lifetime + MySqlBinding::createInteger<uint64_t>(), // option: option_id + MySqlBinding::createInteger<uint8_t>(), // option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space + MySqlBinding::createInteger<uint8_t>(), // option: persistent + MySqlBinding::createInteger<uint8_t>(), // option: cancelled + MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id + MySqlBinding::createInteger<uint8_t>(), // option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // option: pool_id + MySqlBinding::createTimestamp(), // option: modification_ts + MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times + MySqlBinding::createInteger<float>(), // t1_percent + MySqlBinding::createInteger<float>(), // t2_percent + MySqlBinding::createInteger<uint8_t>(), // authoritative + MySqlBinding::createString(BOOT_FILE_NAME_BUF_LENGTH), // boot_file_name + MySqlBinding::createInteger<uint32_t>(), // next_server + MySqlBinding::createString(SERVER_HOSTNAME_BUF_LENGTH), // server_hostname + MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime + MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime + MySqlBinding::createInteger<uint8_t>(), // ddns_send_updates + MySqlBinding::createInteger<uint8_t>(), // ddns_override_no_update + MySqlBinding::createInteger<uint8_t>(), // ddns_override_client_update + MySqlBinding::createInteger<uint8_t>(), // ddns_replace_client_name + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger<uint8_t>(), // reservations_in_subnet + MySqlBinding::createInteger<uint8_t>(), // reservations_out_of_pool + MySqlBinding::createInteger<float>(), // cache_threshold + MySqlBinding::createInteger<uint32_t>(), // cache_max_age + MySqlBinding::createInteger<uint32_t>(), // offer lifetime + MySqlBinding::createString(ALLOCATOR_TYPE_BUF_LENGTH), // allocator + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag + }; + + uint64_t last_network_id = 0; + uint64_t last_option_id = 0; + std::string last_tag; + + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &shared_networks, &last_network_id, &last_option_id, + &last_tag] + (MySqlBindingCollection& out_bindings) { + SharedNetwork4Ptr last_network; + if (!shared_networks.empty()) { + last_network = *shared_networks.rbegin(); + } + + // 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 != out_bindings[0]->getInteger<uint64_t>()) { + // 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(); + + // id at 0. + last_network_id = out_bindings[0]->getInteger<uint64_t>(); + + // name at 1. + last_network = SharedNetwork4::create(out_bindings[1]->getString()); + last_network->setId(last_network_id); + + // client_class at 2. + if (!out_bindings[2]->amNull()) { + last_network->allowClientClass(out_bindings[2]->getString()); + } + + // interface at 3. + if (!out_bindings[3]->amNull()) { + last_network->setIface(out_bindings[3]->getString()); + } + + // match_client_id at 4. + if (!out_bindings[4]->amNull()) { + last_network->setMatchClientId(out_bindings[4]->getBool()); + } + + // modification_ts at 5. + last_network->setModificationTime(out_bindings[5]->getTimestamp()); + + // rebind_timer at 6. + if (!out_bindings[6]->amNull()) { + last_network->setT2(createTriplet(out_bindings[6])); + } + + // relay at 7. + ElementPtr relay_element = out_bindings[7]->getJSON(); + if (relay_element) { + if (relay_element->getType() != Element::list) { + isc_throw(BadValue, "invalid relay value " + << out_bindings[7]->getString()); + } + 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, "relay address must be a string"); + } + last_network->addRelayAddress(IOAddress(relay_element->get(i)->stringValue())); + } + } + + // renew_timer at 8. + if (!out_bindings[8]->amNull()) { + last_network->setT1(createTriplet(out_bindings[8])); + } + + // require_client_classes at 9. + ElementPtr require_element = out_bindings[9]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid require_client_classes value " + << out_bindings[9]->getString()); + } + 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"); + } + last_network->requireClientClass(require_item->stringValue()); + } + } + + // reservations_global at 10. + if (!out_bindings[10]->amNull()) { + last_network->setReservationsGlobal(out_bindings[10]->getBool()); + } + + // user_context at 11. + ElementPtr user_context = out_bindings[11]->getJSON(); + if (user_context) { + last_network->setContext(user_context); + } + + // valid_lifetime at 12. + // min_valid_lifetime at 33. + // max_valid_lifetime at 34. + if (!out_bindings[12]->amNull()) { + last_network->setValid(createTriplet(out_bindings[12], + out_bindings[33], + out_bindings[34])); + } + + // option from 13 to 25. + + // calculate_tee_times at 26. + if (!out_bindings[26]->amNull()) { + last_network->setCalculateTeeTimes(out_bindings[26]->getBool()); + } + + // t1_percent at 27. + if (!out_bindings[27]->amNull()) { + last_network->setT1Percent(out_bindings[27]->getFloat()); + } + + // t2_percent at 28. + if (!out_bindings[28]->amNull()) { + last_network->setT2Percent(out_bindings[28]->getFloat()); + } + + // authoritative at 29. + if (!out_bindings[29]->amNull()) { + last_network->setAuthoritative(out_bindings[29]->getBool()); + } + + // boot_file_name at 30. + if (!out_bindings[30]->amNull()) { + last_network->setFilename(out_bindings[30]->getString()); + } + + // next_server at 31. + if (!out_bindings[31]->amNull()) { + last_network->setSiaddr(IOAddress(out_bindings[31]->getInteger<uint32_t>())); + } + + // server_hostname at 32. + if (!out_bindings[32]->amNull()) { + last_network->setSname(out_bindings[32]->getString()); + } + + // min_valid_lifetime at 33. + // max_valid_lifetime at 34. + + // ddns_send_updates at 35. + if (!out_bindings[35]->amNull()) { + last_network->setDdnsSendUpdates(out_bindings[35]->getBool()); + } + + // ddns_override_no_update at 36. + if (!out_bindings[36]->amNull()) { + last_network->setDdnsOverrideNoUpdate(out_bindings[36]->getBool()); + } + + // ddns_override_client_update at 37. + if (!out_bindings[37]->amNull()) { + last_network->setDdnsOverrideClientUpdate(out_bindings[37]->getBool()); + } + + // ddns_replace_client_name at 38. + if (!out_bindings[38]->amNull()) { + last_network->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode> + (out_bindings[38]->getInteger<uint8_t>())); + } + + // ddns_generated_prefix at 39. + if (!out_bindings[39]->amNull()) { + last_network->setDdnsGeneratedPrefix(out_bindings[39]->getString()); + } + + // ddns_qualifying_suffix at 40. + if (!out_bindings[40]->amNull()) { + last_network->setDdnsQualifyingSuffix(out_bindings[40]->getString()); + } + + // reservations_in_subnet at 41. + if (!out_bindings[41]->amNull()) { + last_network->setReservationsInSubnet(out_bindings[41]->getBool()); + } + + // reservations_in_subnet at 42. + if (!out_bindings[42]->amNull()) { + last_network->setReservationsOutOfPool(out_bindings[42]->getBool()); + } + + // cache_threshold at 43. + if (!out_bindings[43]->amNull()) { + last_network->setCacheThreshold(out_bindings[43]->getFloat()); + } + + // cache_max_age at 44. + if (!out_bindings[44]->amNull()) { + last_network->setCacheMaxAge(out_bindings[44]->getInteger<uint32_t>()); + } + + // offer lifetime at 45. + if (!out_bindings[45]->amNull()) { + Optional<uint32_t> offer_lft(out_bindings[45]->getInteger<uint32_t>()); + last_network->setOfferLft(offer_lft); + } + + // allocator at 46. + if (!out_bindings[46]->amNull()) { + last_network->setAllocatorType(out_bindings[46]->getString()); + } + + // 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 (!out_bindings[47]->amNull() && + (last_tag != out_bindings[47]->getString())) { + last_tag = out_bindings[47]->getString(); + if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) { + last_network->setServerTag(last_tag); + } + } + + // Parse option from 13 to 25. + if (!out_bindings[13]->amNull() && + (last_option_id < out_bindings[13]->getInteger<uint64_t>())) { + last_option_id = out_bindings[13]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 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)); + } + + MySqlBindingCollection in_bindings = { MySqlBinding::createString(name) }; + + auto index = GET_SHARED_NETWORK4_NAME_NO_TAG; + if (server_selector.amUnassigned()) { + index = GET_SHARED_NETWORK4_NAME_UNASSIGNED; + } else if (server_selector.amAny()) { + index = 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() ? GET_ALL_SHARED_NETWORKS4_UNASSIGNED : + GET_ALL_SHARED_NETWORKS4); + MySqlBindingCollection 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(modification_ts) + }; + + auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED : + 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"); + } + + // Create binding for DDNS replace client name mode. + MySqlBindingPtr ddns_rcn_mode_binding; + auto ddns_rcn_mode = shared_network->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); + if (!ddns_rcn_mode.unspecified()) { + ddns_rcn_mode_binding = MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t> + (ddns_rcn_mode.get())); + } else { + ddns_rcn_mode_binding = MySqlBinding::createNull(); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(shared_network->getName()), + MySqlBinding::condCreateString(shared_network->getClientClass(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getIface(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getMatchClientId(Network::Inheritance::NONE)), + MySqlBinding::createTimestamp(shared_network->getModificationTime()), + createBinding(shared_network->getT2(Network::Inheritance::NONE)), + createInputRelayBinding(shared_network), + createBinding(shared_network->getT1(Network::Inheritance::NONE)), + createInputRequiredClassesBinding(shared_network), + MySqlBinding::condCreateBool(shared_network->getReservationsGlobal(Network::Inheritance::NONE)), + createInputContextBinding(shared_network), + createBinding(shared_network->getValid(Network::Inheritance::NONE)), + createMinBinding(shared_network->getValid(Network::Inheritance::NONE)), + createMaxBinding(shared_network->getValid(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(shared_network->getT1Percent(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(shared_network->getT2Percent(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getAuthoritative(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getFilename(Network::Inheritance::NONE)), + MySqlBinding::condCreateIPv4Address(shared_network->getSiaddr(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getSname(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getDdnsSendUpdates(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), + ddns_rcn_mode_binding, + MySqlBinding::condCreateString(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(shared_network->getCacheThreshold(Network::Inheritance::NONE)), + condCreateInteger<uint32_t>(shared_network->getCacheMaxAge(Network::Inheritance::NONE)), + condCreateInteger<uint32_t>(shared_network->getOfferLft(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getAllocatorType(Network::Inheritance::NONE)) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network set", true); + + 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. + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4, + in_bindings); + + } catch (const DuplicateEntry&) { + deleteOptions4(ServerSelector::ANY(), shared_network); + + // Need to add one more binding for WHERE clause. + in_bindings.push_back(MySqlBinding::createString(shared_network->getName())); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4, + in_bindings); + + MySqlBindingCollection in_server_bindings = { + MySqlBinding::createString(shared_network->getName()) + }; + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER, + in_server_bindings); + } + + // Associate the shared network with the servers. + attachElementToServers(MySqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER, + server_selector, + MySqlBinding::createString(shared_network->getName()), + MySqlBinding::createTimestamp(shared_network->getModificationTime())); + + // (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); + } + } + + transaction.commit(); + } + + /// @brief Sends query to insert DHCP option. + /// + /// This method expects that the server selector contains exactly one + /// server tag. + /// + /// @param server_selector Server selector. + /// @param in_bindings Collection of bindings representing an option. + void insertOption4(const ServerSelector& server_selector, + const MySqlBindingCollection& in_bindings) { + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::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 = mysql_insert_id(conn_.mysql_); + + // Timestamp is expected to be in this input binding. + auto timestamp_binding = in_bindings[12]; + + // Associate the option with the servers. + attachElementToServers(MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER, + server_selector, + MySqlBinding::createInteger<uint64_t>(option_id), + timestamp_binding); + } + + /// @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"); + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(0), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createString(tag), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "global option set", false); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption4(server_selector, in_bindings); + } + + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)), + MySqlBinding::createInteger<uint8_t>(1), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + boost::scoped_ptr<MySqlTransaction> transaction; + // Only start new transaction if specified to do so. This function may + // be called from within an existing transaction in which case we + // don't start the new one. + if (!cascade_update) { + transaction.reset(new MySqlTransaction(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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet specific option set", + cascade_update); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption4(server_selector, in_bindings); + } + + if (transaction) { + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(5), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint64_t>(pool_id), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createInteger<uint64_t>(pool_id), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "pool specific option set", + cascade_update); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption4(server_selector, in_bindings); + } + + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(4), + createInputContextBinding(option), + MySqlBinding::createString(shared_network_name), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createString(shared_network_name), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + boost::scoped_ptr<MySqlTransaction> transaction; + // Only start new transaction if specified to do so. This function may + // be called from within an existing transaction in which case we + // don't start the new one. + if (!cascade_update) { + transaction.reset(new MySqlTransaction(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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network specific option set", + cascade_update); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl:: + UPDATE_OPTION4_SHARED_NETWORK, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption4(server_selector, in_bindings); + } + + if (transaction) { + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(2), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(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, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "client class specific option set", + true); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl:: + UPDATE_OPTION4_CLIENT_CLASS, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption4(server_selector, in_bindings); + } + } + + /// @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_def, DHCP4_OPTION_SPACE, + MySqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + MySqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4, + MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + MySqlConfigBackendDHCPv4Impl::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_def, DHCP4_OPTION_SPACE, + MySqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + MySqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_CLIENT_CLASS, + MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4_CLIENT_CLASS, + MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + MySqlConfigBackendDHCPv4Impl::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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(client_class->getName()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)), + MySqlBinding::createInteger<uint8_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint8_t>(code), + MySqlBinding::createString(space), + MySqlBinding::createInteger<uint32_t>(pool_start_address.toUint32()), + MySqlBinding::createInteger<uint32_t>(pool_end_address.toUint32()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(shared_network_name), + MySqlBinding::createInteger<uint8_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(shared_network->getName()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(client_class->getName()) + }; + + // Run DELETE. + return (deleteTransactional(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 MySqlBindingCollection& in_bindings, + ClientClassDictionary& client_classes) { + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createString(CLIENT_CLASS_NAME_BUF_LENGTH), // name + MySqlBinding::createString(CLIENT_CLASS_TEST_BUF_LENGTH), // test + MySqlBinding::createInteger<uint32_t>(), // next server + MySqlBinding::createString(CLIENT_CLASS_SNAME_BUF_LENGTH), // sname + MySqlBinding::createString(CLIENT_CLASS_FILENAME_BUF_LENGTH), // filename + MySqlBinding::createInteger<uint8_t>(), // required + MySqlBinding::createInteger<uint32_t>(), // valid lifetime + MySqlBinding::createInteger<uint32_t>(), // min valid lifetime + MySqlBinding::createInteger<uint32_t>(), // max valid lifetime + MySqlBinding::createInteger<uint8_t>(), // depend on known directly + MySqlBinding::createInteger<uint8_t>(), // depend on known indirectly + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createInteger<uint32_t>(), // offer lifetime + MySqlBinding::createInteger<uint64_t>(), // option def: id + MySqlBinding::createInteger<uint16_t>(), // option def: code + MySqlBinding::createString(OPTION_NAME_BUF_LENGTH), // option def: name + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option def: space + MySqlBinding::createInteger<uint8_t>(), // option def: type + MySqlBinding::createTimestamp(), // option def: modification_ts + MySqlBinding::createInteger<uint8_t>(), // option def: array + MySqlBinding::createString(OPTION_ENCAPSULATE_BUF_LENGTH), // option def: encapsulate + MySqlBinding::createString(OPTION_RECORD_TYPES_BUF_LENGTH), // option def: record_types + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option def: user_context + MySqlBinding::createInteger<uint64_t>(), // option: option_id + MySqlBinding::createInteger<uint8_t>(), // option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space + MySqlBinding::createInteger<uint8_t>(), // option: persistent + MySqlBinding::createInteger<uint8_t>(), // option: cancelled + MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id + MySqlBinding::createInteger<uint8_t>(), // option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // option: pool_id + MySqlBinding::createTimestamp(), // option: modification_ts + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server tag + }; + + std::list<ClientClassDefPtr> class_list; + uint64_t last_option_id = 0; + uint64_t last_option_def_id = 0; + std::string last_tag; + + conn_.selectQuery(index, + in_bindings, out_bindings, + [this, &class_list, &last_option_id, &last_option_def_id, &last_tag] + (MySqlBindingCollection& out_bindings) { + ClientClassDefPtr last_client_class; + if (!class_list.empty()) { + last_client_class = *class_list.rbegin(); + } + + if (!last_client_class || (last_client_class->getId() != out_bindings[0]->getInteger<uint64_t>())) { + 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>(out_bindings[1]->getString(), + ExpressionPtr(), options); + last_client_class->setCfgOptionDef(option_defs); + + // id + last_client_class->setId(out_bindings[0]->getInteger<uint64_t>()); + + // name + last_client_class->setName(out_bindings[1]->getString()); + + // test + if (!out_bindings[2]->amNull()) { + last_client_class->setTest(out_bindings[2]->getString()); + } + + // next server + if (!out_bindings[3]->amNull()) { + last_client_class->setNextServer(IOAddress(out_bindings[3]->getInteger<uint32_t>())); + } + + // sname + if (!out_bindings[4]->amNull()) { + last_client_class->setSname(out_bindings[4]->getString()); + } + + // filename + if (!out_bindings[5]->amNull()) { + last_client_class->setFilename(out_bindings[5]->getString()); + } + + // required + if (!out_bindings[6]->amNull()) { + last_client_class->setRequired(out_bindings[6]->getBool()); + } + + // valid lifetime: default, min, max + last_client_class->setValid(createTriplet(out_bindings[7], out_bindings[8], out_bindings[9])); + + // depend on known directly or indirectly + last_client_class->setDependOnKnown(out_bindings[10]->getBool() || out_bindings[11]->getBool()); + + // modification_ts + last_client_class->setModificationTime(out_bindings[12]->getTimestamp()); + + // user_context + ElementPtr user_context = out_bindings[13]->getJSON(); + if (user_context) { + last_client_class->setContext(user_context); + } + + // offer lifetime + if (!out_bindings[14]->amNull()) { + Optional<uint32_t> offer_lft(out_bindings[14]->getInteger<uint32_t>()); + last_client_class->setOfferLft(offer_lft); + } + + class_list.push_back(last_client_class); + } + + // server tag + if (!out_bindings[38]->amNull() && + (last_tag != out_bindings[38]->getString())) { + last_tag = out_bindings[38]->getString(); + if (!last_tag.empty() && !last_client_class->hasServerTag(ServerTag(last_tag))) { + last_client_class->setServerTag(last_tag); + } + } + + // Parse client class specific option definition from 15 to 24. + if (!out_bindings[15]->amNull() && + (last_option_def_id < out_bindings[15]->getInteger<uint64_t>())) { + last_option_def_id = out_bindings[15]->getInteger<uint64_t>(); + + auto def = processOptionDefRow(out_bindings.begin() + 15); + if (def) { + last_client_class->getCfgOptionDef()->add(def); + } + } + + // Parse client class specific option from 25 to 37. + if (!out_bindings[25]->amNull() && + (last_option_id < out_bindings[25]->getInteger<uint64_t>())) { + last_option_id = out_bindings[25]->getInteger<uint64_t>(); + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(name) + }; + ClientClassDictionary client_classes; + getClientClasses4(MySqlConfigBackendDHCPv4Impl::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) { + MySqlBindingCollection in_bindings; + getClientClasses4(server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4_UNASSIGNED : + MySqlConfigBackendDHCPv4Impl::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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(modification_ts) + }; + getClientClasses4(server_selector.amUnassigned() ? + GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED : + 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); + }); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createString(client_class->getTest()), + MySqlBinding::createInteger<uint32_t>(client_class->getNextServer().toUint32()), + MySqlBinding::createString(client_class->getSname()), + MySqlBinding::createString(client_class->getFilename()), + MySqlBinding::createBool(client_class->getRequired()), + createBinding(client_class->getValid()), + createMinBinding(client_class->getValid()), + createMaxBinding(client_class->getValid()), + MySqlBinding::createBool(depend_on_known), + (follow_class_name.empty() ? MySqlBinding::createNull() : + MySqlBinding::createString(follow_class_name)), + MySqlBinding::createTimestamp(client_class->getModificationTime()), + createInputContextBinding(client_class), + condCreateInteger(client_class->getOfferLft()) + }; + + MySqlTransaction transaction(conn_); + + ScopedAuditRevision audit_revision(this, MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + server_selector, "client class set", true); + // Keeps track of whether the client class is inserted or updated. + auto update = false; + try { + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4, in_bindings); + + } catch (const DuplicateEntry&) { + // Such class already exists. + + // 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); + + // Try to update the class. + in_bindings.push_back(MySqlBinding::createString(client_class->getName())); + if (follow_class_name.empty()) { + // If position is not specified, leave the class at the same position. + // Remove the binding which specifies the position and use different + // query. + in_bindings.erase(in_bindings.begin() + 10, in_bindings.begin() + 11); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4_SAME_POSITION, + in_bindings); + } else { + // Update with specifying the position. + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4, + in_bindings); + } + + // Delete class associations with the servers and dependencies. We will re-create + // them according to the new class specification. + MySqlBindingCollection in_assoc_bindings = { + MySqlBinding::createString(client_class->getName()) + }; + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_DEPENDENCY, + in_assoc_bindings); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_SERVER, + in_assoc_bindings); + update = true; + } + + // Associate client class with the servers. + attachElementToServers(MySqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_SERVER, + server_selector, + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createTimestamp(client_class->getModificationTime())); + + // Iterate over the captured dependencies and try to insert them into the database. + for (auto dependency : dependencies) { + try { + MySqlBindingCollection in_dependency_bindings = { + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createString(dependency) + }; + // We deleted earlier dependencies, so we can simply insert new ones. + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::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) { + MySqlBindingCollection in_check_bindings; + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::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() ? + MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_ANY : + MySqlConfigBackendDHCPv4Impl::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"); + } + + MySqlTransaction 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, MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting a server", false); + + // Specify which server should be deleted. + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(server_tag.get()) + }; + + // Attempt to delete the server. + auto count = conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::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() { + MySqlTransaction 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, MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting all servers", + false); + + MySqlBindingCollection in_bindings; + + // Attempt to delete the servers. + auto count = conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::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(); + } + + 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(mysql_cb_logger, MYSQL_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(mysql_cb_logger, MYSQL_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(mysql_cb_logger, MYSQL_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(&MySqlConfigBackendDHCPv4Impl::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<TaggedStatement, MySqlConfigBackendDHCPv4Impl::NUM_STATEMENTS> +TaggedStatementArray; + +/// @brief Prepared MySQL statements used by the backend to insert and +/// retrieve data from the database. +TaggedStatementArray tagged_statements = { { + { MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + "CALL createAuditRevisionDHCP4(?, ?, ?, ?)" + }, + + // Verify that dependency on KNOWN/UNKNOWN class has not changed. + { MySqlConfigBackendDHCPv4Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + "CALL checkDHCPv4ClientClassKnownDependencyChange()" + }, + + // Select global parameter by name. + { MySqlConfigBackendDHCPv4Impl::GET_GLOBAL_PARAMETER4, + MYSQL_GET_GLOBAL_PARAMETER(dhcp4, AND g.name = ?) + }, + + // Select all global parameters. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, + MYSQL_GET_GLOBAL_PARAMETER(dhcp4) + }, + + // Select modified global parameters. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, + MYSQL_GET_GLOBAL_PARAMETER(dhcp4, AND g.modification_ts >= ?) + }, + + // Select subnet by id. + { MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_NO_TAG, + MYSQL_GET_SUBNET4_NO_TAG(WHERE s.subnet_id = ?) + }, + + // Select subnet by id without specifying server tags. + { MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_ANY, + MYSQL_GET_SUBNET4_ANY(WHERE s.subnet_id = ?) + }, + + // Select unassigned subnet by id. + { MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_UNASSIGNED, + MYSQL_GET_SUBNET4_UNASSIGNED(AND s.subnet_id = ?) + }, + + // Select subnet by prefix. + { MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_NO_TAG, + MYSQL_GET_SUBNET4_NO_TAG(WHERE s.subnet_prefix = ?) + }, + + // Select subnet by prefix without specifying server tags. + { MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_ANY, + MYSQL_GET_SUBNET4_ANY(WHERE s.subnet_prefix = ?) + }, + + // Select unassigned subnet by prefix. + { MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_UNASSIGNED, + MYSQL_GET_SUBNET4_UNASSIGNED(AND s.subnet_prefix = ?) + }, + + // Select all subnets. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4, + MYSQL_GET_SUBNET4_NO_TAG() + }, + + // Select all unassigned subnets. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4_UNASSIGNED, + MYSQL_GET_SUBNET4_UNASSIGNED() + }, + + // Select subnets having modification time later than X. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4, + MYSQL_GET_SUBNET4_NO_TAG(WHERE s.modification_ts >= ?) + }, + + // Select modified and unassigned subnets. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4_UNASSIGNED, + MYSQL_GET_SUBNET4_UNASSIGNED(AND s.modification_ts >= ?) + }, + + // Select subnets belonging to a shared network. + { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK_SUBNETS4, + MYSQL_GET_SUBNET4_ANY(WHERE s.shared_network_name = ?) + }, + + // Select pool by address range for a server. + { MySqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE, + MYSQL_GET_POOL4_RANGE_WITH_TAG(WHERE (srv.tag = ? OR srv.id = 1) AND p.start_address = ? \ + AND p.end_address = ?) + }, + + // Select pool by address range for any server. + { MySqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE_ANY, + MYSQL_GET_POOL4_RANGE_NO_TAG(WHERE p.start_address = ? AND p.end_address = ?) + }, + + // Select shared network by name. + { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_NO_TAG, + MYSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.name = ?) + }, + + // Select shared network by name without specifying server tags. + { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_ANY, + MYSQL_GET_SHARED_NETWORK4_ANY(WHERE n.name = ?) + }, + + // Select unassigned shared network by name. + { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_UNASSIGNED, + MYSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.name = ?) + }, + + // Select all shared networks. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4, + MYSQL_GET_SHARED_NETWORK4_NO_TAG() + }, + + // Select all unassigned shared networks. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4_UNASSIGNED, + MYSQL_GET_SHARED_NETWORK4_UNASSIGNED() + }, + + // Select modified shared networks. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4, + MYSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.modification_ts >= ?) + }, + + // Select modified and unassigned shared networks. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED, + MYSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.modification_ts >= ?) + }, + + // Retrieves option definition by code and space. + { MySqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + MYSQL_GET_OPTION_DEF(dhcp4, AND d.code = ? AND d.space = ?) + }, + + // Retrieves all option definitions. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4, + MYSQL_GET_OPTION_DEF(dhcp4) + }, + + // Retrieves modified option definitions. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4, + MYSQL_GET_OPTION_DEF(dhcp4, AND d.modification_ts >= ?) + }, + + // Retrieves global option by code and space. + { MySqlConfigBackendDHCPv4Impl::GET_OPTION4_CODE_SPACE, + MYSQL_GET_OPTION4(AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + }, + + // Retrieves all global options. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4, + MYSQL_GET_OPTION4(AND o.scope_id = 0) + }, + + // Retrieves modified options. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTIONS4, + MYSQL_GET_OPTION4(AND o.scope_id = 0 AND o.modification_ts >= ?) + }, + + // Retrieves an option for a given subnet, option code and space. + { MySqlConfigBackendDHCPv4Impl::GET_OPTION4_SUBNET_ID_CODE_SPACE, + MYSQL_GET_OPTION4(AND o.scope_id = 1 AND o.dhcp4_subnet_id = ? AND o.code = ? AND o.space = ?) + }, + + // Retrieves an option for a given pool, option code and space. + { MySqlConfigBackendDHCPv4Impl::GET_OPTION4_POOL_ID_CODE_SPACE, + MYSQL_GET_OPTION4(AND o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?) + }, + + // Retrieves an option for a given shared network, option code and space. + { MySqlConfigBackendDHCPv4Impl::GET_OPTION4_SHARED_NETWORK_CODE_SPACE, + MYSQL_GET_OPTION4(AND o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + }, + + // Select a client class by name. + { MySqlConfigBackendDHCPv4Impl::GET_CLIENT_CLASS4_NAME, + MYSQL_GET_CLIENT_CLASS4_WITH_TAG(WHERE c.name = ?) + }, + + // Select all client classes. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4, + MYSQL_GET_CLIENT_CLASS4_WITH_TAG() + }, + + // Select all unassigned client classes. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4_UNASSIGNED, + MYSQL_GET_CLIENT_CLASS4_UNASSIGNED() + }, + + // Select modified client classes. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4, + MYSQL_GET_CLIENT_CLASS4_WITH_TAG(WHERE c.modification_ts >= ?) + }, + + // Select modified client classes. + { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED, + MYSQL_GET_CLIENT_CLASS4_UNASSIGNED(AND c.modification_ts >= ?) + }, + + // Retrieves the most recent audit entries. + { MySqlConfigBackendDHCPv4Impl::GET_AUDIT_ENTRIES4_TIME, + MYSQL_GET_AUDIT_ENTRIES_TIME(dhcp4) + }, + + // Retrieves a server by tag. + { MySqlConfigBackendDHCPv4Impl::GET_SERVER4, + MYSQL_GET_SERVER(dhcp4) + }, + + // Retrieves all servers. + { MySqlConfigBackendDHCPv4Impl::GET_ALL_SERVERS4, + MYSQL_GET_ALL_SERVERS(dhcp4) + }, + + // Insert global parameter. + { MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4, + MYSQL_INSERT_GLOBAL_PARAMETER(dhcp4) + }, + + // Insert association of the global parameter with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER, + MYSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp4) + }, + + // Insert a subnet. + { MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, + "INSERT INTO dhcp4_subnet(" + " subnet_id," + " subnet_prefix," + " 4o6_interface," + " 4o6_interface_id," + " 4o6_subnet," + " 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + + // Insert association of the subnet with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, + MYSQL_INSERT_SUBNET_SERVER(dhcp4) + }, + + // Insert pool for a subnet. + { MySqlConfigBackendDHCPv4Impl::INSERT_POOL4, + MYSQL_INSERT_POOL(dhcp4) + }, + + // Insert a shared network. + { MySqlConfigBackendDHCPv4Impl::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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + + // Insert association of the shared network with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER, + MYSQL_INSERT_SHARED_NETWORK_SERVER(dhcp4) + }, + + // Insert option definition. + { MySqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4, + MYSQL_INSERT_OPTION_DEF(dhcp4) + }, + + // Insert option definition for client class. + { MySqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_CLIENT_CLASS, + MYSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp4) + }, + + // Insert association of the option definition with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER, + MYSQL_INSERT_OPTION_DEF_SERVER(dhcp4) + }, + + // Insert subnet specific option. + { MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4, + MYSQL_INSERT_OPTION4() + }, + + // Insert association of the DHCP option with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER, + MYSQL_INSERT_OPTION_SERVER(dhcp4) + }, + + // Insert client class. + { MySqlConfigBackendDHCPv4Impl::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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + }, + + // Insert association of a client class with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_SERVER, + MYSQL_INSERT_CLIENT_CLASS_SERVER(dhcp4) + }, + + // Insert client class dependency. + { MySqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_DEPENDENCY, + MYSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp4) + }, + + // Insert server with server tag and description. + { MySqlConfigBackendDHCPv4Impl::INSERT_SERVER4, + MYSQL_INSERT_SERVER(dhcp4) + }, + + // Update existing global parameter. + { MySqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4, + MYSQL_UPDATE_GLOBAL_PARAMETER(dhcp4) + }, + + // Update existing subnet. + { MySqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4, + "UPDATE dhcp4_subnet SET" + " subnet_id = ?," + " subnet_prefix = ?," + " 4o6_interface = ?," + " 4o6_interface_id = ?," + " 4o6_subnet = ?," + " 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 = ? " + "WHERE subnet_id = ? OR subnet_prefix = ?" }, + + // Update existing shared network. + { MySqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4, + "UPDATE dhcp4_shared_network SET" + " 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 = ? " + "WHERE name = ?" }, + + // Update existing option definition. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4, + MYSQL_UPDATE_OPTION_DEF(dhcp4) + }, + + // Update existing client class option definition. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4_CLIENT_CLASS, + MYSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp4) + }, + + // Update existing global option. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4, + MYSQL_UPDATE_OPTION4_WITH_TAG(AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + }, + + // Update existing subnet level option. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID, + MYSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 1 AND o.dhcp4_subnet_id = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing pool level option. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID, + MYSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing shared network level option. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK, + MYSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing client class level option. + { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_CLIENT_CLASS, + MYSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing client class with specifying its position. + { MySqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4, + MYSQL_UPDATE_CLIENT_CLASS4("follow_class_name = ?,") + }, + + // Update existing client class without specifying its position. + { MySqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4_SAME_POSITION, + MYSQL_UPDATE_CLIENT_CLASS4("") + }, + + // Update existing server, e.g. server description. + { MySqlConfigBackendDHCPv4Impl::UPDATE_SERVER4, + MYSQL_UPDATE_SERVER(dhcp4) + }, + + // Delete global parameter by name. + { MySqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4, + MYSQL_DELETE_GLOBAL_PARAMETER(dhcp4, AND g.name = ?) + }, + + // Delete all global parameters. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4, + MYSQL_DELETE_GLOBAL_PARAMETER(dhcp4) + }, + + // Delete all global parameters which are unassigned to any servers. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED, + MYSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp4) + }, + + // Delete subnet by id with specifying server tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_WITH_TAG, + MYSQL_DELETE_SUBNET_WITH_TAG(dhcp4, AND s.subnet_id = ?) + }, + + // Delete subnet by id without specifying server tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_ANY, + MYSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.subnet_id = ?) + }, + + // Delete subnet by prefix with specifying server tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_WITH_TAG, + MYSQL_DELETE_SUBNET_WITH_TAG(dhcp4, AND s.subnet_prefix = ?) + }, + + // Delete subnet by prefix without specifying server tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_ANY, + MYSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.subnet_prefix = ?) + }, + + // Delete all subnets. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4, + MYSQL_DELETE_SUBNET_WITH_TAG(dhcp4) + }, + + // Delete all unassigned subnets. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_UNASSIGNED, + MYSQL_DELETE_SUBNET_UNASSIGNED(dhcp4) + }, + + // Delete all subnets for a shared network. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME, + MYSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.shared_network_name = ?) + }, + + // Delete associations of a subnet with server. + { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_SERVER, + MYSQL_DELETE_SUBNET_SERVER(dhcp4), + }, + + // Delete pools for a subnet. + { MySqlConfigBackendDHCPv4Impl::DELETE_POOLS4, + MYSQL_DELETE_POOLS(dhcp4) + }, + + // Delete shared network by name with specifying server tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_WITH_TAG, + MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4, AND n.name = ?) + }, + + // Delete shared network by name without specifying server tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY, + MYSQL_DELETE_SHARED_NETWORK_ANY(dhcp4, WHERE n.name = ?) + }, + + // Delete all shared networks. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4, + MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4) + }, + + // Delete all unassigned shared networks. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED, + MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp4) + }, + + // Delete associations of a shared network with server. + { MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER, + MYSQL_DELETE_SHARED_NETWORK_SERVER(dhcp4) + }, + + // Delete option definition. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEF4_CODE_NAME, + MYSQL_DELETE_OPTION_DEF(dhcp4, AND code = ? AND space = ?) + }, + + // Delete all option definitions. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4, + MYSQL_DELETE_OPTION_DEF(dhcp4) + }, + + // Delete all option definitions which are assigned to no servers. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4_UNASSIGNED, + MYSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp4) + }, + + // Delete client class specific option definitions. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEFS4_CLIENT_CLASS, + MYSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp4) + }, + + // Delete single global option. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4, + MYSQL_DELETE_OPTION_WITH_TAG(dhcp4, AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + }, + + // Delete all global options which are unassigned to any servers. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED, + MYSQL_DELETE_OPTION_UNASSIGNED(dhcp4, AND o.scope_id = 0) + }, + + // Delete single option from a subnet. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID, + MYSQL_DELETE_OPTION_NO_TAG(dhcp4, + WHERE o.scope_id = 1 AND o.dhcp4_subnet_id = ? AND o.code = ? AND o.space = ?) + }, + + // Delete single option from a pool. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4_POOL_RANGE, + MYSQL_DELETE_OPTION_POOL_RANGE(dhcp4, o.scope_id = 5 AND o.code = ? AND o.space = ?) + }, + + // Delete single option from a shared network. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SHARED_NETWORK, + MYSQL_DELETE_OPTION_NO_TAG(dhcp4, + WHERE o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + }, + + // Delete options belonging to a subnet. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SUBNET_ID_PREFIX, + MYSQL_DELETE_OPTION_SUBNET_ID_PREFIX(dhcp4) + }, + + // Delete options belonging to a shared_network. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SHARED_NETWORK, + MYSQL_DELETE_OPTION_NO_TAG(dhcp4, WHERE o.scope_id = 4 AND o.shared_network_name = ?) + }, + + // Delete options belonging to a client class. + { MySqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_CLIENT_CLASS, + MYSQL_DELETE_OPTION_NO_TAG(dhcp4, WHERE o.scope_id = 2 AND o.dhcp_client_class = ?) + }, + + // Delete all dependencies of a client class. + { MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_DEPENDENCY, + MYSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp4) + }, + + // Delete associations of a client class with server. + { MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_SERVER, + MYSQL_DELETE_CLIENT_CLASS_SERVER(dhcp4), + }, + + // Delete all client classes. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4, + MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp4) + }, + + // Delete all unassigned client classes. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED, + MYSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp4) + }, + + // Delete specified client class. + { MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4, + MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp4, AND name = ?) + }, + + // Delete any client class with a given name. + { MySqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_ANY, + MYSQL_DELETE_CLIENT_CLASS_ANY(dhcp4, AND name = ?) + }, + + // Delete a server by tag. + { MySqlConfigBackendDHCPv4Impl::DELETE_SERVER4, + MYSQL_DELETE_SERVER(dhcp4) + }, + + // Deletes all servers except logical server 'all'. + { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SERVERS4, + MYSQL_DELETE_ALL_SERVERS(dhcp4) + } +} +}; + +} // end anonymous namespace + +MySqlConfigBackendDHCPv4Impl::MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters) + : MySqlConfigBackendImpl(parameters, &MySqlConfigBackendDHCPv4Impl::dbReconnect) { + // 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_ = "MySqlConfigBackend4["; + timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this)); + timer_name_ += "]DbReconnectTimer"; + + // Create ReconnectCtl for this connection. + conn_.makeReconnectCtl(timer_name_); +} + +MySqlConfigBackendDHCPv4Impl::~MySqlConfigBackendDHCPv4Impl() { +} + +MySqlConfigBackendDHCPv4::MySqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters) + : impl_(new MySqlConfigBackendDHCPv4Impl(parameters)), base_impl_(impl_) { +} + +bool +MySqlConfigBackendDHCPv4::isUnusable() { + return (impl_->conn_.isUnusable()); +} + +DatabaseConnection::ParameterMap +MySqlConfigBackendDHCPv4::getParameters() const { + return (impl_->getParameters()); +} + +Subnet4Ptr +MySqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector, + const std::string& subnet_prefix) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SUBNET4_BY_PREFIX) + .arg(subnet_prefix); + return (impl_->getSubnet4(server_selector, subnet_prefix)); +} + +Subnet4Ptr +MySqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector, + const SubnetID& subnet_id) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SUBNET4_BY_SUBNET_ID) + .arg(subnet_id); + return (impl_->getSubnet4(server_selector, subnet_id)); +} + +Subnet4Collection +MySqlConfigBackendDHCPv4::getAllSubnets4(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SUBNETS4); + Subnet4Collection subnets; + impl_->getAllSubnets4(server_selector, subnets); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SUBNETS4_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet4Collection +MySqlConfigBackendDHCPv4::getModifiedSubnets4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SUBNETS4) + .arg(util::ptimeToText(modification_time)); + Subnet4Collection subnets; + impl_->getModifiedSubnets4(server_selector, modification_time, subnets); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SUBNETS4_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet4Collection +MySqlConfigBackendDHCPv4::getSharedNetworkSubnets4(const ServerSelector& /* server_selector */, + const std::string& shared_network_name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4) + .arg(shared_network_name); + Subnet4Collection subnets; + impl_->getSharedNetworkSubnets4(ServerSelector::ANY(), shared_network_name, subnets); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT) + .arg(subnets.size()); + return (subnets); +} + +SharedNetwork4Ptr +MySqlConfigBackendDHCPv4::getSharedNetwork4(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK4) + .arg(name); + return (impl_->getSharedNetwork4(server_selector, name)); +} + +SharedNetwork4Collection +MySqlConfigBackendDHCPv4::getAllSharedNetworks4(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SHARED_NETWORKS4); + SharedNetwork4Collection shared_networks; + impl_->getAllSharedNetworks4(server_selector, shared_networks); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +SharedNetwork4Collection +MySqlConfigBackendDHCPv4::getModifiedSharedNetworks4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4) + .arg(util::ptimeToText(modification_time)); + SharedNetwork4Collection shared_networks; + impl_->getModifiedSharedNetworks4(server_selector, modification_time, shared_networks); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +OptionDefinitionPtr +MySqlConfigBackendDHCPv4::getOptionDef4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION_DEF4) + .arg(code).arg(space); + return (impl_->getOptionDef(MySqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE, + server_selector, code, space)); +} + +OptionDefContainer +MySqlConfigBackendDHCPv4::getAllOptionDefs4(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTION_DEFS4); + OptionDefContainer option_defs; + impl_->getAllOptionDefs(MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4, + server_selector, option_defs); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTION_DEFS4_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDefContainer +MySqlConfigBackendDHCPv4::getModifiedOptionDefs4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTION_DEFS4) + .arg(util::ptimeToText(modification_time)); + OptionDefContainer option_defs; + impl_->getModifiedOptionDefs(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4, + server_selector, modification_time, option_defs); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDescriptorPtr +MySqlConfigBackendDHCPv4::getOption4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION4) + .arg(code).arg(space); + return (impl_->getOption(MySqlConfigBackendDHCPv4Impl::GET_OPTION4_CODE_SPACE, + Option::V4, server_selector, code, space)); +} + +OptionContainer +MySqlConfigBackendDHCPv4::getAllOptions4(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTIONS4); + OptionContainer options = impl_->getAllOptions(MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4, + Option::V4, server_selector); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTIONS4_RESULT) + .arg(options.size()); + return (options); +} + +OptionContainer +MySqlConfigBackendDHCPv4::getModifiedOptions4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTIONS4) + .arg(util::ptimeToText(modification_time)); + OptionContainer options = impl_->getModifiedOptions(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTIONS4, + Option::V4, server_selector, modification_time); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTIONS4_RESULT) + .arg(options.size()); + return (options); +} + +StampedValuePtr +MySqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_GLOBAL_PARAMETER4) + .arg(name); + return (impl_->getGlobalParameter4(server_selector, name)); +} + +StampedValueCollection +MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { MySqlBinding::createString(tag.get()) }; + impl_->getGlobalParameters(MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, + in_bindings, parameters); + } + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT) + .arg(parameters.size()); + return (parameters); +} + +StampedValueCollection +MySqlConfigBackendDHCPv4::getModifiedGlobalParameters4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4) + .arg(util::ptimeToText(modification_time)); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createTimestamp(modification_time) + }; + impl_->getGlobalParameters(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, + in_bindings, parameters); + } + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT) + .arg(parameters.size()); + return (parameters); +} + +ClientClassDefPtr +MySqlConfigBackendDHCPv4::getClientClass4(const db::ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_CLIENT_CLASS4) + .arg(name); + return (impl_->getClientClass4(server_selector, name)); +} + +ClientClassDictionary +MySqlConfigBackendDHCPv4::getAllClientClasses4(const db::ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_CLIENT_CLASSES4); + ClientClassDictionary client_classes; + impl_->getAllClientClasses4(server_selector, client_classes); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +ClientClassDictionary +MySqlConfigBackendDHCPv4::getModifiedClientClasses4(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4) + .arg(util::ptimeToText(modification_time)); + ClientClassDictionary client_classes; + impl_->getModifiedClientClasses4(server_selector, modification_time, client_classes); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +AuditEntryCollection +MySqlConfigBackendDHCPv4::getRecentAuditEntries(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4) + .arg(util::ptimeToText(modification_time)) + .arg(modification_id); + AuditEntryCollection audit_entries; + impl_->getRecentAuditEntries(MySqlConfigBackendDHCPv4Impl::GET_AUDIT_ENTRIES4_TIME, + server_selector, modification_time, + modification_id, audit_entries); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT) + .arg(audit_entries.size()); + return (audit_entries); +} + +ServerCollection +MySqlConfigBackendDHCPv4::getAllServers4() const { + ServerCollection servers; + + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SERVERS4); + impl_->getAllServers(MySqlConfigBackendDHCPv4Impl::GET_ALL_SERVERS4, + servers); + + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SERVERS4_RESULT) + .arg(servers.size()); + return (servers); +} + +ServerPtr +MySqlConfigBackendDHCPv4::getServer4(const data::ServerTag& server_tag) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SERVER4) + .arg(server_tag.get()); + return (impl_->getServer(MySqlConfigBackendDHCPv4Impl::GET_SERVER4, server_tag)); +} + +void +MySqlConfigBackendDHCPv4::createUpdateSubnet4(const ServerSelector& server_selector, + const Subnet4Ptr& subnet) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SUBNET4) + .arg(subnet); + impl_->createUpdateSubnet4(server_selector, subnet); +} + +void +MySqlConfigBackendDHCPv4::createUpdateSharedNetwork4(const ServerSelector& server_selector, + const SharedNetwork4Ptr& shared_network) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK4) + .arg(shared_network->getName()); + impl_->createUpdateSharedNetwork4(server_selector, shared_network); +} + +void +MySqlConfigBackendDHCPv4::createUpdateOptionDef4(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_OPTION_DEF4) + .arg(option_def->getName()).arg(option_def->getCode()); + impl_->createUpdateOptionDef4(server_selector, option_def); +} + +void +MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_OPTION4); + impl_->createUpdateOption4(server_selector, option); +} + +void +MySqlConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4) + .arg(shared_network_name); + impl_->createUpdateOption4(server_selector, shared_network_name, option, false); +} + +void +MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4) + .arg(subnet_id); + impl_->createUpdateOption4(server_selector, subnet_id, option, false); +} + +void +MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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 +MySqlConfigBackendDHCPv4::createUpdateGlobalParameter4(const ServerSelector& server_selector, + const StampedValuePtr& value) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4) + .arg(value->getName()); + impl_->createUpdateGlobalParameter4(server_selector, value); +} + +void +MySqlConfigBackendDHCPv4::createUpdateClientClass4(const db::ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4) + .arg(client_class->getName()); + impl_->createUpdateClientClass4(server_selector, client_class, follow_class_name); +} + +void +MySqlConfigBackendDHCPv4::createUpdateServer4(const ServerPtr& server) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SERVER4) + .arg(server->getServerTagAsText()); + impl_->createUpdateServer(MySqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION, + MySqlConfigBackendDHCPv4Impl::INSERT_SERVER4, + MySqlConfigBackendDHCPv4Impl::UPDATE_SERVER4, + server); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_PREFIX_SUBNET4) + .arg(subnet_prefix); + uint64_t result = impl_->deleteSubnet4(server_selector, subnet_prefix); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4) + .arg(subnet_id); + uint64_t result = impl_->deleteSubnet4(server_selector, subnet_id); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteAllSubnets4(const ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SUBNETS4); + + int index = (server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_UNASSIGNED : + MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets", + "deleted all subnets", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SUBNETS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4) + .arg(shared_network_name); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv4Impl::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK4) + .arg(name); + + int index = (server_selector.amAny() ? + MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY : + MySqlConfigBackendDHCPv4Impl::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteAllSharedNetworks4(const ServerSelector& server_selector) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not" + " supported"); + } + + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4); + + int index = (server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED : + MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks", + "deleted all shared networks", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteOptionDef4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION_DEF4) + .arg(code).arg(space); + uint64_t result = impl_->deleteOptionDef4(server_selector, code, space); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION_DEF4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteAllOptionDefs4(const ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_OPTION_DEFS4); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4, + server_selector, "deleting all option definitions", + "deleted all option definitions", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION4) + .arg(code).arg(space); + uint64_t result = impl_->deleteOption4(server_selector, code, space); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_OPTION4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteGlobalParameter4(const ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_GLOBAL_PARAMETER4) + .arg(name); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4, + server_selector, "deleting global parameter", + "global parameter deleted", false, name); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteAllGlobalParameters4(const ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4, + server_selector, "deleting all global parameters", + "all global parameters deleted", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteClientClass4(const db::ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_CLIENT_CLASS4) + .arg(name); + auto result = impl_->deleteClientClass4(server_selector, name); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteAllClientClasses4(const db::ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4); + + int index = (server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED : + MySqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes", + "deleted all client classes", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteServer4(const ServerTag& server_tag) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER4) + .arg(server_tag.get()); + uint64_t result = impl_->deleteServer4(server_tag); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER4_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv4::deleteAllServers4() { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SERVERS4); + uint64_t result = impl_->deleteAllServers4(); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SERVERS4_RESULT) + .arg(result); + return (result); +} + +std::string +MySqlConfigBackendDHCPv4::getType() const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_TYPE4); + return (impl_->getType()); +} + +std::string +MySqlConfigBackendDHCPv4::getHost() const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_HOST4); + return (impl_->getHost()); +} + +uint16_t +MySqlConfigBackendDHCPv4::getPort() const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_PORT4); + return (impl_->getPort()); +} + +bool +MySqlConfigBackendDHCPv4::registerBackendType() { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_REGISTER_BACKEND_TYPE4); + return ( + dhcp::ConfigBackendDHCPv4Mgr::instance().registerBackendFactory("mysql", + [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv4Ptr { + return (dhcp::MySqlConfigBackendDHCPv4Ptr(new dhcp::MySqlConfigBackendDHCPv4(params))); + }) + ); +} + +void +MySqlConfigBackendDHCPv4::unregisterBackendType() { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_UNREGISTER_BACKEND_TYPE4); + dhcp::ConfigBackendDHCPv4Mgr::instance().unregisterBackendFactory("mysql"); +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h new file mode 100644 index 0000000..1c7dc16 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h @@ -0,0 +1,631 @@ +// Copyright (C) 2018-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/. + +#ifndef MYSQL_CONFIG_BACKEND_DHCP4_H +#define MYSQL_CONFIG_BACKEND_DHCP4_H + +#include <mysql_cb_impl.h> +#include <database/database_connection.h> +#include <dhcpsrv/client_class_def.h> +#include <dhcpsrv/config_backend_dhcp4.h> +#include <mysql_cb_log.h> +#include <boost/shared_ptr.hpp> + +namespace isc { +namespace dhcp { + +class MySqlConfigBackendDHCPv4Impl; + +/// @brief Implementation of the MySql 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 MySqlConfigBackendDHCPv4 : public ConfigBackendDHCPv4 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit MySqlConfigBackendDHCPv4(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 "mysql". + 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 MySQL 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 MySQL backend factory and discards MySQL 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 MySqlConfigBackendDHCPv4 + /// class. + boost::shared_ptr<MySqlConfigBackendDHCPv4Impl> impl_; + + /// @brief Pointer to the base implementation of the backend shared by + /// DHCPv4 and DHCPv6 servers. + boost::shared_ptr<MySqlConfigBackendImpl> base_impl_; +}; + +/// @brief Pointer to the @c MySqlConfigBackendDHCPv4 class. +typedef boost::shared_ptr<MySqlConfigBackendDHCPv4> MySqlConfigBackendDHCPv4Ptr; + +} // end of namespace isc::cb +} // end of namespace isc + +#endif // MYSQL_CONFIG_BACKEND_DHCP4_H diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc new file mode 100644 index 0000000..dfe19e1 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc @@ -0,0 +1,4840 @@ +// Copyright (C) 2018-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 <mysql_cb_dhcp6.h> +#include <mysql_cb_impl.h> +#include <mysql_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 <mysql/mysql_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> +#include <mysql.h> +#include <mysqld_error.h> +#include <array> +#include <sstream> +#include <utility> +#include <vector> + +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 MySQL Configuration Backend. +class MySqlConfigBackendDHCPv6Impl : public MySqlConfigBackendImpl { +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, + NUM_STATEMENTS + }; + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit MySqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap& + parameters); + + /// @brief Destructor. + ~MySqlConfigBackendDHCPv6Impl(); + + /// @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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createString(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 name Name of the global parameter. + /// @param value Value of the global parameter. + 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"); + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(value->getName()), + MySqlBinding::createString(value->getValue()), + MySqlBinding::createInteger<uint8_t>(value->getType()), + MySqlBinding::createTimestamp(value->getModificationTime()), + MySqlBinding::createString(tag), + MySqlBinding::createString(value->getName()) + }; + + MySqlTransaction 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, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "global parameter set", false); + + // Try to update the existing row. + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::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.pop_back(); + in_bindings.pop_back(); + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6, + in_bindings); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + + // Let's first get the primary key of the global parameter. + uint64_t id = mysql_insert_id(conn_.mysql_); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER, + server_selector, + MySqlBinding::createInteger<uint64_t>(id), + MySqlBinding::createTimestamp(value->getModificationTime())); + } + + 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 MySqlBindingCollection& in_bindings, + Subnet6Collection& subnets) { + // Create output bindings. The order must match that in the prepared + // statement. Please put comments only at the end of line so + // line counting and indexing match. + // The server tag must be the last field. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint32_t>(), // subnet_id + MySqlBinding::createString(SUBNET6_PREFIX_BUF_LENGTH), // subnet_prefix + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // client_class + MySqlBinding::createString(INTERFACE_BUF_LENGTH), // interface + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createInteger<uint32_t>(), // preferred_lifetime + MySqlBinding::createInteger<uint8_t>(), // rapid_commit + MySqlBinding::createInteger<uint32_t>(), // rebind_timer + MySqlBinding::createString(RELAY_BUF_LENGTH), // relay + MySqlBinding::createInteger<uint32_t>(), // renew_timer + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes + MySqlBinding::createInteger<uint8_t>(), // reservations_global + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // shared_network_name + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createInteger<uint32_t>(), // valid_lifetime + MySqlBinding::createInteger<uint64_t>(), // pool: id + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: start_address + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: end_address + MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id + MySqlBinding::createTimestamp(), // pool: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pd pool: id + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: prefix + MySqlBinding::createInteger<uint8_t>(), // pd pool: prefix_length + MySqlBinding::createInteger<uint8_t>(), // pd pool: delegated_prefix_length + MySqlBinding::createInteger<uint32_t>(), // pd pool: subnet_id + MySqlBinding::createTimestamp(), // pd pool: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pool option: option_id + MySqlBinding::createInteger<uint16_t>(), // pool option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pool option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space + MySqlBinding::createInteger<uint8_t>(), // pool option: persistent + MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled + MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id + MySqlBinding::createTimestamp(), // pool option: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pool option: pd_pool_id + MySqlBinding::createInteger<uint64_t>(), // pd pool option: option_id + MySqlBinding::createInteger<uint16_t>(), // pd pool option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pd pool option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pd pool option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pd pool option: space + MySqlBinding::createInteger<uint8_t>(), // pd pool option: persistent + MySqlBinding::createInteger<uint8_t>(), // pd pool option: cancelled + MySqlBinding::createInteger<uint32_t>(), // pd pool option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // pd pool option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pd pool option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // pd pool option: pool_id + MySqlBinding::createTimestamp(), // pd pool option: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pd pool option: pd_pool_id + MySqlBinding::createInteger<uint64_t>(), // option: option_id + MySqlBinding::createInteger<uint16_t>(), // option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space + MySqlBinding::createInteger<uint8_t>(), // option: persistent + MySqlBinding::createInteger<uint8_t>(), // option: cancelled + MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // option: pool_id + MySqlBinding::createTimestamp(), // option: modification_ts + MySqlBinding::createInteger<uint64_t>(), // option: pd_pool_id + MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times + MySqlBinding::createInteger<float>(), // t1_percent + MySqlBinding::createInteger<float>(), // t2_percent + MySqlBinding::createBlob(INTERFACE_ID_BUF_LENGTH), // interface_id + MySqlBinding::createInteger<uint32_t>(), // min_preferred_lifetime + MySqlBinding::createInteger<uint32_t>(), // max_preferred_lifetime + MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime + MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: excluded_prefix + MySqlBinding::createInteger<uint8_t>(), // pd pool: excluded_prefix_length + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pd pool: client_class + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pd pool: require_client_classes + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool: user_context + MySqlBinding::createInteger<uint8_t>(), // ddns_send_updates + MySqlBinding::createInteger<uint8_t>(), // ddns_override_no_update + MySqlBinding::createInteger<uint8_t>(), // ddns_override_client_update + MySqlBinding::createInteger<uint8_t>(), // ddns_replace_client_name + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger<uint8_t>(), // reservations_in_subnet + MySqlBinding::createInteger<uint8_t>(), // reservations_out_of_pool + MySqlBinding::createInteger<float>(), // cache_threshold + MySqlBinding::createInteger<uint32_t>(), // cache_max_age + MySqlBinding::createString(ALLOCATOR_TYPE_BUF_LENGTH), // allocator + MySqlBinding::createString(ALLOCATOR_TYPE_BUF_LENGTH), // pd_allocator + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag + }; + + 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. + conn_.selectQuery(index, in_bindings, out_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] + (MySqlBindingCollection& out_bindings) { + // Get pointer to the last subnet in the collection. + Subnet6Ptr last_subnet; + if (!subnets.empty()) { + last_subnet = *subnets.rbegin(); + } + + // 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() != out_bindings[0]->getInteger<uint32_t>())) { + // 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_id (0) + SubnetID subnet_id(out_bindings[0]->getInteger<uint32_t>()); + + // subnet_prefix (1) + std::string subnet_prefix = out_bindings[1]->getString(); + auto prefix_pair = Subnet6::parsePrefix(subnet_prefix); + + // preferred_lifetime (5) + // min_preferred_lifetime (72) + // max_preferred_lifetime (73) + auto preferred_lifetime = createTriplet(out_bindings[5], + out_bindings[72], + out_bindings[73]); + + // renew_timer (9) + auto renew_timer = createTriplet(out_bindings[9]); + + // rebind_timer (7) + auto rebind_timer = createTriplet(out_bindings[7]); + + // valid_lifetime (14) + // min_valid_lifetime (74) + // max_valid_lifetime (75) + auto valid_lifetime = createTriplet(out_bindings[14], + out_bindings[74], + out_bindings[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 (2) + if (!out_bindings[2]->amNull()) { + last_subnet->allowClientClass(out_bindings[2]->getString()); + } + + // interface (3) + if (!out_bindings[3]->amNull()) { + last_subnet->setIface(out_bindings[3]->getString()); + } + + // modification_ts (4) + last_subnet->setModificationTime(out_bindings[4]->getTimestamp()); + // 5 is preferred_lifetime + + // rapid_commit (6) + if (!out_bindings[6]->amNull()) { + last_subnet->setRapidCommit(out_bindings[6]->getBool()); + } + + // 7 is rebind_timer + + // relay (8) + ElementPtr relay_element = out_bindings[8]->getJSON(); + if (relay_element) { + if (relay_element->getType() != Element::list) { + isc_throw(BadValue, "invalid relay value " + << out_bindings[8]->getString()); + } + 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, "relay address must be a string"); + } + last_subnet->addRelayAddress(IOAddress(relay_element->get(i)->stringValue())); + } + } + + // 9 is renew_timer + + // require_client_classes (10) + ElementPtr require_element = out_bindings[10]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid require_client_classes value " + << out_bindings[10]->getString()); + } + 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"); + } + last_subnet->requireClientClass(require_item->stringValue()); + } + } + + // reservations_global (11) + if (!out_bindings[11]->amNull()) { + last_subnet->setReservationsGlobal(out_bindings[11]->getBool()); + } + + // shared_network_name (12) + if (!out_bindings[12]->amNull()) { + last_subnet->setSharedNetworkName(out_bindings[12]->getString()); + } + + // user_context (13) + ElementPtr user_context = out_bindings[13]->getJSON(); + if (user_context) { + last_subnet->setContext(user_context); + } + + // 14 is valid_lifetime + + // 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 (68) + if (!out_bindings[68]->amNull()) { + last_subnet->setCalculateTeeTimes(out_bindings[68]->getBool()); + } + + // t1_percent (69) + if (!out_bindings[69]->amNull()) { + last_subnet->setT1Percent(out_bindings[69]->getFloat()); + } + + // t2_percent (70) + if (!out_bindings[70]->amNull()) { + last_subnet->setT2Percent(out_bindings[70]->getFloat()); + } + + // interface_id (71) + if (!out_bindings[71]->amNull()) { + auto iface_id_data = out_bindings[71]->getBlob(); + if (!iface_id_data.empty()) { + OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID, + iface_id_data)); + last_subnet->setInterfaceId(opt_iface_id); + } + } + + // 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 (84) + if (!out_bindings[84]->amNull()) { + last_subnet->setDdnsSendUpdates(out_bindings[84]->getBool()); + } + + // ddns_override_no_update (85) + if (!out_bindings[85]->amNull()) { + last_subnet->setDdnsOverrideNoUpdate(out_bindings[85]->getBool()); + } + + // ddns_override_client_update (86) + if (!out_bindings[86]->amNull()) { + last_subnet->setDdnsOverrideClientUpdate(out_bindings[86]->getBool()); + } + + // ddns_replace_client_name (87) + if (!out_bindings[87]->amNull()) { + last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode> + (out_bindings[87]->getInteger<uint8_t>())); + } + + // ddns_generated_prefix (88) + if (!out_bindings[88]->amNull()) { + last_subnet->setDdnsGeneratedPrefix(out_bindings[88]->getString()); + } + + // ddns_qualifying_suffix (89) + if (!out_bindings[89]->amNull()) { + last_subnet->setDdnsQualifyingSuffix(out_bindings[89]->getString()); + } + + // reservations_in_subnet (90) + if (!out_bindings[90]->amNull()) { + last_subnet->setReservationsInSubnet(out_bindings[90]->getBool()); + } + + // reservations_out_of_pool (91) + if (!out_bindings[91]->amNull()) { + last_subnet->setReservationsOutOfPool(out_bindings[91]->getBool()); + } + + // cache_threshold (92) + if (!out_bindings[92]->amNull()) { + last_subnet->setCacheThreshold(out_bindings[92]->getFloat()); + } + + // cache_max_age (93) + if (!out_bindings[93]->amNull()) { + last_subnet->setCacheMaxAge(out_bindings[93]->getInteger<uint32_t>()); + } + + // allocator (94) + if (!out_bindings[94]->amNull()) { + last_subnet->setAllocatorType(out_bindings[94]->getString()); + } + + // pd_allocator (95) + if (!out_bindings[95]->amNull()) { + last_subnet->setPdAllocatorType(out_bindings[95]->getString()); + } + + // server_tag (96 / last) + + // 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. + if (!out_bindings[96]->amNull() && + (last_tag != out_bindings[96]->getString())) { + last_tag = out_bindings[96]->getString(); + if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) { + last_subnet->setServerTag(last_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 (!out_bindings[15]->amNull() && + !out_bindings[16]->getString().empty() && + !out_bindings[17]->getString().empty() && + (out_bindings[15]->getInteger<uint64_t>() > last_pool_id)) { + last_pool_id = out_bindings[15]->getInteger<uint64_t>(); + last_pool = Pool6::create(Lease::TYPE_NA, + IOAddress(out_bindings[16]->getString()), + IOAddress(out_bindings[17]->getString())); + + // 18 is pool subnet_id (ignored) + // 19 is pool modification_ts (ignored) + + // pool client_class (76) + if (!out_bindings[76]->amNull()) { + last_pool->allowClientClass(out_bindings[76]->getString()); + } + + // pool require_client_classes (77) + ElementPtr require_element = out_bindings[77]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid pool require_client_classes value " + << out_bindings[77]->getString()); + } + 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 pool require_client_classes list must" + "be valid strings"); + } + last_pool->requireClientClass(require_item->stringValue()); + } + } + + // pool user_context (78) + ElementPtr user_context = out_bindings[78]->getJSON(); + 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 (!out_bindings[20]->amNull() && + !out_bindings[21]->getString().empty() && + (out_bindings[22]->getInteger<uint8_t>() != 0) && + (out_bindings[23]->getInteger<uint8_t>() != 0) && + (out_bindings[20]->getInteger<uint64_t>() > last_pd_pool_id)) { + last_pd_pool_id = out_bindings[20]->getInteger<uint64_t>(); + + // 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 (!out_bindings[79]->amNull()) { + excluded_prefix = IOAddress(out_bindings[79]->getString()); + } + last_pd_pool = Pool6::create(IOAddress(out_bindings[21]->getString()), + out_bindings[22]->getInteger<uint8_t>(), + out_bindings[23]->getInteger<uint8_t>(), + excluded_prefix, + out_bindings[80]->getInteger<uint8_t>()); + + // pd pool client_class (81) + if (!out_bindings[81]->amNull()) { + last_pd_pool->allowClientClass(out_bindings[81]->getString()); + } + + // pd pool require_client_classes (82) + ElementPtr require_element = out_bindings[82]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid pd pool require_client_classes value " + << out_bindings[82]->getString()); + } + 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 pd pool require_client_classes list must" + "be valid strings"); + } + last_pd_pool->requireClientClass(require_item->stringValue()); + } + } + + // pd pool user_context (83) + ElementPtr user_context = out_bindings[83]->getJSON(); + if (user_context) { + last_pd_pool->setContext(user_context); + } + + last_subnet->addPool(last_pd_pool); + } + + // Parse pool specific option between 26 and 39 + if (last_pool && !out_bindings[26]->amNull() && + (last_pool_option_id < out_bindings[26]->getInteger<uint64_t>())) { + last_pool_option_id = out_bindings[26]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 26); + if (desc) { + last_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + + // Parse pd pool specific option between 40 and 53 + if (last_pd_pool && !out_bindings[40]->amNull() && + (last_pd_pool_option_id < out_bindings[40]->getInteger<uint64_t>())) { + last_pd_pool_option_id = out_bindings[40]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 40); + if (desc) { + last_pd_pool->getCfgOption()->add(*desc, desc->space_name_); + } + } + + // Parse subnet specific option between 54 and 67 + if (!out_bindings[54]->amNull() && + (last_option_id < out_bindings[54]->getInteger<uint64_t>())) { + last_option_id = out_bindings[54]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 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)); + } + + MySqlBindingCollection in_bindings = { MySqlBinding::createInteger<uint32_t>(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)); + } + + MySqlBindingCollection in_bindings = { MySqlBinding::createString(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); + MySqlBindingCollection 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(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) { + MySqlBindingCollection in_bindings = { MySqlBinding::createString(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 MySqlBindingCollection& in_bindings, + PoolCollection& pools, + std::vector<uint64_t>& pool_ids) { + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // pool: id + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: start_address + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: end_address + MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context + MySqlBinding::createTimestamp(), // pool: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pool option: option_id + MySqlBinding::createInteger<uint16_t>(), // pool option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pool option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space + MySqlBinding::createInteger<uint8_t>(), // pool option: persistent + MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled + MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id + MySqlBinding::createTimestamp(), //pool option: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pool option: pd_pool_id + }; + + uint64_t last_pool_id = 0; + uint64_t last_pool_option_id = 0; + Pool6Ptr last_pool; + + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &last_pool_id, &last_pool_option_id, &last_pool, + &pools, &pool_ids] + (MySqlBindingCollection& out_bindings) { + if (out_bindings[0]->getInteger<uint64_t>() > last_pool_id) { + // pool id (0) + last_pool_id = out_bindings[0]->getInteger<uint64_t>(); + + // pool start_address (1) + // pool end_address (2) + last_pool = Pool6::create(Lease::TYPE_NA, + IOAddress(out_bindings[1]->getString()), + IOAddress(out_bindings[2]->getString())); + + // pool subnet_id (3) (ignored) + + // pool client_class (4) + if (!out_bindings[4]->amNull()) { + last_pool->allowClientClass(out_bindings[4]->getString()); + } + + // pool require_client_classes (5) + ElementPtr require_element = out_bindings[5]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid pool require_client_classes value " + << out_bindings[5]->getString()); + } + 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 pool require_client_classes list must" + "be valid strings"); + } + last_pool->requireClientClass(require_item->stringValue()); + } + } + + // pool user_context (6) + ElementPtr user_context = out_bindings[6]->getJSON(); + 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 && !out_bindings[8]->amNull() && + (last_pool_option_id < out_bindings[8]->getInteger<uint64_t>())) { + last_pool_option_id = out_bindings[8]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 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 MySqlBindingCollection& in_bindings, + PoolCollection& pd_pools, + std::vector<uint64_t>& pd_pool_ids) { + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // pd pool: id + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: prefix + MySqlBinding::createInteger<uint8_t>(), // pd pool: prefix_length + MySqlBinding::createInteger<uint8_t>(), // pd pool: delegated_prefix_length + MySqlBinding::createInteger<uint32_t>(), // pd pool: subnet_id + MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: excluded_prefix + MySqlBinding::createInteger<uint8_t>(), // pd pool: excluded_prefix_length + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pd pool: client_class + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pd pool: require_client_classes + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool: user_context + MySqlBinding::createTimestamp(), // pd pool: modification_ts + MySqlBinding::createInteger<uint64_t>(), // pd pool option: option_id + MySqlBinding::createInteger<uint16_t>(), // pd pool option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pd pool option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pd pool option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pd pool option: space + MySqlBinding::createInteger<uint8_t>(), // pd pool option: persistent + MySqlBinding::createInteger<uint8_t>(), // pd pool option: cancelled + MySqlBinding::createInteger<uint32_t>(), // pd pool option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // pd pool option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pd pool option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // pd pool option: pool_id + MySqlBinding::createTimestamp(), // pd pool option: modification_ts + MySqlBinding::createInteger<uint64_t>() // pd pool option: pd_pool_id + }; + + uint64_t last_pd_pool_id = 0; + uint64_t last_pd_pool_option_id = 0; + Pool6Ptr last_pd_pool; + + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &last_pd_pool_id, &last_pd_pool_option_id, + &last_pd_pool, &pd_pools, &pd_pool_ids] + (MySqlBindingCollection& out_bindings) { + if (out_bindings[0]->getInteger<uint64_t>() > last_pd_pool_id) { + // pd pool id (0) + last_pd_pool_id = out_bindings[0]->getInteger<uint64_t>(); + + // pd pool prefix (1) + // pd pool prefix_length (2) + // pd pool delegated_prefix_length (3) + + // pd pool subnet_id (4 / ignored) + + // excluded_prefix (5) and excluded_prefix_length (6) + IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS(); + if (!out_bindings[5]->amNull()) { + excluded_prefix = IOAddress(out_bindings[5]->getString()); + } + + last_pd_pool = Pool6::create(IOAddress(out_bindings[1]->getString()), + out_bindings[2]->getInteger<uint8_t>(), + out_bindings[3]->getInteger<uint8_t>(), + excluded_prefix, + out_bindings[6]->getInteger<uint8_t>()); + + // pd pool client_class (7) + if (!out_bindings[7]->amNull()) { + last_pd_pool->allowClientClass(out_bindings[7]->getString()); + } + + // pd pool require_client_classes (8) + ElementPtr require_element = out_bindings[8]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid pd pool require_client_classes value " + << out_bindings[8]->getString()); + } + 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 pd pool require_client_classes list must" + "be valid strings"); + } + last_pd_pool->requireClientClass(require_item->stringValue()); + } + } + + // pd pool user_context (9) + ElementPtr user_context = out_bindings[9]->getJSON(); + if (user_context) { + last_pd_pool->setContext(user_context); + } + + // pd pool modification_ts (10) + + 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 && !out_bindings[11]->amNull() && + (last_pd_pool_option_id < out_bindings[11]->getInteger<uint64_t>())) { + last_pd_pool_option_id = out_bindings[11]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 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()) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(pool_start_address.toText()), + MySqlBinding::createString(pool_end_address.toText()) + }; + getPools(GET_POOL6_RANGE_ANY, in_bindings, pools, pool_ids); + } else { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createString(pool_start_address.toText()), + MySqlBinding::createString(pool_end_address.toText()) + }; + 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()) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(pd_pool_prefix.toText()), + MySqlBinding::createInteger<uint8_t>(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createString(pd_pool_prefix.toText()), + MySqlBinding::createInteger<uint8_t>(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 JSON list of required classes. + ElementPtr required_classes_element = Element::createList(); + const auto& required_classes = subnet->getRequiredClasses(); + for (auto required_class = required_classes.cbegin(); + required_class != required_classes.cend(); + ++required_class) { + required_classes_element->add(Element::create(*required_class)); + } + + // Create binding for DDNS replace client name mode. + MySqlBindingPtr ddns_rcn_mode_binding; + auto ddns_rcn_mode = subnet->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); + if (!ddns_rcn_mode.unspecified()) { + ddns_rcn_mode_binding = MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t> + (ddns_rcn_mode.get())); + } else { + ddns_rcn_mode_binding = MySqlBinding::createNull(); + } + + // Create binding with shared network name if the subnet belongs to a + // shared network. + MySqlBindingPtr shared_network_binding; + + 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) { + shared_network_binding = MySqlBinding::createString(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()) { + shared_network_binding = MySqlBinding::createString(subnet->getSharedNetworkName()); + + // If the subnet is not associated with a shared network, create + // null binding. + } else { + shared_network_binding = MySqlBinding::createNull(); + } + + // Create the binding holding interface_id. + MySqlBindingPtr interface_id_binding = MySqlBinding::createNull(); + auto opt_iface_id = subnet->getInterfaceId(Network::Inheritance::NONE); + if (opt_iface_id) { + auto iface_id_data = opt_iface_id->getData(); + if (!iface_id_data.empty()) { + interface_id_binding = MySqlBinding::createBlob(iface_id_data.begin(), + iface_id_data.end()); + } + } + + // Create input bindings. + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()), + MySqlBinding::condCreateString(subnet->getClientClass(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getIface(Network::Inheritance::NONE)), + MySqlBinding::createTimestamp(subnet->getModificationTime()), + createBinding(subnet->getPreferred(Network::Inheritance::NONE)), + createMinBinding(subnet->getPreferred(Network::Inheritance::NONE)), + createMaxBinding(subnet->getPreferred(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getRapidCommit(Network::Inheritance::NONE)), + createBinding(subnet->getT2(Network::Inheritance::NONE)), + createInputRelayBinding(subnet), + createBinding(subnet->getT1(Network::Inheritance::NONE)), + createInputRequiredClassesBinding(subnet), + MySqlBinding::condCreateBool(subnet->getReservationsGlobal(Network::Inheritance::NONE)), + shared_network_binding, + createInputContextBinding(subnet), + createBinding(subnet->getValid(Network::Inheritance::NONE)), + createMinBinding(subnet->getValid(Network::Inheritance::NONE)), + createMaxBinding(subnet->getValid(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getCalculateTeeTimes(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(subnet->getT1Percent(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(subnet->getT2Percent(Network::Inheritance::NONE)), + interface_id_binding, + MySqlBinding::condCreateBool(subnet->getDdnsSendUpdates(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), + ddns_rcn_mode_binding, + MySqlBinding::condCreateString(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsOutOfPool(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(subnet->getCacheThreshold(Network::Inheritance::NONE)), + condCreateInteger<uint32_t>(subnet->getCacheMaxAge(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getAllocatorType(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(subnet->getPdAllocatorType(Network::Inheritance::NONE)) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet set", true); + + try { + + // Try to insert subnet. If this duplicates unique key, i.e. this + // subnet already exists it will throw DuplicateEntry exception in + // which case we'll try an update. + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6, + in_bindings); + + } catch (const DuplicateEntry&) { + deletePools6(subnet); + deletePdPools6(subnet); + deleteOptions6(ServerSelector::ANY(), subnet); + + // Need to add two more bindings for WHERE clause. + in_bindings.push_back(MySqlBinding::createInteger<uint32_t>(subnet->getID())); + in_bindings.push_back(MySqlBinding::createString(subnet->toText())); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6, + in_bindings); + + MySqlBindingCollection in_server_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()) + }; + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER, + in_server_bindings); + } + + // Insert associations with the servers. + attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER, + server_selector, + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createTimestamp(subnet->getModificationTime())); + + // (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); + } + } + + 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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(pool->getFirstAddress().toText()), + MySqlBinding::createString(pool->getLastAddress().toText()), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())), + MySqlBinding::condCreateString(pool->getClientClass()), + createInputRequiredClassesBinding(pool), + createInputContextBinding(pool), + MySqlBinding::createTimestamp(subnet->getModificationTime()) + }; + + // Run INSERT. + conn_.insertQuery(INSERT_POOL6, in_bindings); + + uint64_t pool_id = mysql_insert_id(conn_.mysql_); + 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(); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(pd_pool->getFirstAddress().toText()), + MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(plen)), + MySqlBinding::createInteger<uint8_t>(pd_pool->getLength()), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())), + MySqlBinding::condCreateString(xprefix_txt), + MySqlBinding::createInteger<uint8_t>(xlen), + MySqlBinding::condCreateString(pd_pool->getClientClass()), + createInputRequiredClassesBinding(pd_pool), + createInputContextBinding(pd_pool), + MySqlBinding::createTimestamp(subnet->getModificationTime()) + }; + + // Run INSERT. + conn_.insertQuery(INSERT_PD_POOL, in_bindings); + + uint64_t pd_pool_id = mysql_insert_id(conn_.mysql_); + 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) { + MySqlTransaction 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, + MySqlConfigBackendDHCPv6Impl::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() ? + MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY : + MySqlConfigBackendDHCPv6Impl::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() ? + MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY : + MySqlConfigBackendDHCPv6Impl::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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()) + }; + + // Run DELETE. + return (conn_.updateDeleteQuery(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()) + }; + + // Run DELETE. + return (conn_.updateDeleteQuery(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 MySqlBindingCollection& in_bindings, + SharedNetwork6Collection& shared_networks) { + // Create output bindings. The order must match that in the prepared + // statement. Please put comments only at the end of line so + // line counting and indexing match. + // The server tag must be the last field. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // name + MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // client_class + MySqlBinding::createString(INTERFACE_BUF_LENGTH), // interface + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createInteger<uint32_t>(), // preferred_lifetime + MySqlBinding::createInteger<uint8_t>(), // rapid_commit + MySqlBinding::createInteger<uint32_t>(), // rebind_timer + MySqlBinding::createString(RELAY_BUF_LENGTH), // relay + MySqlBinding::createInteger<uint32_t>(), // renew_timer + MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes + MySqlBinding::createInteger<uint8_t>(), // reservations_global + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createInteger<uint32_t>(), // valid_lifetime + MySqlBinding::createInteger<uint64_t>(), // option: option_id + MySqlBinding::createInteger<uint16_t>(), // option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space + MySqlBinding::createInteger<uint8_t>(), // option: persistent + MySqlBinding::createInteger<uint8_t>(), // option: cancelled + MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // option: pool_id + MySqlBinding::createTimestamp(), // option: modification_ts + MySqlBinding::createInteger<uint64_t>(), // option: pd_pool_id + MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times + MySqlBinding::createInteger<float>(), // t1_percent + MySqlBinding::createInteger<float>(), // t2_percent + MySqlBinding::createBlob(INTERFACE_ID_BUF_LENGTH), // interface_id + MySqlBinding::createInteger<uint32_t>(), // min_preferred_lifetime + MySqlBinding::createInteger<uint32_t>(), // max_preferred_lifetime + MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime + MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime + MySqlBinding::createInteger<uint8_t>(), // ddns_send_updates + MySqlBinding::createInteger<uint8_t>(), // ddns_override_no_update + MySqlBinding::createInteger<uint8_t>(), // ddns_override_client_update + MySqlBinding::createInteger<uint8_t>(), // ddns_replace_client_name + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix + MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger<uint8_t>(), // reservations_in_subnet + MySqlBinding::createInteger<uint8_t>(), // reservations_out_of_pool + MySqlBinding::createInteger<float>(), // cache_threshold + MySqlBinding::createInteger<uint32_t>(), // cache_max_age + MySqlBinding::createString(ALLOCATOR_TYPE_BUF_LENGTH), // allocator + MySqlBinding::createString(ALLOCATOR_TYPE_BUF_LENGTH), // pd_allocator + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag + }; + + uint64_t last_network_id = 0; + uint64_t last_option_id = 0; + std::string last_tag; + + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &shared_networks, &last_network_id, &last_option_id, + &last_tag] + (MySqlBindingCollection& out_bindings) { + SharedNetwork6Ptr last_network; + if (!shared_networks.empty()) { + last_network = *shared_networks.rbegin(); + } + + // 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 != out_bindings[0]->getInteger<uint64_t>()) { + // 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(); + + // id at 0. + last_network_id = out_bindings[0]->getInteger<uint64_t>(); + + // name at 1. + last_network = SharedNetwork6::create(out_bindings[1]->getString()); + last_network->setId(last_network_id); + + // client_class at 2. + if (!out_bindings[2]->amNull()) { + last_network->allowClientClass(out_bindings[2]->getString()); + } + + // interface at 3. + if (!out_bindings[3]->amNull()) { + last_network->setIface(out_bindings[3]->getString()); + } + + // modification_ts at 4. + last_network->setModificationTime(out_bindings[4]->getTimestamp()); + + // preferred_lifetime at 5. + // min_preferred_lifetime at 32. + // max_preferred_lifetime at 33. + if (!out_bindings[5]->amNull()) { + last_network->setPreferred(createTriplet(out_bindings[5], + out_bindings[32], + out_bindings[33])); + } + + // rapid_commit at 6. + if (!out_bindings[6]->amNull()) { + last_network->setRapidCommit(out_bindings[6]->getBool()); + } + + // rebind_timer at 7. + if (!out_bindings[7]->amNull()) { + last_network->setT2(createTriplet(out_bindings[7])); + } + + // relay at 8. + ElementPtr relay_element = out_bindings[8]->getJSON(); + if (relay_element) { + if (relay_element->getType() != Element::list) { + isc_throw(BadValue, "invalid relay value " + << out_bindings[8]->getString()); + } + 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, "relay address must be a string"); + } + last_network->addRelayAddress(IOAddress(relay_element->get(i)->stringValue())); + } + } + + // renew_timer at 9. + if (!out_bindings[9]->amNull()) { + last_network->setT1(createTriplet(out_bindings[9])); + } + + // require_client_classes at 10. + ElementPtr require_element = out_bindings[10]->getJSON(); + if (require_element) { + if (require_element->getType() != Element::list) { + isc_throw(BadValue, "invalid require_client_classes value " + << out_bindings[10]->getString()); + } + 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"); + } + last_network->requireClientClass(require_item->stringValue()); + } + } + + // reservations_global at 11. + if (!out_bindings[11]->amNull()) { + last_network->setReservationsGlobal(out_bindings[11]->getBool()); + } + + // user_context at 12. + ElementPtr user_context = out_bindings[12]->getJSON(); + if (user_context) { + last_network->setContext(user_context); + } + + // valid_lifetime at 13. + // min_valid_lifetime at 34. + // max_valid_lifetime at 35. + if (!out_bindings[13]->amNull()) { + last_network->setValid(createTriplet(out_bindings[13], + out_bindings[34], + out_bindings[35])); + } + + // 14 to 27 are option. + + // calculate_tee_times at 28. + if (!out_bindings[28]->amNull()) { + last_network->setCalculateTeeTimes(out_bindings[28]->getBool()); + } + + // t1_percent at 29. + if (!out_bindings[29]->amNull()) { + last_network->setT1Percent(out_bindings[29]->getFloat()); + } + + // t2_percent at 30. + if (!out_bindings[30]->amNull()) { + last_network->setT2Percent(out_bindings[30]->getFloat()); + } + + // interface_id at 31. + if (!out_bindings[31]->amNull()) { + auto iface_id_data = out_bindings[31]->getBlob(); + if (!iface_id_data.empty()) { + OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID, + iface_id_data)); + last_network->setInterfaceId(opt_iface_id); + } + } + + // 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 (!out_bindings[36]->amNull()) { + last_network->setDdnsSendUpdates(out_bindings[36]->getBool()); + } + + // ddns_override_no_update at 37. + if (!out_bindings[37]->amNull()) { + last_network->setDdnsOverrideNoUpdate(out_bindings[37]->getBool()); + } + + // ddns_override_client_update at 38. + if (!out_bindings[38]->amNull()) { + last_network->setDdnsOverrideClientUpdate(out_bindings[38]->getBool()); + } + + // ddns_replace_client_name at 39. + if (!out_bindings[39]->amNull()) { + last_network->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode> + (out_bindings[39]->getInteger<uint8_t>())); + } + + // ddns_generated_prefix at 40. + if (!out_bindings[40]->amNull()) { + last_network->setDdnsGeneratedPrefix(out_bindings[40]->getString()); + } + + // ddns_qualifying_suffix at 41. + if (!out_bindings[41]->amNull()) { + last_network->setDdnsQualifyingSuffix(out_bindings[41]->getString()); + } + + // reservations_in_subnet at 42. + if (!out_bindings[42]->amNull()) { + last_network->setReservationsInSubnet(out_bindings[42]->getBool()); + } + + // reservations_in_subnet at 43. + if (!out_bindings[43]->amNull()) { + last_network->setReservationsOutOfPool(out_bindings[43]->getBool()); + } + + // cache_threshold at 44. + if (!out_bindings[44]->amNull()) { + last_network->setCacheThreshold(out_bindings[44]->getFloat()); + } + + // cache_max_age at 45. + if (!out_bindings[45]->amNull()) { + last_network->setCacheMaxAge(out_bindings[45]->getInteger<uint32_t>()); + } + + // allocator at 46. + if (!out_bindings[46]->amNull()) { + last_network->setAllocatorType(out_bindings[46]->getString()); + } + + // pd_allocator at 47. + if (!out_bindings[47]->amNull()) { + last_network->setPdAllocatorType(out_bindings[47]->getString()); + } + + // 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 (!out_bindings[48]->amNull() && + (last_tag != out_bindings[48]->getString())) { + last_tag = out_bindings[48]->getString(); + if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) { + last_network->setServerTag(last_tag); + } + } + + // Parse option from 14 to 27. + if (!out_bindings[14]->amNull() && + (last_option_id < out_bindings[14]->getInteger<uint64_t>())) { + last_option_id = out_bindings[14]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 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)); + } + + MySqlBindingCollection in_bindings = { MySqlBinding::createString(name) }; + + auto index = GET_SHARED_NETWORK6_NAME_NO_TAG; + if (server_selector.amUnassigned()) { + index = GET_SHARED_NETWORK6_NAME_UNASSIGNED; + } else if (server_selector.amAny()) { + index = 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() ? GET_ALL_SHARED_NETWORKS6_UNASSIGNED : + GET_ALL_SHARED_NETWORKS6); + MySqlBindingCollection 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(modification_ts) + }; + + auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED : + 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"); + } + + // Create the binding holding interface_id. + MySqlBindingPtr interface_id_binding = MySqlBinding::createNull(); + auto opt_iface_id = shared_network->getInterfaceId(Network::Inheritance::NONE); + if (opt_iface_id) { + auto iface_id_data = opt_iface_id->getData(); + if (!iface_id_data.empty()) { + interface_id_binding = MySqlBinding::createBlob(iface_id_data.begin(), + iface_id_data.end()); + } + } + + // Create binding for DDNS replace client name mode. + MySqlBindingPtr ddns_rcn_mode_binding; + auto ddns_rcn_mode = shared_network->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); + if (!ddns_rcn_mode.unspecified()) { + ddns_rcn_mode_binding = MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t> + (ddns_rcn_mode.get())); + } else { + ddns_rcn_mode_binding = MySqlBinding::createNull(); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(shared_network->getName()), + MySqlBinding::condCreateString(shared_network->getClientClass(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getIface(Network::Inheritance::NONE)), + MySqlBinding::createTimestamp(shared_network->getModificationTime()), + createBinding(shared_network->getPreferred(Network::Inheritance::NONE)), + createMinBinding(shared_network->getPreferred(Network::Inheritance::NONE)), + createMaxBinding(shared_network->getPreferred(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getRapidCommit(Network::Inheritance::NONE)), + createBinding(shared_network->getT2(Network::Inheritance::NONE)), + createInputRelayBinding(shared_network), + createBinding(shared_network->getT1(Network::Inheritance::NONE)), + createInputRequiredClassesBinding(shared_network), + MySqlBinding::condCreateBool(shared_network->getReservationsGlobal(Network::Inheritance::NONE)), + createInputContextBinding(shared_network), + createBinding(shared_network->getValid(Network::Inheritance::NONE)), + createMinBinding(shared_network->getValid(Network::Inheritance::NONE)), + createMaxBinding(shared_network->getValid(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(shared_network->getT1Percent(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(shared_network->getT2Percent(Network::Inheritance::NONE)), + interface_id_binding, + MySqlBinding::condCreateBool(shared_network->getDdnsSendUpdates(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getDdnsOverrideNoUpdate(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), + ddns_rcn_mode_binding, + MySqlBinding::condCreateString(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE)), + MySqlBinding::condCreateFloat(shared_network->getCacheThreshold(Network::Inheritance::NONE)), + condCreateInteger<uint32_t>(shared_network->getCacheMaxAge(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getAllocatorType(Network::Inheritance::NONE)), + MySqlBinding::condCreateString(shared_network->getPdAllocatorType(Network::Inheritance::NONE)) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network set", true); + + 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. + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6, + in_bindings); + + } catch (const DuplicateEntry&) { + deleteOptions6(ServerSelector::ANY(), shared_network); + + // Need to add one more binding for WHERE clause. + in_bindings.push_back(MySqlBinding::createString(shared_network->getName())); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6, + in_bindings); + + MySqlBindingCollection in_server_bindings = { + MySqlBinding::createString(shared_network->getName()) + }; + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER, + in_server_bindings); + } + + // Associate the shared network with the servers. + attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER, + server_selector, + MySqlBinding::createString(shared_network->getName()), + MySqlBinding::createTimestamp(shared_network->getModificationTime())); + + // (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); + } + } + + transaction.commit(); + } + + /// @brief Sends query to insert DHCP option. + /// + /// This method expects that the server selector contains exactly one + /// server tag. + /// + /// @param server_selector Server selector. + /// @param in_bindings Collection of bindings representing an option. + void insertOption6(const ServerSelector& server_selector, + const MySqlBindingCollection& in_bindings) { + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::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 = mysql_insert_id(conn_.mysql_); + + // Timestamp is expected to be in this input binding. + auto timestamp_binding = in_bindings[12]; + + // Associate the option with the servers. + attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER, + server_selector, + MySqlBinding::createInteger<uint64_t>(option_id), + timestamp_binding); + } + + /// @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"); + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(0), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createNull(), + MySqlBinding::createString(tag), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + MySqlTransaction 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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "global option set", false); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption6(server_selector, in_bindings); + } + + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)), + MySqlBinding::createInteger<uint8_t>(1), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)), + MySqlBinding::createInteger<uint16_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + boost::scoped_ptr<MySqlTransaction> transaction; + // Only start new transaction if specified to do so. This function may + // be called from within an existing transaction in which case we + // don't start the new one. + if (!cascade_update) { + transaction.reset(new MySqlTransaction(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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "subnet specific option set", + cascade_update); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption6(server_selector, in_bindings); + } + + if (transaction) { + 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"; + + MySqlBindingCollection in_bindings; + // code + in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(option->option_->getType())); + // value + in_bindings.push_back(createOptionValueBinding(option)); + // formatted_value + in_bindings.push_back(MySqlBinding::condCreateString(option->formatted_value_)); + // space + in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_)); + // persistent + in_bindings.push_back(MySqlBinding::createBool(option->persistent_)); + // cancelled + in_bindings.push_back(MySqlBinding::createBool(option->cancelled_)); + // dhcp_client_class + in_bindings.push_back(MySqlBinding::createNull()); + // dhcp[46]_subnet_id + in_bindings.push_back(MySqlBinding::createNull()); + // scope_id + if (pool_type == Lease::TYPE_NA) { + in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(5)); + } else { + in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(6)); + } + // user_context + in_bindings.push_back(createInputContextBinding(option)); + // shared_network_name + in_bindings.push_back(MySqlBinding::createNull()); + // pool_id + if (pool_type == Lease::TYPE_NA) { + in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id)); + } else { + in_bindings.push_back(MySqlBinding::createNull()); + } + // modification_ts + in_bindings.push_back(MySqlBinding::createTimestamp(option->getModificationTime())); + // pd_pool_id + if (pool_type == Lease::TYPE_PD) { + in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id)); + } else { + in_bindings.push_back(MySqlBinding::createNull()); + } + + // Insert bindings used only during the update. + in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id)); + in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(option->option_->getType())); + in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_)); + + MySqlTransaction 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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, msg, cascade_update); + + auto index = (pool_type == Lease::TYPE_NA ? + MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID : + MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID); + if (conn_.updateDeleteQuery(index, in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption6(server_selector, in_bindings); + } + + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(4), + createInputContextBinding(option), + MySqlBinding::createString(shared_network_name), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createNull(), + MySqlBinding::createString(shared_network_name), + MySqlBinding::createInteger<uint16_t>(option->option_->getType()), + MySqlBinding::condCreateString(option->space_name_) + }; + + boost::scoped_ptr<MySqlTransaction> transaction; + // Only start new transaction if specified to do so. This function may + // be called from within an existing transaction in which case we + // don't start the new one. + if (!cascade_update) { + transaction.reset(new MySqlTransaction(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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "shared network specific option set", + cascade_update); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl:: + UPDATE_OPTION6_SHARED_NETWORK, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption6(server_selector, in_bindings); + } + + if (transaction) { + 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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createBool(option->persistent_), + MySqlBinding::createBool(option->cancelled_), + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createNull(), + MySqlBinding::createInteger<uint8_t>(2), + createInputContextBinding(option), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createTimestamp(option->getModificationTime()), + MySqlBinding::createNull(), + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createInteger<uint8_t>(option->option_->getType()), + MySqlBinding::condCreateString(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, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "client class specific option set", + true); + + if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl:: + UPDATE_OPTION6_CLIENT_CLASS, + in_bindings) == 0) { + // Remove the 3 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 3); + insertOption6(server_selector, in_bindings); + } + } + + /// @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_def, DHCP6_OPTION_SPACE, + MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6, + MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + MySqlConfigBackendDHCPv6Impl::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_def, DHCP6_OPTION_SPACE, + MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS, + MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS, + MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + MySqlConfigBackendDHCPv6Impl::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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(client_class->getName()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)), + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space), + MySqlBinding::createString(pool_start_address.toText()), + MySqlBinding::createString(pool_end_address.toText()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space), + MySqlBinding::createString(pd_pool_prefix.toText()), + MySqlBinding::createInteger<uint8_t>(pd_pool_prefix_length) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(shared_network_name), + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint32_t>(subnet->getID()), + MySqlBinding::createString(subnet->toText()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(shared_network->getName()) + }; + + // Run DELETE. + return (deleteTransactional(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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(client_class->getName()) + }; + + // Run DELETE. + return (deleteTransactional(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 MySqlBindingCollection& in_bindings, + ClientClassDictionary& client_classes) { + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createString(CLIENT_CLASS_NAME_BUF_LENGTH), // name + MySqlBinding::createString(CLIENT_CLASS_TEST_BUF_LENGTH), // test + MySqlBinding::createInteger<uint8_t>(), // required + MySqlBinding::createInteger<uint32_t>(), // valid lifetime + MySqlBinding::createInteger<uint32_t>(), // min valid lifetime + MySqlBinding::createInteger<uint32_t>(), // max valid lifetime + MySqlBinding::createInteger<uint8_t>(), // depend on known directly + MySqlBinding::createInteger<uint8_t>(), // depend on known indirectly + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createInteger<uint64_t>(), // option def: id + MySqlBinding::createInteger<uint16_t>(), // option def: code + MySqlBinding::createString(OPTION_NAME_BUF_LENGTH), // option def: name + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option def: space + MySqlBinding::createInteger<uint8_t>(), // option def: type + MySqlBinding::createTimestamp(), // option def: modification_ts + MySqlBinding::createInteger<uint8_t>(), // option def: array + MySqlBinding::createString(OPTION_ENCAPSULATE_BUF_LENGTH), // option def: encapsulate + MySqlBinding::createString(OPTION_RECORD_TYPES_BUF_LENGTH), // option def: record_types + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option def: user_context + MySqlBinding::createInteger<uint64_t>(), // option: option_id + MySqlBinding::createInteger<uint16_t>(), // option: code + MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value + MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space + MySqlBinding::createInteger<uint8_t>(), // option: persistent + MySqlBinding::createInteger<uint8_t>(), // option: cancelled + MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id + MySqlBinding::createInteger<uint8_t>(), // option: scope_id + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context + MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name + MySqlBinding::createInteger<uint64_t>(), // option: pool_id + MySqlBinding::createTimestamp(), // option: modification_ts + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH),// server tag + MySqlBinding::createInteger<uint32_t>(), // preferred lifetime + MySqlBinding::createInteger<uint32_t>(), // min preferred lifetime + MySqlBinding::createInteger<uint32_t>() // max preferred lifetime + }; + + std::list<ClientClassDefPtr> class_list; + uint64_t last_option_id = 0; + uint64_t last_option_def_id = 0; + std::string last_tag; + + conn_.selectQuery(index, + in_bindings, out_bindings, + [this, &class_list, &last_option_id, &last_option_def_id, &last_tag] + (MySqlBindingCollection& out_bindings) { + ClientClassDefPtr last_client_class; + if (!class_list.empty()) { + last_client_class = *class_list.rbegin(); + } + + if (!last_client_class || (last_client_class->getId() != out_bindings[0]->getInteger<uint64_t>())) { + 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>(out_bindings[1]->getString(), + ExpressionPtr(), options); + last_client_class->setCfgOptionDef(option_defs); + + // id + last_client_class->setId(out_bindings[0]->getInteger<uint64_t>()); + + // name + last_client_class->setName(out_bindings[1]->getString()); + + // test + if (!out_bindings[2]->amNull()) { + last_client_class->setTest(out_bindings[2]->getString()); + } + + // required + if (!out_bindings[3]->amNull()) { + last_client_class->setRequired(out_bindings[3]->getBool()); + } + + // valid lifetime: default, min, max + last_client_class->setValid(createTriplet(out_bindings[4], out_bindings[5], out_bindings[6])); + + // depend on known directly or indirectly + last_client_class->setDependOnKnown(out_bindings[7]->getBool() || out_bindings[8]->getBool()); + + // modification_ts + last_client_class->setModificationTime(out_bindings[9]->getTimestamp()); + + // user_context + ElementPtr user_context = out_bindings[10]->getJSON(); + if (user_context) { + last_client_class->setContext(user_context); + } + + // preferred lifetime: default, min, max + last_client_class->setPreferred(createTriplet(out_bindings[35], + out_bindings[36], + out_bindings[37])); + + class_list.push_back(last_client_class); + } + + // server tag + if (!out_bindings[34]->amNull() && + (last_tag != out_bindings[34]->getString())) { + last_tag = out_bindings[34]->getString(); + if (!last_tag.empty() && !last_client_class->hasServerTag(ServerTag(last_tag))) { + last_client_class->setServerTag(last_tag); + } + } + + // Parse client class specific option definition from 11 to 20. + if (!out_bindings[11]->amNull() && + (last_option_def_id < out_bindings[11]->getInteger<uint64_t>())) { + last_option_def_id = out_bindings[11]->getInteger<uint64_t>(); + + auto def = processOptionDefRow(out_bindings.begin() + 11); + if (def) { + last_client_class->getCfgOptionDef()->add(def); + } + } + + // Parse client class specific option from 21 to 33. + if (!out_bindings[21]->amNull() && + (last_option_id < out_bindings[21]->getInteger<uint64_t>())) { + last_option_id = out_bindings[21]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(name) + }; + ClientClassDictionary client_classes; + getClientClasses6(MySqlConfigBackendDHCPv6Impl::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) { + MySqlBindingCollection in_bindings; + getClientClasses6(server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED : + MySqlConfigBackendDHCPv6Impl::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"); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(modification_ts) + }; + getClientClasses6(server_selector.amUnassigned() ? + GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED : + 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); + }); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createString(client_class->getTest()), + MySqlBinding::createBool(client_class->getRequired()), + createBinding(client_class->getValid()), + createMinBinding(client_class->getValid()), + createMaxBinding(client_class->getValid()), + MySqlBinding::createBool(depend_on_known), + (follow_class_name.empty() ? MySqlBinding::createNull() : + MySqlBinding::createString(follow_class_name)), + createBinding(client_class->getPreferred()), + createMinBinding(client_class->getPreferred()), + createMaxBinding(client_class->getPreferred()), + MySqlBinding::createTimestamp(client_class->getModificationTime()), + createInputContextBinding(client_class) + }; + + MySqlTransaction transaction(conn_); + + ScopedAuditRevision audit_revision(this, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + server_selector, "client class set", true); + // Keeps track of whether the client class is inserted or updated. + auto update = false; + try { + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6, in_bindings); + + } catch (const DuplicateEntry&) { + // Such class already exists. + + // 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); + + // Try to update the class. + in_bindings.push_back(MySqlBinding::createString(client_class->getName())); + if (follow_class_name.empty()) { + // If position is not specified, leave the class at the same position. + // Remove the binding which specifies the position and use different + // query. + in_bindings.erase(in_bindings.begin() + 10, in_bindings.begin() + 11); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6_SAME_POSITION, + in_bindings); + } else { + // Update with specifying the position. + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6, + in_bindings); + } + + // Delete class associations with the servers and dependencies. We will re-create + // them according to the new class specification. + MySqlBindingCollection in_assoc_bindings = { + MySqlBinding::createString(client_class->getName()) + }; + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY, + in_assoc_bindings); + conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER, + in_assoc_bindings); + update = true; + } + + // Associate client class with the servers. + attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER, + server_selector, + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createTimestamp(client_class->getModificationTime())); + + // Iterate over the captured dependencies and try to insert them into the database. + for (auto dependency : dependencies) { + try { + MySqlBindingCollection in_dependency_bindings = { + MySqlBinding::createString(client_class->getName()), + MySqlBinding::createString(dependency) + }; + // We deleted earlier dependencies, so we can simply insert new ones. + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::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) { + MySqlBindingCollection in_check_bindings; + conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::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() ? + MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY : + MySqlConfigBackendDHCPv6Impl::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"); + } + + MySqlTransaction 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, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting a server", false); + + // Specify which server should be deleted. + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(server_tag.get()) + }; + + // Attempt to delete the server. + auto count = conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::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() { + MySqlTransaction 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, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + ServerSelector::ALL(), "deleting all servers", + false); + + MySqlBindingCollection in_bindings; + + // Attempt to delete the servers. + auto count = conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::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(); + } + + 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(mysql_cb_logger, MYSQL_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(mysql_cb_logger, MYSQL_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(mysql_cb_logger, MYSQL_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(&MySqlConfigBackendDHCPv6Impl::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<TaggedStatement, MySqlConfigBackendDHCPv6Impl::NUM_STATEMENTS> +TaggedStatementArray; + +/// @brief Prepared MySQL statements used by the backend to insert and +/// retrieve data from the database. +TaggedStatementArray tagged_statements = { { + { MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + "CALL createAuditRevisionDHCP6(?, ?, ?, ?)" + }, + + // Verify that dependency on KNOWN/UNKNOWN class has not changed. + { MySqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE, + "CALL checkDHCPv6ClientClassKnownDependencyChange()" + }, + + // Select global parameter by name. + { MySqlConfigBackendDHCPv6Impl::GET_GLOBAL_PARAMETER6, + MYSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.name = ?) + }, + + // Select all global parameters. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6, + MYSQL_GET_GLOBAL_PARAMETER(dhcp6) + }, + + // Select modified global parameters. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6, + MYSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.modification_ts >= ?) + }, + + // Select subnet by id. + { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_NO_TAG, + MYSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_id = ?) + }, + + // Select subnet by id without specifying server tags. + { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_ANY, + MYSQL_GET_SUBNET6_ANY(WHERE s.subnet_id = ?) + }, + + // Select unassigned subnet by id. + { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_UNASSIGNED, + MYSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_id = ?) + }, + + // Select subnet by prefix. + { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_NO_TAG, + MYSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_prefix = ?) + }, + + // Select subnet by prefix without specifying server tags. + { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_ANY, + MYSQL_GET_SUBNET6_ANY(WHERE s.subnet_prefix = ?) + }, + + // Select unassigned subnet by prefix. + { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_UNASSIGNED, + MYSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_prefix = ?) + }, + + // Select all subnets. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6, + MYSQL_GET_SUBNET6_NO_TAG() + }, + + // Select all unassigned subnets. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6_UNASSIGNED, + MYSQL_GET_SUBNET6_UNASSIGNED() + }, + + // Select subnets having modification time later than X. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6, + MYSQL_GET_SUBNET6_NO_TAG(WHERE s.modification_ts >= ?) + }, + + // Select modified and unassigned subnets. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6_UNASSIGNED, + MYSQL_GET_SUBNET6_UNASSIGNED(AND s.modification_ts >= ?) + }, + + // Select subnets belonging to a shared network. + { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK_SUBNETS6, + MYSQL_GET_SUBNET6_ANY(WHERE s.shared_network_name = ?) + }, + + // Select pool by address range for a server. + { MySqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE, + MYSQL_GET_POOL6_RANGE_WITH_TAG(WHERE (srv.tag = ? OR srv.id = 1) AND p.start_address = ? \ + AND p.end_address = ?) + }, + + // Select pool by address range for any server. + { MySqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE_ANY, + MYSQL_GET_POOL6_RANGE_NO_TAG(WHERE p.start_address = ? AND p.end_address = ?) + }, + + // Select prefix delegation pool for a server. + { MySqlConfigBackendDHCPv6Impl::GET_PD_POOL, + MYSQL_GET_PD_POOL_WITH_TAG(WHERE (srv.tag = ? OR srv.id = 1) \ + AND p.prefix = ? AND p.prefix_length = ?) + }, + + // Select prefix delegation pool for any server. + { MySqlConfigBackendDHCPv6Impl::GET_PD_POOL_ANY, + MYSQL_GET_PD_POOL_NO_TAG(WHERE p.prefix = ? AND p.prefix_length = ?) + }, + + // Select shared network by name. + { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG, + MYSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.name = ?) + }, + + // Select shared network by name without specifying server tags. + { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY, + MYSQL_GET_SHARED_NETWORK6_ANY(WHERE n.name = ?) + }, + + // Select unassigned shared network by name. + { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED, + MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.name = ?) + }, + + // Select all shared networks. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6, + MYSQL_GET_SHARED_NETWORK6_NO_TAG() + }, + + // Select all unassigned shared networks. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED, + MYSQL_GET_SHARED_NETWORK6_UNASSIGNED() + }, + + // Select modified shared networks. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6, + MYSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.modification_ts >= ?) + }, + + // Select modified and unassigned shared networks. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED, + MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.modification_ts >= ?) + }, + + // Retrieves option definition by code and space. + { MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + MYSQL_GET_OPTION_DEF(dhcp6, AND d.code = ? AND d.space = ?) + }, + + // Retrieves all option definitions. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6, + MYSQL_GET_OPTION_DEF(dhcp6) + }, + + // Retrieves modified option definitions. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6, + MYSQL_GET_OPTION_DEF(dhcp6, AND d.modification_ts >= ?) + }, + + // Retrieves global option by code and space. + { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, + MYSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + }, + + // Retrieves all global options. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6, + MYSQL_GET_OPTION6(AND o.scope_id = 0) + }, + + // Retrieves modified options. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6, + MYSQL_GET_OPTION6(AND o.scope_id = 0 AND o.modification_ts >= ?) + }, + + // Retrieves an option for a given subnet, option code and space. + { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_SUBNET_ID_CODE_SPACE, + MYSQL_GET_OPTION6(AND o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?) + }, + + // Retrieves an option for a given pool, option code and space. + { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_POOL_ID_CODE_SPACE, + MYSQL_GET_OPTION6(AND o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?) + }, + + // Retrieves an option for a given pd pool, option code and space. + { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_PD_POOL_ID_CODE_SPACE, + MYSQL_GET_OPTION6(AND o.scope_id = 6 AND o.pd_pool_id = ? AND o.code = ? AND o.space = ?) + }, + + // Retrieves an option for a given shared network, option code and space. + { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_SHARED_NETWORK_CODE_SPACE, + MYSQL_GET_OPTION6(AND o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + }, + + // Select a client class by name. + { MySqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME, + MYSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.name = ?) + }, + + // Select all client classes. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6, + MYSQL_GET_CLIENT_CLASS6_WITH_TAG() + }, + + // Select all unassigned client classes. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED, + MYSQL_GET_CLIENT_CLASS6_UNASSIGNED() + }, + + // Select modified client classes. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6, + MYSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.modification_ts >= ?) + }, + + // Select modified client classes. + { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED, + MYSQL_GET_CLIENT_CLASS6_UNASSIGNED(AND c.modification_ts >= ?) + }, + + // Retrieves the most recent audit entries. + { MySqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME, + MYSQL_GET_AUDIT_ENTRIES_TIME(dhcp6) + }, + + // Retrieves a server by tag. + { MySqlConfigBackendDHCPv6Impl::GET_SERVER6, + MYSQL_GET_SERVER(dhcp6) + }, + + // Retrieves all servers. + { MySqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6, + MYSQL_GET_ALL_SERVERS(dhcp6) + }, + + // Insert global parameter. + { MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6, + MYSQL_INSERT_GLOBAL_PARAMETER(dhcp6) + }, + + // Insert association of the global parameter with a server. + { MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER, + MYSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp6) + }, + + // Insert a subnet. + { MySqlConfigBackendDHCPv6Impl::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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + + // Insert association of the subnet with a server. + { MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER, + MYSQL_INSERT_SUBNET_SERVER(dhcp6) + }, + + // Insert pool for a subnet. + { MySqlConfigBackendDHCPv6Impl::INSERT_POOL6, + MYSQL_INSERT_POOL(dhcp6) + }, + + // Insert pd pool for a subnet. + { MySqlConfigBackendDHCPv6Impl::INSERT_PD_POOL, + MYSQL_INSERT_PD_POOL() + }, + + // Insert a shared network. + { MySqlConfigBackendDHCPv6Impl::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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + + // Insert association of the shared network with a server. + { MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER, + MYSQL_INSERT_SHARED_NETWORK_SERVER(dhcp6) + }, + + // Insert option definition. + { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6, + MYSQL_INSERT_OPTION_DEF(dhcp6) + }, + + // Insert option definition for client class. + { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS, + MYSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp6) + }, + + // Insert association of the option definition with a server. + { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER, + MYSQL_INSERT_OPTION_DEF_SERVER(dhcp6) + }, + + // Insert subnet specific option. + { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6, + MYSQL_INSERT_OPTION6() + }, + + // Insert association of the DHCP option with a server. + { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER, + MYSQL_INSERT_OPTION_SERVER(dhcp6) + }, + + // Insert client class. + { MySqlConfigBackendDHCPv6Impl::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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + }, + + // Insert association of a client class with a server. + { MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER, + MYSQL_INSERT_CLIENT_CLASS_SERVER(dhcp6) + }, + + // Insert client class dependency. + { MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY, + MYSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp6) + }, + + // Insert server with server tag and description. + { MySqlConfigBackendDHCPv6Impl::INSERT_SERVER6, + MYSQL_INSERT_SERVER(dhcp6) + }, + + // Update existing global parameter. + { MySqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6, + MYSQL_UPDATE_GLOBAL_PARAMETER(dhcp6) + }, + + // Update existing subnet. + { MySqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6, + "UPDATE dhcp6_subnet SET" + " 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 = ? " + "WHERE subnet_id = ? OR subnet_prefix = ?" }, + + // Update existing shared network. + { MySqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6, + "UPDATE dhcp6_shared_network SET" + " 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 = ? " + "WHERE name = ?" }, + + // Update existing option definition. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6, + MYSQL_UPDATE_OPTION_DEF(dhcp6) + }, + + // Update existing client class option definition. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS, + MYSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp6) + }, + + // Update existing global option. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, + MYSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + }, + + // Update existing subnet level option. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing pool level option. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID, + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing pd pool level option. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID, + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing shared network level option. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK, + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing client class level option. + { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS, + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = ? AND o.code = ? AND o.space = ?) + }, + + // Update existing client class with specifying its position. + { MySqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6, + MYSQL_UPDATE_CLIENT_CLASS6("follow_class_name = ?,") + }, + + // Update existing client class without specifying its position. + { MySqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6_SAME_POSITION, + MYSQL_UPDATE_CLIENT_CLASS6("") + }, + + // Update existing server, e.g. server description. + { MySqlConfigBackendDHCPv6Impl::UPDATE_SERVER6, + MYSQL_UPDATE_SERVER(dhcp6) + }, + + // Delete global parameter by name. + { MySqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6, + MYSQL_DELETE_GLOBAL_PARAMETER(dhcp6, AND g.name = ?) + }, + + // Delete all global parameters. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6, + MYSQL_DELETE_GLOBAL_PARAMETER(dhcp6) + }, + + // Delete all global parameters which are unassigned to any servers. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED, + MYSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp6) + }, + + // Delete subnet by id with specifying server tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG, + MYSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_id = ?) + }, + + // Delete subnet by id without specifying server tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY, + MYSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_id = ?) + }, + + // Delete subnet by prefix with specifying server tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG, + MYSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_prefix = ?) + }, + + // Delete subnet by prefix without specifying server tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY, + MYSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_prefix = ?) + }, + + // Delete all subnets. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6, + MYSQL_DELETE_SUBNET_WITH_TAG(dhcp6) + }, + + // Delete all unassigned subnets. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED, + MYSQL_DELETE_SUBNET_UNASSIGNED(dhcp6) + }, + + // Delete all subnets for a shared network. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME, + MYSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.shared_network_name = ?) + }, + + // Delete associations of a subnet with server. + { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER, + MYSQL_DELETE_SUBNET_SERVER(dhcp6), + }, + + // Delete pools for a subnet. + { MySqlConfigBackendDHCPv6Impl::DELETE_POOLS6, + MYSQL_DELETE_POOLS(dhcp6) + }, + + // Delete pd pools for a subnet. + { MySqlConfigBackendDHCPv6Impl::DELETE_PD_POOLS, + MYSQL_DELETE_PD_POOLS() + }, + + // Delete shared network by name with specifying server tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG, + MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6, AND n.name = ?) + }, + + // Delete shared network by name without specifying server tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY, + MYSQL_DELETE_SHARED_NETWORK_ANY(dhcp6, WHERE n.name = ?) + }, + + // Delete all shared networks. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6, + MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6) + }, + + // Delete all unassigned shared networks. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED, + MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp6) + }, + + // Delete associations of a shared network with server. + { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER, + MYSQL_DELETE_SHARED_NETWORK_SERVER(dhcp6) + }, + + // Delete option definition. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEF6_CODE_NAME, + MYSQL_DELETE_OPTION_DEF(dhcp6, AND code = ? AND space = ?) + }, + + // Delete all option definitions. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6, + MYSQL_DELETE_OPTION_DEF(dhcp6) + }, + + // Delete all option definitions which are assigned to no servers. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6_UNASSIGNED, + MYSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp6) + }, + + // Delete client class specific option definitions. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEFS6_CLIENT_CLASS, + MYSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp6) + }, + + // Delete single global option. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6, + MYSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + }, + + // Delete all global options which are unassigned to any servers. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED, + MYSQL_DELETE_OPTION_UNASSIGNED(dhcp6, AND o.scope_id = 0) + }, + + // Delete single option from a subnet. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID, + MYSQL_DELETE_OPTION_NO_TAG(dhcp6, + WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?) + }, + + // Delete single option from a pool. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE, + MYSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = ? AND o.space = ?) + }, + + // Delete single option from a pd pool. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL, + MYSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = ? AND o.space = ?) + }, + + // Delete single option from a shared network. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK, + MYSQL_DELETE_OPTION_NO_TAG(dhcp6, + WHERE o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + }, + + // Delete options belonging to a subnet. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SUBNET_ID_PREFIX, + MYSQL_DELETE_OPTION_SUBNET_ID_PREFIX(dhcp6) + }, + + // Delete options belonging to a shared_network. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SHARED_NETWORK, + MYSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 4 AND o.shared_network_name = ?) + }, + + // Delete options belonging to a client class. + { MySqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_CLIENT_CLASS, + MYSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 2 AND o.dhcp_client_class = ?) + }, + + // Delete all dependencies of a client class. + { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY, + MYSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp6) + }, + + // Delete associations of a client class with server. + { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER, + MYSQL_DELETE_CLIENT_CLASS_SERVER(dhcp6), + }, + + // Delete all client classes. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6, + MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6) + }, + + // Delete all unassigned client classes. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED, + MYSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp6) + }, + + // Delete specified client class. + { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6, + MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6, AND name = ?) + }, + + // Delete any client class with a given name. + { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY, + MYSQL_DELETE_CLIENT_CLASS_ANY(dhcp6, AND name = ?) + }, + + // Delete a server by tag. + { MySqlConfigBackendDHCPv6Impl::DELETE_SERVER6, + MYSQL_DELETE_SERVER(dhcp6) + }, + + // Deletes all servers except logical server 'all'. + { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6, + MYSQL_DELETE_ALL_SERVERS(dhcp6) + } +} +}; + +} // end anonymous namespace + +MySqlConfigBackendDHCPv6Impl::MySqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap& parameters) + : MySqlConfigBackendImpl(parameters, &MySqlConfigBackendDHCPv6Impl::dbReconnect) { + // 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_ = "MySqlConfigBackend6["; + timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this)); + timer_name_ += "]DbReconnectTimer"; + + // Create ReconnectCtl for this connection. + conn_.makeReconnectCtl(timer_name_); +} + +MySqlConfigBackendDHCPv6Impl::~MySqlConfigBackendDHCPv6Impl() { +} + +MySqlConfigBackendDHCPv6::MySqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters) + : impl_(new MySqlConfigBackendDHCPv6Impl(parameters)), base_impl_(impl_) { +} + +bool +MySqlConfigBackendDHCPv6::isUnusable() { + return (impl_->conn_.isUnusable()); +} + +DatabaseConnection::ParameterMap +MySqlConfigBackendDHCPv6::getParameters() const { + return (impl_->getParameters()); +} + +Subnet6Ptr +MySqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector, + const std::string& subnet_prefix) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SUBNET6_BY_PREFIX) + .arg(subnet_prefix); + return (impl_->getSubnet6(server_selector, subnet_prefix)); +} + +Subnet6Ptr +MySqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector, + const SubnetID& subnet_id) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SUBNET6_BY_SUBNET_ID) + .arg(subnet_id); + return (impl_->getSubnet6(server_selector, subnet_id)); +} + +Subnet6Collection +MySqlConfigBackendDHCPv6::getAllSubnets6(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SUBNETS6); + Subnet6Collection subnets; + impl_->getAllSubnets6(server_selector, subnets); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SUBNETS6_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet6Collection +MySqlConfigBackendDHCPv6::getModifiedSubnets6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SUBNETS6) + .arg(util::ptimeToText(modification_time)); + Subnet6Collection subnets; + impl_->getModifiedSubnets6(server_selector, modification_time, subnets); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT) + .arg(subnets.size()); + return (subnets); +} + +Subnet6Collection +MySqlConfigBackendDHCPv6::getSharedNetworkSubnets6(const ServerSelector& /* server_selector */, + const std::string& shared_network_name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6) + .arg(shared_network_name); + Subnet6Collection subnets; + impl_->getSharedNetworkSubnets6(ServerSelector::ANY(), shared_network_name, subnets); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT) + .arg(subnets.size()); + return (subnets); +} + +SharedNetwork6Ptr +MySqlConfigBackendDHCPv6::getSharedNetwork6(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK6) + .arg(name); + return (impl_->getSharedNetwork6(server_selector, name)); +} + +SharedNetwork6Collection +MySqlConfigBackendDHCPv6::getAllSharedNetworks6(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SHARED_NETWORKS6); + SharedNetwork6Collection shared_networks; + impl_->getAllSharedNetworks6(server_selector, shared_networks); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +SharedNetwork6Collection +MySqlConfigBackendDHCPv6::getModifiedSharedNetworks6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6) + .arg(util::ptimeToText(modification_time)); + SharedNetwork6Collection shared_networks; + impl_->getModifiedSharedNetworks6(server_selector, modification_time, shared_networks); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT) + .arg(shared_networks.size()); + return (shared_networks); +} + +OptionDefinitionPtr +MySqlConfigBackendDHCPv6::getOptionDef6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION_DEF6) + .arg(code).arg(space); + return (impl_->getOptionDef(MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE, + server_selector, code, space)); +} + +OptionDefContainer +MySqlConfigBackendDHCPv6::getAllOptionDefs6(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTION_DEFS6); + OptionDefContainer option_defs; + impl_->getAllOptionDefs(MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6, + server_selector, option_defs); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDefContainer +MySqlConfigBackendDHCPv6::getModifiedOptionDefs6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTION_DEFS6) + .arg(util::ptimeToText(modification_time)); + OptionDefContainer option_defs; + impl_->getModifiedOptionDefs(MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6, + server_selector, modification_time, option_defs); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT) + .arg(option_defs.size()); + return (option_defs); +} + +OptionDescriptorPtr +MySqlConfigBackendDHCPv6::getOption6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION6) + .arg(code).arg(space); + return (impl_->getOption(MySqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, + Option::V6, server_selector, code, space)); +} + +OptionContainer +MySqlConfigBackendDHCPv6::getAllOptions6(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTIONS6); + OptionContainer options = impl_->getAllOptions(MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6, + Option::V6, server_selector); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTIONS6_RESULT) + .arg(options.size()); + return (options); +} + +OptionContainer +MySqlConfigBackendDHCPv6::getModifiedOptions6(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTIONS6) + .arg(util::ptimeToText(modification_time)); + OptionContainer options = impl_->getModifiedOptions(MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6, + Option::V6, server_selector, modification_time); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT) + .arg(options.size()); + return (options); +} + +StampedValuePtr +MySqlConfigBackendDHCPv6::getGlobalParameter6(const ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_GLOBAL_PARAMETER6) + .arg(name); + return (impl_->getGlobalParameter6(server_selector, name)); +} + +StampedValueCollection +MySqlConfigBackendDHCPv6::getAllGlobalParameters6(const ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { MySqlBinding::createString(tag.get()) }; + impl_->getGlobalParameters(MySqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6, + in_bindings, parameters); + } + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT) + .arg(parameters.size()); + return (parameters); +} + +StampedValueCollection +MySqlConfigBackendDHCPv6::getModifiedGlobalParameters6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6) + .arg(util::ptimeToText(modification_time)); + StampedValueCollection parameters; + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createTimestamp(modification_time) + }; + impl_->getGlobalParameters(MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6, + in_bindings, parameters); + } + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT) + .arg(parameters.size()); + return (parameters); +} + +ClientClassDefPtr +MySqlConfigBackendDHCPv6::getClientClass6(const db::ServerSelector& server_selector, + const std::string& name) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_CLIENT_CLASS6) + .arg(name); + return (impl_->getClientClass6(server_selector, name)); +} + +ClientClassDictionary +MySqlConfigBackendDHCPv6::getAllClientClasses6(const db::ServerSelector& server_selector) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_CLIENT_CLASSES6); + ClientClassDictionary client_classes; + impl_->getAllClientClasses6(server_selector, client_classes); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +ClientClassDictionary +MySqlConfigBackendDHCPv6::getModifiedClientClasses6(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6) + .arg(util::ptimeToText(modification_time)); + ClientClassDictionary client_classes; + impl_->getModifiedClientClasses6(server_selector, modification_time, client_classes); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT) + .arg(client_classes.getClasses()->size()); + return (client_classes); +} + +AuditEntryCollection +MySqlConfigBackendDHCPv6::getRecentAuditEntries(const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6) + .arg(util::ptimeToText(modification_time)) + .arg(modification_id); + AuditEntryCollection audit_entries; + impl_->getRecentAuditEntries(MySqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME, + server_selector, modification_time, + modification_id, audit_entries); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT) + .arg(audit_entries.size()); + return (audit_entries); +} + +ServerCollection +MySqlConfigBackendDHCPv6::getAllServers6() const { + ServerCollection servers; + + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SERVERS6); + impl_->getAllServers(MySqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6, + servers); + + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SERVERS6_RESULT) + .arg(servers.size()); + return (servers); +} + +ServerPtr +MySqlConfigBackendDHCPv6::getServer6(const data::ServerTag& server_tag) const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SERVER6) + .arg(server_tag.get()); + return (impl_->getServer(MySqlConfigBackendDHCPv6Impl::GET_SERVER6, server_tag)); +} + +void +MySqlConfigBackendDHCPv6::createUpdateSubnet6(const ServerSelector& server_selector, + const Subnet6Ptr& subnet) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SUBNET6) + .arg(subnet); + impl_->createUpdateSubnet6(server_selector, subnet); +} + +void +MySqlConfigBackendDHCPv6::createUpdateSharedNetwork6(const ServerSelector& server_selector, + const SharedNetwork6Ptr& shared_network) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6) + .arg(shared_network->getName()); + impl_->createUpdateSharedNetwork6(server_selector, shared_network); +} + +void +MySqlConfigBackendDHCPv6::createUpdateOptionDef6(const ServerSelector& server_selector, + const OptionDefinitionPtr& option_def) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_OPTION_DEF6) + .arg(option_def->getName()).arg(option_def->getCode()); + impl_->createUpdateOptionDef6(server_selector, option_def); +} + +void +MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_OPTION6); + impl_->createUpdateOption6(server_selector, option); +} + +void +MySqlConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_selector, + const std::string& shared_network_name, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6) + .arg(shared_network_name); + impl_->createUpdateOption6(server_selector, shared_network_name, option, false); +} + +void +MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const SubnetID& subnet_id, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6) + .arg(subnet_id); + impl_->createUpdateOption6(server_selector, subnet_id, option, false); +} + +void +MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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 +MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector, + const asiolink::IOAddress& pd_pool_prefix, + const uint8_t pd_pool_prefix_length, + const OptionDescriptorPtr& option) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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 +MySqlConfigBackendDHCPv6::createUpdateGlobalParameter6(const ServerSelector& server_selector, + const StampedValuePtr& value) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6) + .arg(value->getName()); + impl_->createUpdateGlobalParameter6(server_selector, value); +} + +void +MySqlConfigBackendDHCPv6::createUpdateClientClass6(const db::ServerSelector& server_selector, + const ClientClassDefPtr& client_class, + const std::string& follow_class_name) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6) + .arg(client_class->getName()); + impl_->createUpdateClientClass6(server_selector, client_class, follow_class_name); +} + +void +MySqlConfigBackendDHCPv6::createUpdateServer6(const ServerPtr& server) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SERVER6) + .arg(server->getServerTagAsText()); + impl_->createUpdateServer(MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION, + MySqlConfigBackendDHCPv6Impl::INSERT_SERVER6, + MySqlConfigBackendDHCPv6Impl::UPDATE_SERVER6, + server); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector, + const std::string& subnet_prefix) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_PREFIX_SUBNET6) + .arg(subnet_prefix); + uint64_t result = impl_->deleteSubnet6(server_selector, subnet_prefix); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector, + const SubnetID& subnet_id) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6) + .arg(subnet_id); + uint64_t result = impl_->deleteSubnet6(server_selector, subnet_id); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteAllSubnets6(const ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SUBNETS6); + + int index = (server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED : + MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets", + "deleted all subnets", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6) + .arg(shared_network_name); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK6) + .arg(name); + + int index = (server_selector.amAny() ? + MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY : + MySqlConfigBackendDHCPv6Impl::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteAllSharedNetworks6(const ServerSelector& server_selector) { + if (server_selector.amAny()) { + isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not" + " supported"); + } + + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6); + + int index = (server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED : + MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks", + "deleted all shared networks", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteOptionDef6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION_DEF6) + .arg(code).arg(space); + uint64_t result = impl_->deleteOptionDef6(server_selector, code, space); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION_DEF6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteAllOptionDefs6(const ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_OPTION_DEFS6); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6, + server_selector, "deleting all option definitions", + "deleted all option definitions", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& server_selector, + const uint16_t code, + const std::string& space) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION6) + .arg(code).arg(space); + uint64_t result = impl_->deleteOption6(server_selector, code, space); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_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(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteGlobalParameter6(const ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_GLOBAL_PARAMETER6) + .arg(name); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6, + server_selector, "deleting global parameter", + "global parameter deleted", false, name); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteAllGlobalParameters6(const ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6); + uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6, + server_selector, "deleting all global parameters", + "all global parameters deleted", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteClientClass6(const db::ServerSelector& server_selector, + const std::string& name) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_CLIENT_CLASS6) + .arg(name); + auto result = impl_->deleteClientClass6(server_selector, name); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteAllClientClasses6(const db::ServerSelector& server_selector) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6); + + int index = (server_selector.amUnassigned() ? + MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED : + MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6); + uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes", + "deleted all client classes", true); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteServer6(const ServerTag& server_tag) { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER6) + .arg(server_tag.get()); + uint64_t result = impl_->deleteServer6(server_tag); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER6_RESULT) + .arg(result); + return (result); +} + +uint64_t +MySqlConfigBackendDHCPv6::deleteAllServers6() { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SERVERS6); + uint64_t result = impl_->deleteAllServers6(); + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SERVERS6_RESULT) + .arg(result); + return (result); +} + +std::string +MySqlConfigBackendDHCPv6::getType() const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_TYPE6); + return (impl_->getType()); +} + +std::string +MySqlConfigBackendDHCPv6::getHost() const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_HOST6); + return (impl_->getHost()); +} + +uint16_t +MySqlConfigBackendDHCPv6::getPort() const { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_PORT6); + return (impl_->getPort()); +} + +bool +MySqlConfigBackendDHCPv6::registerBackendType() { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_REGISTER_BACKEND_TYPE6); + return ( + dhcp::ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("mysql", + [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv6Ptr { + return (dhcp::MySqlConfigBackendDHCPv6Ptr(new dhcp::MySqlConfigBackendDHCPv6(params))); + }) + ); +} + +void +MySqlConfigBackendDHCPv6::unregisterBackendType() { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_UNREGISTER_BACKEND_TYPE6); + dhcp::ConfigBackendDHCPv6Mgr::instance().unregisterBackendFactory("mysql"); +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h new file mode 100644 index 0000000..c829bf1 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h @@ -0,0 +1,664 @@ +// Copyright (C) 2019-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 MYSQL_CONFIG_BACKEND_DHCP6_H +#define MYSQL_CONFIG_BACKEND_DHCP6_H + +#include <mysql_cb_impl.h> +#include <database/database_connection.h> +#include <dhcpsrv/client_class_def.h> +#include <dhcpsrv/config_backend_dhcp6.h> +#include <mysql_cb_log.h> +#include <boost/shared_ptr.hpp> + +namespace isc { +namespace dhcp { + +class MySqlConfigBackendDHCPv6Impl; + +/// @brief Implementation of the MySql 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 MySqlConfigBackendDHCPv6 : public ConfigBackendDHCPv6 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit MySqlConfigBackendDHCPv6(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 "mysql". + 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 MySQL 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 MySQL backend factory and discards MySQL 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 MySqlConfigBackendDHCPv6 + /// class. + boost::shared_ptr<MySqlConfigBackendDHCPv6Impl> impl_; + + /// @brief Pointer to the base implementation of the backend shared by + /// DHCPv4 and DHCPv6 servers. + boost::shared_ptr<MySqlConfigBackendImpl> base_impl_; +}; + +/// @brief Pointer to the @c MySqlConfigBackendDHCPv6 class. +typedef boost::shared_ptr<MySqlConfigBackendDHCPv6> MySqlConfigBackendDHCPv6Ptr; + +} // end of namespace isc::cb +} // end of namespace isc + +#endif // MYSQL_CONFIG_BACKEND_DHCP6_H diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc new file mode 100644 index 0000000..679fe20 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -0,0 +1,1110 @@ +// Copyright (C) 2018-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 <mysql_cb_impl.h> +#include <mysql_cb_log.h> +#include <asiolink/io_address.h> +#include <config_backend/constants.h> +#include <dhcp/option_space.h> +#include <util/buffer.h> + +#include <mysql.h> +#include <mysqld_error.h> +#include <cstdint> +#include <utility> + +using namespace isc::asiolink; +using namespace isc::cb; +using namespace isc::data; +using namespace isc::db; +using namespace isc::log; +using namespace isc::util; + +namespace isc { +namespace dhcp { + +isc::asiolink::IOServicePtr MySqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr(); + +MySqlConfigBackendImpl:: +ScopedAuditRevision::ScopedAuditRevision(MySqlConfigBackendImpl* 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); +} + +MySqlConfigBackendImpl:: +ScopedAuditRevision::~ScopedAuditRevision() { + impl_->clearAuditRevision(); +} + +MySqlConfigBackendImpl:: +MySqlConfigBackendImpl(const DatabaseConnection::ParameterMap& parameters, + const DbCallback db_reconnect_callback) + : conn_(parameters, + IOServiceAccessorPtr(new IOServiceAccessor(MySqlConfigBackendImpl::getIOService)), + db_reconnect_callback), timer_name_(""), + audit_revision_ref_count_(0), parameters_(parameters) { + // Test schema version first. + std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR, + MYSQL_SCHEMA_VERSION_MINOR); + std::pair<uint32_t, uint32_t> db_version = + MySqlConnection::getVersion(parameters); + if (code_version != db_version) { + isc_throw(DbOpenError, "MySQL schema version mismatch: need version: " + << code_version.first << "." << code_version.second + << " found version: " << db_version.first << "." + << db_version.second); + } + + // Open the database. + conn_.openDatabase(); + + // Check if we have TLS when we required it. + if (conn_.getTls()) { + std::string cipher = conn_.getTlsCipher(); + if (cipher.empty()) { + LOG_ERROR(mysql_cb_logger, MYSQL_CB_NO_TLS); + } else { + LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, + MYSQL_CB_TLS_CIPHER) + .arg(cipher); + } + } +} + +MySqlConfigBackendImpl::~MySqlConfigBackendImpl() { + // Free up the prepared statements, ignoring errors. (What would we do + // about them? We're destroying this object and are not really concerned + // with errors on a database connection that is about to go away.) + for (int i = 0; i < conn_.statements_.size(); ++i) { + if (conn_.statements_[i] != NULL) { + (void) mysql_stmt_close(conn_.statements_[i]); + conn_.statements_[i] = NULL; + } + } +} + +MySqlBindingPtr +MySqlConfigBackendImpl::createBinding(const Triplet<uint32_t>& triplet) { + if (triplet.unspecified()) { + return (MySqlBinding::createNull()); + } + return (MySqlBinding::createInteger<uint32_t>(triplet.get())); +} + +MySqlBindingPtr +MySqlConfigBackendImpl::createMinBinding(const Triplet<uint32_t>& triplet) { + if (triplet.unspecified() || (triplet.getMin() == triplet.get())) { + return (MySqlBinding::createNull()); + } + return (MySqlBinding::createInteger<uint32_t>(triplet.getMin())); +} + +MySqlBindingPtr +MySqlConfigBackendImpl::createMaxBinding(const Triplet<uint32_t>& triplet) { + if (triplet.unspecified() || (triplet.getMax() == triplet.get())) { + return (MySqlBinding::createNull()); + } + return (MySqlBinding::createInteger<uint32_t>(triplet.getMax())); +} + +Triplet<uint32_t> +MySqlConfigBackendImpl::createTriplet(const MySqlBindingPtr& binding) { + if (!binding) { + isc_throw(Unexpected, "MySQL configuration backend internal error: " + "binding pointer is NULL when creating a triplet value"); + } + + if (binding->amNull()) { + return (Triplet<uint32_t>()); + } + + return (Triplet<uint32_t>(binding->getInteger<uint32_t>())); +} + +Triplet<uint32_t> +MySqlConfigBackendImpl::createTriplet(const MySqlBindingPtr& def_binding, + const MySqlBindingPtr& min_binding, + const MySqlBindingPtr& max_binding) { + if (!def_binding || !min_binding || !max_binding) { + isc_throw(Unexpected, "MySQL configuration backend internal error: " + "binding pointer is NULL when creating a triplet value"); + } + + // This code assumes the database was filled using the API, e.g. it + // is not possible (so not handled) to have only the min_binding not NULL. + if (def_binding->amNull()) { + return (Triplet<uint32_t>()); + } + + uint32_t value = def_binding->getInteger<uint32_t>(); + uint32_t min_value = value; + if (!min_binding->amNull()) { + min_value = min_binding->getInteger<uint32_t>(); + } + uint32_t max_value = value; + if (!max_binding->amNull()) { + max_value = max_binding->getInteger<uint32_t>(); + } + + return (Triplet<uint32_t>(min_value, value, max_value)); +} + +void +MySqlConfigBackendImpl::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(); + } + + MySqlBindingCollection in_bindings = { + MySqlBinding::createTimestamp(audit_ts), + MySqlBinding::createString(tag), + MySqlBinding::createString(log_message), + MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(cascade_transaction)) + }; + conn_.insertQuery(index, in_bindings); +} + +void +MySqlConfigBackendImpl::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 +MySqlConfigBackendImpl::getRecentAuditEntries(const int index, + const db::ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time, + const uint64_t& modification_id, + AuditEntryCollection& audit_entries) { + // Create the output bindings for receiving the data. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createString(AUDIT_ENTRY_OBJECT_TYPE_BUF_LENGTH), // object_type + MySqlBinding::createInteger<uint64_t>(), // object_id + MySqlBinding::createInteger<uint8_t>(), // modification_type + MySqlBinding::createTimestamp(), // modification_time + MySqlBinding::createInteger<uint64_t>(), // revision_id + MySqlBinding::createString(AUDIT_ENTRY_LOG_MESSAGE_BUF_LENGTH) // log_message + }; + + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + + // There are only a few input bindings + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createTimestamp(modification_time), + MySqlBinding::createInteger<uint64_t>(modification_id) + }; + + // Execute select. + conn_.selectQuery(index, in_bindings, out_bindings, + [&audit_entries] (MySqlBindingCollection& out_bindings) { + // Convert the numeric modification type into modification type enum. + AuditEntry::ModificationType mod_type = + static_cast<AuditEntry::ModificationType>(out_bindings[3]->getInteger<uint8_t>()); + + // Create new audit entry and add it to the collection of received + // entries. + AuditEntryPtr audit_entry = + AuditEntry::create(out_bindings[1]->getString(), + out_bindings[2]->getInteger<uint64_t>(), + mod_type, + out_bindings[4]->getTimestamp(), + out_bindings[5]->getInteger<uint64_t>(), + out_bindings[6]->getStringOrDefault("")); + audit_entries.insert(audit_entry); + }); + } +} + +uint64_t +MySqlConfigBackendImpl::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"); + } + + MySqlBindingCollection in_bindings; + return (deleteFromTable(index, server_selector, operation, in_bindings)); +} + +void +MySqlConfigBackendImpl::getGlobalParameters(const int index, + const MySqlBindingCollection& in_bindings, + StampedValueCollection& parameters) { + // The following parameters from the dhcp[46]_global_parameter table are + // returned: + // - id + // - name - parameter name + // - value - parameter value + // - modification_ts - modification timestamp. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createString(GLOBAL_PARAMETER_NAME_BUF_LENGTH), // name + MySqlBinding::createString(GLOBAL_PARAMETER_VALUE_BUF_LENGTH), // value + MySqlBinding::createInteger<uint8_t>(), // parameter_type + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag + }; + + StampedValuePtr last_param; + + StampedValueCollection local_parameters; + + conn_.selectQuery(index, in_bindings, out_bindings, + [&last_param, &local_parameters] + (MySqlBindingCollection& out_bindings) { + + uint64_t id = out_bindings[0]->getInteger<uint64_t>(); + + // If we're starting or if this is new parameter being processed... + if (!last_param || (last_param->getId() != id)) { + + // parameter name + std::string name = out_bindings[1]->getString(); + + if (!name.empty()) { + last_param = StampedValue::create(name, + out_bindings[2]->getString(), + static_cast<Element::types> + (out_bindings[3]->getInteger<uint8_t>())); + + // id + last_param->setId(id); + + // modification_ts + last_param->setModificationTime(out_bindings[4]->getTimestamp()); + + // server_tag + ServerTag last_param_server_tag(out_bindings[5]->getString()); + last_param->setServerTag(last_param_server_tag.get()); + + // 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'. + 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 +MySqlConfigBackendImpl::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; + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag), + MySqlBinding::createInteger<uint16_t>(code), + MySqlBinding::createString(space) + }; + getOptionDefs(index, in_bindings, option_defs); + return (option_defs.empty() ? OptionDefinitionPtr() : *option_defs.begin()); +} + +void +MySqlConfigBackendImpl::getAllOptionDefs(const int index, + const ServerSelector& server_selector, + OptionDefContainer& option_defs) { + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()) + }; + getOptionDefs(index, in_bindings, option_defs); + } +} + +void +MySqlConfigBackendImpl::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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createTimestamp(modification_time) + }; + getOptionDefs(index, in_bindings, option_defs); + } +} + +void +MySqlConfigBackendImpl::getOptionDefs(const int index, + const MySqlBindingCollection& in_bindings, + OptionDefContainer& option_defs) { + // Create output bindings. The order must match that in the prepared + // statement. + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), // id + MySqlBinding::createInteger<uint16_t>(), // code + MySqlBinding::createString(OPTION_NAME_BUF_LENGTH), // name + MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // space + MySqlBinding::createInteger<uint8_t>(), // type + MySqlBinding::createTimestamp(), // modification_ts + MySqlBinding::createInteger<uint8_t>(), // array + MySqlBinding::createString(OPTION_ENCAPSULATE_BUF_LENGTH), // encapsulate + MySqlBinding::createString(OPTION_RECORD_TYPES_BUF_LENGTH), // record_types + MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag + }; + + uint64_t last_def_id = 0; + + OptionDefContainer local_option_defs; + + // Run select query. + conn_.selectQuery(index, in_bindings, out_bindings, + [this, &local_option_defs, &last_def_id] + (MySqlBindingCollection& out_bindings) { + // Get pointer to last fetched option definition. + OptionDefinitionPtr last_def; + if (!local_option_defs.empty()) { + last_def = *local_option_defs.rbegin(); + } + + // 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 != out_bindings[0]->getInteger<uint64_t>())) { + + last_def_id = out_bindings[0]->getInteger<uint64_t>(); + + last_def = processOptionDefRow(out_bindings.begin()); + + // server_tag + ServerTag last_def_server_tag(out_bindings[10]->getString()); + 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 +MySqlConfigBackendImpl::createUpdateOptionDef(const db::ServerSelector& server_selector, + 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"); + + ElementPtr record_types = Element::createList(); + for (auto field : option_def->getRecordFields()) { + record_types->add(Element::create(static_cast<int>(field))); + } + MySqlBindingPtr record_types_binding = record_types->empty() ? + MySqlBinding::createNull() : MySqlBinding::createString(record_types->str()); + + MySqlBindingPtr client_class_binding = client_class_name.empty() ? + MySqlBinding::createNull() : MySqlBinding::createString(client_class_name); + + MySqlBindingCollection in_bindings = { + MySqlBinding::createInteger<uint16_t>(option_def->getCode()), + MySqlBinding::createString(option_def->getName()), + MySqlBinding::createString(option_def->getOptionSpaceName()), + MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option_def->getType())), + MySqlBinding::createTimestamp(option_def->getModificationTime()), + MySqlBinding::createBool(option_def->getArrayType()), + MySqlBinding::createString(option_def->getEncapsulatedSpace()), + record_types_binding, + createInputContextBinding(option_def), + client_class_binding, + MySqlBinding::createString(tag), + MySqlBinding::createInteger<uint16_t>(option_def->getCode()), + MySqlBinding::createString(option_def->getOptionSpaceName()), + }; + + MySqlTransaction 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); + + if (conn_.updateDeleteQuery(update_option_def, in_bindings) == 0) { + // Remove the bindings used only during the update. + in_bindings.resize(in_bindings.size() - 3); + conn_.insertQuery(insert_option_def, in_bindings); + + // Fetch unique identifier of the inserted option definition and use it + // as input to the next query. + uint64_t id = mysql_insert_id(conn_.mysql_); + + // Insert associations of the option definition with servers. + attachElementToServers(insert_option_def_server, + server_selector, + MySqlBinding::createInteger<uint64_t>(id), + MySqlBinding::createTimestamp(option_def->getModificationTime())); + } + + transaction.commit(); +} + +OptionDescriptorPtr +MySqlConfigBackendImpl::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; + MySqlBindingCollection in_bindings; + in_bindings.push_back(MySqlBinding::createString(tag)); + if (universe == Option::V4) { + in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code))); + } else { + in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(code)); + } + in_bindings.push_back(MySqlBinding::createString(space)); + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +OptionContainer +MySqlConfigBackendImpl::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) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()) + }; + getOptions(index, in_bindings, universe, options); + } + + return (options); +} + +OptionContainer +MySqlConfigBackendImpl::getModifiedOptions(const int index, + const Option::Universe& universe, + const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_time) { + OptionContainer options; + + auto const& tags = server_selector.getTags(); + for (auto const& tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag.get()), + MySqlBinding::createTimestamp(modification_time) + }; + getOptions(index, in_bindings, universe, options); + } + + return (options); +} + +OptionDescriptorPtr +MySqlConfigBackendImpl::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"); + + OptionContainer options; + MySqlBindingCollection in_bindings; + in_bindings.push_back(MySqlBinding::createString(tag)); + uint32_t id = static_cast<uint32_t>(subnet_id); + in_bindings.push_back(MySqlBinding::createInteger<uint32_t>(id)); + if (universe == Option::V4) { + in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code))); + } else { + in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(code)); + } + in_bindings.push_back(MySqlBinding::createString(space)); + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +OptionDescriptorPtr +MySqlConfigBackendImpl::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); + + Option::Universe universe = Option::V4; + OptionContainer options; + MySqlBindingCollection in_bindings; + in_bindings.push_back(MySqlBinding::createString(tag)); + in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id)); + if (pool_type == Lease::TYPE_V4) { + in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code))); + } else { + in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(code)); + universe = Option::V6; + } + in_bindings.push_back(MySqlBinding::createString(space)); + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +OptionDescriptorPtr +MySqlConfigBackendImpl::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"); + + OptionContainer options; + MySqlBindingCollection in_bindings; + in_bindings.push_back(MySqlBinding::createString(tag)); + in_bindings.push_back(MySqlBinding::createString(shared_network_name)); + if (universe == Option::V4) { + in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code))); + } else { + in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(code)); + } + in_bindings.push_back(MySqlBinding::createString(space)); + getOptions(index, in_bindings, universe, options); + return (options.empty() ? OptionDescriptorPtr() : + OptionDescriptor::create(*options.begin())); +} + +void +MySqlConfigBackendImpl::getOptions(const int index, + const db::MySqlBindingCollection& in_bindings, + const Option::Universe& universe, + OptionContainer& options) { + // Create output bindings. The order must match that in the prepared + // statement. + MySqlBindingCollection out_bindings; + // option_id + out_bindings.push_back(MySqlBinding::createInteger<uint64_t>()); + // code + if (universe == Option::V4) { + out_bindings.push_back(MySqlBinding::createInteger<uint8_t>()); + } else { + out_bindings.push_back(MySqlBinding::createInteger<uint16_t>()); + } + // value + out_bindings.push_back(MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH)); + // formatted_value + out_bindings.push_back(MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH)); + // space + out_bindings.push_back(MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH)); + // persistent + out_bindings.push_back(MySqlBinding::createInteger<uint8_t>()); + // cancelled + out_bindings.push_back(MySqlBinding::createInteger<uint8_t>()); + // dhcp[46]_subnet_id + out_bindings.push_back(MySqlBinding::createInteger<uint32_t>()); + // scope_id + out_bindings.push_back(MySqlBinding::createInteger<uint8_t>()); + // user_context + out_bindings.push_back(MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH)); + // shared_network_name + out_bindings.push_back(MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH)); + // pool_id + out_bindings.push_back(MySqlBinding::createInteger<uint64_t>()); + // modification_ts + out_bindings.push_back(MySqlBinding::createTimestamp()); + // server_tag + out_bindings.push_back(MySqlBinding::createString(SERVER_TAG_BUF_LENGTH)); + // pd_pool_id + if (universe == Option::V6) { + out_bindings.push_back(MySqlBinding::createInteger<uint64_t>()); + } + + uint64_t last_option_id = 0; + + OptionContainer local_options; + + conn_.selectQuery(index, in_bindings, out_bindings, + [this, universe, &local_options, &last_option_id] + (MySqlBindingCollection& out_bindings) { + // Parse option. + if (!out_bindings[0]->amNull() && + ((last_option_id == 0) || + (last_option_id < out_bindings[0]->getInteger<uint64_t>()))) { + last_option_id = out_bindings[0]->getInteger<uint64_t>(); + + OptionDescriptorPtr desc = processOptionRow(universe, out_bindings.begin()); + if (desc) { + // server_tag for the global option + ServerTag last_option_server_tag(out_bindings[13]->getString()); + 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 +MySqlConfigBackendImpl::processOptionRow(const Option::Universe& universe, + MySqlBindingCollection::iterator first_binding) { + // 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 = (*(first_binding + 4))->getString(); + uint16_t code; + if (universe == Option::V4) { + code = (*(first_binding + 1))->getInteger<uint8_t>(); + } else { + code = (*(first_binding + 1))->getInteger<uint16_t>(); + } + + + // Get formatted value if available. + std::string formatted_value = (*(first_binding + 3))->getStringOrDefault(""); + + OptionPtr option = Option::create(universe, code); + + // If we don't have a formatted value, check for a blob. Add it to the + // option if it exists. + if (formatted_value.empty()) { + std::vector<uint8_t> blob; + if (!(*(first_binding + 2))->amNull()) { + blob = (*(first_binding + 2))->getBlob(); + } + option->setData(blob.begin(), blob.end()); + } + + // Check if the option is persistent. + bool persistent = static_cast<bool>((*(first_binding + 5))->getIntegerOrDefault<uint8_t>(0)); + + // Check if the option is cancelled. + bool cancelled = static_cast<bool>((*(first_binding + 6))->getIntegerOrDefault<uint8_t>(0)); + + // 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((*(first_binding + 12))->getTimestamp()); + + // Set database id for the option. + if (!(*first_binding)->amNull()) { + desc->setId((*first_binding)->getInteger<uint64_t>()); + } + + return (desc); +} + +OptionDefinitionPtr +MySqlConfigBackendImpl::processOptionDefRow(MySqlBindingCollection::iterator first_binding) { + OptionDefinitionPtr def; + + // Check array type, because depending on this value we have to use + // different constructor. + bool array_type = static_cast<bool>((*(first_binding + 6))->getInteger<uint8_t>()); + if (array_type) { + // Create array option. + def = OptionDefinition::create((*(first_binding + 2))->getString(), + (*(first_binding + 1))->getInteger<uint16_t>(), + (*(first_binding + 3))->getString(), + static_cast<OptionDataType> + ((*(first_binding + 4))->getInteger<uint8_t>()), + array_type); + } else { + // Create non-array option. + def = OptionDefinition::create((*(first_binding + 2))->getString(), + (*(first_binding + 1))->getInteger<uint16_t>(), + (*(first_binding + 3))->getString(), + static_cast<OptionDataType> + ((*(first_binding + 4))->getInteger<uint8_t>()), + (*(first_binding + 7))->getStringOrDefault("").c_str()); + } + + // id + def->setId((*(first_binding))->getInteger<uint64_t>()); + + // record_types + ElementPtr record_types_element = (*(first_binding + 8))->getJSON(); + if (record_types_element) { + if (record_types_element->getType() != Element::list) { + isc_throw(BadValue, "invalid record_types value " + << (*(first_binding + 8))->getString()); + } + + // 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((*(first_binding + 5))->getTimestamp()); + + return (def); +} + +void +MySqlConfigBackendImpl::attachElementToServers(const int index, + const ServerSelector& server_selector, + const MySqlBindingPtr& first_binding, + const MySqlBindingPtr& in_bindings) { + // Create the vector from the parameter pack. + MySqlBindingCollection in_server_bindings = { first_binding, in_bindings }; + for (auto const& tag : server_selector.getTags()) { + in_server_bindings.push_back(MySqlBinding::createString(tag.get())); + // Handles the case where the server does not exists. + try { + conn_.insertQuery(index, in_server_bindings); + } catch (const NullKeyError&) { + // The message should give the tag value. + isc_throw(NullKeyError, + "server '" << tag.get() << "' does not exist"); + } + in_server_bindings.pop_back(); + } +} + +MySqlBindingPtr +MySqlConfigBackendImpl::createInputRelayBinding(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())); + } + } + + return (relay_element->empty() ? MySqlBinding::createNull() : + MySqlBinding::condCreateString(relay_element->str())); +} + +MySqlBindingPtr +MySqlConfigBackendImpl::createOptionValueBinding(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()); + return (MySqlBinding::createBlob(blob.begin(), blob.end())); + + } + + return (MySqlBinding::createNull()); +} + +ServerPtr +MySqlConfigBackendImpl::getServer(const int index, const ServerTag& server_tag) { + ServerCollection servers; + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(server_tag.get()) + }; + getServers(index, in_bindings, servers); + + return (servers.empty() ? ServerPtr() : *servers.begin()); +} + +void +MySqlConfigBackendImpl::getAllServers(const int index, db::ServerCollection& servers) { + MySqlBindingCollection in_bindings; + getServers(index, in_bindings, servers); +} + +void +MySqlConfigBackendImpl::getServers(const int index, + const MySqlBindingCollection& in_bindings, + ServerCollection& servers) { + MySqlBindingCollection out_bindings = { + MySqlBinding::createInteger<uint64_t>(), + MySqlBinding::createString(SERVER_TAG_BUF_LENGTH), + MySqlBinding::createString(SERVER_DESCRIPTION_BUF_LENGTH), + MySqlBinding::createTimestamp() + }; + + conn_.selectQuery(index, in_bindings, out_bindings, + [&servers](MySqlBindingCollection& out_bindings) { + + ServerPtr last_server; + uint64_t id = out_bindings[0]->getInteger<uint64_t>(); + if (!last_server || (last_server->getId() != id)) { + + // Set description if it is non-null. + auto desc = (out_bindings[2]->amNull() ? "" : out_bindings[2]->getString()); + last_server = Server::create(ServerTag(out_bindings[1]->getString()), + desc); + + // id + last_server->setId(id); + + // modification_ts + last_server->setModificationTime(out_bindings[3]->getTimestamp()); + + // New server fetched. Let's store it. + servers.insert(last_server); + } + }); +} + +void +MySqlConfigBackendImpl::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"); + } + + // 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); + + MySqlTransaction transaction(conn_); + + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(server->getServerTagAsText()), + MySqlBinding::createString(server->getDescription()), + MySqlBinding::createTimestamp(server->getModificationTime()) + }; + + try { + conn_.insertQuery(create_index, in_bindings); + + } catch (const DuplicateEntry&) { + in_bindings.push_back(MySqlBinding::createString(server->getServerTagAsText())); + conn_.updateDeleteQuery(update_index, in_bindings); + } + + transaction.commit(); +} + +std::string +MySqlConfigBackendImpl::getType() const { + return ("mysql"); +} + +std::string +MySqlConfigBackendImpl::getHost() const { + std::string host = "localhost"; + try { + host = conn_.getParameter("host"); + } catch (...) { + // No host parameter. Return localhost as a default. + } + return (host); +} + +uint16_t +MySqlConfigBackendImpl::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); +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h new file mode 100644 index 0000000..a822a5c --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -0,0 +1,874 @@ +// Copyright (C) 2018-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 MYSQL_CONFIG_BACKEND_IMPL_H +#define MYSQL_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 <util/triplet.h> +#include <mysql/mysql_binding.h> +#include <mysql/mysql_connection.h> +#include <set> +#include <sstream> +#include <string> +#include <vector> + +namespace isc { +namespace dhcp { + +/// @brief Base class for MySQL Config Backend implementations. +/// +/// This class contains common methods for manipulating data in the +/// MySQL database, used by all servers. +/// +/// All POSIX times specified in the methods belonging to this +/// class must be local times. +class MySqlConfigBackendImpl { +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 + /// MySQL CB implementation object which prevents new audit + /// revisions to be created while this instance exists. + /// + /// @param impl pointer to the MySQL 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(MySqlConfigBackendImpl* 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 MySQL CB implementation. + MySqlConfigBackendImpl* 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. + explicit MySqlConfigBackendImpl(const db::DatabaseConnection::ParameterMap& parameters, + const db::DbCallback db_reconnect_callback); + + /// @brief Destructor. + virtual ~MySqlConfigBackendImpl(); + + /// @brief Creates MySQL binding from an @c Optional of integer type. + /// + /// @tparam T Numeric type corresponding to the binding type, e.g. + /// @c uint8_t, @c uint16_t etc. + /// @param value Optional integer of type T. + /// @return Pointer to a null binding if the value is "unspecified" or + /// a pointer to a binding representing integer value. + template<typename T> + static db::MySqlBindingPtr condCreateInteger(const util::Optional<T>& value) { + if (value.unspecified()) { + return (db::MySqlBinding::createNull()); + } + return (db::MySqlBinding::createInteger(value.get())); + } + + /// @brief Creates MySQL binding from a @c Triplet. + /// + /// @param triplet Triplet value from which the binding should be created. + /// @return Pointer to a null binding if the triplet is "unspecified" or + /// a pointer to a binding representing 32-bit unsigned integer value + /// otherwise. + static db::MySqlBindingPtr createBinding(const util::Triplet<uint32_t>& triplet); + + /// @brief Creates MySQL binding from a @c Triplet max value. + /// + /// @param triplet Triplet value from which the binding should be created. + /// @return Pointer to a null binding if the triplet is "unspecified" or + /// the max value is the same as the default value, or a pointer to + /// a binding representing 32-bit unsigned integer value from the max + /// value otherwise. + static db::MySqlBindingPtr createMaxBinding(const util::Triplet<uint32_t>& triplet); + + /// @brief Creates MySQL binding from a @c Triplet min value. + /// + /// @param triplet Triplet value from which the binding should be created. + /// @return Pointer to a null binding if the triplet is "unspecified" or + /// the min value is the same as the default value, or a pointer to + /// a binding representing 32-bit unsigned integer value from the min + /// value otherwise. + static db::MySqlBindingPtr createMinBinding(const util::Triplet<uint32_t>& triplet); + + /// @brief Creates @c Triplet object from MySQL binding. + /// + /// @param binding Pointer to the MySQL binding. + /// @return Triplet value set to "unspecified" if the MySQL binding + /// represents a NULL value or a Triplet value encapsulating 32-bit + /// unsigned integer if the MySQL represents an integer. + /// @throw isc::Unexpected if the provided binding pointer is NULL. + /// @throw isc::InvalidOperation if the binding does not represent + /// a 32-bit unsigned integer. + static util::Triplet<uint32_t> createTriplet(const db::MySqlBindingPtr& binding); + + /// @brief Creates @c Triplet object from MySQL bindings. + /// + /// @param def_binding Pointer to the MySQL binding of the default. + /// @param min_binding Pointer to the MySQL binding of the min value. + /// @param max_binding Pointer to the MySQL binding of the max value. + /// @return Triplet value set to "unspecified" if the MySQL binding + /// represents a NULL value or a Triplet value encapsulating 32-bit + /// unsigned integer if the MySQL represents an integer. + /// When max or max bindings are not NULL their values are used. + /// @throw isc::Unexpected if the provided binding pointer is NULL. + /// @throw isc::InvalidOperation if the binding does not represent + /// a 32-bit unsigned integer. + static util::Triplet<uint32_t> createTriplet(const db::MySqlBindingPtr& def_binding, + const db::MySqlBindingPtr& min_binding, + const db::MySqlBindingPtr& max_binding); + + /// @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 MySQL. + /// + /// 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 logging purposes. + /// @param in_bindings Reference to the MySQL 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::MySqlBindingCollection& in_bindings) { + + // For ANY server, we use queries that lack server tag. + if (!server_selector.amAny() && !server_selector.amUnassigned()) { + auto tag = getServerTag(server_selector, operation); + in_bindings.insert(in_bindings.begin(), db::MySqlBinding::createString(tag)); + } + + return (conn_.updateDeleteQuery(index, in_bindings)); + } + + /// @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. + /// + /// @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::MySqlBindingCollection in_bindings; + + if (db::MySqlBindingTraits<KeyType>::column_type == MYSQL_TYPE_STRING) { + in_bindings.push_back(db::MySqlBinding::createString(key)); + + } else { + in_bindings.push_back(db::MySqlBinding::createInteger<KeyType>(key)); + } + + return (deleteFromTable(index, server_selector, operation, in_bindings)); + } + + /// @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::MySqlBindingCollection& 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::MySqlBindingCollection& in_bindings, + OptionDefContainer& option_defs); + + /// @brief Creates or updates an option definition. + /// + /// @param server_selector Server selector. + /// @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 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::MySqlBindingCollection& in_bindings, + const Option::Universe& universe, + OptionContainer& options); + + /// @brief Returns DHCP option instance from output bindings. + /// + /// 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 first_binding Iterator of the output binding containing + /// option_id. + OptionDescriptorPtr processOptionRow(const Option::Universe& universe, + db::MySqlBindingCollection::iterator first_binding); + + /// @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 first_binding Iterator of the output binding containing + /// option definition id. + /// @return Pointer to the option definition. + OptionDefinitionPtr processOptionDefRow(db::MySqlBindingCollection::iterator first_binding); + + /// @brief Associates a configuration element with multiple servers. + /// + /// @param index Query index. + /// @param server_selector Server selector, perhaps with multiple server tags. + /// @param first_binding First binding to be used in the query. + /// @param in_bindings Parameter pack holding bindings for the query. 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::MySqlBindingPtr& first_binding, + const db::MySqlBindingPtr& in_bindings); + + /// @brief Creates input binding for relay addresses. + /// + /// @param network Pointer to a shared network or subnet for which binding + /// should be created. + /// @return Pointer to the binding (possibly null binding if there are no + /// relay addresses specified). + db::MySqlBindingPtr createInputRelayBinding(const NetworkPtr& network); + + /// @brief Creates input binding for 'require_client_classes' parameter. + /// + /// @tparam T of pointer to objects with getRequiredClasses + /// method, e.g. shared network, subnet, pool or prefix delegation pool. + /// @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> + db::MySqlBindingPtr createInputRequiredClassesBinding(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)); + } + + return (required_classes_element ? + db::MySqlBinding::createString(required_classes_element->str()) : + db::MySqlBinding::createNull()); + } + + /// @brief Creates input binding for user context parameter. + /// + /// @tparam T Type of the configuration element to which context belongs. + /// @param network Pointer to a shared network, subnet or other configuration + /// element for which binding should be created. + /// @return Pointer to the binding (possibly null binding if context is + /// null). + template<typename T> + db::MySqlBindingPtr createInputContextBinding(const T& config_element) { + // Create user context binding if user context exists. + auto context_element = config_element->getContext(); + return (context_element ? db::MySqlBinding::createString(context_element->str()) : + db::MySqlBinding::createNull()); + } + + /// @brief Creates input binding for option value parameter. + /// + /// @param option Option descriptor holding option for which binding is to + /// be created. + /// @return Pointer to the binding (possibly null binding if formatted + /// value is non-empty. + db::MySqlBindingPtr createOptionValueBinding(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 in_bindings Reference to the MySQL input bindings. + /// @param [out] servers Reference to the container where fetched servers + /// will be inserted. + void getServers(const int index, + const db::MySqlBindingCollection& in_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 MySqlConfigBackendDHCPv4Impl::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::MySqlBindingCollection empty_bindings; + for (auto index : indexes) { + conn_.updateDeleteQuery(index, empty_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 "mysql". + 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 MySQL 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 Represents connection to the MySQL database. + db::MySqlConnection 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_; +}; + +} // end of namespace isc::dhcp +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_log.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_log.cc new file mode 100644 index 0000000..1177720 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_log.cc @@ -0,0 +1,17 @@ +// Copyright (C) 2019-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 <mysql_cb_log.h> + +namespace isc { +namespace dhcp { + +isc::log::Logger mysql_cb_logger("mysql-cb-hooks"); + +} // namespace dhcp +} // namespace isc diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_log.h b/src/hooks/dhcp/mysql_cb/mysql_cb_log.h new file mode 100644 index 0000000..dc56330 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_log.h @@ -0,0 +1,22 @@ +// Copyright (C) 2019-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 <mysql_cb_messages.h> + +namespace isc { +namespace dhcp { + +extern isc::log::Logger mysql_cb_logger; + +} // namespace dhcp +} // namespace isc + +#endif diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_messages.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_messages.cc new file mode 100644 index 0000000..00a8dde --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_messages.cc @@ -0,0 +1,405 @@ +// File created from ../../../../src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes + +#include <cstddef> +#include <log/message_types.h> +#include <log/message_initializer.h> + +namespace isc { +namespace cb { + +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4 = "MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6 = "MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6 = "MYSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4 = "MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6 = "MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 = "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 = "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 = "MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 = "MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION4 = "MYSQL_CB_CREATE_UPDATE_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION6 = "MYSQL_CB_CREATE_UPDATE_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION_DEF4 = "MYSQL_CB_CREATE_UPDATE_OPTION_DEF4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION_DEF6 = "MYSQL_CB_CREATE_UPDATE_OPTION_DEF6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SERVER4 = "MYSQL_CB_CREATE_UPDATE_SERVER4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SERVER6 = "MYSQL_CB_CREATE_UPDATE_SERVER6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK4 = "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6 = "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4 = "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6 = "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SUBNET4 = "MYSQL_CB_CREATE_UPDATE_SUBNET4"; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SUBNET6 = "MYSQL_CB_CREATE_UPDATE_SUBNET6"; +extern const isc::log::MessageID MYSQL_CB_DEINIT_OK = "MYSQL_CB_DEINIT_OK"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4 = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6 = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS4 = "MYSQL_CB_DELETE_ALL_OPTION_DEFS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT = "MYSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS6 = "MYSQL_CB_DELETE_ALL_OPTION_DEFS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT = "MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS4 = "MYSQL_CB_DELETE_ALL_SERVERS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS4_RESULT = "MYSQL_CB_DELETE_ALL_SERVERS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS6 = "MYSQL_CB_DELETE_ALL_SERVERS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS6_RESULT = "MYSQL_CB_DELETE_ALL_SERVERS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4 = "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT = "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6 = "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT = "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS4 = "MYSQL_CB_DELETE_ALL_SUBNETS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS4_RESULT = "MYSQL_CB_DELETE_ALL_SUBNETS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS6 = "MYSQL_CB_DELETE_ALL_SUBNETS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT = "MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION4 = "MYSQL_CB_DELETE_BY_POOL_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION4_RESULT = "MYSQL_CB_DELETE_BY_POOL_OPTION4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION6 = "MYSQL_CB_DELETE_BY_POOL_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT = "MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6 = "MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT = "MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET4 = "MYSQL_CB_DELETE_BY_PREFIX_SUBNET4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT = "MYSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET6 = "MYSQL_CB_DELETE_BY_PREFIX_SUBNET6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT = "MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4 = "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT = "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6 = "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT = "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4 = "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT = "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6 = "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT = "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4 = "MYSQL_CB_DELETE_CLIENT_CLASS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT = "MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6 = "MYSQL_CB_DELETE_CLIENT_CLASS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT = "MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4 = "MYSQL_CB_DELETE_GLOBAL_PARAMETER4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT = "MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER6 = "MYSQL_CB_DELETE_GLOBAL_PARAMETER6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT = "MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION4 = "MYSQL_CB_DELETE_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION4_RESULT = "MYSQL_CB_DELETE_OPTION4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION6 = "MYSQL_CB_DELETE_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION6_RESULT = "MYSQL_CB_DELETE_OPTION6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF4 = "MYSQL_CB_DELETE_OPTION_DEF4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF4_RESULT = "MYSQL_CB_DELETE_OPTION_DEF4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF6 = "MYSQL_CB_DELETE_OPTION_DEF6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF6_RESULT = "MYSQL_CB_DELETE_OPTION_DEF6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER4 = "MYSQL_CB_DELETE_SERVER4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER4_RESULT = "MYSQL_CB_DELETE_SERVER4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER6 = "MYSQL_CB_DELETE_SERVER6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER6_RESULT = "MYSQL_CB_DELETE_SERVER6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK4 = "MYSQL_CB_DELETE_SHARED_NETWORK4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK4_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK6 = "MYSQL_CB_DELETE_SHARED_NETWORK6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4 = "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6 = "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4 = "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6 = "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6"; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4 = "MYSQL_CB_GET_ALL_CLIENT_CLASSES4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT = "MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6 = "MYSQL_CB_GET_ALL_CLIENT_CLASSES6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT = "MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS4 = "MYSQL_CB_GET_ALL_OPTIONS4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS4_RESULT = "MYSQL_CB_GET_ALL_OPTIONS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS6 = "MYSQL_CB_GET_ALL_OPTIONS6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS6_RESULT = "MYSQL_CB_GET_ALL_OPTIONS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS4 = "MYSQL_CB_GET_ALL_OPTION_DEFS4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS4_RESULT = "MYSQL_CB_GET_ALL_OPTION_DEFS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS6 = "MYSQL_CB_GET_ALL_OPTION_DEFS6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT = "MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS4 = "MYSQL_CB_GET_ALL_SERVERS4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS4_RESULT = "MYSQL_CB_GET_ALL_SERVERS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS6 = "MYSQL_CB_GET_ALL_SERVERS6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS6_RESULT = "MYSQL_CB_GET_ALL_SERVERS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS4 = "MYSQL_CB_GET_ALL_SHARED_NETWORKS4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT = "MYSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS6 = "MYSQL_CB_GET_ALL_SHARED_NETWORKS6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT = "MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS4 = "MYSQL_CB_GET_ALL_SUBNETS4"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS4_RESULT = "MYSQL_CB_GET_ALL_SUBNETS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6 = "MYSQL_CB_GET_ALL_SUBNETS6"; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6_RESULT = "MYSQL_CB_GET_ALL_SUBNETS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS4 = "MYSQL_CB_GET_CLIENT_CLASS4"; +extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS6 = "MYSQL_CB_GET_CLIENT_CLASS6"; +extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER4 = "MYSQL_CB_GET_GLOBAL_PARAMETER4"; +extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER6 = "MYSQL_CB_GET_GLOBAL_PARAMETER6"; +extern const isc::log::MessageID MYSQL_CB_GET_HOST4 = "MYSQL_CB_GET_HOST4"; +extern const isc::log::MessageID MYSQL_CB_GET_HOST6 = "MYSQL_CB_GET_HOST6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4 = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6 = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS4 = "MYSQL_CB_GET_MODIFIED_OPTIONS4"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS4_RESULT = "MYSQL_CB_GET_MODIFIED_OPTIONS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS6 = "MYSQL_CB_GET_MODIFIED_OPTIONS6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT = "MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS4 = "MYSQL_CB_GET_MODIFIED_OPTION_DEFS4"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT = "MYSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS6 = "MYSQL_CB_GET_MODIFIED_OPTION_DEFS6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT = "MYSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4 = "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT = "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6 = "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT = "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS4 = "MYSQL_CB_GET_MODIFIED_SUBNETS4"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS4_RESULT = "MYSQL_CB_GET_MODIFIED_SUBNETS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS6 = "MYSQL_CB_GET_MODIFIED_SUBNETS6"; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT = "MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION4 = "MYSQL_CB_GET_OPTION4"; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION6 = "MYSQL_CB_GET_OPTION6"; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION_DEF4 = "MYSQL_CB_GET_OPTION_DEF4"; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION_DEF6 = "MYSQL_CB_GET_OPTION_DEF6"; +extern const isc::log::MessageID MYSQL_CB_GET_PORT4 = "MYSQL_CB_GET_PORT4"; +extern const isc::log::MessageID MYSQL_CB_GET_PORT6 = "MYSQL_CB_GET_PORT6"; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4 = "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4"; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT = "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6 = "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6"; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT = "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_SERVER4 = "MYSQL_CB_GET_SERVER4"; +extern const isc::log::MessageID MYSQL_CB_GET_SERVER6 = "MYSQL_CB_GET_SERVER6"; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK4 = "MYSQL_CB_GET_SHARED_NETWORK4"; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK6 = "MYSQL_CB_GET_SHARED_NETWORK6"; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4 = "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4"; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT = "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6 = "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6"; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT = "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT"; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET4_BY_PREFIX = "MYSQL_CB_GET_SUBNET4_BY_PREFIX"; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET4_BY_SUBNET_ID = "MYSQL_CB_GET_SUBNET4_BY_SUBNET_ID"; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET6_BY_PREFIX = "MYSQL_CB_GET_SUBNET6_BY_PREFIX"; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET6_BY_SUBNET_ID = "MYSQL_CB_GET_SUBNET6_BY_SUBNET_ID"; +extern const isc::log::MessageID MYSQL_CB_GET_TYPE4 = "MYSQL_CB_GET_TYPE4"; +extern const isc::log::MessageID MYSQL_CB_GET_TYPE6 = "MYSQL_CB_GET_TYPE6"; +extern const isc::log::MessageID MYSQL_CB_INIT_OK = "MYSQL_CB_INIT_OK"; +extern const isc::log::MessageID MYSQL_CB_NO_TLS = "MYSQL_CB_NO_TLS"; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_FAILED4 = "MYSQL_CB_RECONNECT_ATTEMPT_FAILED4"; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_FAILED6 = "MYSQL_CB_RECONNECT_ATTEMPT_FAILED6"; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4 = "MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4"; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6 = "MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6"; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_FAILED4 = "MYSQL_CB_RECONNECT_FAILED4"; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_FAILED6 = "MYSQL_CB_RECONNECT_FAILED6"; +extern const isc::log::MessageID MYSQL_CB_REGISTER_BACKEND_TYPE4 = "MYSQL_CB_REGISTER_BACKEND_TYPE4"; +extern const isc::log::MessageID MYSQL_CB_REGISTER_BACKEND_TYPE6 = "MYSQL_CB_REGISTER_BACKEND_TYPE6"; +extern const isc::log::MessageID MYSQL_CB_TLS_CIPHER = "MYSQL_CB_TLS_CIPHER"; +extern const isc::log::MessageID MYSQL_CB_UNREGISTER_BACKEND_TYPE4 = "MYSQL_CB_UNREGISTER_BACKEND_TYPE4"; +extern const isc::log::MessageID MYSQL_CB_UNREGISTER_BACKEND_TYPE6 = "MYSQL_CB_UNREGISTER_BACKEND_TYPE6"; + +} // namespace cb +} // namespace isc + +namespace { + +const char* values[] = { + "MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4", "create or update option pool start: %1 pool end: %2", + "MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6", "create or update option pool start: %1 pool end: %2", + "MYSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6", "create or update option prefix: %1 prefix len: %2", + "MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4", "create or update option by subnet id: %1", + "MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6", "create or update option by subnet id: %1", + "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4", "create or update client class: %1", + "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6", "create or update client class: %1", + "MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4", "create or update global parameter: %1", + "MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6", "create or update global parameter: %1", + "MYSQL_CB_CREATE_UPDATE_OPTION4", "create or update option", + "MYSQL_CB_CREATE_UPDATE_OPTION6", "create or update option", + "MYSQL_CB_CREATE_UPDATE_OPTION_DEF4", "create or update option definition: %1 code: %2", + "MYSQL_CB_CREATE_UPDATE_OPTION_DEF6", "create or update option definition: %1 code: %2", + "MYSQL_CB_CREATE_UPDATE_SERVER4", "create or update server: %1", + "MYSQL_CB_CREATE_UPDATE_SERVER6", "create or update server: %1", + "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK4", "create or update shared network: %1", + "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6", "create or update shared network: %1", + "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4", "create or update shared network: %1 option", + "MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6", "create or update shared network: %1 option", + "MYSQL_CB_CREATE_UPDATE_SUBNET4", "create or update subnet: %1", + "MYSQL_CB_CREATE_UPDATE_SUBNET6", "create or update subnet: %1", + "MYSQL_CB_DEINIT_OK", "unloading MYSQL CB hooks library successful", + "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4", "delete all client classes", + "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6", "delete all client classes", + "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4", "delete all global parameters", + "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6", "delete all global parameters", + "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_OPTION_DEFS4", "delete all option definitions", + "MYSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_OPTION_DEFS6", "delete all option definitions", + "MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_SERVERS4", "delete all DHCPv4 servers", + "MYSQL_CB_DELETE_ALL_SERVERS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_SERVERS6", "delete all DHCPv6 servers", + "MYSQL_CB_DELETE_ALL_SERVERS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4", "delete all shared networks", + "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6", "delete all shared networks", + "MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_SUBNETS4", "delete all subnets", + "MYSQL_CB_DELETE_ALL_SUBNETS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_ALL_SUBNETS6", "delete all subnets", + "MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_POOL_OPTION4", "delete pool start: %1 pool end: %2 option code: %3 space: %4", + "MYSQL_CB_DELETE_BY_POOL_OPTION4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_POOL_OPTION6", "delete pool start: %1 pool end: %2 option code: %3 space: %4", + "MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6", "delete prefix: %1 prefix len: %2 option code: %3 space: %4", + "MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_PREFIX_SUBNET4", "delete subnet by prefix: %1", + "MYSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_PREFIX_SUBNET6", "delete subnet by prefix: %1", + "MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4", "delete by subnet id: %1 option code: %2 space: %3", + "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6", "delete by subnet id: %1 option code: %2 space: %3", + "MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4", "delete subnet by subnet id: %1", + "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6", "delete subnet by subnet id: %1", + "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_CLIENT_CLASS4", "delete client class: %1", + "MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_CLIENT_CLASS6", "delete client class: %1", + "MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_GLOBAL_PARAMETER4", "delete global parameter: %1", + "MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_GLOBAL_PARAMETER6", "delete global parameter: %1", + "MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_OPTION4", "delete option code: %1 space: %2", + "MYSQL_CB_DELETE_OPTION4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_OPTION6", "delete option code: %1 space: %2", + "MYSQL_CB_DELETE_OPTION6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_OPTION_DEF4", "delete option definition code: %1 space: %2", + "MYSQL_CB_DELETE_OPTION_DEF4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_OPTION_DEF6", "delete option definition code: %1 space: %2", + "MYSQL_CB_DELETE_OPTION_DEF6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SERVER4", "delete DHCPv4 server: %1", + "MYSQL_CB_DELETE_SERVER4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SERVER6", "delete DHCPv6 server: %1", + "MYSQL_CB_DELETE_SERVER6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SHARED_NETWORK4", "delete shared network: %1", + "MYSQL_CB_DELETE_SHARED_NETWORK4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SHARED_NETWORK6", "delete shared network: %1", + "MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4", "delete shared network: %1 option code: %2 space: %3", + "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6", "delete shared network: %1 option code: %2 space: %3", + "MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4", "delete shared network: %1 subnets", + "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT", "deleted: %1 entries", + "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6", "delete shared network: %1 subnets", + "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT", "deleted: %1 entries", + "MYSQL_CB_GET_ALL_CLIENT_CLASSES4", "retrieving all client classes", + "MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_CLIENT_CLASSES6", "retrieving all client classes", + "MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4", "retrieving all global parameters", + "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6", "retrieving all global parameters", + "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_OPTIONS4", "retrieving all options", + "MYSQL_CB_GET_ALL_OPTIONS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_OPTIONS6", "retrieving all options", + "MYSQL_CB_GET_ALL_OPTIONS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_OPTION_DEFS4", "retrieving all option definitions", + "MYSQL_CB_GET_ALL_OPTION_DEFS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_OPTION_DEFS6", "retrieving all option definitions", + "MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_SERVERS4", "retrieving all servers", + "MYSQL_CB_GET_ALL_SERVERS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_SERVERS6", "retrieving all DHCPv6 servers", + "MYSQL_CB_GET_ALL_SERVERS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_SHARED_NETWORKS4", "retrieving all shared networks", + "MYSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_SHARED_NETWORKS6", "retrieving all shared networks", + "MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_SUBNETS4", "retrieving all subnets", + "MYSQL_CB_GET_ALL_SUBNETS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_ALL_SUBNETS6", "retrieving all subnets", + "MYSQL_CB_GET_ALL_SUBNETS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_CLIENT_CLASS4", "retrieving client class: %1", + "MYSQL_CB_GET_CLIENT_CLASS6", "retrieving client class: %1", + "MYSQL_CB_GET_GLOBAL_PARAMETER4", "retrieving global parameter: %1", + "MYSQL_CB_GET_GLOBAL_PARAMETER6", "retrieving global parameter: %1", + "MYSQL_CB_GET_HOST4", "get host", + "MYSQL_CB_GET_HOST6", "get host", + "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4", "retrieving modified client classes from: %1", + "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6", "retrieving modified client classes from: %1", + "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4", "retrieving modified global parameters from: %1", + "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6", "retrieving modified global parameters from: %1", + "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_OPTIONS4", "retrieving modified options from: %1", + "MYSQL_CB_GET_MODIFIED_OPTIONS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_OPTIONS6", "retrieving modified options from: %1", + "MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_OPTION_DEFS4", "retrieving modified option definitions from: %1", + "MYSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_OPTION_DEFS6", "retrieving modified option definitions from: %1", + "MYSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4", "retrieving modified shared networks from: %1", + "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6", "retrieving modified shared networks from: %1", + "MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_SUBNETS4", "retrieving modified subnets from: %1", + "MYSQL_CB_GET_MODIFIED_SUBNETS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_MODIFIED_SUBNETS6", "retrieving modified subnets from: %1", + "MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_OPTION4", "retrieving option code: %1 space: %2", + "MYSQL_CB_GET_OPTION6", "retrieving option code: %1 space: %2", + "MYSQL_CB_GET_OPTION_DEF4", "retrieving option definition code: %1 space: %2", + "MYSQL_CB_GET_OPTION_DEF6", "retrieving option definition code: %1 space: %2", + "MYSQL_CB_GET_PORT4", "get port", + "MYSQL_CB_GET_PORT6", "get port", + "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4", "retrieving audit entries from: %1 %2", + "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6", "retrieving audit entries from: %1 %2", + "MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_SERVER4", "retrieving DHCPv4 server: %1", + "MYSQL_CB_GET_SERVER6", "retrieving DHCPv6 server: %1", + "MYSQL_CB_GET_SHARED_NETWORK4", "retrieving shared network: %1", + "MYSQL_CB_GET_SHARED_NETWORK6", "retrieving shared network: %1", + "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4", "retrieving shared network: %1 subnets", + "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6", "retrieving shared network: %1 subnets", + "MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT", "retrieving: %1 elements", + "MYSQL_CB_GET_SUBNET4_BY_PREFIX", "retrieving subnet by prefix: %1", + "MYSQL_CB_GET_SUBNET4_BY_SUBNET_ID", "retrieving subnet by subnet id: %1", + "MYSQL_CB_GET_SUBNET6_BY_PREFIX", "retrieving subnet by prefix: %1", + "MYSQL_CB_GET_SUBNET6_BY_SUBNET_ID", "retrieving subnet by subnet id: %1", + "MYSQL_CB_GET_TYPE4", "get type", + "MYSQL_CB_GET_TYPE6", "get type", + "MYSQL_CB_INIT_OK", "loading MYSQL CB hooks library successful", + "MYSQL_CB_NO_TLS", "TLS was required but is not used", + "MYSQL_CB_RECONNECT_ATTEMPT_FAILED4", "database reconnect failed: %1", + "MYSQL_CB_RECONNECT_ATTEMPT_FAILED6", "database reconnect failed: %1", + "MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4", "scheduling attempt %1 of %2 in %3 milliseconds", + "MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6", "scheduling attempt %1 of %2 in %3 milliseconds", + "MYSQL_CB_RECONNECT_FAILED4", "maximum number of database reconnect attempts: %1, has been exhausted without success", + "MYSQL_CB_RECONNECT_FAILED6", "maximum number of database reconnect attempts: %1, has been exhausted without success", + "MYSQL_CB_REGISTER_BACKEND_TYPE4", "register backend", + "MYSQL_CB_REGISTER_BACKEND_TYPE6", "register backend", + "MYSQL_CB_TLS_CIPHER", "TLS cipher: %1", + "MYSQL_CB_UNREGISTER_BACKEND_TYPE4", "unregister backend", + "MYSQL_CB_UNREGISTER_BACKEND_TYPE6", "unregister backend", + NULL +}; + +const isc::log::MessageInitializer initializer(values); + +} // Anonymous namespace + diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_messages.h b/src/hooks/dhcp/mysql_cb/mysql_cb_messages.h new file mode 100644 index 0000000..7b3b39d --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_messages.h @@ -0,0 +1,206 @@ +// File created from ../../../../src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes + +#ifndef MYSQL_CB_MESSAGES_H +#define MYSQL_CB_MESSAGES_H + +#include <log/message_types.h> + +namespace isc { +namespace cb { + +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION_DEF4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION_DEF6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SERVER4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SERVER6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SUBNET4; +extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_SUBNET6; +extern const isc::log::MessageID MYSQL_CB_DEINIT_OK; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SERVERS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION4; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION6; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET4; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET6; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6; +extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER6; +extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION4; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION6; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF4; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF6; +extern const isc::log::MessageID MYSQL_CB_DELETE_OPTION_DEF6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER4; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER6; +extern const isc::log::MessageID MYSQL_CB_DELETE_SERVER6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK4; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK6; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6; +extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTIONS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SERVERS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS4; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6; +extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS4; +extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS6; +extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER4; +extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER6; +extern const isc::log::MessageID MYSQL_CB_GET_HOST4; +extern const isc::log::MessageID MYSQL_CB_GET_HOST6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS4; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS4; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS4; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS6; +extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION4; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION6; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION_DEF4; +extern const isc::log::MessageID MYSQL_CB_GET_OPTION_DEF6; +extern const isc::log::MessageID MYSQL_CB_GET_PORT4; +extern const isc::log::MessageID MYSQL_CB_GET_PORT6; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6; +extern const isc::log::MessageID MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_SERVER4; +extern const isc::log::MessageID MYSQL_CB_GET_SERVER6; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK4; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK6; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6; +extern const isc::log::MessageID MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET4_BY_PREFIX; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET4_BY_SUBNET_ID; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET6_BY_PREFIX; +extern const isc::log::MessageID MYSQL_CB_GET_SUBNET6_BY_SUBNET_ID; +extern const isc::log::MessageID MYSQL_CB_GET_TYPE4; +extern const isc::log::MessageID MYSQL_CB_GET_TYPE6; +extern const isc::log::MessageID MYSQL_CB_INIT_OK; +extern const isc::log::MessageID MYSQL_CB_NO_TLS; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_FAILED4; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_FAILED6; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_FAILED4; +extern const isc::log::MessageID MYSQL_CB_RECONNECT_FAILED6; +extern const isc::log::MessageID MYSQL_CB_REGISTER_BACKEND_TYPE4; +extern const isc::log::MessageID MYSQL_CB_REGISTER_BACKEND_TYPE6; +extern const isc::log::MessageID MYSQL_CB_TLS_CIPHER; +extern const isc::log::MessageID MYSQL_CB_UNREGISTER_BACKEND_TYPE4; +extern const isc::log::MessageID MYSQL_CB_UNREGISTER_BACKEND_TYPE6; + +} // namespace cb +} // namespace isc + +#endif // MYSQL_CB_MESSAGES_H diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes b/src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes new file mode 100644 index 0000000..6272298 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes @@ -0,0 +1,592 @@ +# Copyright (C) 2018-2023 Internet Systems Consortium, Inc. ("ISC") + +$NAMESPACE isc::cb + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 create or update client class: %1 +Debug message issued when triggered an action to create or update client class + +% MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 create or update client class: %1 +Debug message issued when triggered an action to create or update client class + +% MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 create or update global parameter: %1 +Debug message issued when triggered an action to create or update global parameter + +% MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 create or update global parameter: %1 +Debug message issued when triggered an action to create or update global parameter + +% MYSQL_CB_CREATE_UPDATE_OPTION4 create or update option +Debug message issued when triggered an action to create or update option + +% MYSQL_CB_CREATE_UPDATE_OPTION6 create or update option +Debug message issued when triggered an action to create or update option + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_CB_CREATE_UPDATE_SERVER4 create or update server: %1 +Debug message issued when triggered an action to create or update a DHCPv4 +server information. + +% MYSQL_CB_CREATE_UPDATE_SERVER6 create or update server: %1 +Debug message issued when triggered an action to create or update a DHCPv6 +server information. + +% MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK4 create or update shared network: %1 +Debug message issued when triggered an action to create or update shared network + +% MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6 create or update shared network: %1 +Debug message issued when triggered an action to create or update shared network + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_CB_CREATE_UPDATE_SUBNET4 create or update subnet: %1 +Debug message issued when triggered an action to create or update subnet + +% MYSQL_CB_CREATE_UPDATE_SUBNET6 create or update subnet: %1 +Debug message issued when triggered an action to create or update subnet + +% MYSQL_CB_DEINIT_OK unloading MYSQL CB hooks library successful +This informational message indicates that the MySQL Configuration Backend hooks +library has been unloaded successfully. + +% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4 delete all client classes +Debug message issued when triggered an action to delete all client classes + +% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all client classes + +% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6 delete all client classes +Debug message issued when triggered an action to delete all client classes + +% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all client classes + +% MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 delete all global parameters +Debug message issued when triggered an action to delete all global parameters + +% MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all global parameters + +% MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 delete all global parameters +Debug message issued when triggered an action to delete all global parameters + +% MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all global parameters + +% MYSQL_CB_DELETE_ALL_OPTION_DEFS4 delete all option definitions +Debug message issued when triggered an action to delete all option definitions + +% MYSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all option definitions + +% MYSQL_CB_DELETE_ALL_OPTION_DEFS6 delete all option definitions +Debug message issued when triggered an action to delete all option definitions + +% MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all option definitions + +% MYSQL_CB_DELETE_ALL_SERVERS4 delete all DHCPv4 servers +Debug message issued when triggered an action to delete all servers. + +% MYSQL_CB_DELETE_ALL_SERVERS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all servers. + +% MYSQL_CB_DELETE_ALL_SERVERS6 delete all DHCPv6 servers +Debug message issued when triggered an action to delete all servers. + +% MYSQL_CB_DELETE_ALL_SERVERS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all servers. + +% MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4 delete all shared networks +Debug message issued when triggered an action to delete all shared networks + +% MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all shared networks + +% MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6 delete all shared networks +Debug message issued when triggered an action to delete all shared networks + +% MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all shared networks + +% MYSQL_CB_DELETE_ALL_SUBNETS4 delete all subnets +Debug message issued when triggered an action to delete all subnets + +% MYSQL_CB_DELETE_ALL_SUBNETS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all subnets + +% MYSQL_CB_DELETE_ALL_SUBNETS6 delete all subnets +Debug message issued when triggered an action to delete all subnets + +% MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete all subnets + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_POOL_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by pool + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by pool + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by prefix + +% MYSQL_CB_DELETE_BY_PREFIX_SUBNET4 delete subnet by prefix: %1 +Debug message issued when triggered an action to delete subnet by prefix + +% MYSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by prefix + +% MYSQL_CB_DELETE_BY_PREFIX_SUBNET6 delete subnet by prefix: %1 +Debug message issued when triggered an action to delete subnet by prefix + +% MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by prefix + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by subnet id + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option by subnet id + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by subnet id + +% MYSQL_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 + +% MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete subnet by subnet id + +% MYSQL_CB_DELETE_CLIENT_CLASS4 delete client class: %1 +Debug message issued when triggered an action to delete client class + +% MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete client class + +% MYSQL_CB_DELETE_CLIENT_CLASS6 delete client class: %1 +Debug message issued when triggered an action to delete client class + +% MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete client class + +% MYSQL_CB_DELETE_GLOBAL_PARAMETER4 delete global parameter: %1 +Debug message issued when triggered an action to delete global parameter + +% MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete global parameter + +% MYSQL_CB_DELETE_GLOBAL_PARAMETER6 delete global parameter: %1 +Debug message issued when triggered an action to delete global parameter + +% MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete global parameter + +% MYSQL_CB_DELETE_OPTION4 delete option code: %1 space: %2 +Debug message issued when triggered an action to delete option + +% MYSQL_CB_DELETE_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option + +% MYSQL_CB_DELETE_OPTION6 delete option code: %1 space: %2 +Debug message issued when triggered an action to delete option + +% MYSQL_CB_DELETE_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option + +% MYSQL_CB_DELETE_OPTION_DEF4 delete option definition code: %1 space: %2 +Debug message issued when triggered an action to delete option definition + +% MYSQL_CB_DELETE_OPTION_DEF4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option definition + +% MYSQL_CB_DELETE_OPTION_DEF6 delete option definition code: %1 space: %2 +Debug message issued when triggered an action to delete option definition + +% MYSQL_CB_DELETE_OPTION_DEF6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete option definition + +% MYSQL_CB_DELETE_SERVER4 delete DHCPv4 server: %1 +Debug message issued when triggered an action to delete a server. + +% MYSQL_CB_DELETE_SERVER4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete a server. + +% MYSQL_CB_DELETE_SERVER6 delete DHCPv6 server: %1 +Debug message issued when triggered an action to delete a server. + +% MYSQL_CB_DELETE_SERVER6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete a server. + +% MYSQL_CB_DELETE_SHARED_NETWORK4 delete shared network: %1 +Debug message issued when triggered an action to delete shared network + +% MYSQL_CB_DELETE_SHARED_NETWORK4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network + +% MYSQL_CB_DELETE_SHARED_NETWORK6 delete shared network: %1 +Debug message issued when triggered an action to delete shared network + +% MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network + +% MYSQL_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 + +% MYSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network option + +% MYSQL_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 + +% MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network option + +% MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4 delete shared network: %1 subnets +Debug message issued when triggered an action to delete shared network subnets + +% MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network subnets + +% MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6 delete shared network: %1 subnets +Debug message issued when triggered an action to delete shared network subnets + +% MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT deleted: %1 entries +Debug message indicating the result of an action to delete shared network subnets + +% MYSQL_CB_GET_ALL_CLIENT_CLASSES4 retrieving all client classes +Debug message issued when triggered an action to retrieve all client classes + +% MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all client classes + +% MYSQL_CB_GET_ALL_CLIENT_CLASSES6 retrieving all client classes +Debug message issued when triggered an action to retrieve all client classes + +% MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all client classes + +% MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 retrieving all global parameters +Debug message issued when triggered an action to retrieve all global parameters + +% MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all global parameters + +% MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 retrieving all global parameters +Debug message issued when triggered an action to retrieve all global parameters + +% MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all global parameters + +% MYSQL_CB_GET_ALL_OPTIONS4 retrieving all options +Debug message issued when triggered an action to retrieve all options + +% MYSQL_CB_GET_ALL_OPTIONS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all options + +% MYSQL_CB_GET_ALL_OPTIONS6 retrieving all options +Debug message issued when triggered an action to retrieve all options + +% MYSQL_CB_GET_ALL_OPTIONS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all options + +% MYSQL_CB_GET_ALL_OPTION_DEFS4 retrieving all option definitions +Debug message issued when triggered an action to retrieve all option definitions + +% MYSQL_CB_GET_ALL_OPTION_DEFS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all option definitions + +% MYSQL_CB_GET_ALL_OPTION_DEFS6 retrieving all option definitions +Debug message issued when triggered an action to retrieve all option definitions + +% MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all option definitions + +% MYSQL_CB_GET_ALL_SERVERS4 retrieving all servers +Debug message issued when triggered an action to retrieve all DHCPv4 +servers + +% MYSQL_CB_GET_ALL_SERVERS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all DHCPv4 +servers + +% MYSQL_CB_GET_ALL_SERVERS6 retrieving all DHCPv6 servers +Debug message issued when triggered an action to retrieve all DHCPv6 +servers + +% MYSQL_CB_GET_ALL_SERVERS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all DHCPv6 +servers + +% MYSQL_CB_GET_ALL_SHARED_NETWORKS4 retrieving all shared networks +Debug message issued when triggered an action to retrieve all shared networks + +% MYSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all shared networks + +% MYSQL_CB_GET_ALL_SHARED_NETWORKS6 retrieving all shared networks +Debug message issued when triggered an action to retrieve all shared networks + +% MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all shared networks + +% MYSQL_CB_GET_ALL_SUBNETS4 retrieving all subnets +Debug message issued when triggered an action to retrieve all subnets + +% MYSQL_CB_GET_ALL_SUBNETS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all subnets + +% MYSQL_CB_GET_ALL_SUBNETS6 retrieving all subnets +Debug message issued when triggered an action to retrieve all subnets + +% MYSQL_CB_GET_ALL_SUBNETS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve all subnets + +% MYSQL_CB_GET_CLIENT_CLASS4 retrieving client class: %1 +Debug message issued when triggered an action to retrieve a client class + +% MYSQL_CB_GET_CLIENT_CLASS6 retrieving client class: %1 +Debug message issued when triggered an action to retrieve a client class + +% MYSQL_CB_GET_GLOBAL_PARAMETER4 retrieving global parameter: %1 +Debug message issued when triggered an action to retrieve global parameter + +% MYSQL_CB_GET_GLOBAL_PARAMETER6 retrieving global parameter: %1 +Debug message issued when triggered an action to retrieve global parameter + +% MYSQL_CB_GET_HOST4 get host +Debug message issued when triggered an action to retrieve host + +% MYSQL_CB_GET_HOST6 get host +Debug message issued when triggered an action to retrieve host + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_CB_GET_MODIFIED_OPTIONS4 retrieving modified options from: %1 +Debug message issued when triggered an action to retrieve modified options from specified time + +% MYSQL_CB_GET_MODIFIED_OPTIONS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified options from specified time + +% MYSQL_CB_GET_MODIFIED_OPTIONS6 retrieving modified options from: %1 +Debug message issued when triggered an action to retrieve modified options from specified time + +% MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified options from specified time + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_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 + +% MYSQL_CB_GET_MODIFIED_SUBNETS4 retrieving modified subnets from: %1 +Debug message issued when triggered an action to retrieve modified subnets from specified time + +% MYSQL_CB_GET_MODIFIED_SUBNETS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified subnets from specified time + +% MYSQL_CB_GET_MODIFIED_SUBNETS6 retrieving modified subnets from: %1 +Debug message issued when triggered an action to retrieve modified subnets from specified time + +% MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve modified subnets from specified time + +% MYSQL_CB_GET_OPTION4 retrieving option code: %1 space: %2 +Debug message issued when triggered an action to retrieve option + +% MYSQL_CB_GET_OPTION6 retrieving option code: %1 space: %2 +Debug message issued when triggered an action to retrieve option + +% MYSQL_CB_GET_OPTION_DEF4 retrieving option definition code: %1 space: %2 +Debug message issued when triggered an action to retrieve option definition + +% MYSQL_CB_GET_OPTION_DEF6 retrieving option definition code: %1 space: %2 +Debug message issued when triggered an action to retrieve option definition + +% MYSQL_CB_GET_PORT4 get port +Debug message issued when triggered an action to retrieve port + +% MYSQL_CB_GET_PORT6 get port +Debug message issued when triggered an action to retrieve port + +% MYSQL_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. + +% MYSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve audit entries from specified time + +% MYSQL_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 + +% MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve audit entries from specified time + +% MYSQL_CB_GET_SERVER4 retrieving DHCPv4 server: %1 +Debug message issued when triggered an action to retrieve a DHCPv4 server information. + +% MYSQL_CB_GET_SERVER6 retrieving DHCPv6 server: %1 +Debug message issued when triggered an action to retrieve a DHCPv6 server information. + +% MYSQL_CB_GET_SHARED_NETWORK4 retrieving shared network: %1 +Debug message issued when triggered an action to retrieve shared network + +% MYSQL_CB_GET_SHARED_NETWORK6 retrieving shared network: %1 +Debug message issued when triggered an action to retrieve shared network + +% MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4 retrieving shared network: %1 subnets +Debug message issued when triggered an action to retrieve shared network subnets + +% MYSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve shared network subnets + +% MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6 retrieving shared network: %1 subnets +Debug message issued when triggered an action to retrieve shared network subnets + +% MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT retrieving: %1 elements +Debug message indicating the result of an action to retrieve shared network subnets + +% MYSQL_CB_GET_SUBNET4_BY_PREFIX retrieving subnet by prefix: %1 +Debug message issued when triggered an action to retrieve subnet by prefix + +% MYSQL_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 + +% MYSQL_CB_GET_SUBNET6_BY_PREFIX retrieving subnet by prefix: %1 +Debug message issued when triggered an action to retrieve subnet by prefix + +% MYSQL_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 + +% MYSQL_CB_GET_TYPE4 get type +Debug message issued when triggered an action to retrieve type + +% MYSQL_CB_GET_TYPE6 get type +Debug message issued when triggered an action to retrieve type + +% MYSQL_CB_INIT_OK loading MYSQL CB hooks library successful +This informational message indicates that the MySQL Configuration Backend hooks +library has been loaded successfully. Enjoy! + +% MYSQL_CB_NO_TLS TLS was required but is not used +This error message is issued when TLS for the connection was required but +TLS is not used. + +% MYSQL_CB_RECONNECT_ATTEMPT_FAILED4 database reconnect failed: %1 +Error message issued when an attempt to reconnect has failed. + +% MYSQL_CB_RECONNECT_ATTEMPT_FAILED6 database reconnect failed: %1 +Error message issued when an attempt to reconnect has failed. + +% MYSQL_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. + +% MYSQL_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. + +% MYSQL_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. + +% MYSQL_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. + +% MYSQL_CB_REGISTER_BACKEND_TYPE4 register backend +Debug message issued when triggered an action to register backend + +% MYSQL_CB_REGISTER_BACKEND_TYPE6 register backend +Debug message issued when triggered an action to register backend + +% MYSQL_CB_TLS_CIPHER TLS cipher: %1 +A debug message issued when a new MySQL connected is created with TLS. +The TLS cipher name is logged. + +% MYSQL_CB_UNREGISTER_BACKEND_TYPE4 unregister backend +Debug message issued when triggered an action to unregister backend + +% MYSQL_CB_UNREGISTER_BACKEND_TYPE6 unregister backend +Debug message issued when triggered an action to unregister backend diff --git a/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h new file mode 100644 index 0000000..60b3e80 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h @@ -0,0 +1,1356 @@ +// Copyright (C) 2018-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 MYSQL_QUERY_MACROS_DHCP_H +#define MYSQL_QUERY_MACROS_DHCP_H + +/// @file mysql_query_macros_dhcp.h +/// Collection of common macros defining MySQL 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 MySQL 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 MySQL query. The fixed +/// part of the WHERE clause is included in the macro. + +/// @todo Update queries to also fetch server tags to associate +/// returned configuration elements with particular servers. + +namespace isc { +namespace dhcp { + +namespace { + +#ifndef MYSQL_GET_GLOBAL_PARAMETER +#define MYSQL_GET_GLOBAL_PARAMETER(table_prefix, ...) \ + "SELECT" \ + " g.id," \ + " g.name," \ + " g.value," \ + " g.parameter_type," \ + " g.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 = ? OR s.id = 1) " #__VA_ARGS__ \ + " ORDER BY g.id, s.id" +#endif + +#ifndef MYSQL_GET_SUBNET4 +#define MYSQL_GET_SUBNET4_COMMON(server_join, ...) \ + "SELECT" \ + " s.subnet_id," \ + " s.subnet_prefix," \ + " s.4o6_interface," \ + " s.4o6_interface_id," \ + " s.4o6_subnet," \ + " s.boot_file_name," \ + " s.client_class," \ + " s.interface," \ + " s.match_client_id," \ + " s.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," \ + " p.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," \ + " x.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," \ + " o.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 MYSQL_GET_SUBNET4_NO_TAG(...) \ + MYSQL_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 MYSQL_GET_SUBNET4_ANY(...) \ + MYSQL_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 MYSQL_GET_SUBNET4_UNASSIGNED(...) \ + MYSQL_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 MYSQL_GET_SUBNET6 +#define MYSQL_GET_SUBNET6_COMMON(server_join, ...) \ + "SELECT" \ + " s.subnet_id," \ + " s.subnet_prefix," \ + " s.client_class," \ + " s.interface," \ + " s.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," \ + " p.modification_ts," \ + " d.id," \ + " d.prefix," \ + " d.prefix_length," \ + " d.delegated_prefix_length," \ + " d.subnet_id," \ + " d.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," \ + " x.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," \ + " y.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," \ + " o.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 MYSQL_GET_SUBNET6_NO_TAG(...) \ + MYSQL_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 MYSQL_GET_SUBNET6_ANY(...) \ + MYSQL_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 MYSQL_GET_SUBNET6_UNASSIGNED(...) \ + MYSQL_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 MYSQL_GET_POOL4_COMMON +#define MYSQL_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," \ + " p.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," \ + " x.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 MYSQL_GET_POOL4_RANGE_WITH_TAG(...) \ + MYSQL_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 MYSQL_GET_POOL4_RANGE_NO_TAG(...) \ + MYSQL_GET_POOL4_COMMON("", __VA_ARGS__) +#endif + +#ifndef MYSQL_GET_POOL6_COMMON +#define MYSQL_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," \ + " p.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," \ + " x.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 MYSQL_GET_POOL6_RANGE_WITH_TAG(...) \ + MYSQL_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 MYSQL_GET_POOL6_RANGE_NO_TAG(...) \ + MYSQL_GET_POOL6_COMMON("", __VA_ARGS__) +#endif + +#ifndef MYSQL_GET_PD_POOL_COMMON +#define MYSQL_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," \ + " p.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," \ + " x.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 MYSQL_GET_PD_POOL_WITH_TAG(...) \ + MYSQL_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 MYSQL_GET_PD_POOL_NO_TAG(...) \ + MYSQL_GET_PD_POOL_COMMON("", __VA_ARGS__) +#endif + +#ifndef MYSQL_GET_SHARED_NETWORK4 +#define MYSQL_GET_SHARED_NETWORK4_COMMON(server_join, ...) \ + "SELECT" \ + " n.id," \ + " n.name," \ + " n.client_class," \ + " n.interface," \ + " n.match_client_id," \ + " n.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," \ + " o.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 MYSQL_GET_SHARED_NETWORK4_NO_TAG(...) \ + MYSQL_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 MYSQL_GET_SHARED_NETWORK4_ANY(...) \ + MYSQL_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 MYSQL_GET_SHARED_NETWORK4_UNASSIGNED(...) \ + MYSQL_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 MYSQL_GET_SHARED_NETWORK6 +#define MYSQL_GET_SHARED_NETWORK6_COMMON(server_join, ...) \ + "SELECT" \ + " n.id," \ + " n.name," \ + " n.client_class," \ + " n.interface," \ + " n.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," \ + " o.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 MYSQL_GET_SHARED_NETWORK6_NO_TAG(...) \ + MYSQL_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 MYSQL_GET_SHARED_NETWORK6_ANY(...) \ + MYSQL_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 MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(...) \ + MYSQL_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 MYSQL_GET_OPTION_DEF +#define MYSQL_GET_OPTION_DEF(table_prefix, ...) \ + "SELECT" \ + " d.id," \ + " d.code," \ + " d.name," \ + " d.space," \ + " d.type," \ + " d.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 = ? OR s.id = 1) " #__VA_ARGS__ \ + " ORDER BY d.id" +#endif + +#ifndef MYSQL_GET_OPTION_COMMON +#define MYSQL_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," \ + " o.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 = ? OR s.id = 1) " #__VA_ARGS__ \ + " ORDER BY o.option_id, s.id" + +#define MYSQL_GET_OPTION4(...) \ + MYSQL_GET_OPTION_COMMON(dhcp4, "", __VA_ARGS__) + +#define MYSQL_GET_OPTION6(...) \ + MYSQL_GET_OPTION_COMMON(dhcp6, ", o.pd_pool_id ", __VA_ARGS__) +#endif + +#ifndef MYSQL_GET_AUDIT_ENTRIES_TIME +#define MYSQL_GET_AUDIT_ENTRIES_TIME(table_prefix) \ + "SELECT" \ + " a.id," \ + " a.object_type," \ + " a.object_id," \ + " a.modification_type," \ + " r.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 = ? OR s.id = 1) AND ((r.modification_ts, r.id) > (?, ?))" \ + " ORDER BY r.modification_ts, r.id" +#endif + +#ifndef MYSQL_GET_SERVERS_COMMON +#define MYSQL_GET_SERVERS_COMMON(table_prefix, ...) \ + "SELECT" \ + " s.id," \ + " s.tag," \ + " s.description," \ + " s.modification_ts " \ + "FROM " #table_prefix "_server AS s " \ + "WHERE s.id > 1 " \ + __VA_ARGS__ \ + "ORDER BY s.id" + +#define MYSQL_GET_ALL_SERVERS(table_prefix) \ + MYSQL_GET_SERVERS_COMMON(table_prefix, "") + +#define MYSQL_GET_SERVER(table_prefix) \ + MYSQL_GET_SERVERS_COMMON(table_prefix, "AND s.tag = ? ") +#endif + +#ifndef MYSQL_GET_CLIENT_CLASS4_COMMON +#define MYSQL_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, " \ + " c.modification_ts," \ + " c.user_context," \ + " c.offer_lifetime," \ + " d.id," \ + " d.code," \ + " d.name," \ + " d.space," \ + " d.type," \ + " d.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," \ + " x.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 MYSQL_GET_CLIENT_CLASS4_WITH_TAG(...) \ + MYSQL_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 MYSQL_GET_CLIENT_CLASS4_UNASSIGNED(...) \ + MYSQL_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 MYSQL_GET_CLIENT_CLASS6_COMMON +#define MYSQL_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, " \ + " c.modification_ts," \ + " c.user_context," \ + " d.id," \ + " d.code," \ + " d.name," \ + " d.space," \ + " d.type," \ + " d.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," \ + " x.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 MYSQL_GET_CLIENT_CLASS6_WITH_TAG(...) \ + MYSQL_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 MYSQL_GET_CLIENT_CLASS6_UNASSIGNED(...) \ + MYSQL_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 MYSQL_INSERT_GLOBAL_PARAMETER +#define MYSQL_INSERT_GLOBAL_PARAMETER(table_prefix) \ + "INSERT INTO " #table_prefix "_global_parameter(" \ + " name," \ + " value," \ + " parameter_type," \ + " modification_ts" \ + ") VALUES (?, ?, ?, ?)" +#endif + +#ifndef MYSQL_INSERT_GLOBAL_PARAMETER_SERVER +#define MYSQL_INSERT_GLOBAL_PARAMETER_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_global_parameter_server(" \ + " parameter_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES (?, ?, (SELECT id FROM " #table_prefix "_server WHERE tag = ?))" +#endif + +#ifndef MYSQL_INSERT_SUBNET_SERVER +#define MYSQL_INSERT_SUBNET_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_subnet_server(" \ + " subnet_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES (?, ?, (SELECT id FROM " #table_prefix "_server WHERE tag = ?))" +#endif + +#ifndef MYSQL_INSERT_POOL +#define MYSQL_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 (?, ?, ?, ?, ?, ?, ?)" +#endif + +#ifndef MYSQL_INSERT_PD_POOL +#define MYSQL_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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" +#endif + +#ifndef MYSQL_INSERT_SHARED_NETWORK_SERVER +#define MYSQL_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 = ?), ?," \ + " (SELECT id FROM " #table_prefix "_server WHERE tag = ?)" \ + ")" +#endif + +#ifndef MYSQL_INSERT_OPTION_DEF +#define MYSQL_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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" +#endif + +#ifndef MYSQL_INSERT_OPTION_DEF_CLIENT_CLASS +#define MYSQL_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 (?, ?, ?, ?, ?, ?, ?, ?, ?, (SELECT id FROM " #table_prefix "_client_class WHERE name = ?))" +#endif + +#ifndef MYSQL_INSERT_OPTION_DEF_SERVER +#define MYSQL_INSERT_OPTION_DEF_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_option_def_server(" \ + " option_def_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES (?, ?, (SELECT id FROM " #table_prefix "_server WHERE tag = ?))" +#endif + +#ifndef MYSQL_INSERT_OPTION_COMMON +#define MYSQL_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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" last ")" + +#define MYSQL_INSERT_OPTION4() \ + MYSQL_INSERT_OPTION_COMMON(dhcp4, "", "") + +#define MYSQL_INSERT_OPTION6() \ + MYSQL_INSERT_OPTION_COMMON(dhcp6, ", pd_pool_id ", ", ?") +#endif + +#ifndef MYSQL_INSERT_OPTION_SERVER +#define MYSQL_INSERT_OPTION_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_options_server (" \ + " option_id," \ + " modification_ts," \ + " server_id" \ + ") VALUES (?, ?, (SELECT id FROM " #table_prefix "_server WHERE tag = ?))" +#endif + +#ifndef MYSQL_INSERT_CLIENT_CLASS_SERVER +#define MYSQL_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 = ?), ?, (SELECT id FROM " #table_prefix "_server WHERE tag = ?))" +#endif + +#ifndef MYSQL_INSERT_CLIENT_CLASS_DEPENDENCY +#define MYSQL_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 = ?), (SELECT id FROM " #table_prefix "_client_class WHERE name = ?))" +#endif + +#ifndef MYSQL_INSERT_SERVER +#define MYSQL_INSERT_SERVER(table_prefix) \ + "INSERT INTO " #table_prefix "_server (" \ + " tag," \ + " description," \ + " modification_ts" \ + ") VALUES (?, ?, ?)" +#endif + +#ifndef MYSQL_UPDATE_GLOBAL_PARAMETER +#define MYSQL_UPDATE_GLOBAL_PARAMETER(table_prefix) \ + "UPDATE " #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 " \ + "SET" \ + " g.name = ?," \ + " g.value = ?," \ + " g.parameter_type = ?," \ + " g.modification_ts = ? " \ + "WHERE s.tag = ? AND g.name = ?" +#endif + +#ifndef MYSQL_UPDATE_OPTION_DEF +#define MYSQL_UPDATE_OPTION_DEF(table_prefix) \ + "UPDATE " #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 " \ + "SET" \ + " d.code = ?," \ + " d.name = ?," \ + " d.space = ?," \ + " d.type = ?," \ + " d.modification_ts = ?," \ + " d.is_array = ?," \ + " d.encapsulate = ?," \ + " d.record_types = ?," \ + " d.user_context = ?, " \ + " d.class_id = ? " \ + "WHERE s.tag = ? AND d.code = ? AND d.space = ?" +#endif + +#ifndef MYSQL_UPDATE_OPTION_DEF_CLIENT_CLASS +#define MYSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(table_prefix) \ + "UPDATE " #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 " \ + "SET" \ + " d.code = ?," \ + " d.name = ?," \ + " d.space = ?," \ + " d.type = ?," \ + " d.modification_ts = ?," \ + " d.is_array = ?," \ + " d.encapsulate = ?," \ + " d.record_types = ?," \ + " d.user_context = ? " \ + "WHERE d.class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = ?) " \ + " AND s.tag = ? AND d.code = ? AND d.space = ?" +#endif + +#ifndef MYSQL_UPDATE_OPTION_COMMON +#define MYSQL_UPDATE_OPTION_COMMON(table_prefix, server_join, pd_pool_id, ...) \ + "UPDATE " #table_prefix "_options AS o " \ + server_join \ + "SET" \ + " o.code = ?," \ + " o.value = ?," \ + " o.formatted_value = ?," \ + " o.space = ?," \ + " o.persistent = ?," \ + " o.cancelled = ?," \ + " o.dhcp_client_class = ?," \ + " o." #table_prefix "_subnet_id = ?," \ + " o.scope_id = ?," \ + " o.user_context = ?," \ + " o.shared_network_name = ?," \ + " o.pool_id = ?," \ + " o.modification_ts = ? " \ + pd_pool_id \ + "WHERE " #__VA_ARGS__ + +#define MYSQL_UPDATE_OPTION4_WITH_TAG(...) \ + MYSQL_UPDATE_OPTION_COMMON(dhcp4, \ + "INNER JOIN dhcp4_options_server AS a" \ + " ON o.option_id = a.option_id " \ + "INNER JOIN dhcp4_server AS s" \ + " ON a.server_id = s.id ", \ + "", s.tag = ? __VA_ARGS__) + +#define MYSQL_UPDATE_OPTION4_NO_TAG(...) \ + MYSQL_UPDATE_OPTION_COMMON(dhcp4, "", "", __VA_ARGS__) + +#define MYSQL_UPDATE_OPTION6_WITH_TAG(...) \ + MYSQL_UPDATE_OPTION_COMMON(dhcp6, \ + "INNER JOIN dhcp6_options_server AS a" \ + " ON o.option_id = a.option_id " \ + "INNER JOIN dhcp6_server AS s" \ + " ON a.server_id = s.id ", \ + ", o.pd_pool_id = ? ", s.tag = ? __VA_ARGS__) + +#define MYSQL_UPDATE_OPTION6_NO_TAG(...) \ + MYSQL_UPDATE_OPTION_COMMON(dhcp6, "", ", o.pd_pool_id = ? ", __VA_ARGS__) +#endif + +#ifndef MYSQL_UPDATE_CLIENT_CLASS4 +#define MYSQL_UPDATE_CLIENT_CLASS4(follow_class_name_set) \ + "UPDATE dhcp4_client_class SET" \ + " 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_set \ + " modification_ts = ?, " \ + " user_context = ?," \ + " offer_lifetime = ? "\ + "WHERE name = ?" +#endif + +#ifndef MYSQL_UPDATE_CLIENT_CLASS6 +#define MYSQL_UPDATE_CLIENT_CLASS6(follow_class_name_set) \ + "UPDATE dhcp6_client_class SET" \ + " name = ?," \ + " test = ?," \ + " only_if_required = ?," \ + " valid_lifetime = ?," \ + " min_valid_lifetime = ?," \ + " max_valid_lifetime = ?," \ + " depend_on_known_directly = ?," \ + follow_class_name_set \ + " preferred_lifetime = ?, " \ + " min_preferred_lifetime = ?, " \ + " max_preferred_lifetime = ?, " \ + " modification_ts = ?, " \ + " user_context = ? " \ + "WHERE name = ?" +#endif + +#ifndef MYSQL_UPDATE_SERVER +#define MYSQL_UPDATE_SERVER(table_prefix) \ + "UPDATE " #table_prefix "_server " \ + "SET" \ + " tag = ?," \ + " description = ?," \ + " modification_ts = ? " \ + "WHERE tag = ?" +#endif + +#ifndef MYSQL_DELETE_GLOBAL_PARAMETER +#define MYSQL_DELETE_GLOBAL_PARAMETER(table_prefix, ...) \ + "DELETE g 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 = ? " #__VA_ARGS__ +#endif + +#ifndef MYSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED +#define MYSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(table_prefix, ...) \ + "DELETE g 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 MYSQL_DELETE_SUBNET +#define MYSQL_DELETE_SUBNET_COMMON(table_prefix, ...) \ + "DELETE s FROM " #table_prefix "_subnet AS s " \ + "INNER JOIN " #table_prefix "_subnet_server AS a " \ + " ON s.subnet_id = a.subnet_id " \ + "INNER JOIN " #table_prefix "_server AS srv" \ + " ON a.server_id = srv.id " \ + #__VA_ARGS__ + +#define MYSQL_DELETE_SUBNET_WITH_TAG(table_prefix, ...) \ + MYSQL_DELETE_SUBNET_COMMON(table_prefix, WHERE srv.tag = ? __VA_ARGS__) + +#define MYSQL_DELETE_SUBNET_ANY(table_prefix, ...) \ + "DELETE s FROM " #table_prefix "_subnet AS s " \ + #__VA_ARGS__ + +#define MYSQL_DELETE_SUBNET_UNASSIGNED(table_prefix, ...) \ + "DELETE s 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 MYSQL_DELETE_SUBNET_SERVER +#define MYSQL_DELETE_SUBNET_SERVER(table_prefix) \ + "DELETE FROM " #table_prefix "_subnet_server " \ + "WHERE subnet_id = ?" +#endif + +#ifndef MYSQL_DELETE_POOLS +#define MYSQL_DELETE_POOLS(table_prefix) \ + "DELETE FROM " #table_prefix "_pool " \ + "WHERE subnet_id = ? OR subnet_id = " \ + "(SELECT subnet_id FROM " #table_prefix "_subnet" \ + " WHERE subnet_prefix = ?)" +#endif + +#ifndef MYSQL_DELETE_PD_POOLS +#define MYSQL_DELETE_PD_POOLS() \ + "DELETE FROM dhcp6_pd_pool " \ + "WHERE subnet_id = ? OR subnet_id = " \ + "(SELECT subnet_id FROM dhcp6_subnet" \ + " WHERE subnet_prefix = ?)" +#endif + +#ifndef MYSQL_DELETE_SHARED_NETWORK_COMMON +#define MYSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, ...) \ + "DELETE n FROM " #table_prefix "_shared_network AS n " \ + "INNER JOIN " #table_prefix "_shared_network_server AS a" \ + " ON n.id = a.shared_network_id " \ + "INNER JOIN " #table_prefix "_server AS s" \ + " ON a.server_id = s.id " \ + #__VA_ARGS__ + +#define MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(table_prefix, ...) \ + MYSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, WHERE s.tag = ? __VA_ARGS__) + +#define MYSQL_DELETE_SHARED_NETWORK_ANY(table_prefix, ...) \ + "DELETE n FROM " #table_prefix "_shared_network AS n " \ + #__VA_ARGS__ + +#define MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(table_prefix, ...) \ + "DELETE n 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 MYSQL_DELETE_SHARED_NETWORK_SERVER +#define MYSQL_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 = ?)" +#endif + +#ifndef MYSQL_DELETE_OPTION_DEF +#define MYSQL_DELETE_OPTION_DEF(table_prefix, ...) \ + "DELETE d 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 = ? " #__VA_ARGS__ +#endif + +#ifndef MYSQL_DELETE_OPTION_DEF_UNASSIGNED +#define MYSQL_DELETE_OPTION_DEF_UNASSIGNED(table_prefix, ...) \ + "DELETE d 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 MYSQL_DELETE_OPTION_DEFS_CLIENT_CLASS +#define MYSQL_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 = ?)" +#endif + +#ifndef MYSQL_DELETE_OPTION_WITH_TAG +#define MYSQL_DELETE_OPTION_WITH_TAG(table_prefix, ...) \ + "DELETE o 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 = ? " #__VA_ARGS__ +#endif + +#ifndef MYSQL_DELETE_OPTION_NO_TAG +#define MYSQL_DELETE_OPTION_NO_TAG(table_prefix, ...) \ + "DELETE o FROM " #table_prefix "_options AS o " \ + #__VA_ARGS__ +#endif + +#ifndef MYSQL_DELETE_OPTION_SUBNET_ID_PREFIX +#define MYSQL_DELETE_OPTION_SUBNET_ID_PREFIX(table_prefix) \ + "DELETE o FROM " #table_prefix "_options AS o " \ + "INNER JOIN " #table_prefix "_subnet AS s " \ + " ON s.subnet_id = o." #table_prefix "_subnet_id " \ + "WHERE o.scope_id = 1 AND (s.subnet_id = ? OR s.subnet_prefix = ?)" +#endif + +#ifndef MYSQL_DELETE_OPTION_UNASSIGNED +#define MYSQL_DELETE_OPTION_UNASSIGNED(table_prefix, ...) \ + "DELETE o 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 MYSQL_DELETE_OPTION_POOL_RANGE +#define MYSQL_DELETE_OPTION_POOL_RANGE(table_prefix, ...) \ + "DELETE o FROM " #table_prefix "_options AS o " \ + "WHERE " #__VA_ARGS__ \ + " AND o.pool_id = " \ + " (SELECT id FROM " #table_prefix "_pool" \ + " WHERE start_address = ? AND end_address = ?)" +#endif + +#ifndef MYSQL_DELETE_OPTION_PD_POOL +#define MYSQL_DELETE_OPTION_PD_POOL(...) \ + "DELETE o FROM dhcp6_options AS o " \ + "WHERE " #__VA_ARGS__ \ + " AND o.pd_pool_id = " \ + " (SELECT id FROM dhcp6_pd_pool" \ + " WHERE prefix = ? AND prefix_length = ?)" +#endif + +#ifndef MYSQL_DELETE_CLIENT_CLASS_DEPENDENCY +#define MYSQL_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 = ?)" +#endif + +#ifndef MYSQL_DELETE_CLIENT_CLASS_SERVER +#define MYSQL_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 = ?)" +#endif + +#ifndef MYSQL_DELETE_CLIENT_CLASS_COMMON +#define MYSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, ...) \ + "DELETE c FROM " #table_prefix "_client_class AS c " \ + "INNER JOIN " #table_prefix "_client_class_server AS a" \ + " ON c.id = a.class_id " \ + "INNER JOIN " #table_prefix "_server AS s" \ + " ON a.server_id = s.id " \ + #__VA_ARGS__ + +#define MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(table_prefix, ...) \ + MYSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, WHERE s.tag = ? __VA_ARGS__) + +#define MYSQL_DELETE_CLIENT_CLASS_ANY(table_prefix, ...) \ + MYSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, __VA_ARGS__) + +#define MYSQL_DELETE_CLIENT_CLASS_UNASSIGNED(table_prefix, ...) \ + "DELETE c 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 MYSQL_DELETE_SERVER +#define MYSQL_DELETE_SERVER(table_prefix) \ + "DELETE FROM " #table_prefix "_server " \ + "WHERE tag = ?" +#endif + +#ifndef MYSQL_DELETE_ALL_SERVERS +#define MYSQL_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/mysql_cb/tests/Makefile.am b/src/hooks/dhcp/mysql_cb/tests/Makefile.am new file mode 100644 index 0000000..8f1d8cb --- /dev/null +++ b/src/hooks/dhcp/mysql_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/mysql_cb -I$(top_srcdir)/src/hooks/dhcp/mysql_cb +AM_CPPFLAGS += $(BOOST_INCLUDES) $(MYSQL_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 += mysql_cb_unittests + +mysql_cb_unittests_SOURCES = mysql_cb_dhcp4_unittest.cc +mysql_cb_unittests_SOURCES += mysql_cb_dhcp4_mgr_unittest.cc +mysql_cb_unittests_SOURCES += mysql_cb_dhcp6_unittest.cc +mysql_cb_unittests_SOURCES += mysql_cb_dhcp6_mgr_unittest.cc +mysql_cb_unittests_SOURCES += mysql_cb_impl_unittest.cc +mysql_cb_unittests_SOURCES += run_unittests.cc + +mysql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) + +mysql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) + +mysql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS) + +mysql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/mysql_cb/libmysqlcb.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/mysql/testutils/libmysqltest.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/mysql/libkea-mysql.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la +mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +mysql_cb_unittests_LDADD += $(LOG4CPLUS_LIBS) +mysql_cb_unittests_LDADD += $(CRYPTO_LIBS) +mysql_cb_unittests_LDADD += $(BOOST_LIBS) +mysql_cb_unittests_LDADD += $(GTEST_LDADD) +endif +noinst_PROGRAMS = $(TESTS) diff --git a/src/hooks/dhcp/mysql_cb/tests/Makefile.in b/src/hooks/dhcp/mysql_cb/tests/Makefile.in new file mode 100644 index 0000000..f4fa993 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/Makefile.in @@ -0,0 +1,1123 @@ +# 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 = mysql_cb_unittests +noinst_PROGRAMS = $(am__EXEEXT_2) +subdir = src/hooks/dhcp/mysql_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 = mysql_cb_unittests$(EXEEXT) +am__EXEEXT_2 = $(am__EXEEXT_1) +PROGRAMS = $(noinst_PROGRAMS) +am__mysql_cb_unittests_SOURCES_DIST = mysql_cb_dhcp4_unittest.cc \ + mysql_cb_dhcp4_mgr_unittest.cc mysql_cb_dhcp6_unittest.cc \ + mysql_cb_dhcp6_mgr_unittest.cc mysql_cb_impl_unittest.cc \ + run_unittests.cc +@HAVE_GTEST_TRUE@am_mysql_cb_unittests_OBJECTS = mysql_cb_unittests-mysql_cb_dhcp4_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ mysql_cb_unittests-mysql_cb_dhcp6_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ mysql_cb_unittests-mysql_cb_impl_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ mysql_cb_unittests-run_unittests.$(OBJEXT) +mysql_cb_unittests_OBJECTS = $(am_mysql_cb_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@mysql_cb_unittests_DEPENDENCIES = $(top_builddir)/src/hooks/dhcp/mysql_cb/libmysqlcb.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/mysql/testutils/libmysqltest.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/mysql/libkea-mysql.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 = +mysql_cb_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) \ + $(mysql_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)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Po \ + ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Po \ + ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Po \ + ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Po \ + ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Po \ + ./$(DEPDIR)/mysql_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 = $(mysql_cb_unittests_SOURCES) +DIST_SOURCES = $(am__mysql_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/mysql_cb \ + -I$(top_srcdir)/src/hooks/dhcp/mysql_cb $(BOOST_INCLUDES) \ + $(MYSQL_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@mysql_cb_unittests_SOURCES = \ +@HAVE_GTEST_TRUE@ mysql_cb_dhcp4_unittest.cc \ +@HAVE_GTEST_TRUE@ mysql_cb_dhcp4_mgr_unittest.cc \ +@HAVE_GTEST_TRUE@ mysql_cb_dhcp6_unittest.cc \ +@HAVE_GTEST_TRUE@ mysql_cb_dhcp6_mgr_unittest.cc \ +@HAVE_GTEST_TRUE@ mysql_cb_impl_unittest.cc run_unittests.cc +@HAVE_GTEST_TRUE@mysql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +@HAVE_GTEST_TRUE@mysql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) +@HAVE_GTEST_TRUE@mysql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS) +@HAVE_GTEST_TRUE@mysql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/mysql_cb/libmysqlcb.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/mysql/testutils/libmysqltest.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/mysql/libkea-mysql.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/mysql_cb/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/mysql_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 + +mysql_cb_unittests$(EXEEXT): $(mysql_cb_unittests_OBJECTS) $(mysql_cb_unittests_DEPENDENCIES) $(EXTRA_mysql_cb_unittests_DEPENDENCIES) + @rm -f mysql_cb_unittests$(EXEEXT) + $(AM_V_CXXLD)$(mysql_cb_unittests_LINK) $(mysql_cb_unittests_OBJECTS) $(mysql_cb_unittests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql_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 $@ $< + +mysql_cb_unittests-mysql_cb_dhcp4_unittest.o: mysql_cb_dhcp4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp4_unittest.o -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp4_unittest.o `test -f 'mysql_cb_dhcp4_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp4_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp4_unittest.o `test -f 'mysql_cb_dhcp4_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp4_unittest.cc + +mysql_cb_unittests-mysql_cb_dhcp4_unittest.obj: mysql_cb_dhcp4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp4_unittest.obj -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp4_unittest.obj `if test -f 'mysql_cb_dhcp4_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp4_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp4_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp4_unittest.obj `if test -f 'mysql_cb_dhcp4_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp4_unittest.cc'; fi` + +mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.o: mysql_cb_dhcp4_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.o -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.o `test -f 'mysql_cb_dhcp4_mgr_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp4_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp4_mgr_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.o `test -f 'mysql_cb_dhcp4_mgr_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp4_mgr_unittest.cc + +mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.obj: mysql_cb_dhcp4_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.obj `if test -f 'mysql_cb_dhcp4_mgr_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp4_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp4_mgr_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp4_mgr_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.obj `if test -f 'mysql_cb_dhcp4_mgr_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp4_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp4_mgr_unittest.cc'; fi` + +mysql_cb_unittests-mysql_cb_dhcp6_unittest.o: mysql_cb_dhcp6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp6_unittest.o -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp6_unittest.o `test -f 'mysql_cb_dhcp6_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp6_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp6_unittest.o `test -f 'mysql_cb_dhcp6_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp6_unittest.cc + +mysql_cb_unittests-mysql_cb_dhcp6_unittest.obj: mysql_cb_dhcp6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp6_unittest.obj -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp6_unittest.obj `if test -f 'mysql_cb_dhcp6_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp6_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp6_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp6_unittest.obj `if test -f 'mysql_cb_dhcp6_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp6_unittest.cc'; fi` + +mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.o: mysql_cb_dhcp6_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.o -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.o `test -f 'mysql_cb_dhcp6_mgr_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp6_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp6_mgr_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.o `test -f 'mysql_cb_dhcp6_mgr_unittest.cc' || echo '$(srcdir)/'`mysql_cb_dhcp6_mgr_unittest.cc + +mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.obj: mysql_cb_dhcp6_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.obj `if test -f 'mysql_cb_dhcp6_mgr_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp6_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp6_mgr_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_dhcp6_mgr_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.obj `if test -f 'mysql_cb_dhcp6_mgr_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_dhcp6_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_dhcp6_mgr_unittest.cc'; fi` + +mysql_cb_unittests-mysql_cb_impl_unittest.o: mysql_cb_impl_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_impl_unittest.o -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_impl_unittest.o `test -f 'mysql_cb_impl_unittest.cc' || echo '$(srcdir)/'`mysql_cb_impl_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_impl_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_impl_unittest.o `test -f 'mysql_cb_impl_unittest.cc' || echo '$(srcdir)/'`mysql_cb_impl_unittest.cc + +mysql_cb_unittests-mysql_cb_impl_unittest.obj: mysql_cb_impl_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-mysql_cb_impl_unittest.obj -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Tpo -c -o mysql_cb_unittests-mysql_cb_impl_unittest.obj `if test -f 'mysql_cb_impl_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_impl_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_impl_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Tpo $(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mysql_cb_impl_unittest.cc' object='mysql_cb_unittests-mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-mysql_cb_impl_unittest.obj `if test -f 'mysql_cb_impl_unittest.cc'; then $(CYGPATH_W) 'mysql_cb_impl_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/mysql_cb_impl_unittest.cc'; fi` + +mysql_cb_unittests-run_unittests.o: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-run_unittests.Tpo -c -o mysql_cb_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mysql_cb_unittests-run_unittests.Tpo $(DEPDIR)/mysql_cb_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_cb_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc + +mysql_cb_unittests-run_unittests.obj: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT mysql_cb_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/mysql_cb_unittests-run_unittests.Tpo -c -o mysql_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)/mysql_cb_unittests-run_unittests.Tpo $(DEPDIR)/mysql_cb_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='mysql_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) $(mysql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(mysql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o mysql_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)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Po + -rm -f ./$(DEPDIR)/mysql_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)/mysql_cb_unittests-mysql_cb_dhcp4_mgr_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp4_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_mgr_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_dhcp6_unittest.Po + -rm -f ./$(DEPDIR)/mysql_cb_unittests-mysql_cb_impl_unittest.Po + -rm -f ./$(DEPDIR)/mysql_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/mysql_cb/tests/mysql_cb_dhcp4_mgr_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_mgr_unittest.cc new file mode 100644 index 0000000..fe94b55 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_mgr_unittest.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2018-2019 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 <mysql_cb_dhcp4.h> +#include <mysql/testutils/mysql_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 MySqlConfigBackendDHCPv4Mgr. +class MySqlConfigBackendDHCPv4MgrTest : public GenericBackendTest { +public: + /// @brief Constructor. + MySqlConfigBackendDHCPv4MgrTest() { + // Recreate a fresh mgr. + ConfigBackendDHCPv4Mgr::create(); + + // Ensure we have the proper schema with no transient data. + createMySQLSchema(); + } + + /// @brief Destructor. + virtual ~MySqlConfigBackendDHCPv4MgrTest() { + // Destroy the mgr. + ConfigBackendDHCPv4Mgr::destroy(); + + // If data wipe enabled, delete transient data otherwise destroy the schema. + destroyMySQLSchema(); + } +}; + +// This test verifies that MySQL backend can be registered with and +// unregistered from the Config Backend Manager. +TEST_F(MySqlConfigBackendDHCPv4MgrTest, factoryRegistration) { + + // Get the mgr singleton. + ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance(); + + // With no factory registered, attempting to add a MySQL db should fail. + ASSERT_THROW(mgr.addBackend(validMySQLConnectionString()), InvalidType); + + // Now we'll register the MySQL factory. + ASSERT_NO_THROW(MySqlConfigBackendDHCPv4::registerBackendType()); + + // With the factory registered, attempting to add a MySQL db should succeed. + ASSERT_NO_THROW(mgr.addBackend(validMySQLConnectionString())); + + // Create a MySQL backend selector for convenience. + BackendSelector mysql(BackendSelector::Type::MYSQL); + + // Should be able to create a global parameter. + StampedValuePtr server_tag = StampedValue::create("server-tag", "whale"); + ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter4(mysql, ServerSelector::ALL(), + server_tag)); + // Verify parameter can be fetched. + server_tag.reset(); + ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter4(mysql, 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 MySQL. + ASSERT_NO_THROW(MySqlConfigBackendDHCPv4::unregisterBackendType()); + + // With no factory registered, attempting to add a MySQL db should fail. + ASSERT_THROW(mgr.addBackend(validMySQLConnectionString()), InvalidType); + + // Attempting to read the global parameter should fail. + ASSERT_THROW(mgr.getPool()->getGlobalParameter4(mysql, ServerSelector::ALL(), "server-tag"), + NoSuchDatabase); +} + +} diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc new file mode 100644 index 0000000..63d1f10 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc @@ -0,0 +1,515 @@ +// Copyright (C) 2018-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 <database/testutils/schema.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/mysql_generic_backend_unittest.h> +#include <dhcpsrv/testutils/test_utils.h> +#include <mysql_cb_dhcp4.h> +#include <mysql/testutils/mysql_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 <mysql.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 MySQL configuration backend. +/// +/// It exposes protected members of the @c MySqlConfigBackendDHCPv4. +class TestMySqlConfigBackendDHCPv4 : public MySqlConfigBackendDHCPv4 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit TestMySqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters) + : MySqlConfigBackendDHCPv4(parameters) { + } + + using MySqlConfigBackendDHCPv4::base_impl_; +}; + +/// @brief Test fixture class for @c MySqlConfigBackendDHCPv4. +class MySqlConfigBackendDHCPv4Test : public GenericConfigBackendDHCPv4Test { +public: + /// @brief Constructor. + MySqlConfigBackendDHCPv4Test() {} + + /// @brief Destructor. + virtual ~MySqlConfigBackendDHCPv4Test() {} + + /// @brief Creates the MySQL back end schema + virtual void createSchema() { + createMySQLSchema(); + } + + /// @brief Destroys the MySQL back end schema + virtual void destroySchema() { + destroyMySQLSchema(); + } + + /// @brief Returns a valid MySQL back end specific connection + /// string + std::string validConnectionString() { + return (validMySQLConnectionString()); + } + + /// @brief Instantiates an instance of a MySQL 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 TestMySqlConfigBackendDHCPv4(params))); + } + + /// @brief Counts rows in a selected table in MySQL 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<TestMySqlConfigBackendDHCPv4>(cbptr_); + if (!p) { + ADD_FAILURE() << "cbptr_ does not cast to TestMySqlConfigBackendDHCPv4"; + return (0); + } + + // Reuse the existing connection of the backend. + auto impl = boost::dynamic_pointer_cast<MySqlConfigBackendImpl>(p->base_impl_); + auto& conn = impl->conn_; + + return (MySqlGenericBackendTest::countRows(conn, table)); + } +}; + +TEST_F(MySqlConfigBackendDHCPv4Test, getType) { + getTypeTest("mysql"); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getHost) { + getHostTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getPort) { + getPortTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteServerTest) { + createUpdateDeleteServerTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAndDeleteAllServersTest) { + getAndDeleteAllServersTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4Test) { + createUpdateDeleteGlobalParameter4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, globalParameters4WithServerTagsTest) { + globalParameters4WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllGlobalParameters4Test) { + getAllGlobalParameters4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedGlobalParameters4Test) { + getModifiedGlobalParameters4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, nullKeyErrorTest) { + nullKeyErrorTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSubnet4SelectorsTest) { + createUpdateSubnet4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4Test) { + getSubnet4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4byIdSelectorsTest) { + getSubnet4byIdSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4WithOptionalUnspecifiedTest) { + getSubnet4WithOptionalUnspecifiedTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4SharedNetworkTest) { + getSubnet4SharedNetworkTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4ByPrefixTest) { + getSubnet4ByPrefixTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4byPrefixSelectorsTest) { + getSubnet4byPrefixSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4Test) { + getAllSubnets4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4SelectorsTest) { + getAllSubnets4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4WithServerTagsTest) { + getAllSubnets4WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSubnets4SelectorsTest) { + getModifiedSubnets4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteSubnet4Test) { + deleteSubnet4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteSubnet4ByIdSelectorsTest) { + deleteSubnet4ByIdSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteSubnet4ByPrefixSelectorsTest) { + deleteSubnet4ByPrefixSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteAllSubnets4SelectorsTest) { + deleteAllSubnets4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, unassignedSubnet4Test) { + unassignedSubnet4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSubnets4Test) { + getModifiedSubnets4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, subnetLifetimeTest) { + subnetLifetimeTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetworkSubnets4Test) { + getSharedNetworkSubnets4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, subnetUpdatePoolsTest) { + subnetUpdatePoolsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, subnetOptionsTest) { + subnetOptionsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4Test) { + getSharedNetwork4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4SelectorsTest) { + getSharedNetwork4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4Test) { + createUpdateSharedNetwork4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4SelectorsTest) { + createUpdateSharedNetwork4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4WithOptionalUnspecifiedTest) { + getSharedNetwork4WithOptionalUnspecifiedTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetworkSubnets4Test) { + deleteSharedNetworkSubnets4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllSharedNetworks4Test) { + getAllSharedNetworks4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllSharedNetworks4SelectorsTest) { + getAllSharedNetworks4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllSharedNetworks4WithServerTagsTest) { + getAllSharedNetworks4WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4Test) { + getModifiedSharedNetworks4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4SelectorsTest) { + getModifiedSharedNetworks4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetwork4Test) { + deleteSharedNetwork4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetwork4SelectorsTest) { + deleteSharedNetwork4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteAllSharedNetworks4SelectorsTest) { + deleteAllSharedNetworks4SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, unassignedSharedNetworkTest) { + unassignedSharedNetworkTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, sharedNetworkLifetimeTest) { + sharedNetworkLifetimeTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, sharedNetworkOptionsTest) { + sharedNetworkOptionsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getOptionDef4Test) { + getOptionDef4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, optionDefs4WithServerTagsTest) { + optionDefs4WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllOptionDefs4Test) { + getAllOptionDefs4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedOptionDefs4Test) { + getModifiedOptionDefs4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteOption4Test) { + createUpdateDeleteOption4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, globalOptions4WithServerTagsTest) { + globalOptions4WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getAllOptions4Test) { + getAllOptions4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedOptions4Test) { + getModifiedOptions4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteSubnetOption4Test) { + createUpdateDeleteSubnetOption4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeletePoolOption4Test) { + createUpdateDeletePoolOption4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteSharedNetworkOption4Test) { + createUpdateDeleteSharedNetworkOption4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, subnetOptionIdOrderTest) { + subnetOptionIdOrderTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, sharedNetworkOptionIdOrderTest) { + sharedNetworkOptionIdOrderTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, setAndGetAllClientClasses4Test) { + setAndGetAllClientClasses4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getClientClass4Test) { + getClientClass4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateClientClass4OptionsTest) { + createUpdateClientClass4OptionsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedClientClasses4Test) { + getModifiedClientClasses4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteClientClass4Test) { + deleteClientClass4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, deleteAllClientClasses4Test) { + deleteAllClientClasses4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, clientClassDependencies4Test) { + clientClassDependencies4Test(); +} + +TEST_F(MySqlConfigBackendDHCPv4Test, multipleAuditEntriesTest) { + multipleAuditEntriesTest(); +} + +/// @brief Test fixture for verifying database connection loss-recovery +/// behavior. +class MySqlConfigBackendDHCPv4DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest { +public: + /// @brief Constructor + MySqlConfigBackendDHCPv4DbLostCallbackTest() {}; + + /// @brief Destructor + virtual ~MySqlConfigBackendDHCPv4DbLostCallbackTest() {}; + + /// @brief Creates the MySQL CB schema. + virtual void createSchema() { + createMySQLSchema(); + } + + /// @brief Destroys the MySQL CB schema. + virtual void destroySchema() { + destroyMySQLSchema(); + } + + /// @brief Method which returns a valid back end specific connection + /// string + virtual std::string validConnectionString() { + return (validMySQLConnectionString()); + } + + /// @brief Method which returns an invalid back end specific connection + /// string. + virtual std::string invalidConnectionString() { + return (connectionString(MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, + VALID_USER, VALID_PASSWORD)); + } + + /// @brief Registers MySQL as a CB backend type. + virtual void registerBackendType() { + isc::dhcp::MySqlConfigBackendDHCPv4::registerBackendType(); + } + + /// @brief Unregisters MySQL as a CB backend type. + virtual void unregisterBackendType() { + isc::dhcp::MySqlConfigBackendDHCPv4::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::MySqlConfigBackendImpl::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(MySqlConfigBackendDHCPv4DbLostCallbackTest, testNoCallbackOnOpenFailure) { + MultiThreadingTest mt(false); + testNoCallbackOnOpenFailure(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) { + MultiThreadingTest mt(true); + testNoCallbackOnOpenFailure(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedAfterTimeoutCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedAfterTimeoutCallback(); +} + +} diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_mgr_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_mgr_unittest.cc new file mode 100644 index 0000000..fe1252f --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_mgr_unittest.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2019 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 <mysql_cb_dhcp6.h> +#include <mysql/testutils/mysql_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 MySqlConfigBackendDHCPv6Mgr. +class MySqlConfigBackendDHCPv6MgrTest : public GenericBackendTest { +public: + /// @brief Constructor. + MySqlConfigBackendDHCPv6MgrTest() { + // Recreate a fresh mgr. + ConfigBackendDHCPv6Mgr::create(); + + // Ensure we have the proper schema with no transient data. + createMySQLSchema(); + } + + /// @brief Destructor. + virtual ~MySqlConfigBackendDHCPv6MgrTest() { + // Destroy the mgr. + ConfigBackendDHCPv6Mgr::destroy(); + + // If data wipe enabled, delete transient data otherwise destroy the schema. + destroyMySQLSchema(); + } +}; + +// This test verifies that MySQL backend can be registered with and +// unregistered from the Config Backend Manager. +TEST_F(MySqlConfigBackendDHCPv6MgrTest, factoryRegistration) { + + // Get the mgr singleton. + ConfigBackendDHCPv6Mgr& mgr = ConfigBackendDHCPv6Mgr::instance(); + + // With no factory registered, attempting to add a MySQL db should fail. + ASSERT_THROW(mgr.addBackend(validMySQLConnectionString()), InvalidType); + + // Now we'll register the MySQL factory. + ASSERT_NO_THROW(MySqlConfigBackendDHCPv6::registerBackendType()); + + // With the factory registered, attempting to add a MySQL db should succeed. + ASSERT_NO_THROW(mgr.addBackend(validMySQLConnectionString())); + + // Create a MySQL backend selector for convenience. + BackendSelector mysql(BackendSelector::Type::MYSQL); + + // Should be able to create a global parameter. + StampedValuePtr server_tag = StampedValue::create("server-tag", "whale"); + ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(mysql, ServerSelector::ALL(), + server_tag)); + // Verify parameter can be fetched. + server_tag.reset(); + ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter6(mysql, 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 MySQL. + ASSERT_NO_THROW(MySqlConfigBackendDHCPv6::unregisterBackendType()); + + // With no factory registered, attempting to add a MySQL db should fail. + ASSERT_THROW(mgr.addBackend(validMySQLConnectionString()), InvalidType); + + // Attempting to read the global parameter should fail. + ASSERT_THROW(mgr.getPool()->getGlobalParameter6(mysql, ServerSelector::ALL(), "server-tag"), + NoSuchDatabase); +} + +} diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc new file mode 100644 index 0000000..73d8891 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc @@ -0,0 +1,519 @@ +// Copyright (C) 2019-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 <database/testutils/schema.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/mysql_generic_backend_unittest.h> +#include <dhcpsrv/testutils/test_utils.h> +#include <mysql_cb_dhcp6.h> +#include <mysql/testutils/mysql_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 <mysql.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 MySQL configuration backend. +/// +/// It exposes protected members of the @c MySqlConfigBackendDHCPv6. +class TestMySqlConfigBackendDHCPv6 : public MySqlConfigBackendDHCPv6 { +public: + + /// @brief Constructor. + /// + /// @param parameters A data structure relating keywords and values + /// concerned with the database. + explicit TestMySqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters) + : MySqlConfigBackendDHCPv6(parameters) { + } + + using MySqlConfigBackendDHCPv6::base_impl_; +}; + +/// @brief Test fixture class for @c MySqlConfigBackendDHCPv6. +class MySqlConfigBackendDHCPv6Test : public GenericConfigBackendDHCPv6Test { +public: + /// @brief Constructor. + MySqlConfigBackendDHCPv6Test() {} + + /// @brief Destructor. + virtual ~MySqlConfigBackendDHCPv6Test() {} + + /// @brief Creates the MySQL back end schema + virtual void createSchema() { + createMySQLSchema(); + } + + /// @brief Destroys the MySQL back end schema + virtual void destroySchema() { + destroyMySQLSchema(); + } + + /// @brief Returns a valid MySQL back end specific connection + /// string + std::string validConnectionString() { + return (validMySQLConnectionString()); + } + + /// @brief Instantiates an instance of a MySQL 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 TestMySqlConfigBackendDHCPv6(params))); + } + + /// @brief Counts rows in a selected table in MySQL 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<TestMySqlConfigBackendDHCPv6>(cbptr_); + if (!p) { + ADD_FAILURE() << "cbptr_ does not cast to TestMySqlConfigBackendDHCPv6"; + return (0); + } + + // Reuse the existing connection of the backend. + auto impl = boost::dynamic_pointer_cast<MySqlConfigBackendImpl>(p->base_impl_); + auto& conn = impl->conn_; + + return (MySqlGenericBackendTest::countRows(conn, table)); + } +}; + +TEST_F(MySqlConfigBackendDHCPv6Test, getType) { + getTypeTest("mysql"); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getHost) { + getHostTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getPort) { + getPortTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteServerTest) { + createUpdateDeleteServerTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAndDeleteAllServersTest) { + getAndDeleteAllServersTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteGlobalParameter6Test) { + createUpdateDeleteGlobalParameter6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, globalParameters6WithServerTagsTest) { + globalParameters6WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllGlobalParameters6Test) { + getAllGlobalParameters6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedGlobalParameters6Test) { + getModifiedGlobalParameters6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, nullKeyErrorTest) { + nullKeyErrorTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSubnet6SelectorsTest) { + createUpdateSubnet6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6Test) { + getSubnet6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6byIdSelectorsTest) { + getSubnet6byIdSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6WithOptionalUnspecifiedTest) { + getSubnet6WithOptionalUnspecifiedTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6SharedNetworkTest) { + getSubnet6SharedNetworkTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6ByPrefixTest) { + getSubnet6ByPrefixTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6byPrefixSelectorsTest) { + getSubnet6byPrefixSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllSubnets6Test) { + getAllSubnets6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllSubnets6SelectorsTest) { + getAllSubnets6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllSubnets6WithServerTagsTest) { + getAllSubnets6WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSubnets6SelectorsTest) { + getModifiedSubnets6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteSubnet6Test) { + deleteSubnet6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteSubnet6ByIdSelectorsTest) { + deleteSubnet6ByIdSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteSubnet6ByPrefixSelectorsTest) { + deleteSubnet6ByPrefixSelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllSubnets6SelectorsTest) { + deleteAllSubnets6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSubnet6Test) { + unassignedSubnet6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSubnets6Test) { + getModifiedSubnets6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, subnetLifetimeTest) { + subnetLifetimeTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetworkSubnets6Test) { + getSharedNetworkSubnets6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, subnetUpdatePoolsTest) { + subnetUpdatePoolsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, subnetOptionsTest) { + subnetOptionsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6Test) { + getSharedNetwork6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6SelectorsTest) { + getSharedNetwork6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6Test) { + createUpdateSharedNetwork6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6SelectorsTest) { + createUpdateSharedNetwork6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6WithOptionalUnspecifiedTest) { + getSharedNetwork6WithOptionalUnspecifiedTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetworkSubnets6Test) { + deleteSharedNetworkSubnets6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6Test) { + getAllSharedNetworks6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6SelectorsTest) { + getAllSharedNetworks6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6WithServerTagsTest) { + getAllSharedNetworks6WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6Test) { + getModifiedSharedNetworks6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6SelectorsTest) { + getModifiedSharedNetworks6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6Test) { + deleteSharedNetwork6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6SelectorsTest) { + deleteSharedNetwork6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllSharedNetworks6SelectorsTest) { + deleteAllSharedNetworks6SelectorsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSharedNetworkTest) { + unassignedSharedNetworkTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkLifetimeTest) { + sharedNetworkLifetimeTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkOptionsTest) { + sharedNetworkOptionsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getOptionDef6Test) { + getOptionDef6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, optionDefs6WithServerTagsTest) { + optionDefs6WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllOptionDefs6Test) { + getAllOptionDefs6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedOptionDefs6Test) { + getModifiedOptionDefs6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteOption6Test) { + createUpdateDeleteOption6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, globalOptions6WithServerTagsTest) { + globalOptions6WithServerTagsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllOptions6Test) { + getAllOptions6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedOptions6Test) { + getModifiedOptions6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteSubnetOption6Test) { + createUpdateDeleteSubnetOption6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeletePoolOption6Test) { + createUpdateDeletePoolOption6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeletePdPoolOption6Test) { + createUpdateDeletePdPoolOption6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteSharedNetworkOption6Test) { + createUpdateDeleteSharedNetworkOption6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, subnetOptionIdOrderTest) { + subnetOptionIdOrderTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkOptionIdOrderTest) { + sharedNetworkOptionIdOrderTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, setAndGetAllClientClasses6Test) { + setAndGetAllClientClasses6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getClientClass6Test) { + getClientClass6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateClientClass6OptionsTest) { + createUpdateClientClass6OptionsTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedClientClasses6Test) { + getModifiedClientClasses6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteClientClass6Test) { + deleteClientClass6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllClientClasses6Test) { + deleteAllClientClasses6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, clientClassDependencies6Test) { + clientClassDependencies6Test(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, multipleAuditEntriesTest) { + multipleAuditEntriesTest(); +} + +/// @brief Test fixture for verifying database connection loss-recovery +/// behavior. +class MySqlConfigBackendDHCPv6DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest { +public: + /// @brief Constructor + MySqlConfigBackendDHCPv6DbLostCallbackTest() {}; + + /// @brief Destructor + virtual ~MySqlConfigBackendDHCPv6DbLostCallbackTest() {}; + + /// @brief Creates the MySQL CB schema. + virtual void createSchema() { + createMySQLSchema(); + } + + /// @brief Destroys the MySQL CB schema. + virtual void destroySchema() { + destroyMySQLSchema(); + } + + /// @brief Method which returns a valid back end specific connection + /// string + virtual std::string validConnectionString() { + return (validMySQLConnectionString()); + } + + /// @brief Method which returns an invalid back end specific connection + /// string. + virtual std::string invalidConnectionString() { + return (connectionString(MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, + VALID_USER, VALID_PASSWORD)); + } + + /// @brief Registers MySQL as a CB backend type. + virtual void registerBackendType() { + isc::dhcp::MySqlConfigBackendDHCPv6::registerBackendType(); + } + + /// @brief Unregisters MySQL as a CB backend type. + virtual void unregisterBackendType() { + isc::dhcp::MySqlConfigBackendDHCPv6::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::MySqlConfigBackendImpl::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(MySqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailure) { + MultiThreadingTest mt(false); + testNoCallbackOnOpenFailure(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) { + MultiThreadingTest mt(true); + testNoCallbackOnOpenFailure(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndRecoveredAfterTimeoutCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) { + MultiThreadingTest mt(false); + testDbLostAndFailedAfterTimeoutCallback(); +} + +TEST_F(MySqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) { + MultiThreadingTest mt(true); + testDbLostAndFailedAfterTimeoutCallback(); +} + +} diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_impl_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_impl_unittest.cc new file mode 100644 index 0000000..b25f047 --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_impl_unittest.cc @@ -0,0 +1,60 @@ +// Copyright (C) 2019-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 <mysql_cb_impl.h> +#include <gtest/gtest.h> + +using namespace isc::db; +using namespace isc::dhcp; +using namespace isc::util; + +namespace { + +// Test that the MySQL binding can be created from a triplet. +TEST(MySqlConfigBackendImplTest, createBindingFromTriplet) { + // Create a binding from an unspecified triplet. + auto binding = MySqlConfigBackendImpl::createBinding(Triplet<uint32_t>()); + // The binding pointer should be non-null but the type of the binding + // should be null. + ASSERT_TRUE(binding); + EXPECT_TRUE(binding->amNull()); + + // This time create a triplet encapsulating a number. + binding = MySqlConfigBackendImpl::createBinding(Triplet<uint32_t>(123)); + ASSERT_TRUE(binding); + // The binding type should be non-null. + ASSERT_FALSE(binding->amNull()); + ASSERT_EQ(MYSQL_TYPE_LONG, binding->getType()); + // Check that the correct value was stored in the binding. + EXPECT_EQ(123, binding->getInteger<uint32_t>()); +} + +// Test that the triplet can be created from the MySQL binding. +TEST(MySqlConfigBackendImplTest, createTripletFromBinding) { + // Create a binding encapsulating a number and try to create a triplet + // from this binding. + MySqlBindingPtr binding = MySqlBinding::createInteger<uint32_t>(234); + Triplet<uint32_t> triplet; + ASSERT_NO_THROW(triplet = MySqlConfigBackendImpl::createTriplet(binding)); + + // The triplet should be specified and equal to the value stored in the + // binding. + ASSERT_FALSE(triplet.unspecified()); + EXPECT_EQ(234, triplet.get()); + + // Create a null binding and then use it to create a triplet. + binding = MySqlBinding::createNull(); + ASSERT_NO_THROW(triplet = MySqlConfigBackendImpl::createTriplet(binding)); + // This time the triplet should be unspecified. + EXPECT_TRUE(triplet.unspecified()); + + // Finally, make sure that the null binding pointer is rejected. + EXPECT_THROW(MySqlConfigBackendImpl::createTriplet(MySqlBindingPtr()), + isc::Unexpected); +} + +} // namespace diff --git a/src/hooks/dhcp/mysql_cb/tests/run_unittests.cc b/src/hooks/dhcp/mysql_cb/tests/run_unittests.cc new file mode 100644 index 0000000..6ec23da --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/tests/run_unittests.cc @@ -0,0 +1,20 @@ +// Copyright (C) 2017-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 <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/mysql_cb/version.cc b/src/hooks/dhcp/mysql_cb/version.cc new file mode 100644 index 0000000..8f9df4f --- /dev/null +++ b/src/hooks/dhcp/mysql_cb/version.cc @@ -0,0 +1,18 @@ +// Copyright (C) 2018-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); +} + +} |