Commit 884d8bb4 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[master] Merge branch 'trac3681_rebase' (Common MySQL Connection class)

Conflicts:
	src/lib/dhcpsrv/lease_mgr.h
	src/lib/dhcpsrv/memfile_lease_mgr.cc
	src/lib/dhcpsrv/mysql_lease_mgr.cc
	src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
	src/lib/dhcpsrv/tests/schema_mysql_copy.h
parents bd353866 5fc3a5aa
......@@ -80,6 +80,7 @@ We have received the following contributions:
2014-12: Extract MAC address from DUID-LL and DUID-LLT types
2015-01: Extract MAC address from remote-id
2015-05: MySQL schema extended to cover host reservation
2015-04: Common MySQL Connector Pool
Kea uses log4cplus (http://sourceforge.net/projects/log4cplus/) for logging,
Boost (http://www.boost.org/) library for almost everything, and can use Botan
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -38,6 +38,11 @@ keaadmin=@abs_top_builddir@/src/bin/admin/kea-admin
mysql_wipe() {
printf "Wiping whole database %s\n" $db_name
# ipv6_reservations table must be deleted first, as it has contraints that
# are dependent on hosts. Therefore hosts table cannot be deleted before
# ipv6_reservations.
mysql_execute "DROP TABLE IF EXISTS ipv6_reservations;"
# First we build the list of drop table commands
# We don't bother with "cascade" because as of MySQL
# 5.1 it is only there to ease porting, it doesn't
......@@ -257,7 +262,6 @@ EOF
ERRCODE=$?
assert_eq 0 $ERRCODE "dhcp6_options table is missing or broken. (returned status code %d, expected %d)"
# Verify that it reports version 3.0.
version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name)
......
......@@ -93,6 +93,7 @@ libkea_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h
libkea_dhcpsrv_la_SOURCES += d2_client_cfg.cc d2_client_cfg.h
libkea_dhcpsrv_la_SOURCES += d2_client_mgr.cc d2_client_mgr.h
libkea_dhcpsrv_la_SOURCES += daemon.cc daemon.h
libkea_dhcpsrv_la_SOURCES += database_connection.cc database_connection.h
libkea_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
libkea_dhcpsrv_la_SOURCES += host.cc host.h
libkea_dhcpsrv_la_SOURCES += host_container.h
......@@ -111,6 +112,7 @@ libkea_dhcpsrv_la_SOURCES += memfile_lease_storage.h
if HAVE_MYSQL
libkea_dhcpsrv_la_SOURCES += mysql_lease_mgr.cc mysql_lease_mgr.h
libkea_dhcpsrv_la_SOURCES += mysql_connection.cc mysql_connection.h
endif
if HAVE_PGSQL
libkea_dhcpsrv_la_SOURCES += pgsql_lease_mgr.cc pgsql_lease_mgr.h
......
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcpsrv/database_connection.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <exceptions/exceptions.h>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <vector>
using namespace std;
namespace isc {
namespace dhcp {
std::string
DatabaseConnection::getParameter(const std::string& name) const {
ParameterMap::const_iterator param = parameters_.find(name);
if (param == parameters_.end()) {
isc_throw(BadValue, "Parameter " << name << " not found");
}
return (param->second);
}
DatabaseConnection::ParameterMap
DatabaseConnection::parse(const std::string& dbaccess) {
DatabaseConnection::ParameterMap mapped_tokens;
if (!dbaccess.empty()) {
vector<string> tokens;
// We need to pass a string to is_any_of, not just char*. Otherwise
// there are cryptic warnings on Debian6 running g++ 4.4 in
// /usr/include/c++/4.4/bits/stl_algo.h:2178 "array subscript is above
// array bounds"
boost::split(tokens, dbaccess, boost::is_any_of(string("\t ")));
BOOST_FOREACH(std::string token, tokens) {
size_t pos = token.find("=");
if (pos != string::npos) {
string name = token.substr(0, pos);
string value = token.substr(pos + 1);
mapped_tokens.insert(make_pair(name, value));
} else {
LOG_ERROR(dhcpsrv_logger, DHCPSRV_INVALID_ACCESS).arg(dbaccess);
isc_throw(InvalidParameter, "Cannot parse " << token
<< ", expected format is name=value");
}
}
}
return (mapped_tokens);
}
std::string
DatabaseConnection::redactedAccessString(const ParameterMap& parameters) {
// Reconstruct the access string: start of with an empty string, then
// work through all the parameters in the original string and add them.
std::string access;
for (DatabaseConnection::ParameterMap::const_iterator i = parameters.begin();
i != parameters.end(); ++i) {
// Separate second and subsequent tokens are preceded by a space.
if (!access.empty()) {
access += " ";
}
// Append name of parameter...
access += i->first;
access += "=";
// ... and the value, except in the case of the password, where a
// redacted value is appended.
if (i->first == std::string("password")) {
access += "*****";
} else {
access += i->second;
}
}
return (access);
}
};
};
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DATABASE_CONNECTION_H
#define DATABASE_CONNECTION_H
#include <boost/noncopyable.hpp>
#include <exceptions/exceptions.h>
#include <map>
#include <string>
namespace isc {
namespace dhcp {
/// @brief Exception thrown if name of database is not specified
class NoDatabaseName : public Exception {
public:
NoDatabaseName(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Exception thrown on failure to open database
class DbOpenError : public Exception {
public:
DbOpenError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Exception thrown on failure to execute a database function
class DbOperationError : public Exception {
public:
DbOperationError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Common database connection class.
///
/// This class provides functions that are common for establishing
/// connection with different types of databases; enables operations
/// on access parameters strings. In particular, it provides a way
/// to parse parameters in key=value format. This class is expected
/// to be a base class for all @ref LeaseMgr and possibly
/// @ref BaseHostDataSource derived classes.
class DatabaseConnection : public boost::noncopyable {
public:
/// @brief Database configuration parameter map
typedef std::map<std::string, std::string> ParameterMap;
/// @brief Constructor
///
/// @param parameters A data structure relating keywords and values
/// concerned with the database.
DatabaseConnection(const ParameterMap& parameters)
:parameters_(parameters) {
}
/// @brief Returns value of a connection parameter.
///
/// @param name Name of the parameter which value should be returned.
/// @return Value of one of the connection parameters.
/// @throw BadValue if parameter is not found
std::string getParameter(const std::string& name) const;
/// @brief Parse database access string
///
/// Parses the string of "keyword=value" pairs and separates them
/// out into the map.
///
/// @param dbaccess Database access string.
///
/// @return @ref ParameterMap of keyword/value pairs.
static ParameterMap parse(const std::string& dbaccess);
/// @brief Redact database access string
///
/// Takes the database parameters and returns a database access string
/// passwords replaced by asterisks. This string is used in log messages.
///
/// @param parameters Database access parameters (output of "parse").
///
/// @return Redacted database access string.
static std::string redactedAccessString(const ParameterMap& parameters);
private:
/// @brief List of parameters passed in dbconfig
///
/// That will be mostly used for storing database name, username,
/// password and other parameters required for DB access. It is not
/// intended to keep any DHCP-related parameters.
ParameterMap parameters_;
};
}; // end of isc::dhcp namespace
}; // end of isc namespace
#endif // DATABASE_CONNECTION_H
File mode changed from 100644 to 100755
......@@ -29,6 +29,7 @@
#include <time.h>
using namespace std;
namespace isc {
......@@ -36,14 +37,6 @@ namespace dhcp {
const time_t LeaseMgr::MAX_DB_TIME = 2147483647;
std::string LeaseMgr::getParameter(const std::string& name) const {
ParameterMap::const_iterator param = parameters_.find(name);
if (param == parameters_.end()) {
isc_throw(BadValue, "Parameter not found");
}
return (param->second);
}
Lease6Ptr
LeaseMgr::getLease6(Lease::Type type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const {
......
......@@ -68,27 +68,6 @@
namespace isc {
namespace dhcp {
/// @brief Exception thrown if name of database is not specified
class NoDatabaseName : public Exception {
public:
NoDatabaseName(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Exception thrown on failure to open database
class DbOpenError : public Exception {
public:
DbOpenError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Exception thrown on failure to execute a database function
class DbOperationError : public Exception {
public:
DbOperationError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Multiple lease records found where one expected
class MultipleRecords : public Exception {
public:
......@@ -127,15 +106,9 @@ public:
// If I'm still alive I'll be too old to care. You fix it.
static const time_t MAX_DB_TIME;
/// Database configuration parameter map
typedef std::map<std::string, std::string> ParameterMap;
/// @brief Constructor
///
/// @param parameters A data structure relating keywords and values
/// concerned with the database.
LeaseMgr(const ParameterMap& parameters)
: parameters_(parameters)
LeaseMgr()
{}
/// @brief Destructor
......@@ -425,17 +398,6 @@ public:
/// @todo: Add host management here
/// As host reservation is outside of scope for 2012, support for hosts
/// is currently postponed.
/// @brief returns value of the parameter
virtual std::string getParameter(const std::string& name) const;
private:
/// @brief list of parameters passed in dbconfig
///
/// That will be mostly used for storing database name, username,
/// password and other parameters required for DB access. It is not
/// intended to keep any DHCP-related parameters.
ParameterMap parameters_;
};
}; // end of isc::dhcp namespace
......
......@@ -45,71 +45,13 @@ LeaseMgrFactory::getLeaseMgrPtr() {
return (leaseMgrPtr);
}
LeaseMgr::ParameterMap
LeaseMgrFactory::parse(const std::string& dbaccess) {
LeaseMgr::ParameterMap mapped_tokens;
if (!dbaccess.empty()) {
vector<string> tokens;
// We need to pass a string to is_any_of, not just char*. Otherwise
// there are cryptic warnings on Debian6 running g++ 4.4 in
// /usr/include/c++/4.4/bits/stl_algo.h:2178 "array subscript is above
// array bounds"
boost::split(tokens, dbaccess, boost::is_any_of(string("\t ")));
BOOST_FOREACH(std::string token, tokens) {
size_t pos = token.find("=");
if (pos != string::npos) {
string name = token.substr(0, pos);
string value = token.substr(pos + 1);
mapped_tokens.insert(make_pair(name, value));
} else {
LOG_ERROR(dhcpsrv_logger, DHCPSRV_INVALID_ACCESS).arg(dbaccess);
isc_throw(InvalidParameter, "Cannot parse " << token
<< ", expected format is name=value");
}
}
}
return (mapped_tokens);
}
std::string
LeaseMgrFactory::redactedAccessString(const LeaseMgr::ParameterMap& parameters) {
// Reconstruct the access string: start of with an empty string, then
// work through all the parameters in the original string and add them.
std::string access;
for (LeaseMgr::ParameterMap::const_iterator i = parameters.begin();
i != parameters.end(); ++i) {
// Separate second and subsequent tokens are preceded by a space.
if (!access.empty()) {
access += " ";
}
// Append name of parameter...
access += i->first;
access += "=";
// ... and the value, except in the case of the password, where a
// redacted value is appended.
if (i->first == std::string("password")) {
access += "*****";
} else {
access += i->second;
}
}
return (access);
}
void
LeaseMgrFactory::create(const std::string& dbaccess) {
const std::string type = "type";
// Parse the access string and create a redacted string for logging.
LeaseMgr::ParameterMap parameters = parse(dbaccess);
std::string redacted = redactedAccessString(parameters);
DatabaseConnection::ParameterMap parameters = DatabaseConnection::parse(dbaccess);
std::string redacted = DatabaseConnection::redactedAccessString(parameters);
// Is "type" present?
if (parameters.find(type) == parameters.end()) {
......
// Copyright (C) 2012, 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2013,2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -16,6 +16,7 @@
#define LEASE_MGR_FACTORY_H
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/database_connection.h>
#include <exceptions/exceptions.h>
#include <boost/scoped_ptr.hpp>
......@@ -100,26 +101,7 @@ public:
/// create() to create one before calling this method.
static LeaseMgr& instance();
/// @brief Parse database access string
///
/// Parses the string of "keyword=value" pairs and separates them
/// out into the map.
///
/// @param dbaccess Database access string.
///
/// @return std::map<std::string, std::string> Map of keyword/value pairs.
static LeaseMgr::ParameterMap parse(const std::string& dbaccess);
/// @brief Redact database access string
///
/// Takes the database parameters and returns a database access string
/// passwords replaced by asterisks. This string is used in log messages.
///
/// @param parameters Database access parameters (output of "parse").
///
/// @return Redacted database access string.
static std::string redactedAccessString(
const LeaseMgr::ParameterMap& parameters);
private:
/// @brief Hold pointer to lease manager
......
......@@ -18,6 +18,7 @@
#include <dhcpsrv/lease_file_loader.h>
#include <dhcpsrv/memfile_lease_mgr.h>
#include <dhcpsrv/timer_mgr.h>
#include <dhcpsrv/database_connection.h>
#include <exceptions/exceptions.h>
#include <util/pid_file.h>
#include <util/process_spawn.h>
......@@ -249,11 +250,11 @@ LFCSetup::getExitStatus() const {
const int Memfile_LeaseMgr::MAJOR_VERSION;
const int Memfile_LeaseMgr::MINOR_VERSION;
Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
: LeaseMgr(parameters), lfc_setup_()
Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& parameters)
: LeaseMgr(), lfc_setup_(), conn_(parameters)
{
// Check the universe and use v4 file or v6 file.
std::string universe = getParameter("universe");
std::string universe = conn_.getParameter("universe");
if (universe == "4") {
std::string file4 = initLeaseFilePath(V4);
if (!file4.empty()) {
......@@ -840,7 +841,7 @@ std::string
Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
std::string persist_val;
try {
persist_val = getParameter("persist");
persist_val = conn_.getParameter("persist");
} catch (const Exception&) {
// If parameter persist hasn't been specified, we use a default value
// 'yes'.
......@@ -858,7 +859,7 @@ Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
std::string lease_file;
try {
lease_file = getParameter("name");
lease_file = conn_.getParameter("name");
} catch (const Exception&) {
lease_file = getDefaultLeaseFilePath(u);
}
......@@ -944,7 +945,7 @@ void
Memfile_LeaseMgr::lfcSetup() {
std::string lfc_interval_str = "0";
try {
lfc_interval_str = getParameter("lfc-interval");
lfc_interval_str = conn_.getParameter("lfc-interval");
} catch (const std::exception&) {
// Ignore and default to 0.
}
......
......@@ -20,6 +20,7 @@
#include <dhcpsrv/csv_lease_file4.h>
#include <dhcpsrv/csv_lease_file6.h>
#include <dhcpsrv/memfile_lease_storage.h>
#include <dhcpsrv/database_connection.h>
#include <dhcpsrv/lease_mgr.h>
#include <util/process_spawn.h>
......@@ -99,7 +100,6 @@ public:
/// @}
/// @brief Specifies universe (V4, V6)
///
/// This enumeration is used by various functions in Memfile %Lease Manager,
......@@ -124,7 +124,7 @@ public:
///
/// @param parameters A data structure relating keywords and values
/// concerned with the database.
Memfile_LeaseMgr(const ParameterMap& parameters);
Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& parameters);
/// @brief Destructor (closes file)
virtual ~Memfile_LeaseMgr();
......@@ -655,8 +655,14 @@ private:
/// @brief A pointer to the Lease File Cleanup configuration.
boost::scoped_ptr<LFCSetup> lfc_setup_;
//@}
/// @brief Parameters storage
///
/// DatabaseConnection object is used only for storing, accessing and
/// printing parameter map.
DatabaseConnection conn_;
//@}
};
}; // end of isc::dhcp namespace
......
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/mysql_connection.h>
#include <exceptions/exceptions.h>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdint.h>
#include <string>
using namespace isc;
using namespace isc::dhcp;
using namespace std;
namespace isc {
namespace dhcp {
/// @brief Maximum size of database fields
///
/// The following constants define buffer sizes for variable length database
/// fields. The values should be greater than or equal to the length set in
/// the schema definition.
///
/// The exception is the length of any VARCHAR fields: buffers for these should
/// be set greater than or equal to the length of the field plus 1: this allows
/// for the insertion of a trailing null whatever data is returned.
const my_bool MLM_FALSE = 0; ///< False value
const my_bool MLM_TRUE = 1; ///< True value
///@}
// Open the database using the parameters passed to the constructor.
void
MySqlConnection::openDatabase() {
// Set up the values of the parameters
const char* host = "localhost";
string shost;
try {
shost = getParameter("host");
host = shost.c_str();
} catch (...) {
// No host. Fine, we'll use "localhost"
}
const char* user = NULL;