diff --git a/.gitignore b/.gitignore
index 9afda8d91e..46f6973e3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,9 @@ config.h.in~
/test-driver
/ylwrap
+/.cproject
+/.project
+/.vscode
/all.info
/coverage-cpp-html
/dns++.pc
@@ -45,3 +48,5 @@ config.h.in~
/logger_lockfile
/report.info
+*.tmp
+*parser.dot
diff --git a/Makefile.am b/Makefile.am
index 2c0733c29c..c23fe48402 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -110,8 +110,8 @@ endif
--output report.info; \
sed --in-place --expression "s|$(abs_top_srcdir)|$(abs_top_builddir)|g" report.info; \
"$(GENHTML)" --frames --show-details --title 'Kea code coverage report' --legend \
- --function-coverage --ignore-errors source --demangle-cpp \
- --output "$(OVERALL_COVERAGE_DIR)" report.info; \
+ --function-coverage --ignore-errors source --demangle-cpp \
+ --output "$(OVERALL_COVERAGE_DIR)" report.info; \
printf "Generated C++ code coverage report in HTML at %s.\n" "$(OVERALL_COVERAGE_DIR)"; \
else \
echo "C++ code coverage not enabled at configuration time." ; \
diff --git a/configure.ac b/configure.ac
index 00842da9bc..49f403927d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,15 +62,15 @@ AC_SUBST(SEP)
# If cross compiling assume the message compiler executable was
# magically already in place...
if test "$cross_compiling" = "yes"; then
- AC_MSG_CHECKING("build (vs. host) compiled message compiler")
- if test -x "${srcdir}/src/lib/log/compiler/message"; then
- AC_MSG_RESULT(yes)
- else
- AC_MSG_RESULT(no)
- AC_MSG_WARN("you must install a message compiler in:")
- AC_MSG_WARN(" ${srcdir}/src/lib/log/compiler/message")
- AC_MSG_WARN("compiled for build ($build).")
- fi
+ AC_MSG_CHECKING("build (vs. host) compiled message compiler")
+ if test -x "${srcdir}/src/lib/log/compiler/message"; then
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN("you must install a message compiler in:")
+ AC_MSG_WARN(" ${srcdir}/src/lib/log/compiler/message")
+ AC_MSG_WARN("compiled for build ($build).")
+ fi
fi
AM_CONDITIONAL([CROSS_COMPILING], [test "$cross_compiling" = "yes"])
@@ -410,7 +410,7 @@ case "$host" in
;;
esac
if [ test $kea_undefined_pthread_behavior = "yes" ]; then
- AC_DEFINE([HAS_UNDEFINED_PTHREAD_BEHAVIOR], [1], [Does this platform have some undefined pthreads behavior?])
+ AC_DEFINE([HAS_UNDEFINED_PTHREAD_BEHAVIOR], [1], [Does this platform have some undefined pthreads behavior?])
fi
# Our experiments have shown Solaris 10 has broken support for the
@@ -816,7 +816,7 @@ if test "$CQL_CONFIG" != "" ; then
CQL_INCLUDEDIR=`$CQL_CONFIG --cflags-only-I $cql_lib`
CQL_CPPFLAGS="`$CQL_CONFIG --cflags-only-other $cql_lib` $CQL_INCLUDEDIR"
- CQL_LIBS="`$CQL_CONFIG --libs $cql_lib`"
+ CQL_LIBS="`$CQL_CONFIG --libs $cql_lib`"
CQL_VERSION=`$CQL_CONFIG --modversion $cql_lib`
AC_SUBST(CQL_CPPFLAGS)
@@ -1403,6 +1403,8 @@ AC_CONFIG_FILES([Makefile
src/bin/perfdhcp/Makefile
src/bin/perfdhcp/tests/Makefile
src/bin/perfdhcp/tests/testdata/Makefile
+ src/bin/kea_config_tool/Makefile
+ src/bin/kea_config_tool/tests/Makefile
src/bin/shell/Makefile
src/bin/shell/kea-shell
src/bin/shell/tests/Makefile
@@ -1492,6 +1494,8 @@ AC_CONFIG_FILES([Makefile
src/share/database/scripts/Makefile
src/share/database/scripts/cql/Makefile
src/share/database/scripts/cql/upgrade_1.0_to_2.0.sh
+ src/share/database/scripts/cql/config_upgrade_0.0_to_1.0.sh
+ src/share/database/scripts/cql/master_upgrade_0.0_to_1.0.sh
src/share/database/scripts/mysql/Makefile
src/share/database/scripts/mysql/upgrade_1.0_to_2.0.sh
src/share/database/scripts/mysql/upgrade_2.0_to_3.0.sh
@@ -1501,6 +1505,8 @@ AC_CONFIG_FILES([Makefile
src/share/database/scripts/mysql/upgrade_5.0_to_5.1.sh
src/share/database/scripts/mysql/upgrade_5.1_to_5.2.sh
src/share/database/scripts/mysql/upgrade_5.2_to_6.0.sh
+ src/share/database/scripts/mysql/config_upgrade_0.0_to_1.0.sh
+ src/share/database/scripts/mysql/master_upgrade_0.0_to_1.0.sh
src/share/database/scripts/pgsql/Makefile
src/share/database/scripts/pgsql/upgrade_1.0_to_2.0.sh
src/share/database/scripts/pgsql/upgrade_2.0_to_3.0.sh
@@ -1508,6 +1514,8 @@ AC_CONFIG_FILES([Makefile
src/share/database/scripts/pgsql/upgrade_3.1_to_3.2.sh
src/share/database/scripts/pgsql/upgrade_3.2_to_3.3.sh
src/share/database/scripts/pgsql/upgrade_3.3_to_4.0.sh
+ src/share/database/scripts/pgsql/config_upgrade_0.0_to_1.0.sh
+ src/share/database/scripts/pgsql/master_upgrade_0.0_to_1.0.sh
tools/Makefile
tools/path_replacer.sh
])
@@ -1672,9 +1680,9 @@ if test "$CQL_CPPFLAGS" != "" ; then
cat >> config.report << END
Cassandra CQL:
- CQL_VERSION: ${CQL_VERSION}
- CQL_CPPFLAGS: ${CQL_CPPFLAGS}
- CQL_LIBS: ${CQL_LIBS}
+ CQL_VERSION: ${CQL_VERSION}
+ CQL_CPPFLAGS: ${CQL_CPPFLAGS}
+ CQL_LIBS: ${CQL_LIBS}
END
else
cat >> config.report << END
@@ -1696,6 +1704,7 @@ Google Test:
END
else
cat >> config.report << END
+
Google Test:
no
END
@@ -1714,6 +1723,7 @@ Google Benchmark:
END
else
cat >> config.report << END
+
Google Benchmark:
no
END
diff --git a/doc/.gitignore b/doc/.gitignore
index fd8742ed43..e7d9de716b 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -1,2 +1,3 @@
/version.ent
-html
+/html
+/latex
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 16cffb0ba0..716da2c4ac 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -57,6 +57,48 @@ nobase_dist_doc_DATA += examples/kea6/simple.json
nobase_dist_doc_DATA += examples/kea6/softwire46.json
nobase_dist_doc_DATA += examples/kea6/stateless.json
nobase_dist_doc_DATA += examples/kea6/with-ddns.json
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea4/kea4-master-mysql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea4/kea4-master-pgsql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea4/kea4-master-cql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea4/kea4-shard-mysql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea4/kea4-shard-pgsql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea4/kea4-shard-cql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea6/kea6-master-mysql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea6/kea6-master-pgsql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea6/kea6-master-cql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea6/kea6-shard-mysql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea6/kea6-shard-pgsql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/local/kea6/kea6-shard-cql.conf
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.generic
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/servers.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/credentials.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.generic
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/servers.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/credentials.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.generic
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/servers.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/credentials.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.generic
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/servers.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/credentials.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.generic
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea4/kea_shard/servers.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea4/kea_shard/credentials.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.generic
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea6/kea_shard/servers.json
+nobase_dist_doc_DATA += examples/kea-config-tool/initial-config-cql/kea6/kea_shard/credentials.json
+nobase_dist_doc_DATA += examples/kea-config-tool/master-db-connect-mysql.ini
+nobase_dist_doc_DATA += examples/kea-config-tool/master-db-connect-pgsql.ini
+nobase_dist_doc_DATA += examples/kea-config-tool/master-db-connect-cql.ini
+nobase_dist_doc_DATA += examples/kea-config-tool/shard-db-connect-mysql.ini
+nobase_dist_doc_DATA += examples/kea-config-tool/shard-db-connect-pgsql.ini
+nobase_dist_doc_DATA += examples/kea-config-tool/shard-db-connect-cql.ini
devel:
mkdir -p html
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.generic b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.generic
new file mode 100644
index 0000000000..3cd318ee95
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.generic
@@ -0,0 +1,3 @@
+#####################################################
+############### FOR FUTURE USE #####################
+#####################################################
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.json b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.json
new file mode 100644
index 0000000000..d8cdb7f9d0
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/config.json
@@ -0,0 +1,35 @@
+{
+ "Dhcp4": {
+ "lease-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_shard",
+ "max-statement-tries": 1,
+ "password": "keatest",
+ "type": "cql",
+ "user": "keatest"
+ },
+ "expired-leases-processing": {
+ "flush-reclaimed-timer-wait-time": 25,
+ "hold-reclaimed-time": 3600,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 250,
+ "reclaim-timer-wait-time": 10,
+ "unwarned-reclaim-cycles": 5
+ },
+ "valid-lifetime": 40,
+ "renew-timer": 10,
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.16 - 192.0.2.128"
+ }
+ ],
+ "relay": {
+ "ip-address": "192.0.2.1"
+ }
+ }
+ ]
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/credentials.json b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/credentials.json
new file mode 100644
index 0000000000..66f1dd2e2a
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/credentials.json
@@ -0,0 +1,9 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "cql",
+ "password": "keatest",
+ "keyspace": "kea_shard",
+ "contact-points": "127.0.0.1"
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/servers.json b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/servers.json
new file mode 100644
index 0000000000..6dcfc9ebf0
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea4/kea_shard/servers.json
@@ -0,0 +1,37 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "cql",
+ "password": "keatest",
+ "keyspace": "kea_shard",
+ "contact-points": "127.0.0.1"
+ },
+ "master-config": [
+ {
+ "instance-id": "kea-dhcp4-server",
+ "server-config": {
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [
+ "ens4"
+ ]
+ }
+ },
+ "Logging": {
+ "loggers": [
+ {
+ "name": "kea-dhcp4",
+ "output_options": [
+ {
+ "output": "/var/log/kea-dhcp4.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.generic b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.generic
new file mode 100644
index 0000000000..3cd318ee95
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.generic
@@ -0,0 +1,3 @@
+#####################################################
+############### FOR FUTURE USE #####################
+#####################################################
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.json b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.json
new file mode 100644
index 0000000000..6995411c0b
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/config.json
@@ -0,0 +1,47 @@
+{
+ "Dhcp6": {
+ "server-id": {
+ "htype": 1,
+ "identifier": "56847afe6699",
+ "time": 512640186,
+ "type": "LLT"
+ },
+ "lease-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_shard",
+ "max-statement-tries": 1,
+ "password": "keatest",
+ "type": "cql",
+ "user": "keatest"
+ },
+ "expired-leases-processing": {
+ "flush-reclaimed-timer-wait-time": 25,
+ "hold-reclaimed-time": 3600,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 250,
+ "reclaim-timer-wait-time": 10,
+ "unwarned-reclaim-cycles": 5
+ },
+ "preferred-lifetime": 30,
+ "valid-lifetime": 40,
+ "renew-timer": 10,
+ "rebind-timer": 20,
+ "subnet6": [
+ {
+ "subnet": "3001:db8:1::/48",
+ "pools": [
+ {
+ "pool": "3001:db8:1::/80"
+ }
+ ],
+ "pd-pools": [
+ {
+ "prefix": "3001:db8:1:1::",
+ "prefix-len": 80,
+ "delegated-len": 96
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/credentials.json b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/credentials.json
new file mode 100644
index 0000000000..66f1dd2e2a
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/credentials.json
@@ -0,0 +1,9 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "cql",
+ "password": "keatest",
+ "keyspace": "kea_shard",
+ "contact-points": "127.0.0.1"
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/servers.json b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/servers.json
new file mode 100644
index 0000000000..c3bba83394
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-cql/kea6/kea_shard/servers.json
@@ -0,0 +1,37 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "cql",
+ "password": "keatest",
+ "keyspace": "kea_shard",
+ "contact-points": "127.0.0.1"
+ },
+ "master-config": [
+ {
+ "instance-id": "kea-dhcp6-server",
+ "server-config": {
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [
+ "ens4/2001:db8:1::1"
+ ]
+ }
+ },
+ "Logging": {
+ "loggers": [
+ {
+ "name": "kea-dhcp6",
+ "output_options": [
+ {
+ "output": "/var/log/kea-dhcp6.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.generic b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.generic
new file mode 100644
index 0000000000..3cd318ee95
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.generic
@@ -0,0 +1,3 @@
+#####################################################
+############### FOR FUTURE USE #####################
+#####################################################
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.json b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.json
new file mode 100644
index 0000000000..b6b3daae07
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/config.json
@@ -0,0 +1,34 @@
+{
+ "Dhcp4": {
+ "lease-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ },
+ "expired-leases-processing": {
+ "flush-reclaimed-timer-wait-time": 25,
+ "hold-reclaimed-time": 3600,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 250,
+ "reclaim-timer-wait-time": 10,
+ "unwarned-reclaim-cycles": 5
+ },
+ "valid-lifetime": 40,
+ "renew-timer": 10,
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.16 - 192.0.2.128"
+ }
+ ],
+ "relay": {
+ "ip-address": "192.0.2.1"
+ }
+ }
+ ]
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/credentials.json b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/credentials.json
new file mode 100644
index 0000000000..dd45e8c5b3
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/credentials.json
@@ -0,0 +1,9 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "mysql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/servers.json b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/servers.json
new file mode 100644
index 0000000000..17eb815963
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea4/kea_shard/servers.json
@@ -0,0 +1,37 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "mysql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ },
+ "master-config": [
+ {
+ "instance-id": "kea-dhcp4-server",
+ "server-config": {
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [
+ "ens4"
+ ]
+ }
+ },
+ "Logging": {
+ "loggers": [
+ {
+ "name": "kea-dhcp4",
+ "output_options": [
+ {
+ "output": "/var/log/kea-dhcp4.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.generic b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.generic
new file mode 100644
index 0000000000..3cd318ee95
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.generic
@@ -0,0 +1,3 @@
+#####################################################
+############### FOR FUTURE USE #####################
+#####################################################
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.json b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.json
new file mode 100644
index 0000000000..56fc58dc40
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/config.json
@@ -0,0 +1,46 @@
+{
+ "Dhcp6": {
+ "server-id": {
+ "htype": 1,
+ "identifier": "56847afe6699",
+ "time": 512640186,
+ "type": "LLT"
+ },
+ "lease-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ },
+ "expired-leases-processing": {
+ "flush-reclaimed-timer-wait-time": 25,
+ "hold-reclaimed-time": 3600,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 250,
+ "reclaim-timer-wait-time": 10,
+ "unwarned-reclaim-cycles": 5
+ },
+ "preferred-lifetime": 30,
+ "valid-lifetime": 40,
+ "renew-timer": 10,
+ "rebind-timer": 20,
+ "subnet6": [
+ {
+ "subnet": "3001:db8:1::/48",
+ "pools": [
+ {
+ "pool": "3001:db8:1::/80"
+ }
+ ],
+ "pd-pools": [
+ {
+ "prefix": "3001:db8:1:1::",
+ "prefix-len": 80,
+ "delegated-len": 96
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/credentials.json b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/credentials.json
new file mode 100644
index 0000000000..dd45e8c5b3
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/credentials.json
@@ -0,0 +1,9 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "mysql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/servers.json b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/servers.json
new file mode 100644
index 0000000000..2ba7b233ce
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-mysql/kea6/kea_shard/servers.json
@@ -0,0 +1,37 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "mysql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ },
+ "master-config": [
+ {
+ "instance-id": "kea-dhcp6-server",
+ "server-config": {
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [
+ "ens4/2001:db8:1::1"
+ ]
+ }
+ },
+ "Logging": {
+ "loggers": [
+ {
+ "name": "kea-dhcp6",
+ "output_options": [
+ {
+ "output": "/var/log/kea-dhcp6.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.generic b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.generic
new file mode 100644
index 0000000000..3cd318ee95
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.generic
@@ -0,0 +1,3 @@
+#####################################################
+############### FOR FUTURE USE #####################
+#####################################################
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.json b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.json
new file mode 100644
index 0000000000..15d8695b54
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/config.json
@@ -0,0 +1,34 @@
+{
+ "Dhcp4": {
+ "lease-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ },
+ "expired-leases-processing": {
+ "flush-reclaimed-timer-wait-time": 25,
+ "hold-reclaimed-time": 3600,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 250,
+ "reclaim-timer-wait-time": 10,
+ "unwarned-reclaim-cycles": 5
+ },
+ "valid-lifetime": 40,
+ "renew-timer": 10,
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.16 - 192.0.2.128"
+ }
+ ],
+ "relay": {
+ "ip-address": "192.0.2.1"
+ }
+ }
+ ]
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/credentials.json b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/credentials.json
new file mode 100644
index 0000000000..8e97420584
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/credentials.json
@@ -0,0 +1,9 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "postgresql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/servers.json b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/servers.json
new file mode 100644
index 0000000000..a509b3547b
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea4/kea_shard/servers.json
@@ -0,0 +1,37 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "postgresql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ },
+ "master-config": [
+ {
+ "instance-id": "kea-dhcp4-server",
+ "server-config": {
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [
+ "ens4"
+ ]
+ }
+ },
+ "Logging": {
+ "loggers": [
+ {
+ "name": "kea-dhcp4",
+ "output_options": [
+ {
+ "output": "/var/log/kea-dhcp4.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.generic b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.generic
new file mode 100644
index 0000000000..3cd318ee95
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.generic
@@ -0,0 +1,3 @@
+#####################################################
+############### FOR FUTURE USE #####################
+#####################################################
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.json b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.json
new file mode 100644
index 0000000000..8ac5b1be5d
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/config.json
@@ -0,0 +1,46 @@
+{
+ "Dhcp6": {
+ "server-id": {
+ "htype": 1,
+ "identifier": "56847afe6699",
+ "time": 512640186,
+ "type": "LLT"
+ },
+ "lease-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ },
+ "expired-leases-processing": {
+ "flush-reclaimed-timer-wait-time": 25,
+ "hold-reclaimed-time": 3600,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 250,
+ "reclaim-timer-wait-time": 10,
+ "unwarned-reclaim-cycles": 5
+ },
+ "preferred-lifetime": 30,
+ "valid-lifetime": 40,
+ "renew-timer": 10,
+ "rebind-timer": 20,
+ "subnet6": [
+ {
+ "subnet": "3001:db8:1::/48",
+ "pools": [
+ {
+ "pool": "3001:db8:1::/80"
+ }
+ ],
+ "pd-pools": [
+ {
+ "prefix": "3001:db8:1:1::",
+ "prefix-len": 80,
+ "delegated-len": 96
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/credentials.json b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/credentials.json
new file mode 100644
index 0000000000..8e97420584
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/credentials.json
@@ -0,0 +1,9 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "postgresql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ }
+}
diff --git a/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/servers.json b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/servers.json
new file mode 100644
index 0000000000..f8eb84e6e6
--- /dev/null
+++ b/doc/examples/kea-config-tool/initial-config-pgsql/kea6/kea_shard/servers.json
@@ -0,0 +1,37 @@
+{
+ "config-database": {
+ "user": "keatest",
+ "type": "postgresql",
+ "password": "keatest",
+ "name": "kea_shard",
+ "host": "127.0.0.1"
+ },
+ "master-config": [
+ {
+ "instance-id": "kea-dhcp6-server",
+ "server-config": {
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [
+ "ens4/2001:db8:1::1"
+ ]
+ }
+ },
+ "Logging": {
+ "loggers": [
+ {
+ "name": "kea-dhcp6",
+ "output_options": [
+ {
+ "output": "/var/log/kea-dhcp6.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/doc/examples/kea-config-tool/local/kea4/kea4-master-cql.conf b/doc/examples/kea-config-tool/local/kea4/kea4-master-cql.conf
new file mode 100644
index 0000000000..5f84100b63
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea4/kea4-master-cql.conf
@@ -0,0 +1,14 @@
+{
+ "Dhcp4": {
+ "instance-id": "kea-dhcp4-server",
+ "configuration-type": "database",
+ "master-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_master",
+ "max-statement-tries": 1,
+ "password": "keatest",
+ "type": "cql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea4/kea4-master-mysql.conf b/doc/examples/kea-config-tool/local/kea4/kea4-master-mysql.conf
new file mode 100644
index 0000000000..19d00f6d75
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea4/kea4-master-mysql.conf
@@ -0,0 +1,13 @@
+{
+ "Dhcp4": {
+ "instance-id": "kea-dhcp4-server",
+ "configuration-type": "database",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea4/kea4-master-pgsql.conf b/doc/examples/kea-config-tool/local/kea4/kea4-master-pgsql.conf
new file mode 100644
index 0000000000..83ee23c171
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea4/kea4-master-pgsql.conf
@@ -0,0 +1,13 @@
+{
+ "Dhcp4": {
+ "instance-id": "kea-dhcp4-server",
+ "configuration-type": "database",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea4/kea4-shard-cql.conf b/doc/examples/kea-config-tool/local/kea4/kea4-shard-cql.conf
new file mode 100644
index 0000000000..bde83dd557
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea4/kea4-shard-cql.conf
@@ -0,0 +1,18 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "config-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_shard",
+ "max-statement-tries": 1,
+ "password": "keatest",
+ "type": "cql",
+ "user": "keatest"
+ },
+ "interfaces-config": {
+ "interfaces": [
+ "ens4"
+ ]
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea4/kea4-shard-mysql.conf b/doc/examples/kea-config-tool/local/kea4/kea4-shard-mysql.conf
new file mode 100644
index 0000000000..eba53a82d8
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea4/kea4-shard-mysql.conf
@@ -0,0 +1,17 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ },
+ "interfaces-config": {
+ "interfaces": [
+ "ens4"
+ ]
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea4/kea4-shard-pgsql.conf b/doc/examples/kea-config-tool/local/kea4/kea4-shard-pgsql.conf
new file mode 100644
index 0000000000..3a14417e8e
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea4/kea4-shard-pgsql.conf
@@ -0,0 +1,17 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ },
+ "interfaces-config": {
+ "interfaces": [
+ "ens4"
+ ]
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea6/kea6-master-cql.conf b/doc/examples/kea-config-tool/local/kea6/kea6-master-cql.conf
new file mode 100644
index 0000000000..eb0e92e565
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea6/kea6-master-cql.conf
@@ -0,0 +1,14 @@
+{
+ "Dhcp6": {
+ "instance-id": "kea-dhcp6-server",
+ "configuration-type": "database",
+ "master-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_master",
+ "max-statement-tries": 1,
+ "password": "keatest",
+ "type": "cql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea6/kea6-master-mysql.conf b/doc/examples/kea-config-tool/local/kea6/kea6-master-mysql.conf
new file mode 100644
index 0000000000..9cf67e8172
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea6/kea6-master-mysql.conf
@@ -0,0 +1,13 @@
+{
+ "Dhcp6": {
+ "instance-id": "kea-dhcp6-server",
+ "configuration-type": "database",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea6/kea6-master-pgsql.conf b/doc/examples/kea-config-tool/local/kea6/kea6-master-pgsql.conf
new file mode 100644
index 0000000000..b20593e4f6
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea6/kea6-master-pgsql.conf
@@ -0,0 +1,13 @@
+{
+ "Dhcp6": {
+ "instance-id": "kea-dhcp6-server",
+ "configuration-type": "database",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea6/kea6-shard-cql.conf b/doc/examples/kea-config-tool/local/kea6/kea6-shard-cql.conf
new file mode 100644
index 0000000000..17eb29a6f8
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea6/kea6-shard-cql.conf
@@ -0,0 +1,18 @@
+{
+ "Dhcp6": {
+ "configuration-type": "database",
+ "config-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_shard",
+ "max-statement-tries": 1,
+ "password": "keatest",
+ "type": "cql",
+ "user": "keatest"
+ },
+ "interfaces-config": {
+ "interfaces": [
+ "ens4/2001:db8:1::1"
+ ]
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea6/kea6-shard-mysql.conf b/doc/examples/kea-config-tool/local/kea6/kea6-shard-mysql.conf
new file mode 100644
index 0000000000..fdb99ec48d
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea6/kea6-shard-mysql.conf
@@ -0,0 +1,17 @@
+{
+ "Dhcp6": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ },
+ "interfaces-config": {
+ "interfaces": [
+ "ens4/2001:db8:1::1"
+ ]
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/local/kea6/kea6-shard-pgsql.conf b/doc/examples/kea-config-tool/local/kea6/kea6-shard-pgsql.conf
new file mode 100644
index 0000000000..3512d09fe7
--- /dev/null
+++ b/doc/examples/kea-config-tool/local/kea6/kea6-shard-pgsql.conf
@@ -0,0 +1,17 @@
+{
+ "Dhcp6": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ },
+ "interfaces-config": {
+ "interfaces": [
+ "ens4/2001:db8:1::1"
+ ]
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/master-db-connect-cql.ini b/doc/examples/kea-config-tool/master-db-connect-cql.ini
new file mode 100644
index 0000000000..778550f51d
--- /dev/null
+++ b/doc/examples/kea-config-tool/master-db-connect-cql.ini
@@ -0,0 +1,26 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "instance-id": "kea-config-tool",
+ "master-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_master",
+ "max-statement-tries": 1,
+ "password": "",
+ "type": "cql",
+ "user": ""
+ }
+ },
+ "Dhcp6": {
+ "configuration-type": "database",
+ "instance-id": "kea-config-tool",
+ "master-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_master",
+ "max-statement-tries": 1,
+ "password": "",
+ "type": "cql",
+ "user": ""
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/master-db-connect-mysql.ini b/doc/examples/kea-config-tool/master-db-connect-mysql.ini
new file mode 100644
index 0000000000..abe2561275
--- /dev/null
+++ b/doc/examples/kea-config-tool/master-db-connect-mysql.ini
@@ -0,0 +1,24 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "instance-id": "kea-config-tool",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ }
+ },
+ "Dhcp6": {
+ "configuration-type": "database",
+ "instance-id": "kea-config-tool",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/master-db-connect-pgsql.ini b/doc/examples/kea-config-tool/master-db-connect-pgsql.ini
new file mode 100644
index 0000000000..4977a4e59c
--- /dev/null
+++ b/doc/examples/kea-config-tool/master-db-connect-pgsql.ini
@@ -0,0 +1,24 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "instance-id": "kea-config-tool",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ }
+ },
+ "Dhcp6": {
+ "configuration-type": "database",
+ "instance-id": "kea-config-tool",
+ "master-database": {
+ "host": "127.0.0.1",
+ "name": "kea_master",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/shard-db-connect-cql.ini b/doc/examples/kea-config-tool/shard-db-connect-cql.ini
new file mode 100644
index 0000000000..a2371e77fe
--- /dev/null
+++ b/doc/examples/kea-config-tool/shard-db-connect-cql.ini
@@ -0,0 +1,24 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "config-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_shard",
+ "max-statement-tries": 1,
+ "password": "",
+ "type": "cql",
+ "user": ""
+ }
+ },
+ "Dhcp6": {
+ "configuration-type": "database",
+ "config-database": {
+ "contact-points": "127.0.0.1",
+ "keyspace": "kea_shard",
+ "max-statement-tries": 1,
+ "password": "",
+ "type": "cql",
+ "user": ""
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/shard-db-connect-mysql.ini b/doc/examples/kea-config-tool/shard-db-connect-mysql.ini
new file mode 100644
index 0000000000..22f094797d
--- /dev/null
+++ b/doc/examples/kea-config-tool/shard-db-connect-mysql.ini
@@ -0,0 +1,22 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ }
+ },
+ "Dhcp6": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "mysql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea-config-tool/shard-db-connect-pgsql.ini b/doc/examples/kea-config-tool/shard-db-connect-pgsql.ini
new file mode 100644
index 0000000000..708648825b
--- /dev/null
+++ b/doc/examples/kea-config-tool/shard-db-connect-pgsql.ini
@@ -0,0 +1,22 @@
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ }
+ },
+ "Dhcp6": {
+ "configuration-type": "database",
+ "config-database": {
+ "host": "127.0.0.1",
+ "name": "kea_shard",
+ "password": "keatest",
+ "type": "postgresql",
+ "user": "keatest"
+ }
+ }
+}
diff --git a/doc/examples/kea4/backends.json b/doc/examples/kea4/backends.json
index dc59289441..9ce41e292e 100644
--- a/doc/examples/kea4/backends.json
+++ b/doc/examples/kea4/backends.json
@@ -72,7 +72,8 @@
// "type": "cql",
// "keyspace": "keatest",
// "contact-points": "192.0.2.1,192.0.2.2,192.0.2.3",
-// "port": 9042
+// "port": 9042,
+// "max-statement-tries": 3
// },
// Addresses will be assigned with a lifetime of 4000 seconds.
diff --git a/doc/examples/kea4/cassandra.json b/doc/examples/kea4/cassandra.json
index e26c79a352..7ebf42c2cf 100644
--- a/doc/examples/kea4/cassandra.json
+++ b/doc/examples/kea4/cassandra.json
@@ -35,6 +35,10 @@
// in milliseconds. The default is 5000 [ms].
"connect-timeout": 5000,
+ // Maximum number of tries for a statement (i.e. select, insert, update,
+ // delete) before giving up and throwing an exception
+ "max-statement-tries": 1,
+
// This parameter sets the timeout for waiting for a response
// from a node. Expressed in milliseconds. The default is 12000 [ms].
"request-timeout": 12000,
diff --git a/doc/examples/kea6/backends.json b/doc/examples/kea6/backends.json
index 7a3c087aac..f9665bfe29 100644
--- a/doc/examples/kea6/backends.json
+++ b/doc/examples/kea6/backends.json
@@ -72,7 +72,8 @@
// "type": "cql",
// "keyspace": "keatest",
// "contact-points": "192.0.2.1,192.0.2.2,192.0.2.3",
-// "port": 9042
+// "port": 9042,
+// "max-statement-tries": 3
// },
// Addresses will be assigned with preferred and valid lifetimes
diff --git a/doc/examples/kea6/cassandra.json b/doc/examples/kea6/cassandra.json
index 2733105913..0814ed2017 100644
--- a/doc/examples/kea6/cassandra.json
+++ b/doc/examples/kea6/cassandra.json
@@ -34,6 +34,10 @@
// in milliseconds. The default is 5000 [ms].
"connect-timeout": 5000,
+ // Maximum number of tries for a statement (i.e. select, insert, update,
+ // delete) before giving up and throwing an exception
+ "max-statement-tries": 1,
+
// This parameter sets the timeout for waiting for a response
// from a node. Expressed in milliseconds. The default is 12000 [ms].
"request-timeout": 12000,
diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am
index 1cb54cc6fc..c23dcc4a70 100644
--- a/doc/guide/Makefile.am
+++ b/doc/guide/Makefile.am
@@ -10,6 +10,7 @@ DOCBOOK += keactrl.xml dhcp4-srv.xml dhcp6-srv.xml lease-expiration.xml logging.
DOCBOOK += ddns.xml hooks.xml hooks-ha.xml hooks-host-cache.xml hooks-radius.xml
DOCBOOK += hooks-stat-cmds.xml libdhcp.xml lfc.xml stats.xml ctrl-channel.xml
DOCBOOK += faq.xml classify.xml shell.xml agent.xml
+DOCBOOK += kea-config-tool.xml
EXTRA_DIST = $(DOCBOOK)
diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml
index 6fcb4dd7c6..7e05d163c0 100644
--- a/doc/guide/dhcp4-srv.xml
+++ b/doc/guide/dhcp4-srv.xml
@@ -578,6 +578,7 @@ immediately upon detecting a loss of connectivity (MySQL and Postgres only).
"type": "cql",
"keyspace": "keatest",
"contact-points": "192.0.2.1, 192.0.2.2, 192.0.2.3",
+ "max-statement-tries": 1,
"port": 9042,
"reconnect-wait-time": 2000,
"connect-timeout": 5000,
diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml
index 3c3fcc94c2..6355cb3f2f 100644
--- a/doc/guide/dhcp6-srv.xml
+++ b/doc/guide/dhcp6-srv.xml
@@ -1405,7 +1405,7 @@ temporarily override a list of interface names and listen on all interfaces.
s46-br90ipv6-addressfalse
s46-dmr91ipv6-prefixfalse
s46-v4v6bind92record (ipv4-address, ipv6-prefix)false
-s46-portparams93record(uint8, psid)false
+s46-portparams93record (uint8, psid)false
s46-cont-mape94emptyfalse
s46-cont-mapt95emptyfalse
s46-cont-lw96emptyfalse
diff --git a/doc/guide/intro.xml b/doc/guide/intro.xml
index 1d0d1f32c4..a88ea04ef4 100644
--- a/doc/guide/intro.xml
+++ b/doc/guide/intro.xml
@@ -79,7 +79,7 @@
- In order to store lease information in a MySQL database, Kea requires MySQL
+ In order to store lease information in a MySQL database, Kea requires MySQL
headers and libraries. This is an optional dependency in that Kea can be
built without MySQL support.
@@ -87,7 +87,7 @@
- In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL
+ In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL
headers and libraries. This is an optional dependency in that Kea can be
built without PostgreSQL support.
@@ -95,7 +95,7 @@
- In order to store lease information in a Cassandra database (CQL), Kea
+ In order to store lease information in a Cassandra database (CQL), Kea
requires Cassandra headers and libraries. This is an optional dependency
in that Kea can be built without Cassandra support.
@@ -158,12 +158,19 @@
+
+
+ kea-config-tool —
+ A tool used to reconfigure a Kea server in realtime.
+
+
+
kea-lfc —
This process removes redundant information from the files used
to provide persistent storage for the memfile data base backend.
- While it can be run standalone, it is normally run as and when
+ While it can be run standalone, it is normally run as and when
required by the Kea DHCP servers.
diff --git a/doc/guide/kea-config-tool.xml b/doc/guide/kea-config-tool.xml
new file mode 100644
index 0000000000..adbd4ccda5
--- /dev/null
+++ b/doc/guide/kea-config-tool.xml
@@ -0,0 +1,280 @@
+
+Kea Config Tool
+
+ Kea Configuration Tool is a tool used by system administrators to
+ initialize and maintain Kea server configuration when the server uses
+ database backend for leases, reservations and stateless configuration.
+
+
+ The tool can be used to manage both DHCPv4 and DHCPv6 server
+ configurations.
+
+ The executable file's name is kea-config-tool.
+
+
+ The dependencies are statically linked so no Kea libraries are
+ required in order to run it.
+
+Usage
+
+
+ There are three types of commands supported by the tool:
+
+ -dbinit:
+ Database initialization
+ -shard:
+ Operations with shards databases
+ -master:
+ Operations with the master database
+
+
+
+ -dbinit command
+
+
+ The -dbinit command is a wrapper for
+ kea-admin. When passed as argument to
+ kea-config-tool, it executes the kea-admin
+ and returns it’s exit status.
+
+ It can be used to create and delete databases, intialize tables
+ that store leases, hosts, reservations or any other usual Kea table.
+ Also, this supports creation of server configuration tables in shard
+ databases and master database.
+
+
+ -shard command
+
+
+ This command is able to write server configuration data into
+ shards and save server configuration data from shards.
+
+ Command format
+
+ To write the provided server configuration into shards:
+ -shard -set-config -4|-6 master-config-file
+ input-shards-directory-path [list-of-shards]
+ To retrieve server configuration from shards and writes them
+ locally: -shard -get-config -4|-6 master-config-file
+ output-shards-directory-path list-of-shards
+
+
+ Command options
+
+
+ -4|-6: specifies if the operation
+ applies either to the DHCPv4 server or to the DHCPv6 server
+
+ master-config-file:
+ configuration file which provides backend credentials to the
+ master database.
+ The following is a DHCPv4 configuration example:
+
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "master-database": {
+ "type": "cql",
+ "keyspace": "kea_master",
+ "contact-points": "127.0.0.1",
+ "max-statement-tries": 1,
+ "name": "keatest",
+ "user": "keatest",
+ "password": "keatest",
+ "port": "9042"
+ }
+ }
+}
+
+ And a DHCPv6 configuration example:
+
+{
+ "Dhcp6": {
+ "configuration-type": "database",
+ "master-database": {
+ "type": "cql",
+ "keyspace": "kea_master",
+ "contact-points": "127.0.0.1",
+ "max-statement-tries": 1,
+ "name": "keatest",
+ "user": "keatest",
+ "password": "keatest",
+ "port": "9042"
+ }
+ }
+}
+
+
+ input-shards-directory-path: the path
+ to the shards configuration directory. The directory must
+ contain one directory for each shard database. It is mandatory
+ that the shard directory has the same name as the shard
+ database. The directory should contain the following shard
+ configuration files: config.json,
+ config.generic, config.timestamp
+ . The config.json file contains
+ the JSON server configuration data and is required by the Kea
+ server. The config.generic file may contain
+ generic data (i.e. YAML or other format) used by system
+ administrators to generate the JSON configuration data. The
+ config.timestamp file contains the
+ timestamp of the database record. If the
+ config.timestamp file is missing then the timestamp
+ of the configuration is considered zero.
+ output-shards-directory-path: the path
+ where the shards configuration files will be stored. A directory
+ structure containing shard settings is created.
+ list-of-shards: comma-separated
+ shards' names for which the command is applied (for the case
+ when list-of-shards is optional and no value
+ is provided then the command is executed for all found shards).
+
+
+
+
+
+ -master command
+
+
+ This command is able to write server configuration data into the
+ master database and save server configuration data from the master
+ database.
+
+ Command format
+
+
+ To write the provided server configuration into shards:
+ -master -set-servers -4|-6 master-config-file
+ input-shards-directory-path [list-of-shards]
+ To retrieve server configuration locally from shards:
+ -master -get-servers -4|-6 master-config-file
+ output-shards-directory-path list-of-shards
+
+
+ Command options
+
+
+ -4|-6: specifies if the operation
+ applies either to the DHCPv4 server or to the DHCPv6 server
+
+ master-config-file: configuration
+ file which provides backend credentials to the master database.
+ The following is a DHCPv4 configuration example:
+
+{
+ "Dhcp4": {
+ "configuration-type": "database",
+ "master-database": {
+ "type": "cql",
+ "keyspace": "kea_master",
+ "contact-points": "127.0.0.1",
+ "max-statement-tries": 1,
+ "name": "keatest",
+ "user": "keatest",
+ "password": "keatest",
+ "port": "9042"
+ }
+ }
+}
+
+ And a DHCPv6 configuration example:
+
+{
+ "Dhcp6": {
+ "configuration-type": "database",
+ "master-database": {
+ "type": "cql",
+ "keyspace": "kea_master",
+ "contact-points": "127.0.0.1",
+ "max-statement-tries": 1,
+ "name": "keatest",
+ "user": "keatest",
+ "password": "keatest",
+ "port": "9042"
+ }
+ }
+}
+
+
+ input-shards-directory-path: the path
+ to the shards configuration directory. The directory must
+ contain one directory for each shard database. It is mandatory
+ that the shard directory has the same name as the shard
+ database. The directory should contain the following shard
+ configuration files: config.json,
+ config.generic, config.timestamp
+ . The config.json file contains
+ the JSON server configuration data and is required by the Kea
+ server. The config.generic file may contain
+ generic data (i.e. YAML or other format) used by system
+ administrators to generate the JSON configuration data. The
+ config.timestamp file contains the
+ timestamp of the database record. If the
+ config.timestamp file is missing then the timestamp
+ of the configuration is considered zero.
+ output-shards-directory-path: the path
+ where the shards configuration files will be stored. A directory
+ structure containing shard settings is created.
+ list-of-shards: comma-separated
+ shards' names for which the command is applied (for the case
+ when list-of-shards is optional and no value
+ is provided then the command is executed for all found shards).
+
+
+
+
+
+Building with DataStax Cassandra C++ Driver
+
+ Package dependencies:
+
+ autoconf
+ automake
+ autotools-dev
+ g++
+ libboost-system-dev
+ liblog4cplus
+ libtool
+ libuv0
+ libuv-dev
+ m4
+ make
+ python-support
+
+
+
+ Get the sources from
+ https://gitlab.qualitance.com/terastream/dhcp/tree/kea-datastax
+ into /path/to/kea/sources
+ .
+
+ Download datastax_scripts.tar.
+
+ Untar datastax_scripts.tar:
+ tar -fvxz datastax_scripts.tar
+
+ Download the DataStax C++ driver from
+ https://github.com/datastax/cpp-driver.
+
+ Set the path to the DataStax cpp driver in
+ datastax_cassandra_config_defines.sh configuration file:
+ DSC_PATH="/path/to/datastax/cpp/driver"
+
+
+ Run build and install commands:
+
+ mkdir /usr/kea
+ cd /path/to/kea/sources
+
+ autoreconf --install
+ ./configure --enable-static-link
+ --enable-static
+ --with-cql=/path/to/datastax/script/directory/datastax_cassandra_config.sh
+ --prefix=/usr/kea
+ make
+ sudo make install
+
+
+
+
+
diff --git a/doc/guide/lfc.xml b/doc/guide/lfc.xml
index e689bde5aa..b90fe696bc 100644
--- a/doc/guide/lfc.xml
+++ b/doc/guide/lfc.xml
@@ -15,7 +15,7 @@
kea-lfc is a service process that removes
redundant information from the files used to provide persistent storage
for the memfile data base backend. This service is written to run as a
- stand alone process.
+ stand alone process.
While kea-lfc can be started externally, there is
usually no need to do this. kea-lfc is run on a periodic
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index 67bd58a5c4..2452a26161 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -1,5 +1,5 @@
# The following build order must be maintained.
-SUBDIRS = dhcp4 dhcp6 d2 agent perfdhcp admin lfc keactrl
+SUBDIRS = dhcp4 dhcp6 d2 agent perfdhcp admin lfc keactrl kea_config_tool
if KEA_SHELL
SUBDIRS += shell
diff --git a/src/bin/admin/admin-utils.sh b/src/bin/admin/admin-utils.sh
index 2a9d4dccf8..649c31f779 100755
--- a/src/bin/admin/admin-utils.sh
+++ b/src/bin/admin/admin-utils.sh
@@ -18,12 +18,34 @@
mysql_execute() {
QUERY=$1
shift
- if [ $# -gt 1 ]; then
- mysql -N -B "$@" -e "${QUERY}"
+ if [ $# -gt 0 ]; then
+ cmdline=$(mysql_compose_connect_cmd_line)
+ cmdline="$cmdline $* -e \"$QUERY\""
+ eval "mysql " $cmdline
retcode=$?
else
- mysql -N -B --database="${db_name}" --user="${db_user}" --password="${db_password}" -e "${QUERY}"
- retcode=$?
+ cmdline=$(mysql_compose_connect_cmd_line)
+ cmdline="$cmdline -e \"$QUERY\" $db_name"
+ eval "mysql " $cmdline
+ retcode="$?"
+ fi
+
+ return $retcode
+}
+
+mysql_execute_no_dbname() {
+ QUERY=$1
+ shift
+
+ cmdline=$(mysql_compose_connect_cmd_line)
+ cmdline="$cmdline -e \"$QUERY\""
+
+ eval "mysql " $cmdline
+ retcode="$?"
+
+ if [ $retcode -ne 0 ]; then
+ printf "mysql returned with exit status $retcode\n"
+ exit $retcode
fi
return $retcode
@@ -32,22 +54,80 @@ mysql_execute() {
mysql_execute_script() {
file=$1
shift
- if [ $# -ge 1 ]; then
- mysql -N -B "$@" < "${file}"
+ if [ $# -gt 0 ]; then
+ cmdline=$(mysql_compose_connect_cmd_line)
+ eval "mysql " $cmdline $* < ${file}
retcode=$?
else
- mysql -N -B --database="${db_name}" --user="${db_user}" --password="${db_password}" < "${file}"
- retcode=$?
+ cmdline=$(mysql_compose_connect_cmd_line)
+ eval "mysql "$cmdline $db_name < ${file}
+ retcode="$?"
fi
return $retcode
}
mysql_version() {
- mysql_execute "SELECT CONCAT_WS('.', version, minor) FROM schema_version" "$@"
+ mysql_execute "SELECT CONCAT_WS('.', version, minor) FROM schema_version;" "$@"
return $?
}
+mysql_config_version() {
+ VERSION="0.0"
+
+ RESULT=$(mysql_execute "SHOW TABLES;" "$@")
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "mysql_config_version table query failed, mysql status = $ERRCODE"
+ exit 1
+ fi
+
+ COUNT=$(echo $RESULT | grep config_schema_version | wc -w)
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "mysql_config_version table query failed, mysql status = $ERRCODE"
+ exit 1
+ fi
+
+ if [ $COUNT -gt 0 ]; then
+ VERSION=$(mysql_execute "SELECT CONCAT(version,'.',minor) FROM config_schema_version;" "$@")
+ fi
+ ERRCODE=$?
+ echo $VERSION
+
+ return $ERRCODE
+}
+
+mysql_master_version() {
+ VERSION="0.0"
+
+ RESULT=`mysql_execute "SHOW TABLES;" "$@"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "mysql_master_version table query failed, mysql status = $ERRCODE"
+ exit 1
+ fi
+
+ COUNT=`echo $RESULT | grep master_schema_version | wc -w`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "mysql_master_version table query failed, mysql status = $ERRCODE"
+ exit 1
+ fi
+
+ if [ $COUNT -gt 0 ]; then
+ VERSION=$(mysql_execute "SELECT CONCAT(version,'.',minor) FROM master_schema_version;" "$@")
+ fi
+ ERRCODE=$?
+ echo $VERSION
+
+ return $ERRCODE
+}
+
# Submits given SQL text to PostgreSQL
# There are two ways of calling this method.
# pgsql_execute SQL_QUERY - This call is simpler, but requires db_user,
@@ -62,16 +142,38 @@ pgsql_execute() {
QUERY=$1
shift
if [ $# -gt 0 ]; then
- echo "${QUERY}" | psql --set ON_ERROR_STOP=1 -A -t -h localhost -q "$@"
+ export PGPASSWORD=$db_password
+ cmdline=$(pgsql_compose_connect_cmd_line)
+ cmdline="$cmdline $*"
+ echo $QUERY | psql $cmdline
retcode=$?
else
export PGPASSWORD=$db_password
- echo "${QUERY}" | psql --set ON_ERROR_STOP=1 -A -t -h localhost -q -U "${db_user}" -d "${db_name}"
+ cmdline=$(pgsql_compose_connect_cmd_line)
+ cmdline="$cmdline -d $db_name"
+ echo $QUERY | psql $cmdline
retcode=$?
fi
return $retcode
}
+pgsql_execute_no_dbname() {
+ QUERY=$1
+ shift
+ export PGPASSWORD=$db_password
+ cmdline=$(pgsql_compose_connect_cmd_line)
+# Sometimes we don't need to connect to a specific database
+# (e.g. when we want to create a new one)
+# Postgresql client requires to connect all the time a database.
+# The first database is always created by the initdb command when
+# the data storage area is initialized is called postgres.
+# So we will connect to the default database "postgres")
+ cmdline="$cmdline -d postgres"
+ echo $QUERY | psql $cmdline
+ retcode=$?
+ return $retcode
+}
+
# Submits SQL in a given file to PostgreSQL
# There are two ways of calling this method.
# pgsql_execute SQL_FILE - This call is simpler, but requires db_user,
@@ -86,11 +188,16 @@ pgsql_execute_script() {
file=$1
shift
if [ $# -gt 0 ]; then
- psql --set ON_ERROR_STOP=1 -A -t -h localhost -q -f "${file}" "$@"
+ export PGPASSWORD=$db_password
+ cmdline=$(pgsql_compose_connect_cmd_line)
+ cmdline="$cmdline -d $db_name -f $file $*"
+ eval "psql "$cmdline
retcode=$?
else
export PGPASSWORD=$db_password
- psql --set ON_ERROR_STOP=1 -A -t -h localhost -q -U "${db_user}" -d "${db_name}" -f "${file}"
+ cmdline=$(pgsql_compose_connect_cmd_line)
+ cmdline="$cmdline -d $db_name -f $file"
+ eval "psql "$cmdline
retcode=$?
fi
return $retcode
@@ -101,14 +208,74 @@ pgsql_version() {
return $?
}
+pgsql_config_version() {
+ VERSION="0.0"
+
+ RESULT=`pgsql_execute "\d" "$@"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "pgsql_config_version table query failed, pgsql status = $ERRCODE"
+ exit 1
+ fi
+
+ COUNT=`echo $RESULT | grep config_schema_version | wc -w`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "pgsql_config_version table query failed, pgsql status = $ERRCODE"
+ exit 1
+ fi
+
+ if [ $COUNT -gt 0 ]; then
+ VERSION=`pgsql_execute "SELECT version || '.' || minor FROM config_schema_version" "$@"`
+ fi
+ ERRCODE=$?
+ echo $VERSION
+
+ return $ERRCODE
+}
+
+pgsql_master_version() {
+ VERSION="0.0"
+
+ RESULT=`pgsql_execute "\d" "$@"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "pgsql_master_version table query failed, pgsql status = $ERRCODE"
+ exit 1
+ fi
+
+ COUNT=`echo $RESULT | grep master_schema_version | wc -w`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ printf "pgsql_master_version table query failed, pgsql status = $ERRCODE"
+ exit 1
+ fi
+
+ if [ $COUNT -gt 0 ]; then
+ VERSION=`pgsql_execute "SELECT version || '.' || minor FROM master_schema_version" "$@"`
+ fi
+ ERRCODE=$?
+ echo $VERSION
+
+ return $ERRCODE
+}
+
cql_execute() {
query=$1
shift
- if [ $# -gt 1 ]; then
- cqlsh "$@" -e "$query"
+ if [ $# -gt 0 ]; then
+ cmdline=$(cql_compose_connect_cmd_line)
+ cmdline="$cmdline $* -e \"$query\""
+ eval "cqlsh " $cmdline
retcode=$?
else
- cqlsh -u "${db_user}" -p "${db_password}" -k "${db_name}" -e "${query}"
+ cmdline=$(cql_compose_connect_cmd_line)
+ cmdline="$cmdline -k $db_name -e \"$query\""
+ eval "cqlsh " $cmdline
retcode=$?
fi
@@ -120,14 +287,35 @@ cql_execute() {
return $retcode
}
+cql_execute_no_keyspace() {
+ query=$1
+ shift
+
+ cmdline=$(cql_compose_connect_cmd_line)
+ cmdline="$cmdline -e \"$query\""
+ eval "cqlsh " $cmdline
+ retcode=$?
+
+ if [ $retcode -ne 0 ]; then
+ printf "cqlsh returned with exit status $retcode\n"
+ exit $retcode
+ fi
+
+ return $retcode
+}
+
cql_execute_script() {
file=$1
shift
- if [ $# -gt 1 ]; then
- cqlsh "$@" -e "$file"
+ if [ $# -gt 0 ]; then
+ cmdline=$(cql_compose_connect_cmd_line)
+ cmdline="$cmdline $* -f \"$file\""
+ eval "cqlsh " $cmdline
retcode=$?
else
- cqlsh -u "${db_user}" -p "${db_password}" -k "${db_name}" -f "${file}"
+ cmdline=$(cql_compose_connect_cmd_line)
+ cmdline="$cmdline -k $db_name -f \"$file\""
+ eval "cqlsh " $cmdline
retcode=$?
fi
@@ -143,6 +331,117 @@ cql_version() {
version=$(cql_execute "SELECT version, minor FROM schema_version" "$@")
error=$?
version=$(echo "$version" | grep -A 1 "+" | grep -v "+" | tr -d ' ' | cut -d "|" -f 1-2 | tr "|" ".")
- echo "$version"
+ echo $version
+ return $error
+}
+
+cql_config_version() {
+ version="0.0"
+ result=$(cql_execute "DESCRIBE tables;" "$@")
+ count=$(echo $result | grep config_schema_version | wc -w)
+ if [ $count -gt 0 ]; then
+ version=$(cql_execute "SELECT version, minor FROM config_schema_version" "$@")
+ version=$(echo "$version" | grep -A 1 "+" | grep -v "+" | tr -d ' ' | cut -d "|" -f 1-2 --output-delimiter=".")
+ fi
+ error=$?
+ echo $version
return $error
}
+
+cql_master_version() {
+ version="0.0"
+ result=$(cql_execute "DESCRIBE tables;" "$@")
+ count=$(echo $result | grep master_schema_version | wc -w)
+ if [ $count -gt 0 ]; then
+ version=$(cql_execute "SELECT version, minor FROM master_schema_version" "$@")
+ version=$(echo "$version" | grep -A 1 "+" | grep -v "+" | tr -d ' ' | cut -d "|" -f 1-2 --output-delimiter=".")
+ fi
+ error=$?
+ echo $version
+ return $error
+}
+
+mysql_compose_connect_cmd_line() {
+ local line="-N -B"
+
+ if [ -n "$db_server_address" ]; then
+ line="$line --host=$db_server_address"
+ fi
+
+ if [ -n "$db_server_port" ]; then
+ line="$line --port=$db_server_port"
+ fi
+
+ if [ -n "$db_user" ]; then
+ line="$line --user=$db_user"
+ fi
+
+ if [ -n "$db_password" ]; then
+ line="$line --password=$db_password"
+ fi
+
+ if [ -n "$db_host" ]; then
+ line="$line --host=$db_host"
+ fi
+
+ echo $line
+}
+
+pgsql_compose_connect_cmd_line() {
+ local line="--set ON_ERROR_STOP=1 -A -t -q"
+
+ if [ -n "$db_server_address" ]
+ then
+ line="$line -h $db_server_address"
+ else
+ if [ -n "$db_host" ]; then
+ line="$line -h $db_host"
+ else
+ line="$line -h localhost"
+ fi
+ fi
+
+ if [ -n "$db_server_port" ]; then
+ line="$line -p $db_server_port"
+ fi
+
+ if [ -n "$db_user" ]; then
+ line="$line -U $db_user"
+ fi
+
+ if [ -n "$db_host" ]; then
+ line="$line -h $db_host"
+ fi
+
+ echo $line
+}
+
+cql_compose_connect_cmd_line() {
+ local line=""
+
+ if [ -n "$db_server_address" ]; then
+ line=$line" "$db_server_address
+ fi
+
+ if [ -n "$db_server_port" ]; then
+ line=$line" "$db_server_port
+ fi
+
+ if [ -n "$db_server_version" ]; then
+ line=$line" --cqlversion="$db_server_version
+ fi
+
+ if [ -n "$db_user" ]; then
+ line=$line" -u "$db_user
+ fi
+
+ if [ -n "$db_password" ]; then
+ line=$line" -p "$db_password
+ fi
+
+ if [ -n "$db_use_ssl" ]; then
+ line=$line" --ssl"
+ fi
+
+ echo $line
+}
diff --git a/src/bin/admin/kea-admin.in b/src/bin/admin/kea-admin.in
index 4be383ddb4..df650d9845 100644
--- a/src/bin/admin/kea-admin.in
+++ b/src/bin/admin/kea-admin.in
@@ -25,6 +25,11 @@ db_host="localhost"
db_user="keatest"
db_password="keatest"
db_name="keatest"
+db_server_address=""
+db_server_port=""
+
+# These are CQL default parameters
+db_server_version=""
# lease dump parameters
dump_type=0
@@ -50,16 +55,32 @@ usage() {
printf "\n"
printf "COMMAND: Currently supported operations are:\n"
printf "\n"
+ printf " - -h or --help: Displays this help.\n"
+ printf " - db-create: Creates new empty databases. Useful for first time installation.\n"
+ printf " - db-remove: Removes an existing database.\n"
+ printf " - create-db-and-users: internal use only\n"
printf " - lease-init: Initializes new lease database. Useful for first time installation.\n"
+ printf " - lease-drop: Drops all tables in the lease database. \n"
printf " - lease-version: Checks version of the existing lease database scheme. Useful\n"
printf " - for checking lease DB version when preparing for an upgrade.\n"
printf " - lease-upgrade: Upgrades your lease database scheme\n"
printf " - lease-dump: Dump current leases to a CSV file\n"
+ printf " - config-init: Initalizes new config database. Useful for first time installation.\n"
+ printf " - config-version: Checks version of the existing config database scheme. Useful\n"
+ printf " - for checking config DB version when preparing for an upgrade.\n"
+ printf " - config-upgrade: Upgrades your config database scheme\n"
+ printf " - master-init: Initalizes new master config database. Useful for first time installation.\n"
+ printf " - master-version: Checks version of the existing master config database scheme. Useful\n"
+ printf " - for checking master config DB version when preparing for an upgrade.\n"
+ printf " - master-upgrade: Upgrades your master config database scheme\n"
printf "\n"
printf "BACKEND - one of the supported backends: memfile|mysql|pgsql|cql\n"
printf "\n"
printf "PARAMETERS: Parameters are optional in general, but may be required\n"
printf " for specific operation.\n"
+ printf " -s or --server - specifies remote database server address\n"
+ printf " -sp or --server-port - specifies remote database server port\n"
+ printf " --db-server-version - specifies remote database version\n"
printf " -h or --host hostname - specifies a hostname of a database to connect to\n"
printf " -u or --user name - specifies username when connecting to a database\n"
printf " -p or --password pass - specifies a password when connecting to a database\n"
@@ -125,12 +146,24 @@ memfile_init() {
exit 1
}
+memfile_config_init() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
+memfile_master_init() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
# Initializes a new, empty MySQL database.
# It essentially calls scripts/mysql/dhcpdb_create.mysql script, with
# some extra sanity checks. It will refuse to use it if there are any
# existing tables. It's better safe than sorry.
mysql_init() {
- printf "Checking if there is a database initialized already. Please ignore errors.\n"
+ printf "Checking if there is a database initialized already.\n"
# Let's try to count the number of tables. Anything above 0 means that there
# is some database in place. If there is anything, we abort. Note that
@@ -140,7 +173,7 @@ mysql_init() {
#
RESULT=`mysql_execute "SHOW TABLES;"`
ERRCODE=$?
- if [ $ERRCODE -ne 0 ]
+ if [ $ERRCODE -ne 0 ]
then
log_error "mysql_init table query failed, mysql status = $ERRCODE"
exit 1
@@ -155,7 +188,7 @@ mysql_init() {
fi
printf "Initializing database using script %s\n" $scripts_dir/mysql/dhcpdb_create.mysql
- mysql -B --host=$db_host --user=$db_user --password=$db_password $db_name < $scripts_dir/mysql/dhcpdb_create.mysql
+ mysql_execute_script $scripts_dir/mysql/dhcpdb_create.mysql
ERRCODE=$?
printf "mysql returned status code $ERRCODE\n"
@@ -169,8 +202,107 @@ mysql_init() {
exit $ERRCODE
}
+#Creates a new, empty MySQL database.
+mysql_db_create() {
+ for name in $(echo $db_name | tr "," "\n")
+ do
+ printf "Creating '$name' database\n"
+
+ command="CREATE DATABASE $name;"
+ RESULT=`mysql_execute_no_dbname "$command"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ log_error "Database creation failed, status code: $ERRCODE?"
+ exit 1
+ fi
+
+ printf "The database has been created.\n"
+ done
+ exit 0
+}
+
+#Removes an existing MySQL database.
+mysql_db_remove() {
+ for name in $(echo $db_name | tr "," "\n")
+ do
+ printf "Removing '$name' database\n"
+
+ command="DROP DATABASE $name;"
+ RESULT=`mysql_execute_no_dbname "$command"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ log_error "Database deletion failed, status code: $ERRCODE?"
+ exit 1
+ fi
+
+ printf "The database has been removed.\n"
+ done
+ exit 0
+}
+
+mysql_config_init() {
+ mysql_execute_script $scripts_dir/mysql/configdb_create.mysql
+
+ version=`mysql_config_version`
+ printf "Config DB version reported after initialization: $version\n"
+
+ exit 0
+}
+
+mysql_master_init() {
+
+ mysql_execute_script $scripts_dir/mysql/masterdb_create.mysql
+
+ version=`mysql_master_version`
+ printf "Config DB version reported after initialization: $version\n"
+
+ exit 0
+}
+
+#Creates a new, empty Postgresql database.
+pgsql_db_create() {
+ for name in $(echo $db_name | tr "," "\n")
+ do
+ printf "Creating '$name' database\n"
+
+ command="CREATE DATABASE $name;"
+ RESULT=`pgsql_execute_no_dbname "$command"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ log_error "Database creation failed, status code: $ERRCODE?"
+ exit 1
+ fi
+
+ printf "The database has been created.\n"
+ done
+ exit 0
+}
+
+#Removes an existing MySQL database.
+pgsql_db_remove() {
+ for name in $(echo $db_name | tr "," "\n")
+ do
+ printf "Removing '$name' database\n"
+
+ command="DROP DATABASE $name;"
+ RESULT=`pgsql_execute_no_dbname "$command"`
+ ERRCODE=$?
+ if [ $ERRCODE -ne 0 ]
+ then
+ log_error "Database deletion failed, status code: $ERRCODE?"
+ exit 1
+ fi
+
+ printf "The database has been removed.\n"
+ done
+ exit 0
+}
+
pgsql_init() {
- printf "Checking if there is a database initialized already. Please ignore errors.\n"
+ printf "Checking if there is a database initialized already.\n"
# Let's try to count the number of tables. Anything above 0 means that there
# is some database in place. If there is anything, we abort.
@@ -202,24 +334,144 @@ pgsql_init() {
exit 0
}
+pgsql_config_init() {
+ pgsql_execute_script $scripts_dir/pgsql/configdb_create.pgsql
+
+ version=`pgsql_config_version`
+ printf "Config DB version reported after initialization: $version\n"
+
+ exit 0
+}
+
+pgsql_master_init() {
+
+ pgsql_execute_script $scripts_dir/pgsql/masterdb_create.pgsql
+
+ version=`pgsql_master_version`
+ printf "Config DB version reported after initialization: $version\n"
+
+ exit 0
+}
+
+# Creates a new, empty CQL database.
+cql_db_create() {
+ #setting default values for the keyspace strategy and replication
+ strategy="SimpleStrategy"
+ replication="1"
+
+ for name in $(echo $db_name | tr "," "\n")
+ do
+ printf "Creating '$name' keyspace\n"
+
+ command="create KEYSPACE $name WITH REPLICATION = { 'class' : '$strategy', 'replication_factor' : $replication };"
+ RESULT=`cql_execute_no_keyspace "$command"`
+ ERRCODE=$?
+ if [ "$ERRCODE" -ne 0 ]; then
+ log_error "Keyspace creation failed, status code: $ERRCODE?"
+ exit 1
+ fi
+
+ printf "The keyspace has been created.\n"
+ done
+
+ exit 0
+}
+
+# Removes an existing CQL database.
+cql_db_remove() {
+ for name in $(echo $db_name | tr "," "\n")
+ do
+ printf "Removing '$name' keyspace\n"
+
+ command="drop KEYSPACE $name"
+ RESULT=`cql_execute_no_keyspace "$command"`
+ ERRCODE=$?
+ if [ "$ERRCODE" -ne 0 ]; then
+ log_error "Keyspace deletion failed, status code: $ERRCODE?"
+ exit 1
+ fi
+
+ printf "The keyspace has been removed.\n"
+ done
+
+ exit 0
+}
+
cql_init() {
- printf "Checking if there is a database initialized already... Please ignore errors.\n"
+ printf "Checking if there is a database initialized already...\n"
result=$(cql_execute "DESCRIBE tables;")
+ cql_exit_code=${?}
if [ $(echo "$result" | grep "" | wc -w) -gt 0 ]; then
printf "Creating and initializing tables using script %s...\n" $scripts_dir/cql/dhcpdb_create.cql
cql_execute_script $scripts_dir/cql/dhcpdb_create.cql
else
- log_error "Expected empty database $db_name, but the following tables are present \n$result. Aborting."
+ if [ ${cql_exit_code} -eq 0 ]; then
+ log_error "ERROR: Expected empty database $db_name, but the following tables are present: \n$result. Aborting."
+ else
+ log_error "ERROR: Unable to execute cql_execute, reason: \n$result. Aborting."
+ fi
exit 2
fi
version=$(cql_version)
- printf "Lease DB version reported after initialization: %s\n" "$version"
+ printf "Lease DB version reported after initialization: %s\n" "${version}"
+
+ exit 0
+}
+
+cql_config_init() {
+ cql_execute_script $scripts_dir/cql/configdb_create.cql
+
+ version=`cql_config_version`
+ printf "Config DB version reported after initialization: $version\n"
exit 0
}
+cql_master_init() {
+ cql_execute_script $scripts_dir/cql/masterdb_create.cql
+
+ version=`cql_master_version`
+ printf "Config DB version reported after initialization: $version\n"
+
+ exit 0
+}
+
+# Drop functions
+memfile_drop() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
+mysql_drop() {
+ script=$scripts_dir/mysql/dhcpdb_drop.mysql
+ printf "Droping tables in database using script $script%s\n"
+ mysql -B --user=$db_user --password=$db_password $db_name < $script
+ return_code=$?
+ printf "mysql_drop returned with code $return_code\n"
+ exit $return_code
+}
+
+pgsql_drop() {
+ script="$scripts_dir/pgsql/dhcpdb_drop.pgsql"
+ printf "Droping tables in database using script $script%s\n"
+ pgsql_execute_script $script
+ return_code=$?
+ printf "pgsql_drop returned with code $return_code\n"
+ exit $return_code
+}
+
+cql_drop() {
+ script="$scripts_dir/cql/dhcpdb_drop.cql"
+ printf "Droping tables in database using script $script%s\n"
+ cql_execute_script $script
+ return_code=$?
+ printf "cql_drop returned with code $return_code\n"
+ exit $return_code
+}
+
### Functions that implement database version checking commands
memfile_version() {
# @todo Implement this as part of #3601
@@ -227,6 +479,18 @@ memfile_version() {
exit 1
}
+memfile_config_version() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
+memfile_master_version() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
### Functions used for upgrade
memfile_upgrade() {
# @todo Implement this as part of #3601
@@ -234,6 +498,20 @@ memfile_upgrade() {
exit 1
}
+### Functions used for upgrade
+memfile_config_upgrade() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
+### Functions used for upgrade
+memfile_master_upgrade() {
+ # @todo Implement this as part of #3601
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
# Upgrades existing MySQL database installation. The idea is that
# it will go over all upgrade scripts from (prefix)/share/kea/scripts/mysql
# and run them one by one. They will be named properly, so they will
@@ -270,6 +548,66 @@ mysql_upgrade() {
printf "\n"
}
+mysql_config_upgrade() {
+
+ printf "Config DB version reported before upgrade: "
+ mysql_config_version
+ printf "\n"
+
+ # Check if the scripts directory exists at all.
+ if [ ! -d ${scripts_dir}/mysql ]; then
+ log_error "Invalid scripts directory: ${scripts_dir}/mysql"
+ exit 1
+ fi
+
+ # Check if there are any files in it
+ num_files=$(find ${scripts_dir}/mysql/config_upgrade*.sh -type f | wc -l)
+ if [ $num_files -eq 0 ]; then
+ log_error "No scripts in ${scripts_dir}/mysql or the directory is not readable or does not have any config_upgrade* scripts."
+ exit 1
+ fi
+
+ for script in ${scripts_dir}/mysql/config_upgrade*.sh
+ do
+ echo "Processing $script file..."
+ sh ${script} --user=${db_user} --password=${db_password} ${db_name}
+ done
+
+ printf "Config DB version reported after upgrade: "
+ mysql_config_version
+ printf "\n"
+}
+
+mysql_master_upgrade() {
+
+ printf "Config DB version reported before upgrade: "
+ mysql_master_version
+ printf "\n"
+
+ # Check if the scripts directory exists at all.
+ if [ ! -d ${scripts_dir}/mysql ]; then
+ log_error "Invalid scripts directory: ${scripts_dir}/mysql"
+ exit 1
+ fi
+
+ Check if there are any files in it
+ num_files=$(find ${scripts_dir}/mysql/master_upgrade*.sh -type f | wc -l)
+ if [ $num_files -eq 0 ]; then
+ log_error "No scripts in ${scripts_dir}/mysql or the directory is not readable or does not have any config_upgrade* scripts."
+ exit 1
+ fi
+
+ for script in ${scripts_dir}/mysql/master_upgrade*.sh
+ do
+ echo "Processing $script file..."
+ sh ${script} --user=${db_user} --password=${db_password} ${db_name}
+ done
+
+ printf "Config DB version reported after upgrade: "
+ mysql_master_version
+ printf "\n"
+}
+
pgsql_upgrade() {
version=`pgsql_version`
printf "Lease DB version reported before upgrade: $version\n"
@@ -289,7 +627,7 @@ pgsql_upgrade() {
# Postgres psql does not accept pw on command line, but can do it
# thru an env
- export PGPASSWORD=$db_password
+ export db_password
for script in ${scripts_dir}/pgsql/upgrade*.sh
do
@@ -302,6 +640,70 @@ pgsql_upgrade() {
exit 0
}
+pgsql_config_upgrade() {
+ version=`pgsql_config_version`
+ printf "Config DB version reported before upgrade: $version\n"
+
+ # Check if the scripts directory exists at all.
+ if [ ! -d ${scripts_dir}/pgsql ]; then
+ log_error "Invalid scripts directory: ${scripts_dir}/pgsql"
+ exit 1
+ fi
+
+ # Check if there are any files in it
+ num_files=$(find ${scripts_dir}/pgsql/config_upgrade*.sh -type f | wc -l)
+ if [ $num_files -eq 0 ]; then
+ log_error "No scripts in ${scripts_dir}/pgsql or the directory is not readable or does not have any config_upgrade* scripts."
+ exit 1
+ fi
+
+ # Postgres psql does not accept pw on command line, but can do it
+ # thru an env
+ export db_password
+
+ for script in ${scripts_dir}/pgsql/config_upgrade*.sh
+ do
+ echo "Processing $script file..."
+ sh ${script} -U ${db_user} -h localhost -d ${db_name}
+ done
+
+ version=`pgsql_config_version`
+ printf "Config DB version reported after upgrade: $version\n"
+ exit 0
+}
+
+pgsql_master_upgrade() {
+ version=`pgsql_master_version`
+ printf "Config DB version reported before upgrade: $version\n"
+
+ # Check if the scripts directory exists at all.
+ if [ ! -d ${scripts_dir}/pgsql ]; then
+ log_error "Invalid scripts directory: ${scripts_dir}/pgsql"
+ exit 1
+ fi
+
+ # Check if there are any files in it
+ num_files=$(find ${scripts_dir}/pgsql/master_upgrade*.sh -type f | wc -l)
+ if [ $num_files -eq 0 ]; then
+ log_error "No scripts in ${scripts_dir}/pgsql or the directory is not readable or does not have any config_upgrade* scripts."
+ exit 1
+ fi
+
+ # Postgres psql does not accept pw on command line, but can do it
+ # thru an env
+ export db_password
+
+ for script in ${scripts_dir}/pgsql/master_upgrade*.sh
+ do
+ echo "Processing $script file..."
+ sh ${script} -U ${db_user} -h localhost -d ${db_name}
+ done
+
+ version=`pgsql_master_version`
+ printf "Config DB version reported after upgrade: $version\n"
+ exit 0
+}
+
cql_upgrade() {
version=`cql_version`
printf "Lease DB version reported before upgrade: $version\n"
@@ -324,7 +726,11 @@ cql_upgrade() {
for script in ${scripts_dir}/cql/upgrade*.sh
do
echo "Processing $script file..."
- sh ${script} -u ${db_user} -p ${db_password} -k ${db_name}
+ if [ -z ${db_server_version} ]; then
+ sh ${script} -u ${db_user} -p ${db_password} -k ${db_name}
+ else
+ sh ${script} -u ${db_user} -p ${db_password} -k ${db_name} --cqlversion=${db_server_version}
+ fi
done
else
echo "No upgrade script available."
@@ -335,6 +741,80 @@ cql_upgrade() {
exit 0
}
+cql_config_upgrade() {
+ version=`cql_config_version`
+ printf "Config DB version reported before upgrade: $version\n"
+
+ # Check if the scripts directory exists at all.
+ if [ ! -d ${scripts_dir}/cql ]; then
+ log_error "Invalid scripts directory: ${scripts_dir}/cql"
+ exit 1
+ fi
+
+ # Check if directory is readable.
+ if [ ! -r ${scripts_dir}/cql ]; then
+ log_error "Directory is not readable: ${scripts_dir}/cql"
+ exit 1
+ fi
+
+ # Check if there are upgrade scripts.
+ files=$(find ${scripts_dir}/cql/config_upgrade*.sh -type f)
+ if [ $? -eq 0 ]; then # Upgrade scripts are present.
+ for script in ${scripts_dir}/cql/config_upgrade*.sh
+ do
+ echo "Processing $script file..."
+ if [ -z ${db_server_version} ]; then
+ sh ${script} -u ${db_user} -p ${db_password} -k ${db_name}
+ else
+ sh ${script} -u ${db_user} -p ${db_password} -k ${db_name} --cqlversion=${db_server_version}
+ fi
+ done
+ else
+ echo "No upgrade script available."
+ fi
+
+ version=`cql_config_version`
+ printf "Config DB version reported after upgrade: $version\n"
+ exit 0
+}
+
+cql_master_upgrade() {
+ version=`cql_master_version`
+ printf "Config DB version reported before upgrade: $version\n"
+
+ # Check if the scripts directory exists at all.
+ if [ ! -d ${scripts_dir}/cql ]; then
+ log_error "Invalid scripts directory: ${scripts_dir}/cql"
+ exit 1
+ fi
+
+ # Check if directory is readable.
+ if [ ! -r ${scripts_dir}/cql ]; then
+ log_error "Directory is not readable: ${scripts_dir}/cql"
+ exit 1
+ fi
+
+ # Check if there are upgrade scripts.
+ files=$(find ${scripts_dir}/cql/master_upgrade*.sh -type f)
+ if [ $? -eq 0 ]; then # Upgrade scripts are present.
+ for script in ${scripts_dir}/cql/master_upgrade*.sh
+ do
+ echo "Processing $script file..."
+ if [ -z ${db_server_version} ]; then
+ sh ${script} -u ${db_user} -p ${db_password} -k ${db_name}
+ else
+ sh ${script} -u ${db_user} -p ${db_password} -k ${db_name} --cqlversion=${db_server_version}
+ fi
+ done
+ else
+ echo "No upgrade script available."
+ fi
+
+ version=`cql_master_version`
+ printf "Config DB version reported after upgrade: $version\n"
+ exit 0
+}
+
# Utility function which tests if the given file exists and
# if so notifies the user and provides them the opportunity
# to abort the current command.
@@ -528,6 +1008,39 @@ cql_dump() {
exit 0
}
+
+memfile_create_database_and_users() {
+ log_error "NOT IMPLEMENTED"
+ exit 1
+}
+
+mysql_create_database_and_users() {
+ for query in "GRANT ALL ON *.* TO keatest IDENTIFIED BY 'keatest';" \
+ "CREATE DATABASE keatest;" \
+ "CREATE USER 'keatest_readonly'@'localhost' IDENTIFIED BY 'keatest';" \
+ "GRANT SELECT ON keatest.* TO keatest_readonly IDENTIFIED BY 'keatest';" \
+ ; do
+ mysql_execute "${query}" --host=${db_server_address} --port=${db_server_port} --user=root --password=${db_password}
+ done
+}
+
+pgsql_create_database_and_users() {
+ export db_password
+ for query in "CREATE USER keatest WITH PASSWORD 'keatest';" \
+ "CREATE DATABASE keatest;" \
+ "GRANT ALL ON DATABASE keatest TO keatest;" \
+ "CREATE USER keatest_readonly WITH PASSWORD 'keatest';" \
+ ; do
+ pgsql_execute "${query}" --host=${db_server_address} --port=${db_server_port} --username=postgres
+ done
+ export db_password="keatest"
+ pgsql_execute "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO keatest_readonly;" --host=${db_server_address} --port=${db_server_port} --username=keatest
+}
+
+cql_create_database_and_users() {
+ cql_execute_no_keyspace "CREATE KEYSPACE keatest WITH replication = {'class' : 'SimpleStrategy','replication_factor' : 1}"
+}
+
### Script starts here ###
# First, find what the command is
@@ -537,7 +1050,11 @@ if [ -z ${command} ]; then
usage
exit 1
fi
-is_in_list "${command}" "lease-init lease-version lease-upgrade lease-dump"
+if [ "${command}" = "-h" -o "${command}" = "--help" ]; then
+ usage
+ exit 0
+fi
+is_in_list "${command}" "db-create db-remove lease-init lease-drop lease-version lease-upgrade lease-dump config-init config-version config-upgrade master-init master-version master-upgrade create-db-and-users"
if [ ${_inlist} -eq 0 ]; then
log_error "invalid command: ${command}"
exit 1
@@ -563,6 +1080,36 @@ while [ ! -z "${1}" ]
do
option=${1}
case ${option} in
+ # Specify server address
+ -s|--server)
+ shift
+ db_server_address=${1}
+ if [ -z ${db_server_address} ]; then
+ log_error "-s or --server requires a parameter"
+ usage
+ exit 1
+ fi
+ ;;
+ # Specify server port
+ -sp|--server-port)
+ shift
+ db_server_port=${1}
+ if [ -z ${db_server_port} ]; then
+ log_error "-sp or --server-port requires a parameter"
+ usage
+ exit 1
+ fi
+ ;;
+ # Specify CQL database version
+ --db-server-version)
+ shift
+ db_server_version=${1}
+ if [ -z ${db_server_version} ]; then
+ log_error "--db-server-version requires a parameter"
+ usage
+ exit 1
+ fi
+ ;;
# Specify database host
-h|--host)
shift
@@ -649,6 +1196,40 @@ do
done
case ${command} in
+ # Create the database
+ db-create)
+ case ${backend} in
+ memfile)
+ log_error "this command is not compatible with memory file backend"
+ ;;
+ mysql)
+ mysql_db_create
+ ;;
+ pgsql)
+ pgsql_db_create
+ ;;
+ cql)
+ cql_db_create
+ ;;
+ esac
+ ;;
+ # Removes the database
+ db-remove)
+ case ${backend} in
+ memfile)
+ log_error "this command is not compatible with memory file backend"
+ ;;
+ mysql)
+ mysql_db_remove
+ ;;
+ pgsql)
+ pgsql_db_remove
+ ;;
+ cql)
+ cql_db_remove
+ ;;
+ esac
+ ;;
# Initialize the database
lease-init)
case ${backend} in
@@ -666,6 +1247,22 @@ case ${command} in
;;
esac
;;
+ lease-drop)
+ case ${backend} in
+ memfile)
+ memfile_drop
+ ;;
+ mysql)
+ mysql_drop
+ ;;
+ pgsql)
+ pgsql_drop
+ ;;
+ cql)
+ cql_drop
+ ;;
+ esac
+ ;;
lease-version)
case ${backend} in
memfile)
@@ -673,7 +1270,6 @@ case ${command} in
;;
mysql)
mysql_version
- printf "\n"
;;
pgsql)
pgsql_version
@@ -715,6 +1311,118 @@ case ${command} in
;;
esac
;;
+ config-init)
+ case ${backend} in
+ memfile)
+ memfile_config_init
+ ;;
+ mysql)
+ mysql_config_init
+ ;;
+ pgsql)
+ pgsql_config_init
+ ;;
+ cql)
+ cql_config_init
+ ;;
+ esac
+ ;;
+ config-version)
+ case ${backend} in
+ memfile)
+ memfile_config_version
+ ;;
+ mysql)
+ mysql_config_version
+ ;;
+ pgsql)
+ pgsql_config_version
+ ;;
+ cql)
+ cql_config_version
+ ;;
+ esac
+ ;;
+ config-upgrade)
+ case ${backend} in
+ memfile)
+ memfile_config_upgrade
+ ;;
+ mysql)
+ mysql_config_upgrade
+ ;;
+ pgsql)
+ pgsql_config_upgrade
+ ;;
+ cql)
+ cql_config_upgrade
+ ;;
+ esac
+ ;;
+ master-init)
+ case ${backend} in
+ memfile)
+ memfile_master_init
+ ;;
+ mysql)
+ mysql_master_init
+ ;;
+ pgsql)
+ pgsql_master_init
+ ;;
+ cql)
+ cql_master_init
+ ;;
+ esac
+ ;;
+ master-version)
+ case ${backend} in
+ memfile)
+ memfile_master_version
+ ;;
+ mysql)
+ mysql_master_version
+ ;;
+ pgsql)
+ pgsql_master_version
+ ;;
+ cql)
+ cql_master_version
+ ;;
+ esac
+ ;;
+ master-upgrade)
+ case ${backend} in
+ memfile)
+ memfile_master_upgrade
+ ;;
+ mysql)
+ mysql_master_upgrade
+ ;;
+ pgsql)
+ pgsql_master_upgrade
+ ;;
+ cql)
+ cql_master_upgrade
+ ;;
+ esac
+ ;;
+ create-db-and-users)
+ case ${backend} in
+ memfile)
+ memfile_create_database_and_users
+ ;;
+ mysql)
+ mysql_create_database_and_users
+ ;;
+ pgsql)
+ pgsql_create_database_and_users
+ ;;
+ cql)
+ cql_create_database_and_users
+ ;;
+ esac
+ ;;
esac
exit 0
diff --git a/src/bin/admin/kea-admin.xml b/src/bin/admin/kea-admin.xml
index 3d69c63d48..737dace93c 100644
--- a/src/bin/admin/kea-admin.xml
+++ b/src/bin/admin/kea-admin.xml
@@ -73,6 +73,35 @@
+
+ -h or --help
+
+ Displays help information.
+
+
+
+
+ db-create
+
+ Creates new empty databases. Useful for first time
+ installation.
+
+
+
+
+ db-remove
+
+ Removes an existing database.
+
+
+
+
+ create-db-and-users
+
+ Internal use only.
+
+
+
lease-init
diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.cql b/src/bin/admin/tests/dhcpdb_create_1.0.cql
index 577f2ae277..bf08101df6 100644
--- a/src/bin/admin/tests/dhcpdb_create_1.0.cql
+++ b/src/bin/admin/tests/dhcpdb_create_1.0.cql
@@ -1,4 +1,4 @@
--- Copyright (C) 2015-2017 Deutsche Telekom AG.
+-- Copyright (C) 2015-2018 Deutsche Telekom AG.
-- Author: Razvan Becheriu
@@ -133,6 +133,8 @@ CREATE TABLE IF NOT EXISTS lease_hwaddr_source (
PRIMARY KEY ((hwaddr_source))
);
+INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (0, 'HWADDR_SOURCE_UNKNOWN');
+
-- Hardware address obtained from raw sockets
INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (1, 'HWADDR_SOURCE_RAW');
@@ -154,6 +156,8 @@ INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (32, 'HWADDR_SOURCE
-- Hardware address extracted from docsis options
INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (64, 'HWADDR_SOURCE_DOCSIS_CMTS');
+INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (128, 'HWADDR_SOURCE_DOCSIS_MODEM');
+
-- Create table holding mapping of the lease states to their names.
-- This is not used in queries from the DHCP server but rather in
-- direct queries from the lease database management tools.
diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.mysql b/src/bin/admin/tests/dhcpdb_create_1.0.mysql
index b4823afbff..9f68439ffe 100644
--- a/src/bin/admin/tests/dhcpdb_create_1.0.mysql
+++ b/src/bin/admin/tests/dhcpdb_create_1.0.mysql
@@ -123,7 +123,7 @@ COMMIT;
#
# Portability
# ===========
-# The "ENGINE = INNODB" on some tables is not portablea to another database
+# The "ENGINE = INNODB" on some tables is not portable to another database
# and will need to be removed.
#
# Some columns contain binary data so are stored as VARBINARY instead of
diff --git a/src/bin/admin/tests/pgsql_tests.sh.in b/src/bin/admin/tests/pgsql_tests.sh.in
index ef0854ef25..16f8d1de33 100644
--- a/src/bin/admin/tests/pgsql_tests.sh.in
+++ b/src/bin/admin/tests/pgsql_tests.sh.in
@@ -488,7 +488,7 @@ pgsql_upgrade_schema_to_version() {
# Postgres psql does not accept pw on command line, but can do it
# thru an env
- export PGPASSWORD=$db_password
+ export db_password
for script in ${db_scripts_dir}/pgsql/upgrade*.sh
do
diff --git a/src/bin/agent/Makefile.am b/src/bin/agent/Makefile.am
index 6b346fb159..cfb0988543 100644
--- a/src/bin/agent/Makefile.am
+++ b/src/bin/agent/Makefile.am
@@ -19,7 +19,7 @@ EXTRA_DIST += agent.dox agent_hooks.dox
if GENERATE_DOCS
kea-ctrl-agent.8: kea-ctrl-agent.xml
@XSLTPROC@ --novalid --xinclude --nonet -o $@ \
- http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
+ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
$(srcdir)/kea-ctrl-agent.xml
else
@@ -109,6 +109,7 @@ parser: agent_lexer.cc location.hh position.hh stack.hh agent_parser.cc agent_pa
# Note C++11 deprecated register still used by flex < 2.6.0
location.hh position.hh stack.hh agent_parser.cc agent_parser.h: agent_parser.yy
$(YACC) --defines=agent_parser.h --report=all --report-file=agent_parser.report -o agent_parser.cc agent_parser.yy
+ $(YACC) --graph --defines=agent_parser.h --report=all --report-file=agent_parser.report -o agent_parser.cc agent_parser.yy
agent_lexer.cc: agent_lexer.ll
$(LEX) --prefix agent_ -o agent_lexer.cc agent_lexer.ll
diff --git a/src/bin/agent/agent_lexer.cc b/src/bin/agent/agent_lexer.cc
index 3a386d84a7..3a85021cc6 100644
--- a/src/bin/agent/agent_lexer.cc
+++ b/src/bin/agent/agent_lexer.cc
@@ -1412,7 +1412,7 @@ unsigned int comment_start_line = 0;
using namespace isc;
using isc::agent::AgentParser;
-};
+} // namespace
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::agent::ParserContext::fatal(msg)
diff --git a/src/bin/agent/agent_lexer.ll b/src/bin/agent/agent_lexer.ll
index aa1f92c825..8dbc05805d 100644
--- a/src/bin/agent/agent_lexer.ll
+++ b/src/bin/agent/agent_lexer.ll
@@ -38,7 +38,7 @@ unsigned int comment_start_line = 0;
using namespace isc;
using isc::agent::AgentParser;
-};
+} // namespace
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::agent::ParserContext::fatal(msg)
diff --git a/src/bin/d2/Makefile.am b/src/bin/d2/Makefile.am
index 9b11c32e5f..ea2a487f2f 100644
--- a/src/bin/d2/Makefile.am
+++ b/src/bin/d2/Makefile.am
@@ -136,6 +136,7 @@ parser: d2_lexer.cc location.hh position.hh stack.hh d2_parser.cc d2_parser.h
# Note C++11 deprecated register still used by flex < 2.6.0
location.hh position.hh stack.hh d2_parser.cc d2_parser.h: d2_parser.yy
$(YACC) --defines=d2_parser.h --report=all --report-file=d2_parser.report -o d2_parser.cc d2_parser.yy
+ $(YACC) --graph --defines=d2_parser.h --report=all --report-file=d2_parser.report -o d2_parser.cc d2_parser.yy
d2_lexer.cc: d2_lexer.ll
$(LEX) --prefix d2_parser_ -o d2_lexer.cc d2_lexer.ll
diff --git a/src/bin/d2/d2_lexer.cc b/src/bin/d2/d2_lexer.cc
index 915f94cab7..fca5683052 100644
--- a/src/bin/d2/d2_lexer.cc
+++ b/src/bin/d2/d2_lexer.cc
@@ -1124,7 +1124,7 @@ bool start_token_flag = false;
isc::d2::D2ParserContext::ParserType start_token_value;
unsigned int comment_start_line = 0;
-};
+} // namespace
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::d2::D2ParserContext::fatal(msg)
diff --git a/src/bin/d2/d2_lexer.ll b/src/bin/d2/d2_lexer.ll
index bc26b334bd..8bc8eacbd8 100644
--- a/src/bin/d2/d2_lexer.ll
+++ b/src/bin/d2/d2_lexer.ll
@@ -34,7 +34,7 @@ bool start_token_flag = false;
isc::d2::D2ParserContext::ParserType start_token_value;
unsigned int comment_start_line = 0;
-};
+} // namespace
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::d2::D2ParserContext::fatal(msg)
diff --git a/src/bin/d2/d2_simple_parser.cc b/src/bin/d2/d2_simple_parser.cc
index 708cb7a24f..5d5e766a36 100644
--- a/src/bin/d2/d2_simple_parser.cc
+++ b/src/bin/d2/d2_simple_parser.cc
@@ -4,6 +4,8 @@
// 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
+
#include
#include
#include
diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am
index cc19d70882..ae967a50ca 100644
--- a/src/bin/dhcp4/Makefile.am
+++ b/src/bin/dhcp4/Makefile.am
@@ -31,7 +31,7 @@ EXTRA_DIST += dhcp4_parser.yy
if GENERATE_DOCS
kea-dhcp4.8: kea-dhcp4.xml
@XSLTPROC@ --novalid --xinclude --nonet -o $@ \
- http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
+ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
$(srcdir)/kea-dhcp4.xml
else
@@ -64,6 +64,8 @@ libdhcp4_la_SOURCES += dhcp4_lexer.ll location.hh position.hh stack.hh
libdhcp4_la_SOURCES += dhcp4_parser.cc dhcp4_parser.h
libdhcp4_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h
+libdhcp4_la_LIBADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
+
nodist_libdhcp4_la_SOURCES = dhcp4_messages.h dhcp4_messages.cc
EXTRA_DIST += dhcp4_messages.mes
@@ -119,6 +121,7 @@ parser: dhcp4_lexer.cc location.hh position.hh stack.hh dhcp4_parser.cc dhcp4_pa
# Note C++11 deprecated register still used by flex < 2.6.0
location.hh position.hh stack.hh dhcp4_parser.cc dhcp4_parser.h: dhcp4_parser.yy
$(YACC) --defines=dhcp4_parser.h --report=all --report-file=dhcp4_parser.report -o dhcp4_parser.cc dhcp4_parser.yy
+ $(YACC) --graph --defines=dhcp4_parser.h --report=all --report-file=dhcp4_parser.report -o dhcp4_parser.cc dhcp4_parser.yy
dhcp4_lexer.cc: dhcp4_lexer.ll
$(LEX) --prefix parser4_ -o dhcp4_lexer.cc dhcp4_lexer.ll
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
index 6f62bd5642..cb7fd643da 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
@@ -5,27 +5,35 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include
+
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
+#include
#include
#include
#include
#include
+
#include
+
+#include
#include
-using namespace isc::data;
+using namespace isc::config;
using namespace isc::dhcp;
+using namespace isc::data;
using namespace isc::hooks;
-using namespace isc::config;
using namespace isc::stats;
using namespace std;
@@ -75,34 +83,6 @@ namespace dhcp {
ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
-void
-ControlledDhcpv4Srv::init(const std::string& file_name) {
- // Configure the server using JSON file.
- ConstElementPtr result = loadConfigFile(file_name);
- int rcode;
- ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
- if (rcode != 0) {
- string reason = comment ? comment->stringValue() :
- "no details available";
- isc_throw(isc::BadValue, reason);
- }
-
- // We don't need to call openActiveSockets() or startD2() as these
- // methods are called in processConfig() which is called by
- // processCommand("config-set", ...)
-
- // Set signal handlers. When the SIGHUP is received by the process
- // the server reconfiguration will be triggered. When SIGTERM or
- // SIGINT will be received, the server will start shutting down.
- signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
- // Set the pointer to the handler function.
- signal_handler_ = signalHandler;
-}
-
-void ControlledDhcpv4Srv::cleanup() {
- // Nothing to do here. No need to disconnect from anything.
-}
-
/// @brief Configure DHCPv4 server using the configuration file specified.
///
/// This function is used to both configure the DHCP server on its startup
@@ -119,16 +99,14 @@ ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
// configuration from a JSON file.
isc::data::ConstElementPtr json;
- isc::data::ConstElementPtr dhcp4;
- isc::data::ConstElementPtr logger;
isc::data::ConstElementPtr result;
// Basic sanity check: file name must not be empty.
try {
if (file_name.empty()) {
// Basic sanity check: file name must not be empty.
- isc_throw(isc::BadValue, "JSON configuration file not specified."
- " Please use -c command line option.");
+ isc_throw(isc::BadValue, "JSON configuration file not specified. Please "
+ "use -c command line option.");
}
// Read contents of the file and parse it as JSON
@@ -182,6 +160,33 @@ ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
return (result);
}
+void
+ControlledDhcpv4Srv::init(const std::string& file_name) {
+ // Configure the server using JSON file.
+ ConstElementPtr result = loadConfigFile(file_name);
+ int rcode;
+ ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
+ if (rcode != 0) {
+ string reason = comment ? comment->stringValue() :
+ "no details available";
+ isc_throw(isc::BadValue, reason);
+ }
+
+ // We don't need to call openActiveSockets() or startD2() as these
+ // methods are called in processConfig() which is called by
+ // processCommand("config-set", ...)
+
+ // Set signal handlers. When the SIGHUP is received by the process
+ // the server reconfiguration will be triggered. When SIGTERM or
+ // SIGINT will be received, the server will start shutting down.
+ signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
+ // Set the pointer to the handler function.
+ signal_handler_ = signalHandler;
+}
+
+void ControlledDhcpv4Srv::cleanup() {
+ // Nothing to do here. No need to disconnect from anything.
+}
ConstElementPtr
ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr) {
@@ -189,28 +194,26 @@ ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr) {
ControlledDhcpv4Srv::getInstance()->shutdown();
} else {
LOG_WARN(dhcp4_logger, DHCP4_NOT_RUNNING);
- ConstElementPtr answer = isc::config::createAnswer(1,
- "Shutdown failure.");
+ ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure.");
return (answer);
}
- ConstElementPtr answer = isc::config::createAnswer(0, "Shutting down.");
+ ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down.");
return (answer);
}
ConstElementPtr
ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
-
/// @todo delete any stored CalloutHandles referring to the old libraries
/// Get list of currently loaded libraries and reload them.
HookLibsCollection loaded = HooksManager::getLibraryInfo();
bool status = HooksManager::loadLibraries(loaded);
if (!status) {
LOG_ERROR(dhcp4_logger, DHCP4_HOOKS_LIBS_RELOAD_FAIL);
- ConstElementPtr answer = isc::config::createAnswer(1,
+ ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR,
"Failed to reload hooks libraries.");
return (answer);
}
- ConstElementPtr answer = isc::config::createAnswer(0,
+ ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
"Hooks libraries successfully reloaded.");
return (answer);
}
@@ -218,7 +221,6 @@ ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
ConstElementPtr
ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
ConstElementPtr /*args*/) {
-
// Get configuration file name.
std::string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
try {
@@ -231,7 +233,7 @@ ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
LOG_ERROR(dhcp4_logger, DHCP4_DYNAMIC_RECONFIGURATION_FAIL)
.arg(file);
return (createAnswer(CONTROL_RESULT_ERROR,
- "Config reload failed:" + string(ex.what())));
+ "Config reload failed: " + string(ex.what())));
}
}
@@ -244,8 +246,7 @@ ControlledDhcpv4Srv::commandConfigGetHandler(const string&,
}
ConstElementPtr
-ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
- ConstElementPtr args) {
+ControlledDhcpv4Srv::commandConfigWriteHandler(const string&, ConstElementPtr args) {
string filename;
if (args) {
@@ -264,6 +265,7 @@ ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
if (filename.empty()) {
// filename parameter was not specified, so let's use whatever we remember
+ // from the command-line
filename = getConfigFile();
}
@@ -297,7 +299,7 @@ ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
ConstElementPtr
ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
ConstElementPtr args) {
- const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
+ const int status_code = CONTROL_RESULT_ERROR;
ConstElementPtr dhcp4;
string message;
@@ -349,7 +351,7 @@ ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
// the logging first in case there's a configuration failure.
int rcode = 0;
isc::config::parseAnswer(rcode, result);
- if (rcode == 0) {
+ if (rcode == CONTROL_RESULT_SUCCESS) {
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
// Use new configuration.
@@ -465,17 +467,16 @@ ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
ElementPtr extended = Element::create(Dhcpv4Srv::getVersion(true));
ElementPtr arguments = Element::createMap();
arguments->set("extended", extended);
- ConstElementPtr answer = isc::config::createAnswer(0,
+ ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
Dhcpv4Srv::getVersion(false),
arguments);
return (answer);
}
ConstElementPtr
-ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
- ConstElementPtr) {
+ControlledDhcpv4Srv::commandBuildReportHandler(const string&, ConstElementPtr) {
ConstElementPtr answer =
- isc::config::createAnswer(0, isc::detail::getConfigReport());
+ isc::config::createAnswer(CONTROL_RESULT_SUCCESS, isc::detail::getConfigReport());
return (answer);
}
@@ -516,8 +517,8 @@ ControlledDhcpv4Srv::processCommand(const string& command,
ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
if (!srv) {
- ConstElementPtr no_srv = isc::config::createAnswer(1,
- "Server object not initialized, so can't process command '" +
+ ConstElementPtr no_srv = isc::config::createAnswer(CONTROL_RESULT_ERROR,
+ "Server object not initialized, can't process command '" +
command + "', arguments: '" + txt + "'.");
return (no_srv);
}
@@ -560,12 +561,11 @@ ControlledDhcpv4Srv::processCommand(const string& command,
return (srv->commandConfigWriteHandler(command, args));
}
- ConstElementPtr answer = isc::config::createAnswer(1,
- "Unrecognized command:" + command);
- return (answer);
+ return(isc::config::createAnswer(CONTROL_RESULT_ERROR, "Unrecognized command: " +
+ command));
} catch (const Exception& ex) {
- return (isc::config::createAnswer(1, "Error while processing command '"
- + command + "':" + ex.what() +
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Error while processing command '" +
+ command + "': " + ex.what() +
", params: '" + txt + "'"));
}
}
@@ -576,6 +576,114 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_RECEIVED)
.arg(config->str());
+ ConstElementPtr answer = configureDhcp4ServerId(config);
+ // Check that configuration was successful.
+ try {
+ int rcode = 0;
+ isc::config::parseAnswer(rcode, answer);
+ if (rcode != 0) {
+ return (answer);
+ }
+ } catch (const std::exception& ex) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Failed to process server identifier: " +
+ string(ex.what())));
+ }
+
+ // Parse (and store in config manager) the 'configuration-type' parameter
+ // in order to decide if the Dhcp4 configuration will be read from the provided
+ // 'config' argument or from database
+ answer = configureDhcp4ServerConfigSource(config);
+
+ // Check that configuration was successful.
+ try {
+ int rcode = 0;
+ isc::config::parseAnswer(rcode, answer);
+ if (rcode != 0) {
+ return (answer);
+ }
+ } catch (const std::exception& ex) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR,
+ "Failed to process server configuration type: " +
+ string(ex.what())));
+ }
+
+ auto stagingCfg = CfgMgr::instance().getStagingCfg();
+ CfgSrvConfigType& configurationType = stagingCfg->getConfigurationType();
+
+ // Read master/shard configuration into dhcpConfig.
+ ConstElementPtr interfacesConfig;
+ if (configurationType.type_ == CfgSrvConfigType::MASTER_DATABASE) {
+ ElementPtr dhcpConfig;
+ ElementPtr databaseLogging;
+ SrvConfigMasterInfoPtr configData;
+ try {
+ ConstElementPtr answer =
+ readDhcpv4SrvConfigFromMasterDatabase(dhcpConfig, databaseLogging, configData);
+ int rcode = 0;
+ parseAnswer(rcode, answer);
+ if (rcode != 0) {
+ return (answer);
+ }
+
+ if (configData == SrvConfigMasterInfoPtr()) {
+ isc_throw(Unexpected, "Null master configuration data returned");
+ }
+ } catch (const exception& ex) {
+ return createAnswer(1, "Failed to process master database server configuration: " +
+ string(ex.what()));
+ }
+
+ // If there's no logging element, we'll just pass NULL pointer,
+ // which will be handled by configureLogger().
+ Daemon::configureLogger(databaseLogging, stagingCfg);
+
+ // Apply the new logger configuration to log4cplus.
+ stagingCfg->applyLoggingCfg();
+
+ ConstElementPtr configDatabase = Element::fromJSON(configData->config_database_);
+ if (configDatabase) {
+ // Update the config manager with the server configuration type
+ configurationType.type_ = CfgSrvConfigType::CONFIG_DATABASE;
+
+ DbAccessParser parser(DBType::CONFIG_DB);
+ CfgDbAccessPtr stagingCfgDbAccess = stagingCfg->getCfgDbAccess();
+ parser.parse(stagingCfgDbAccess, configDatabase);
+ }
+
+ interfacesConfig = dhcpConfig->get("interfaces-config");
+ } else if (configurationType.type_ == CfgSrvConfigType::CONFIG_DATABASE) {
+ interfacesConfig = config->get("interfaces-config");
+ }
+
+ // Read database configuration and apply it to the current configuration.
+ if (configurationType.type_ == CfgSrvConfigType::MASTER_DATABASE ||
+ configurationType.type_ == CfgSrvConfigType::CONFIG_DATABASE) {
+ if (!interfacesConfig) {
+ return createAnswer(
+ 1, "no mandatory 'interfaces-config' entry in the local configuration");
+ }
+
+ ElementPtr databaseConfig;
+ try {
+ ConstElementPtr answer = readDhcpv4SrvConfigFromDatabase(databaseConfig);
+ int rcode = 0;
+ parseAnswer(rcode, answer);
+ if (rcode != 0) {
+ return (answer);
+ }
+ } catch (const exception& ex) {
+ return createAnswer(1,
+ "Failed to process configuration database server configuration: " +
+ string(ex.what()));
+ }
+
+ // Keep the 'interfaces-config' settings from the config file received at startup
+ databaseConfig->set("interfaces-config", interfacesConfig);
+
+ // The configuration for 'Dhcp4' will now point to the one read from the database.
+ config = ConstElementPtr(databaseConfig);
+ }
+
ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
// Single stream instance used in all error clauses
@@ -583,10 +691,10 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
if (!srv) {
err << "Server object not initialized, can't process config.";
- return (isc::config::createAnswer(1, err.str()));
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
- ConstElementPtr answer = configureDhcp4Server(*srv, config);
+ answer = configureDhcp4Server(*srv, config);
// Check that configuration was successful. If not, do not reopen sockets
// and don't bother with DDNS stuff.
@@ -597,8 +705,8 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
return (answer);
}
} catch (const std::exception& ex) {
- err << "Failed to process configuration:" << ex.what();
- return (isc::config::createAnswer(1, err.str()));
+ err << "Failed to process configuration: " << ex.what();
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
// Re-open lease and host database with new parameters.
@@ -610,7 +718,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
cfg_db->createManagers();
} catch (const std::exception& ex) {
err << "Unable to open database: " << ex.what();
- return (isc::config::createAnswer(1, err.str()));
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
// Server will start DDNS communications if its enabled.
@@ -619,7 +727,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
} catch (const std::exception& ex) {
err << "Error starting DHCP_DDNS client after server reconfiguration: "
<< ex.what();
- return (isc::config::createAnswer(1, err.str()));
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
// Setup DHCPv4-over-DHCPv6 IPC
@@ -629,7 +737,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
std::ostringstream err;
err << "error starting DHCPv4-over-DHCPv6 IPC "
" after server reconfiguration: " << ex.what();
- return (isc::config::createAnswer(1, err.str()));
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
// Configuration may change active interfaces. Therefore, we have to reopen
@@ -639,8 +747,8 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
// log warnings. Since we allow that this fails for some interfaces there
// is no need to rollback configuration if socket fails to open on any
// of the interfaces.
- CfgMgr::instance().getStagingCfg()->getCfgIface()->
- openSockets(AF_INET, srv->getPort(), getInstance()->useBroadcast());
+ CfgMgr::instance().getStagingCfg()->getCfgIface()->openSockets(AF_INET, srv->getPort(),
+ getInstance()->useBroadcast());
// Install the timers for handling leases reclamation.
try {
@@ -653,9 +761,13 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
err << "unable to setup timers for periodically running the"
" reclamation of the expired leases: "
<< ex.what() << ".";
- return (isc::config::createAnswer(1, err.str()));
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
+ // Finally, we can commit runtime option definitions in libdhcp++. This is
+ // exception free.
+ LibDHCP::commitRuntimeOptionDefs();
+
// This hook point notifies hooks libraries that the configuration of the
// DHCPv4 server has completed. It provides the hook library with the pointer
// to the common IO service object, new server configuration in the JSON
@@ -683,7 +795,7 @@ isc::data::ConstElementPtr
ControlledDhcpv4Srv::checkConfig(isc::data::ConstElementPtr config) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_RECEIVED)
- .arg(config->str());
+ .arg(config->str());
ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
@@ -692,7 +804,7 @@ ControlledDhcpv4Srv::checkConfig(isc::data::ConstElementPtr config) {
if (!srv) {
err << "Server object not initialized, can't process config.";
- return (isc::config::createAnswer(1, err.str()));
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
return (configureDhcp4Server(*srv, config, true));
@@ -754,21 +866,20 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
CommandMgr::instance().registerCommand("statistic-get",
boost::bind(&StatsMgr::statisticGetHandler, _1, _2));
- CommandMgr::instance().registerCommand("statistic-reset",
- boost::bind(&StatsMgr::statisticResetHandler, _1, _2));
-
- CommandMgr::instance().registerCommand("statistic-remove",
- boost::bind(&StatsMgr::statisticRemoveHandler, _1, _2));
-
CommandMgr::instance().registerCommand("statistic-get-all",
boost::bind(&StatsMgr::statisticGetAllHandler, _1, _2));
+ CommandMgr::instance().registerCommand("statistic-reset",
+ boost::bind(&StatsMgr::statisticResetHandler, _1, _2));
+
CommandMgr::instance().registerCommand("statistic-reset-all",
boost::bind(&StatsMgr::statisticResetAllHandler, _1, _2));
+ CommandMgr::instance().registerCommand("statistic-remove",
+ boost::bind(&StatsMgr::statisticRemoveHandler, _1, _2));
+
CommandMgr::instance().registerCommand("statistic-remove-all",
boost::bind(&StatsMgr::statisticRemoveAllHandler, _1, _2));
-
}
void ControlledDhcpv4Srv::shutdown() {
@@ -792,14 +903,14 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
// Deregister any registered commands (please keep in alphabetic order)
CommandMgr::instance().deregisterCommand("build-report");
CommandMgr::instance().deregisterCommand("config-get");
+ CommandMgr::instance().deregisterCommand("config-set");
CommandMgr::instance().deregisterCommand("config-reload");
CommandMgr::instance().deregisterCommand("config-test");
CommandMgr::instance().deregisterCommand("config-write");
- CommandMgr::instance().deregisterCommand("leases-reclaim");
- CommandMgr::instance().deregisterCommand("libreload");
- CommandMgr::instance().deregisterCommand("config-set");
CommandMgr::instance().deregisterCommand("dhcp-disable");
CommandMgr::instance().deregisterCommand("dhcp-enable");
+ CommandMgr::instance().deregisterCommand("leases-reclaim");
+ CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("shutdown");
CommandMgr::instance().deregisterCommand("statistic-get");
CommandMgr::instance().deregisterCommand("statistic-get-all");
@@ -815,8 +926,148 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
;
}
- server_ = NULL; // forget this instance. Noone should call any handlers at
- // this stage.
+ server_ = NULL; // forget this instance. There should be no callback anymore
+ // at this stage anyway.
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv4Srv::readDhcpv4SrvConfigFromMasterDatabase(
+ isc::data::ElementPtr& db_local_config,
+ isc::data::ElementPtr& db_logging,
+ SrvConfigMasterInfoPtr& configData) {
+
+ std::string server_id = CfgMgr::instance().getStagingCfg()->getInstanceId();
+
+ // Re-open configuration database with new parameters.
+ try {
+ CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+ cfg_db->setAppendedParameters("universe=4");
+ cfg_db->createSrvMasterCfgManagers();
+
+ // Read the contents from database
+ configData = SrvConfigMasterMgrFactory::instance().getConfig4(server_id);
+ if (configData == SrvConfigMasterInfoPtr()) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR,
+ "No entry found in master database for server id: "
+ + server_id ));
+ }
+
+ CfgMgr::instance().getStagingCfg()->setMasterServerCfgTimestamp(configData->timestamp_);
+ } catch (const std::exception& ex) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Unable to open database: " +
+ std::string(ex.what())));
+ }
+
+ // Parse the contents as JSON
+ isc::data::ConstElementPtr json;
+ json = isc::data::Element::fromJSON(configData->server_config_, true);
+ if (!json) {
+ isc_throw(isc::BadValue, "no configuration found");
+ }
+
+ // Let's do sanity check before we call json->get() which
+ // works only for map.
+ if (json->getType() != isc::data::Element::map) {
+ isc_throw(isc::BadValue, "Configuration from database is expected to be "
+ "a map, i.e., start with { and end with } and contain "
+ "at least an entry called 'Dhcp4' that itself is a map. "
+ "The database contains a valid JSON, but its top element is not a map."
+ " Did you forget to add { } around your configuration?");
+ }
+
+ try {
+ isc::data::ConstElementPtr dhcp4;
+ // Get Dhcp4 component from the config
+ dhcp4 = json->get("Dhcp4");
+
+ if (!dhcp4) {
+ isc_throw(isc::BadValue, "no mandatory 'Dhcp4' entry in"
+ " the configuration");
+ }
+
+ // Replace the dhcp4 current config with the one read from database
+ db_local_config = boost::const_pointer_cast(dhcp4);
+
+ isc::data::ConstElementPtr logging;
+ // Get Logging component from the config
+ logging = json->get("Logging");
+
+ if (logging) {
+ // Replace the Logging current config with the one read from database
+ db_logging = boost::const_pointer_cast(logging);
+ } else {
+ db_logging = isc::data::ElementPtr();
+ }
+
+ } catch (const std::exception& ex) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR,
+ "Server Configuration error using using database: " +
+ std::string(ex.what())));
+ }
+
+ return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
+ "Server Configuration successfully loaded from database."));
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv4Srv::readDhcpv4SrvConfigFromDatabase(isc::data::ElementPtr& db_config) {
+ SrvConfigInfoPtr configData;
+
+ // Re-open configuration database with new parameters.
+ try {
+ CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+ cfg_db->setAppendedParameters("universe=4");
+ cfg_db->createSrvCfgManagers();
+
+ // Read the contents from database
+ configData = SrvConfigMgrFactory::instance().getJsonConfig4();
+ if (configData == SrvConfigInfoPtr()) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "No entry found in database: "));
+ }
+ CfgMgr::instance().getStagingCfg()->setServerCfgTimestamp(configData->timestamp_);
+ } catch (const std::exception& ex) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Unable to open database: " +
+ std::string(ex.what())));
+ }
+
+ // Parse the contents as JSON
+ isc::data::ConstElementPtr json;
+ json = isc::data::Element::fromJSON(configData->json_data_, true);
+ if (!json) {
+ isc_throw(isc::BadValue, "no configuration found");
+ }
+
+ // Let's do sanity check before we call json->get() which
+ // works only for map.
+ if (json->getType() != isc::data::Element::map) {
+ isc_throw(isc::BadValue, "Configuration from database is expected to be "
+ "a map, i.e., start with { and end with } and contain "
+ "at least an entry called 'Dhcp4' that itself is a map. "
+ "The database contains a valid JSON, but its top element is not a map."
+ " Did you forget to add { } around your configuration?");
+ }
+
+ try {
+ isc::data::ConstElementPtr dhcp4;
+ // Get Dhcp4 component from the config
+ dhcp4 = json->get("Dhcp4");
+
+ if (!dhcp4) {
+ isc_throw(isc::BadValue, "no mandatory 'Dhcp4' entry in"
+ " the configuration");
+ }
+
+ // Replace the dhcp4 current config with the one read from database
+ db_config = boost::const_pointer_cast(dhcp4);
+
+ } catch (const std::exception& ex) {
+ return (isc::config::createAnswer(CONTROL_RESULT_ERROR,
+ "Server Configuration error using using database: " +
+ std::string(ex.what())));
+ }
+
+ return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
+ "Server Configuration successfully loaded from database."));
}
void ControlledDhcpv4Srv::sessionReader(void) {
@@ -886,7 +1137,7 @@ ControlledDhcpv4Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
if (!TimerMgr::instance()->isTimerRegistered("Dhcp4DbReconnectTimer")) {
TimerMgr::instance()->registerTimer("Dhcp4DbReconnectTimer",
boost::bind(&ControlledDhcpv4Srv::dbReconnect, this,
- db_reconnect_ctl),
+ db_reconnect_ctl),
db_reconnect_ctl->retryInterval() * 1000,
asiolink::IntervalTimer::ONE_SHOT);
}
@@ -921,5 +1172,5 @@ ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
return(true);
}
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+} // namespace dhcp
+} // namespace isc
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h
index 06d5ee6472..ae158ae158 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.h
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h
@@ -14,6 +14,8 @@
#include
#include
#include
+#include
+#include
namespace isc {
namespace dhcp {
@@ -31,7 +33,7 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
ControlledDhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT);
/// @brief Destructor.
- ~ControlledDhcpv4Srv();
+ virtual ~ControlledDhcpv4Srv();
/// @brief Initializes the server.
///
@@ -41,12 +43,12 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
/// This method may throw if initialization fails.
void init(const std::string& config_file);
- /// @brief Loads specific config file
+ /// @brief Loads specific configuration file
///
/// This utility method is called whenever we know a filename of the config
/// and need to load it. It calls config-set command once the content of
/// the file has been loaded and verified to be a sane JSON configuration.
- /// config-set handler will process the config file (load it as current
+ /// config-set handler will process the config file (apply it as current
/// configuration).
///
/// @param file_name name of the file to be loaded
@@ -119,12 +121,44 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
return (server_);
}
-
private:
+ /// @brief Retrieves the server configuration information from the master database.
+ ///
+ /// Retrieves the server configuration information from the master database.
+ /// The information contains server specific settings and the shard credentials
+ /// where resides the rest of the configuration (common configuration for all servers)
+ ///
+ ///
+ /// @param dhcp4_config On input contains the current dhcp4 configuration in json format.
+ /// On output contains the new configuration read from database (also in json format)
+ ///
+ /// @return answer that contains result of the reconfiguration.
+ /// @throw Dhcp4ConfigError if trying to create a parser for NULL config.
+ static isc::data::ConstElementPtr
+ readDhcpv4SrvConfigFromMasterDatabase(isc::data::ElementPtr& db_local_config,
+ data::ElementPtr& db_logging,
+ SrvConfigMasterInfoPtr& configData);
+
+ /// @brief Retrieves the server configuration information from database
+ /// and updates the current configuration.
+ ///
+ /// Retrieves the server configuration information from database
+ /// and replaces the current configuration received as paramater with the
+ /// new one.
+ ///
+ ///
+ /// @param db_config On input contains the current dhcp4 configuration in json format.
+ /// On output contains the new configuration read from database (also in json format)
+ ///
+ /// @return answer that contains result of the reconfiguration.
+ /// @throw Dhcp4ConfigError if trying to create a parser for NULL config.
+ static isc::data::ConstElementPtr
+ readDhcpv4SrvConfigFromDatabase(isc::data::ElementPtr& db_config);
+
/// @brief Callback that will be called from iface_mgr when data
/// is received over control socket.
///
- /// This static callback method is called from IfaceMgr::receive6() method,
+ /// This static callback method is called from IfaceMgr::receive4() method,
/// when there is a new command or configuration sent over control socket
/// (that was sent from some yet unspecified sender).
static void sessionReader(void);
@@ -245,7 +279,6 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
commandDhcpEnableHandler(const std::string& command,
isc::data::ConstElementPtr args);
-
/// @Brief handler for processing 'version-get' command
///
/// This handler processes version-get command, which returns
@@ -361,7 +394,7 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
/// @brief Static pointer to the sole instance of the DHCP server.
///
/// This is required for config and command handlers to gain access to
- /// the server
+ /// the server. Some of them need to be static methods.
static ControlledDhcpv4Srv* server_;
/// @brief IOService object, used for all ASIO operations.
@@ -374,7 +407,7 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
TimerMgrPtr timer_mgr_;
};
-}; // namespace isc::dhcp
-}; // namespace isc
+} // namespace dhcp
+} // namespace isc
#endif
diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll
index 6650d75f95..cba865ddca 100644
--- a/src/bin/dhcp4/dhcp4_lexer.ll
+++ b/src/bin/dhcp4/dhcp4_lexer.ll
@@ -36,7 +36,7 @@ unsigned int comment_start_line = 0;
using namespace isc::dhcp;
-};
+}
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::dhcp::Parser4Context::fatal(msg)
@@ -267,6 +267,42 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
+\"configuration-type\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::DHCP4:
+ return isc::dhcp::Dhcp4Parser::make_CONFIGURATION_TYPE(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("configuration-type", driver.loc_);
+ }
+}
+
+\"instance-id\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::DHCP4:
+ return isc::dhcp::Dhcp4Parser::make_INSTANCE_ID(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("instance-id", driver.loc_);
+ }
+}
+
+\"master-database\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::DHCP4:
+ return isc::dhcp::Dhcp4Parser::make_MASTER_DATABASE(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("master-database", driver.loc_);
+ }
+}
+
+\"config-database\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::DHCP4:
+ return isc::dhcp::Dhcp4Parser::make_CONFIG_DATABASE(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("config-database", driver.loc_);
+ }
+}
+
\"re-detect\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::INTERFACES_CONFIG:
@@ -314,6 +350,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"type\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
case isc::dhcp::Parser4Context::OPTION_DEF:
@@ -361,6 +399,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"user\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_USER(driver.loc_);
@@ -371,6 +411,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"password\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_PASSWORD(driver.loc_);
@@ -381,6 +423,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"host\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_HOST(driver.loc_);
@@ -391,6 +435,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"port\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_PORT(driver.loc_);
@@ -401,6 +447,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"persist\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_PERSIST(driver.loc_);
@@ -411,6 +459,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"lfc-interval\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_LFC_INTERVAL(driver.loc_);
@@ -419,28 +469,22 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
-\"connect-timeout\" {
- switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::LEASE_DATABASE:
- case isc::dhcp::Parser4Context::HOSTS_DATABASE:
- return isc::dhcp::Dhcp4Parser::make_CONNECT_TIMEOUT(driver.loc_);
- default:
- return isc::dhcp::Dhcp4Parser::make_STRING("connect-timeout", driver.loc_);
- }
-}
-
-\"keyspace\" {
+\"tcp-nodelay\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
- return isc::dhcp::Dhcp4Parser::make_KEYSPACE(driver.loc_);
+ return isc::dhcp::Dhcp4Parser::make_TCP_NODELAY(driver.loc_);
default:
- return isc::dhcp::Dhcp4Parser::make_STRING("keyspace", driver.loc_);
+ return isc::dhcp::Dhcp4Parser::make_STRING("tcp-nodelay", driver.loc_);
}
}
\"reconnect-wait-time\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_RECONNECT_WAIT_TIME(driver.loc_);
@@ -451,6 +495,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"request-timeout\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_REQUEST_TIMEOUT(driver.loc_);
@@ -461,6 +507,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"tcp-keepalive\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_TCP_KEEPALIVE(driver.loc_);
@@ -469,18 +517,34 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
-\"tcp-nodelay\" {
+\"connect-timeout\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
- return isc::dhcp::Dhcp4Parser::make_TCP_NODELAY(driver.loc_);
+ return isc::dhcp::Dhcp4Parser::make_CONNECT_TIMEOUT(driver.loc_);
default:
- return isc::dhcp::Dhcp4Parser::make_STRING("tcp-nodelay", driver.loc_);
+ return isc::dhcp::Dhcp4Parser::make_STRING("connect-timeout", driver.loc_);
+ }
+}
+
+\"keyspace\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
+ case isc::dhcp::Parser4Context::LEASE_DATABASE:
+ case isc::dhcp::Parser4Context::HOSTS_DATABASE:
+ return isc::dhcp::Dhcp4Parser::make_KEYSPACE(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("keyspace", driver.loc_);
}
}
\"contact-points\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_CONTACT_POINTS(driver.loc_);
@@ -491,6 +555,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"max-reconnect-tries\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp4Parser::make_MAX_RECONNECT_TRIES(driver.loc_);
@@ -499,6 +565,18 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
+\"max-statement-tries\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
+ case isc::dhcp::Parser4Context::LEASE_DATABASE:
+ case isc::dhcp::Parser4Context::HOSTS_DATABASE:
+ return isc::dhcp::Dhcp4Parser::make_MAX_STATEMENT_TRIES(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("max-statement-tries", driver.loc_);
+ }
+}
+
\"valid-lifetime\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
@@ -586,6 +664,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"name\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::MASTER_DATABASE:
+ case isc::dhcp::Parser4Context::CONFIG_DATABASE:
case isc::dhcp::Parser4Context::LEASE_DATABASE:
case isc::dhcp::Parser4Context::HOSTS_DATABASE:
case isc::dhcp::Parser4Context::OPTION_DEF:
@@ -1070,7 +1150,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
-
\"parameters\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::HOOKS_LIBRARIES:
@@ -1526,8 +1605,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
-
-
{JSONString} {
/* A string has been matched. It contains the actual string and single quotes.
We need to get those quotes out of the way and just use its content, e.g.
@@ -1820,5 +1897,5 @@ class Dummy {
/* cppcheck-suppress unusedPrivateFunction */
void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
};
-}
+} // namespace
#endif /* !__clang_analyzer__ */
diff --git a/src/bin/dhcp4/dhcp4_log.cc b/src/bin/dhcp4/dhcp4_log.cc
index 4f82a1b3a9..b1d48e2b5c 100644
--- a/src/bin/dhcp4/dhcp4_log.cc
+++ b/src/bin/dhcp4/dhcp4_log.cc
@@ -14,6 +14,15 @@
namespace isc {
namespace dhcp {
+const int DBG_DHCP4_START = isc::log::DBGLVL_START_SHUT;
+const int DBG_DHCP4_SHUT = isc::log::DBGLVL_START_SHUT;
+const int DBG_DHCP4_COMMAND = isc::log::DBGLVL_COMMAND;
+const int DBG_DHCP4_BASIC = isc::log::DBGLVL_TRACE_BASIC;
+const int DBG_DHCP4_HOOKS = isc::log::DBGLVL_TRACE_BASIC;
+const int DBG_DHCP4_BASIC_DATA = isc::log::DBGLVL_TRACE_BASIC_DATA;
+const int DBG_DHCP4_DETAIL = isc::log::DBGLVL_TRACE_DETAIL;
+const int DBG_DHCP4_DETAIL_DATA = isc::log::DBGLVL_TRACE_DETAIL_DATA;
+
const char* DHCP4_ROOT_LOGGER_NAME = "kea-dhcp4";
const char* DHCP4_APP_LOGGER_NAME = "dhcp4";
const char* DHCP4_BAD_PACKET_LOGGER_NAME = "bad-packets";
@@ -29,6 +38,6 @@ isc::log::Logger options4_logger(DHCP4_OPTIONS_LOGGER_NAME);
isc::log::Logger ddns4_logger(DHCP4_DDNS_LOGGER_NAME);
isc::log::Logger lease4_logger(DHCP4_LEASE_LOGGER_NAME);
-} // namespace dhcp
-} // namespace isc
+} // namespace dhcp
+} // namespace isc
diff --git a/src/bin/dhcp4/dhcp4_log.h b/src/bin/dhcp4/dhcp4_log.h
index 34a790cb39..02fa7aad8e 100644
--- a/src/bin/dhcp4/dhcp4_log.h
+++ b/src/bin/dhcp4/dhcp4_log.h
@@ -21,19 +21,19 @@ namespace dhcp {
//@{
/// @brief Debug level used to log information during server startup.
-const int DBG_DHCP4_START = isc::log::DBGLVL_START_SHUT;
+extern const int DBG_DHCP4_START;
/// @brief Debug level used to log information during server shutdown.
-const int DBG_DHCP4_SHUT = isc::log::DBGLVL_START_SHUT;
+extern const int DBG_DHCP4_SHUT;
/// @brief Debug level used to log receiving commands.
-const int DBG_DHCP4_COMMAND = isc::log::DBGLVL_COMMAND;
+extern const int DBG_DHCP4_COMMAND;
/// @brief Debug level used to trace basic operations within the code.
-const int DBG_DHCP4_BASIC = isc::log::DBGLVL_TRACE_BASIC;
+extern const int DBG_DHCP4_BASIC;
/// @brief Debug level used to trace hook related operations
-const int DBG_DHCP4_HOOKS = isc::log::DBGLVL_TRACE_BASIC;
+extern const int DBG_DHCP4_HOOKS;
/// @brief Debug level used to log the traces with some basic data.
///
@@ -42,7 +42,7 @@ const int DBG_DHCP4_HOOKS = isc::log::DBGLVL_TRACE_BASIC;
/// more detailed information in cases when it is warranted and the
/// extraction of the data doesn't impact the server's performance
/// significantly.
-const int DBG_DHCP4_BASIC_DATA = isc::log::DBGLVL_TRACE_BASIC_DATA;
+extern const int DBG_DHCP4_BASIC_DATA;
/// @brief Debug level used to trace detailed errors.
///
@@ -50,10 +50,10 @@ const int DBG_DHCP4_BASIC_DATA = isc::log::DBGLVL_TRACE_BASIC_DATA;
/// packets. (These are not logged at severities of WARN or higher for fear
/// that a set of deliberately invalid packets set to the server could overwhelm
/// the logging.)
-const int DBG_DHCP4_DETAIL = isc::log::DBGLVL_TRACE_DETAIL;
+extern const int DBG_DHCP4_DETAIL;
/// @brief This level is used to log the contents of packets received and sent.
-const int DBG_DHCP4_DETAIL_DATA = isc::log::DBGLVL_TRACE_DETAIL_DATA;
+extern const int DBG_DHCP4_DETAIL_DATA;
//@}
@@ -105,7 +105,7 @@ extern isc::log::Logger packet4_logger;
/// @brief Logger for options parser.
///
/// This logger is used to issue log messages related to processing of the
-/// DHCP options
+/// DHCP options
extern isc::log::Logger options4_logger;
/// @brief Logger for Hostname or FQDN processing.
@@ -121,7 +121,7 @@ extern isc::log::Logger lease4_logger;
//@}
-} // namespace dhcp4
-} // namespace isc
+} // namespace dhcp4
+} // namespace isc
#endif // DHCP4_LOG_H
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index 22362d2259..11ccbef9e8 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -233,7 +233,7 @@ the message.
% DHCP4_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv6 server
This debug message is printed when the server is receiving a DHCPv4o6
-from the DHCPv6 server over inter-process communication socket.
+from the DHCPv4 server over inter-process communication socket.
% DHCP4_DHCP4O6_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4
A debug message including the detailed data about the packet being
@@ -763,10 +763,15 @@ will drop its message if the received message was DHCPDISCOVER,
and will send DHCPNAK if the received message was DHCPREQUEST.
The argument includes the client and the transaction identification
information.
-<<<<<<< HEAD
-=======
-% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 port %3 on interface %4
-This debug message is printed when the server is receiving a DHCPv4o6
-from the DHCPv6 server over inter-process communication.
->>>>>>> trac5404
+% DHCP4_TRANSACTION_FAILED transaction failed. error: %1
+The transaction failed with the error message.
+
+% DHCP4_FORCE_RELOAD_CONFIGURATION DHCPv4 force configuration reload.
+A force configuration reload event has been initiated.
+
+% DHCP4_SHARD_CONFIGURATION_CHANGED DHCPv4 shard configuration is different.
+A different shard configuration has been detected.
+
+% DHCP4_MASTER_CONFIGURATION_CHANGED DHCPv4 master configuration is different.
+A different master configuration has been detected.
diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy
index 555cb965f3..82113eabc5 100644
--- a/src/bin/dhcp4/dhcp4_parser.yy
+++ b/src/bin/dhcp4/dhcp4_parser.yy
@@ -66,6 +66,11 @@ using namespace std;
SERVER_HOSTNAME "server-hostname"
BOOT_FILE_NAME "boot-file-name"
+ CONFIGURATION_TYPE "configuration-type"
+ INSTANCE_ID "instance-id"
+
+ MASTER_DATABASE "master-database"
+ CONFIG_DATABASE "config-database"
LEASE_DATABASE "lease-database"
HOSTS_DATABASE "hosts-database"
HOSTS_DATABASES "hosts-databases"
@@ -82,13 +87,14 @@ using namespace std;
LFC_INTERVAL "lfc-interval"
READONLY "readonly"
CONNECT_TIMEOUT "connect-timeout"
- CONTACT_POINTS "contact-points"
- KEYSPACE "keyspace"
- MAX_RECONNECT_TRIES "max-reconnect-tries"
+ TCP_NODELAY "tcp-nodelay"
RECONNECT_WAIT_TIME "reconnect-wait-time"
REQUEST_TIMEOUT "request-timeout"
TCP_KEEPALIVE "tcp-keepalive"
- TCP_NODELAY "tcp-nodelay"
+ CONTACT_POINTS "contact-points"
+ KEYSPACE "keyspace"
+ MAX_RECONNECT_TRIES "max-reconnect-tries"
+ MAX_STATEMENT_TRIES "max-statement-tries"
VALID_LIFETIME "valid-lifetime"
RENEW_TIMER "renew-timer"
@@ -428,6 +434,8 @@ global_param: valid_lifetime
| subnet4_list
| shared_networks
| interfaces_config
+ | master_database
+ | config_database
| lease_database
| hosts_database
| hosts_databases
@@ -448,6 +456,8 @@ global_param: valid_lifetime
| user_context
| comment
| unknown_map_entry
+ | configuration_type
+ | instance_id
;
valid_lifetime: VALID_LIFETIME COLON INTEGER {
@@ -480,7 +490,6 @@ match_client_id: MATCH_CLIENT_ID COLON BOOLEAN {
ctx.stack_.back()->set("match-client-id", match);
};
-
interfaces_config: INTERFACES_CONFIG {
ElementPtr i(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("interfaces-config", i);
@@ -531,6 +540,26 @@ dhcp_socket_type: DHCP_SOCKET_TYPE {
ctx.leave();
};
+master_database: MASTER_DATABASE {
+ ElementPtr i(new MapElement(ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("master-database", i);
+ ctx.stack_.push_back(i);
+ ctx.enter(ctx.MASTER_DATABASE);
+} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+ ctx.stack_.pop_back();
+ ctx.leave();
+};
+
+config_database: CONFIG_DATABASE {
+ ElementPtr i(new MapElement(ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("config-database", i);
+ ctx.stack_.push_back(i);
+ ctx.enter(ctx.CONFIG_DATABASE);
+} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+ ctx.stack_.pop_back();
+ ctx.leave();
+};
+
socket_type: RAW { $$ = ElementPtr(new StringElement("raw", ctx.loc2pos(@1))); }
| UDP { $$ = ElementPtr(new StringElement("udp", ctx.loc2pos(@1))); }
;
@@ -620,12 +649,13 @@ database_map_param: database_type
| lfc_interval
| readonly
| connect_timeout
- | contact_points
- | max_reconnect_tries
+ | tcp_nodelay
| reconnect_wait_time
| request_timeout
| tcp_keepalive
- | tcp_nodelay
+ | contact_points
+ | max_reconnect_tries
+ | max_statement_tries
| keyspace
| unknown_map_entry
;
@@ -700,6 +730,16 @@ connect_timeout: CONNECT_TIMEOUT COLON INTEGER {
ctx.stack_.back()->set("connect-timeout", n);
};
+tcp_nodelay: TCP_NODELAY COLON BOOLEAN {
+ ElementPtr n(new BoolElement($3, ctx.loc2pos(@3)));
+ ctx.stack_.back()->set("tcp-nodelay", n);
+};
+
+reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER {
+ ElementPtr n(new IntElement($3, ctx.loc2pos(@3)));
+ ctx.stack_.back()->set("reconnect-wait-time", n);
+};
+
request_timeout: REQUEST_TIMEOUT COLON INTEGER {
ElementPtr n(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("request-timeout", n);
@@ -710,11 +750,6 @@ tcp_keepalive: TCP_KEEPALIVE COLON INTEGER {
ctx.stack_.back()->set("tcp-keepalive", n);
};
-tcp_nodelay: TCP_NODELAY COLON BOOLEAN {
- ElementPtr n(new BoolElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("tcp-nodelay", n);
-};
-
contact_points: CONTACT_POINTS {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
@@ -736,9 +771,9 @@ max_reconnect_tries: MAX_RECONNECT_TRIES COLON INTEGER {
ctx.stack_.back()->set("max-reconnect-tries", n);
};
-reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER {
+max_statement_tries: MAX_STATEMENT_TRIES COLON INTEGER {
ElementPtr n(new IntElement($3, ctx.loc2pos(@3)));
- ctx.stack_.back()->set("reconnect-wait-time", n);
+ ctx.stack_.back()->set("max-statement-tries", n);
};
host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS {
@@ -782,6 +817,22 @@ client_id : CLIENT_ID {
ctx.stack_.back()->add(client);
};
+configuration_type: CONFIGURATION_TYPE {
+ ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+ ElementPtr prf(new StringElement($4, ctx.loc2pos(@4)));
+ ctx.stack_.back()->set("configuration-type", prf);
+ ctx.leave();
+};
+
+instance_id: INSTANCE_ID {
+ ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+ ElementPtr prf(new StringElement($4, ctx.loc2pos(@4)));
+ ctx.stack_.back()->set("instance-id", prf);
+ ctx.leave();
+};
+
flex_id: FLEX_ID {
ElementPtr flex_id(new StringElement("flex-id", ctx.loc2pos(@1)));
ctx.stack_.back()->add(flex_id);
@@ -1918,7 +1969,7 @@ replace_client_name: REPLACE_CLIENT_NAME {
replace_client_name_value:
WHEN_PRESENT {
- $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1)));
+ $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1)));
}
| NEVER {
$$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1)));
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index dfda5279b6..ea510c00f2 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -5,6 +5,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include
+
#include
#include
#include
@@ -35,7 +36,10 @@
#include
#include
#include
-#include
+#include
+#include
+#include
+#include
#include
#include
#include
@@ -44,7 +48,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -185,7 +188,7 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
.arg(query_->getLabel())
.arg(classes.toText());
}
-};
+}
void
Dhcpv4Exchange::initResponse() {
@@ -986,54 +989,132 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp, bool allow_packet_park) {
AllocEngine::ClientContext4Ptr ctx;
+ bool transactionError = false;
+ bool reloadConfiguration = false;
try {
- switch (query->getType()) {
- case DHCPDISCOVER:
- rsp = processDiscover(query);
- break;
+ LeaseMgrFactory::instance().startTransaction();
+ } catch (const std::exception& ex) {
+ LOG_INFO(dhcp4_logger, DHCP4_TRANSACTION_FAILED).arg(ex.what());
+ transactionError = true;
+ }
+ if (!transactionError) {
+ bool rollback = false;
+ bool apply = true;
+ try {
+ switch (query->getType()) {
+ case DHCPDISCOVER:
+ rsp = processDiscover(query);
+ break;
- case DHCPREQUEST:
- // Note that REQUEST is used for many things in DHCPv4: for
- // requesting new leases, renewing existing ones and even
- // for rebinding.
- rsp = processRequest(query, ctx);
- break;
+ case DHCPREQUEST:
+ // Note that REQUEST is used for many things in DHCPv4: for
+ // requesting new leases, renewing existing ones and even
+ // for rebinding.
+ rsp = processRequest(query, ctx);
+ break;
- case DHCPRELEASE:
- processRelease(query, ctx);
- break;
+ case DHCPRELEASE:
+ processRelease(query, ctx);
+ break;
- case DHCPDECLINE:
- processDecline(query, ctx);
- break;
+ case DHCPDECLINE:
+ processDecline(query, ctx);
+ break;
- case DHCPINFORM:
- rsp = processInform(query);
- break;
+ case DHCPINFORM:
+ rsp = processInform(query);
+ break;
- default:
- // Only action is to output a message if debug is enabled,
- // and that is covered by the debug statement before the
- // "switch" statement.
- ;
- }
- } catch (const std::exception& e) {
+ default:
+ // Only action is to output a message if debug is enabled,
+ // and that is covered by the debug statement before the
+ // "switch" statement.
+ ;
+ }
+ } catch (const TransactionException& e) {
+ LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_BASIC,
+ DHCP4_PACKET_DROP_0007)
+ .arg(query->getLabel())
+ .arg(e.what());
- // Catch-all exception (we used to call only isc::Exception, but
- // std::exception could potentially be raised and if we don't catch
- // it here, it would be caught in main() and the process would
- // terminate). Just log the problem and ignore the packet.
- // (The problem is logged as a debug message because debug is
- // disabled by default - it prevents a DDOS attack based on the
- // sending of problem packets.)
- LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_BASIC,
- DHCP4_PACKET_DROP_0007)
- .arg(query->getLabel())
- .arg(e.what());
+ // Increase the statistic of dropped packets.
+ isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
+ static_cast(1));
+ rollback = true;
+ apply = false;
+ } catch (const std::exception& e) {
- // Increase the statistic of dropped packets.
- isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
- static_cast(1));
+ // Catch-all exception (we used to call only isc::Exception, but
+ // std::exception could potentially be raised and if we don't catch
+ // it here, it would be caught in main() and the process would
+ // terminate). Just log the problem and ignore the packet.
+ // (The problem is logged as a debug message because debug is
+ // disabled by default - it prevents a DDOS attack based on the
+ // sending of problem packets.)
+ LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_BASIC,
+ DHCP4_PACKET_DROP_0007)
+ .arg(query->getLabel())
+ .arg(e.what());
+
+ // Increase the statistic of dropped packets.
+ isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
+ static_cast(1));
+ rollback = true;
+ }
+ if (rollback) {
+ if (apply) {
+ try {
+ LeaseMgrFactory::instance().rollback();
+ } catch (const std::exception& ex) {
+ LOG_INFO(dhcp4_logger, DHCP4_TRANSACTION_FAILED).arg(ex.what());
+ }
+ }
+ } else {
+ try {
+ if (SrvConfigMgrFactory::initialized()) {
+ SrvConfigInfoPtr configInfo =
+ SrvConfigMgrFactory::instance().getConfig4Timestamp();
+ if (configInfo && configInfo->timestamp_ !=
+ CfgMgr::instance().getCurrentCfg()->getServerCfgTimestamp()) {
+ LOG_INFO(dhcp4_logger, DHCP4_SHARD_CONFIGURATION_CHANGED);
+ reloadConfiguration = true;
+ }
+ }
+ if (SrvConfigMasterMgrFactory::initialized()) {
+ std::string server_id = CfgMgr::instance().getCurrentCfg()->getInstanceId();
+ SrvConfigMasterInfoPtr masterConfigInfo =
+ SrvConfigMasterMgrFactory::instance().getMasterConfig4Timestamp(server_id);
+ if (masterConfigInfo && masterConfigInfo->timestamp_ !=
+ CfgMgr::instance().getCurrentCfg()->getMasterServerCfgTimestamp()) {
+ LOG_INFO(dhcp4_logger, DHCP4_MASTER_CONFIGURATION_CHANGED);
+ reloadConfiguration = true;
+ }
+ }
+ } catch (const std::exception& ex) {
+ LOG_INFO(dhcp4_logger, DHCP4_TRANSACTION_FAILED).arg(ex.what());
+ reloadConfiguration = true;
+ }
+ if (!reloadConfiguration) {
+ try {
+ LeaseMgrFactory::instance().commit();
+ } catch (const std::exception& ex) {
+ LOG_INFO(dhcp4_logger, DHCP4_TRANSACTION_FAILED).arg(ex.what());
+ reloadConfiguration = true;
+ }
+ } else {
+ try {
+ LeaseMgrFactory::instance().rollback();
+ } catch (const std::exception& ex) {
+ LOG_INFO(dhcp4_logger, DHCP4_TRANSACTION_FAILED).arg(ex.what());
+ }
+ }
+ }
+ }
+
+ if (reloadConfiguration) {
+ LOG_INFO(dhcp4_logger, DHCP4_FORCE_RELOAD_CONFIGURATION);
+ kill(getpid(), SIGHUP);
+ rsp = Pkt4Ptr();
}
bool packet_park = false;
@@ -3593,5 +3674,5 @@ void Dhcpv4Srv::discardPackets() {
HooksManager::clearParkingLots();
}
-} // namespace dhcp
-} // namespace isc
+} // namespace dhcp
+} // namespace isc
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index c095cdfef0..6ba524d049 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
// Undefine the macro OPTIONAL which is defined in some operating
// systems but conflicts with a member of the RequirementLevel enum in
@@ -281,8 +282,8 @@ class Dhcpv4Srv : public Daemon {
///
/// @brief Get UDP port on which server should listen.
///
- /// Typically, server listens on UDP port number 67. Other ports are used
- /// for testing purposes only.
+ /// Typically, server listens on UDP port 67. Other ports are only
+ /// used for testing purposes.
///
/// @return UDP port on which server should listen.
uint16_t getPort() const {
@@ -931,7 +932,6 @@ class Dhcpv4Srv : public Daemon {
bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
protected:
-
/// @brief Holds information about disabled DHCP service and/or
/// disabled subnet/network scopes.
NetworkStatePtr network_state_;
@@ -976,7 +976,7 @@ class Dhcpv4Srv : public Daemon {
static int getHookIndexLease4Decline();
};
-}; // namespace isc::dhcp
-}; // namespace isc
+} // namespace dhcp
+} // namespace isc
#endif // DHCP4_SRV_H
diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc
index 646091cd09..d14062fa0d 100644
--- a/src/bin/dhcp4/json_config_parser.cc
+++ b/src/bin/dhcp4/json_config_parser.cc
@@ -6,15 +6,21 @@
#include
+#include
+#include
#include
#include
#include
+#include
#include
+#include
#include
+#include
#include
#include
-#include
#include
+#include
+#include
#include
#include
#include
@@ -26,26 +32,29 @@
#include
#include
#include
-#include
#include
-#include
+#include
#include
#include
+#include
#include
#include
-#include
+#include
+#include
-#include
#include
+#include
+#include