/// @{
/// @brief Invalid values in the Cassandra database
+static constexpr char NULL_DHCP4_SERVER_HOSTNAME[] = "";
+static constexpr char NULL_DHCP4_BOOT_FILE_NAME[] = "";
+static constexpr char NULL_USER_CONTEXT[] = "";
static constexpr char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] = "::";
static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
static constexpr cass_bool_t NULL_OPTION_IS_PERSISTENT = cass_false;
static constexpr char NULL_OPTION_CLIENT_CLASS[] = "";
static constexpr cass_int32_t NULL_OPTION_SUBNET_ID = -1;
-// static constexpr CassCollection* NULL_COLLECTION = NULL;
+static constexpr char NULL_OPTION_USER_CONTEXT[] = "";
+static constexpr cass_int32_t NULL_OPTION_SCOPE_ID = -1;
/// @}
/// @brief Invalid reservation used to check for an invalid IPv6Resrv formed
/// @brief Reserved IPv4 address
cass_int32_t host_ipv4_address_;
+ /// @brief Next server address (siaddr).
+ cass_int32_t host_ipv4_next_server_;
+
+ /// @brief Server hostname (sname).
+ std::string host_ipv4_server_hostname_;
+
+ /// @brief Boot file name (file).
+ std::string host_ipv4_boot_file_name_;
+
/// @brief Name reserved for the host
std::string hostname_;
+ /// @brief User context
+ std::string user_context_;
+
/// @brief A string holding comma separated list of IPv4 client classes
std::string host_ipv4_client_classes_;
/// @brief Subnet identifier
cass_int32_t option_subnet_id_;
+
+ /// @brief Buffer holding textual user context of an option.
+ std::string option_user_context_;
+
+ /// @brief Option scope id
+ cass_int32_t option_scope_id_;
}; // CqlHostExchange
constexpr StatementTag CqlHostExchange::INSERT_HOST;
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
") VALUES ( "
// id
"?, "
// host
- "?, ?, ?, ?, ?, ?, ?, ?, "
+ "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
// denormalized reservation, option
- "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
+ "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
") "
"IF NOT EXISTS "
}},
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE host_identifier = ? "
"AND host_identifier_type = ? "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE host_ipv4_address = ? "
"ALLOW FILTERING "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE host_ipv4_subnet_id = ? "
"AND host_identifier = ? "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE host_ipv6_subnet_id = ? "
"AND host_identifier = ? "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE host_ipv4_subnet_id = ? "
"AND host_ipv4_address = ? "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE reserved_ipv6_prefix_address = ? "
"AND reserved_ipv6_prefix_length = ? "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
+ "host_ipv4_next_server, "
+ "host_ipv4_server_hostname, "
+ "host_ipv4_boot_file_name, "
"hostname, "
+ "user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
- "option_subnet_id "
+ "option_subnet_id, "
+ "option_user_context, "
+ "option_scope_id "
"FROM host_reservations "
"WHERE host_ipv6_subnet_id = ? "
"AND reserved_ipv6_prefix_address = ? "
CqlHostExchange::CqlHostExchange(CqlConnection& connection)
: host_(NULL), connection_(connection), id_(0), host_identifier_type_(0),
host_ipv4_subnet_id_(0), host_ipv6_subnet_id_(0), host_ipv4_address_(0),
+ host_ipv4_next_server_(0),
+ host_ipv4_server_hostname_(NULL_DHCP4_SERVER_HOSTNAME),
+ host_ipv4_boot_file_name_(NULL_DHCP4_BOOT_FILE_NAME),
+ user_context_(NULL_USER_CONTEXT),
reserved_ipv6_prefix_length_(NULL_RESERVED_IPV6_PREFIX_LENGTH),
reserved_ipv6_prefix_address_type_(NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE),
iaid_(NULL_IAID), option_universe_(NULL_OPTION_UNIVERSE),
option_code_(NULL_OPTION_CODE),
option_is_persistent_(NULL_OPTION_IS_PERSISTENT),
- option_subnet_id_(NULL_OPTION_SUBNET_ID) {
+ option_subnet_id_(NULL_OPTION_SUBNET_ID),
+ option_user_context_(NULL_OPTION_USER_CONTEXT),
+ option_scope_id_(NULL_OPTION_SCOPE_ID) {
}
CqlHostExchange::~CqlHostExchange() {
// id: blob
data.add(&id_);
-
// host_identifier: blob
data.add(&host_identifier_);
// host_identifier_type: int
data.add(&host_ipv6_subnet_id_);
// host_ipv4_address: int
data.add(&host_ipv4_address_);
+ // host_ipv4_next_server: int
+ data.add(&host_ipv4_next_server_);
+ // host_ipv4_server_hostname: text
+ data.add(&host_ipv4_server_hostname_);
+ // host_ipv4_boot_file_name: text
+ data.add(&host_ipv4_boot_file_name_);
// hostname: text
data.add(&hostname_);
+ // user_context: text
+ data.add(&user_context_);
// host_ipv4_client_classes: text
data.add(&host_ipv4_client_classes_);
// host_ipv6_client_classes: text
// iaid: int
data.add(&iaid_);
/// @}
-
/// @brief Denormalized option columns
/// @{
// option_universe: int
data.add(&option_client_class_);
// option_subnet_id: int
data.add(&option_subnet_id_);
+ // option_user_context: text
+ data.add(&option_user_context_);
+ // option_scope_id: int
+ data.add(&option_scope_id_);
/// @}
}
// host_ipv4_address: int
host_ipv4_address_ = static_cast<cass_int32_t>(host->getIPv4Reservation().toUint32());
+ // host_ipv4_next_server: int
+ host_ipv4_next_server_ = static_cast<cass_int32_t>(host->getNextServer().toUint32());
+
+ // host_ipv4_server_hostname: text
+ host_ipv4_server_hostname_ = host->getServerHostname();
+
+ // host_ipv4_boot_file_name: text
+ host_ipv4_boot_file_name_ = host->getBootFileName();
+
// hostname: text
hostname_ = host->getHostname();
if (hostname_.size() > HOSTNAME_MAX_LENGTH) {
<< " is greater than allowed of " << HOSTNAME_MAX_LENGTH);
}
+ // user_context: text
+ ConstElementPtr ctx = host->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = NULL_USER_CONTEXT;
+ }
+
// host_ipv4_client_classes: text
host_ipv4_client_classes_ = host->getClientClasses4().toText(",");
if (host_ipv4_client_classes_.size() > CLIENT_CLASSES_MAX_LENGTH) {
option_is_persistent_ = NULL_OPTION_IS_PERSISTENT;
option_client_class_ = NULL_OPTION_CLIENT_CLASS;
option_subnet_id_ = NULL_OPTION_SUBNET_ID;
+ option_user_context_ = NULL_OPTION_USER_CONTEXT;
+ option_scope_id_ = NULL_OPTION_SCOPE_ID;
} else {
// option_universe: int
option_universe_ = option_descriptor.option_->getUniverse();
} else {
option_subnet_id_ = 0;
}
+
+ // option_user_context: text
+ ConstElementPtr ctx = option_descriptor.getContext();
+ if (ctx) {
+ option_user_context_ = ctx->str();
+ } else {
+ option_user_context_ = NULL_OPTION_USER_CONTEXT;
+ }
+
+ // option_scope_id: int
+ // Using fixed scope_id = 3, which associates an option with host.
+ option_scope_id_ = 3;
}
// id: bigint
data.add(&host_ipv4_subnet_id_);
data.add(&host_ipv6_subnet_id_);
data.add(&host_ipv4_address_);
+ data.add(&host_ipv4_next_server_);
+ data.add(&host_ipv4_server_hostname_);
+ data.add(&host_ipv4_boot_file_name_);
data.add(&hostname_);
+ data.add(&user_context_);
data.add(&host_ipv4_client_classes_);
data.add(&host_ipv6_client_classes_);
}
data.add(&option_is_persistent_);
data.add(&option_client_class_);
data.add(&option_subnet_id_);
+ data.add(&option_user_context_);
+ data.add(&option_scope_id_);
} catch (const Exception& ex) {
isc_throw(DbOperationError,
Host* host = new Host(host_identifier.data(), host_identifier.size(),
host_identifier_type, ipv4_subnet_id, ipv6_subnet_id,
ipv4_reservation, hostname_,
- host_ipv4_client_classes_, host_ipv6_client_classes_);
+ host_ipv4_client_classes_, host_ipv6_client_classes_
+ host_ipv4_next_server_, host_ipv4_server_hostname_,
+ host_ipv4_boot_file_name_);
+
+ // Set the user context if there is one.
+ if (!user_context_.empty()) {
+ try {
+ ConstElementPtr ctx = Element::fromJSON(user_context_);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context_
+ << "' is not a JSON map");
+ }
+ host->setContext(ctx);
+ } catch (const isc::data::JSONError& ex) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is invalid JSON: " << ex.what());
+ }
+ }
+
host->setHostId(id);
const IPv6Resrv reservation = retrieveReservation();
}
}
- return (OptionWrapper(OptionDescriptorPtr(new OptionDescriptor(option, option_is_persistent_,
- option_formatted_value_)), option_space_));
+ OptionWrapper result(OptionDescriptorPtr(new OptionDescriptor(option, option_is_persistent_,
+ option_formatted_value_)), option_space_);
+ // Set the user context if there is one into the option descriptor.
+ if (!option_user_context_.empty()) {
+ try {
+ ConstElementPtr ctx = Element::fromJSON(option_user_context_));
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "option user context '" << option_user_context_
+ << "' is no a JSON map");
+ }
+ result.option_descriptor_->setContext(ctx);
+ } catch (const isc::data::JSONError& ex) {
+ isc_throw(BadValue, "option user context '" << option_user_context_
+ << "' is invalid JSON: " << ex.what());
+ }
+ }
+
+ return result;
}
/// @brief Implementation of the @ref CqlHostDataSource.