Browse Source

[5272] lease4-add, lease6-add implemented

Tomek Mrugalski 7 years ago
parent
commit
92280f3da1

+ 4 - 0
src/hooks/dhcp/lease_cmds/.gitignore

@@ -0,0 +1,4 @@
+/lease_cmds_messages.cc
+/lease_cmds_messages.h
+/s-messages
+/html

+ 112 - 69
src/hooks/dhcp/lease_cmds/lease_cmds.cc

@@ -57,7 +57,7 @@ public:
         TYPE_HWADDR,  ///< query by hardware address (v4 only)
         TYPE_HWADDR,  ///< query by hardware address (v4 only)
         TYPE_DUID     ///< query by DUID (v6 only)
         TYPE_DUID     ///< query by DUID (v6 only)
     } Type;
     } Type;
-    
+
     /// @brief Specifies subnet-id (always used)
     /// @brief Specifies subnet-id (always used)
     SubnetID subnet_id;
     SubnetID subnet_id;
 
 
@@ -71,13 +71,31 @@ public:
     /// @brief Specifies identifier value (used when query_by_addr is false)
     /// @brief Specifies identifier value (used when query_by_addr is false)
     isc::dhcp::DuidPtr duid;
     isc::dhcp::DuidPtr duid;
 
 
+    static Type txtToType(const std::string& txt) {
+        if (txt == "address") {
+            return (Parameters::TYPE_ADDR);
+        } else if (txt == "hw-address") {
+            return (Parameters::TYPE_HWADDR);
+        } else if (txt == "duid") {
+            return (Parameters::TYPE_DUID);
+        } else {
+            isc_throw(BadValue, "Incorrect identifier type: "
+                      << txt << ", the only supported values are: "
+                      "address, hw-address, duid");
+        }
+    }
+
     /// @brief specifies parameter types (true = query by address, false =
     /// @brief specifies parameter types (true = query by address, false =
     ///         query by indetifier-type,identifier)
     ///         query by indetifier-type,identifier)
     Type query_type;
     Type query_type;
 
 
+    Lease::Type lease_type;
+
+    uint32_t iaid;
+
     /// @brief Default contstructor.
     /// @brief Default contstructor.
     Parameters()
     Parameters()
-        :addr("::"), query_type(TYPE_ADDR) {
+        :addr("::"), query_type(TYPE_ADDR), lease_type(Lease::TYPE_NA), iaid(0) {
     }
     }
 };
 };
 
 
@@ -135,8 +153,8 @@ private:
     ///         "valid-lft": 3600,
     ///         "valid-lft": 3600,
     ///         "expire": 1499282530,
     ///         "expire": 1499282530,
     ///         "subnet-id": 1,
     ///         "subnet-id": 1,
-    ///         "fdqn_fwd": true,
-    ///         "fqdn_rev": true,
+    ///         "fdqn-fwd": true,
+    ///         "fqdn-rev": true,
     ///         "hostname": "myhost.example.org",
     ///         "hostname": "myhost.example.org",
     ///         "state": 0
     ///         "state": 0
     ///     }
     ///     }
@@ -236,6 +254,7 @@ private:
 };
 };
 
 
 LeaseCmdsImpl::LeaseCmdsImpl() {
 LeaseCmdsImpl::LeaseCmdsImpl() {
+    /// @todo: Remove family_
     family_ = CfgMgr::instance().getFamily();
     family_ = CfgMgr::instance().getFamily();
 
 
     registerCommands();
     registerCommands();
@@ -311,32 +330,34 @@ LeaseCmdsImpl::leaseAddHandler(const std::string& name,
             isc_throw(isc::BadValue, "'lease' parameters must be specified");
             isc_throw(isc::BadValue, "'lease' parameters must be specified");
         }
         }
 
 
+        ConstSrvConfigPtr config = CfgMgr::instance().getCurrentCfg();
+
         Lease4Ptr lease4;
         Lease4Ptr lease4;
         Lease6Ptr lease6;
         Lease6Ptr lease6;
         if (v4) {
         if (v4) {
-            LeaseDataParser4 parser;
-            lease4 = parser.parse(lease_data);
+            Lease4Parser parser;
+            lease4 = parser.parse(config, lease_data);
 
 
-            checkLeaseIntegrity(lease4);
+            // checkLeaseIntegrity(config, lease4);
 
 
             if (lease4) {
             if (lease4) {
-                LeaseMgrFactory::instance().add(lease4);
+                LeaseMgrFactory::instance().addLease(lease4);
             }
             }
             
             
         } else {
         } else {
-            LeaseDataParser6 parser;
-            lease6 = parser.parse(lease_data);
+            Lease6Parser parser;
+            lease6 = parser.parse(config, lease_data);
 
 
-            checkLeaseIntegrity(lease6);
+            // checkLeaseIntegrity(config, lease6);
 
 
             if (lease6) {
             if (lease6) {
-                LeaseMgrFactory::instance().add(lease6);
+                LeaseMgrFactory::instance().addLease(lease6);
             }
             }
         }
         }
 
 
 
 
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
-        LOG_ERROR(lease_cmds_logger, LEASE_CMDS_RESERV_ADD_FAILED)
+        LOG_ERROR(lease_cmds_logger, v4 ? LEASE_CMDS_ADD4_FAILED : LEASE_CMDS_ADD6_FAILED)
             .arg(txt)
             .arg(txt)
             .arg(ex.what());
             .arg(ex.what());
         return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
         return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
@@ -366,15 +387,14 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
     }
     }
     x.subnet_id = tmp->intValue();
     x.subnet_id = tmp->intValue();
 
 
-    tmp = params->get("ip-address");
-    ConstLeasePtr host;
+    tmp = params->get("address");
     if (tmp) {
     if (tmp) {
         if (tmp->getType() != Element::string) {
         if (tmp->getType() != Element::string) {
-            isc_throw(BadValue, "'ip-address' is not a string.");
+            isc_throw(BadValue, "'address' is not a string.");
         }
         }
 
 
         x.addr = IOAddress(tmp->stringValue());
         x.addr = IOAddress(tmp->stringValue());
-        x.query_by_addr = true;
+        x.query_type = Parameters::TYPE_ADDR;
         return (x);
         return (x);
     }
     }
 
 
@@ -394,32 +414,29 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
     }
     }
 
 
     // Got the parameters. Let's see if their values make sense.
     // Got the parameters. Let's see if their values make sense.
-
-    // Try to parse the identifier value first.
-    try {
-        x.ident = util::str::quotedStringToBinary(ident->stringValue());
-        if (x.ident.empty()) {
-            util::str::decodeFormattedHexString(ident->stringValue(),
-                                                x.ident);
-        }
-    } catch (...) {
-        // The string doesn't match any known pattern, so we have to
-        // report an error at this point.
-        isc_throw(BadValue, "Unable to parse 'identifier' value.");
+    // Try to convert identifier-type
+    x.query_type = Parameters::txtToType(type->stringValue());
+
+    switch (x.query_type) {
+    case Parameters::TYPE_HWADDR: {
+        HWAddr hw = HWAddr::fromText(ident->stringValue());
+        x.hwaddr = HWAddrPtr(new HWAddr(hw));
+        break;
     }
     }
-
-    if (x.ident.empty()) {
-        isc_throw(BadValue, "Unable to query for empty 'identifier'.");
+    case Parameters::TYPE_DUID: {
+        DUID duid = DUID::fromText(ident->stringValue());
+        x.duid = DuidPtr(new DUID(duid));
+    }
+    case Parameters::TYPE_ADDR: {
+        // We should never get here. The address clause should have been caught
+        // earlier.
+        return (x);
+    }
+    default: {
+        isc_throw(BadValue, "Identifier type " << type->stringValue() <<
+                  " is not supported.");
     }
     }
-
-    // Next, try to convert identifier-type
-    try {
-        x.type = Lease::getIdentifierType(type->stringValue());
-    } catch (const std::exception& ex) {
-        isc_throw(BadValue, "Value of 'identifier-type' was not recognized.");
     }
     }
-
-    x.query_by_addr = false;
     return (x);
     return (x);
 }
 }
 
 
@@ -433,77 +450,93 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
         p = getParameters(params);
         p = getParameters(params);
 
 
         switch (p.query_type) {
         switch (p.query_type) {
-        case TYPE_ADDR: {
+        case Parameters::TYPE_ADDR: {
             // Query by address
             // Query by address
             if (v4) {
             if (v4) {
-                lease4 = LeaseMgr::instance().getLease4(p.subnet_id, p.addr);
+                lease4 = LeaseMgrFactory::instance().getLease4(p.addr);
             } else {
             } else {
-                lease6 = LeaseMgr::instance().getLease6(p.subnet_id, p.addr);
+                lease6 = LeaseMgrFactory::instance().getLease6(p.lease_type, p.addr);
             }
             }
             break;
             break;
         }
         }
-        case TYPE_HWADDR:
+        case Parameters::TYPE_HWADDR:
             if (v4) {
             if (v4) {
-                lease4 = LeaseMgr::instance().getLease4(p.subnet_id, p.hwaddr);
+                if (!p.hwaddr) {
+                    return (createAnswer(CONTROL_RESULT_ERROR,
+                                         "Program error: Query by hw-address "
+                                         "requires hwaddr to be specified"));
+                }
+                lease4 = LeaseMgrFactory::instance().getLease4(*p.hwaddr, p.subnet_id);
             } else {
             } else {
                 return (createAnswer(CONTROL_RESULT_ERROR,
                 return (createAnswer(CONTROL_RESULT_ERROR,
                                      "Query by hw-address is not allowed in v6."));
                                      "Query by hw-address is not allowed in v6."));
             }
             }
-        case TYPE_DUID:
-            if (v6) {
-                lease6 = LeaseMgr::instance().getLease6(p.subnet_id, p.duid);
+        case Parameters::TYPE_DUID:
+            if (!v4) {
+                if (!p.duid) {
+                    return (createAnswer(CONTROL_RESULT_ERROR,
+                                         "Program error: Query by duid "
+                                         "requires duid to be specified"));
+                }
+                lease6 = LeaseMgrFactory::instance().getLease6(p.lease_type, *p.duid,
+                                                               p.iaid, p.subnet_id);
             } else {
             } else {
                 return (createAnswer(CONTROL_RESULT_ERROR,
                 return (createAnswer(CONTROL_RESULT_ERROR,
                                      "Query by duid is not allowed in v4."));
                                      "Query by duid is not allowed in v4."));
             }
             }
-        default:
-            return (createAnswer(CONTROL_RESULT_ERROR,
-                                 "Unknown query type: " << static_cast<int>(p.query_type)));
+        default: {
+            stringstream tmp;
+            tmp << "Unknown query type: " << static_cast<int>(p.query_type);
+            return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
+        }
         }
         }
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
-        return (createAnswer(CONTROL_RESULT_ERROR,
-                             "Failure during leaseX-get: " << ex.what()));
+        stringstream tmp;
+        tmp << "Failure during leaseX-get: " << ex.what();
+        return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
     }
     }
 
 
     ElementPtr lease_json;
     ElementPtr lease_json;
     if (v4 && lease4) {
     if (v4 && lease4) {
-        lease_json = lease4->toElement4();
+        lease_json = lease4->toElement();
+        return (createAnswer(CONTROL_RESULT_SUCCESS, "DHCPv4 lease found.", lease_json));
     }
     }
     if (!v4 && lease6) {
     if (!v4 && lease6) {
-        lease_json = lease6->toElement6();
+        lease_json = lease6->toElement();
+        return (createAnswer(CONTROL_RESULT_SUCCESS, "DHCPv6 lease found.", lease_json));
         
         
     }
     }
-    if (lease) {
-        return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease found.", lease_json));
-    } else {
-        return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease not found."));
-    }
+
+    // If we got here, the lease has not been found.
+    return (createAnswer(CONTROL_RESULT_EMPTY, "Lease not found."));
 }
 }
 
 
 ConstElementPtr
 ConstElementPtr
-LeaseCmdsImpl::reservationDelHandler(const std::string& /*name*/,
-                                    ConstElementPtr params) {
+LeaseCmdsImpl::leaseDelHandler(const std::string& name,
+                               ConstElementPtr params) {
     Parameters p;
     Parameters p;
-    bool deleted;
+    bool deleted = false;
+#if 0    
     try {
     try {
         p = getParameters(params);
         p = getParameters(params);
 
 
         if (p.query_by_addr) {
         if (p.query_by_addr) {
             // try to delete by address
             // try to delete by address
-            deleted = LeaseMgr::instance().del(p.subnet_id, p.addr);
+            deleted = LeaseMgrFactory::instance().del(p.subnet_id, p.addr);
         } else {
         } else {
             // try to delete by identifier
             // try to delete by identifier
             if (family_ == AF_INET) {
             if (family_ == AF_INET) {
-                deleted = LeaseMgr::instance().del4(p.subnet_id, p.type,
-                                                   &p.ident[0], p.ident.size());
+                deleted = LeaseMgrFactory::instance().del4(p.subnet_id, p.type,
+                                                           &p.ident[0], p.ident.size());
             } else {
             } else {
-                deleted = LeaseMgr::instance().del6(p.subnet_id, p.type,
-                                                   &p.ident[0], p.ident.size());
+                deleted = LeaseMgrFactory::instance().del6(p.subnet_id, p.type,
+                                                           &p.ident[0], p.ident.size());
             }
             }
         }
         }
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
         return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
     }
     }
+#endif
 
 
     if (deleted) {
     if (deleted) {
         return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease deleted."));
         return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease deleted."));
@@ -513,8 +546,18 @@ LeaseCmdsImpl::reservationDelHandler(const std::string& /*name*/,
     }
     }
 }
 }
 
 
+ConstElementPtr
+LeaseCmdsImpl::leaseUpdateHandler(const string& command, ConstElementPtr args) {
+    return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
+}
+
+ConstElementPtr
+LeaseCmdsImpl::leaseWipeHandler(const string& command, ConstElementPtr args) {
+    return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
+}
+
+
 uint16_t LeaseCmdsImpl::family_ = AF_INET;
 uint16_t LeaseCmdsImpl::family_ = AF_INET;
-LeaseDataSourcePtr LeaseCmdsImpl::db_storage_;
 
 
 LeaseCmds::LeaseCmds()
 LeaseCmds::LeaseCmds()
     :impl_(new LeaseCmdsImpl()) {
     :impl_(new LeaseCmdsImpl()) {

+ 2 - 2
src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes

@@ -18,11 +18,11 @@ the log message.
 This info message indicates that the Lease Commands hooks library has been
 This info message indicates that the Lease Commands hooks library has been
 removed successfully.
 removed successfully.
 
 
-% LEASE_CMDS_ADD4_FAILED Lease4-add command failed (parameters: %1, reason: %2)
+% LEASE_CMDS_ADD4_FAILED lease4-add command failed (parameters: %1, reason: %2)
 The lease4-add command has failed. Both the reason as well as the
 The lease4-add command has failed. Both the reason as well as the
 parameters passed are logged.
 parameters passed are logged.
 
 
-% LEASE_CMDS_ADD6_FAILED Lease4-add command failed (parameters: %1, reason: %2)
+% LEASE_CMDS_ADD6_FAILED Lease6-add command failed (parameters: %1, reason: %2)
 The lease6-add command has failed. Both the reason as well as the
 The lease6-add command has failed. Both the reason as well as the
 parameters passed are logged.
 parameters passed are logged.
 
 

+ 234 - 6
src/hooks/dhcp/lease_cmds/lease_parser.cc

@@ -4,14 +4,242 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
+#include <cc/data.h>
+#include <dhcp/hwaddr.h>
+#include <asiolink/io_address.h>
+#include <dhcpsrv/lease.h>
+#include <lease_parser.h>
 
 
-// V4:
-// address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state
+#include <config.h>
 
 
-// V6:
-// address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,state
+using namespace std;
+using namespace isc::dhcp;
+using namespace isc::data;
+using namespace isc::asiolink;
 
 
-#include <config.h>
+// Can't use a constructor as a function
+namespace {
+IOAddress buildIOAddress(const std::string& str) { return (IOAddress(str)); }
+};
+
+namespace isc {
+namespace lease_cmds {
+
+IOAddress
+LeaseParser::getIOAddress(const ConstElementPtr& scope,
+                           const std::string& name) {
+    return (getAndConvert<IOAddress,
+            buildIOAddress>(scope, name, "address"));
+}
+
+Lease4Ptr
+Lease4Parser::parse(ConstSrvConfigPtr& cfg,
+                    const ConstElementPtr& lease_info) {
+    if (!lease_info) {
+        isc_throw(BadValue, "lease information missing");
+    }
+
+    // These are mandatory parameters.
+    IOAddress addr = getIOAddress(lease_info, "ip-address");
+    SubnetID subnet_id = getUint32(lease_info, "subnet-id");
+
+    if (!addr.isV4()) {
+        isc_throw(BadValue, "Non-IPv4 address specified: " << addr);
+    }
+
+    // Not a most straightforward conversion, but it works.
+    string hwaddr_txt = getString(lease_info, "hw-address");
+    HWAddr hwaddr = HWAddr::fromText(hwaddr_txt);
+    HWAddrPtr hwaddr_ptr = HWAddrPtr(new HWAddr(hwaddr));
+
+    Subnet4Ptr subnet = cfg->getCfgSubnets4()->getSubnet(subnet_id);
+    if (!subnet) {
+        isc_throw(BadValue, "Invalid subnet-id: No IPv4 subnet with subnet-id="
+                  << subnet_id << " currently configured.");
+    }
+
+    // Client-id is optional.
+    ClientIdPtr client_id;
+    if (lease_info->contains("client-id")) {
+        string txt = getString(lease_info, "client-id");
+        client_id = ClientId::fromText(txt);
+    }
+
+    // These parameters are optional. If not specified, we'll derive them from
+    // the current subnet configuration, if possible.
+    uint32_t valid_lft = 0;
+    if (lease_info->contains("valid-lft")) {
+        valid_lft = getUint32(lease_info, "valid-lft");
+    } else {
+        valid_lft = subnet->getValid();
+    }
+
+    /// Let's calculate client last transmission time (cltt). If expiration
+    /// timestamp is specified explicitly, we will use that. Note there are no
+    /// checks whether this is in the past. There may be valid cases when user
+    /// wants to insert expired leases, e.g. when migrating from one DHCP server
+    /// to another and wants to migrate the database as is, without disarding
+    /// any leases.
+    time_t cltt;
+    if (lease_info->contains("expire")) {
+        int64_t tmp = getUint32(lease_info, "expire");
+        cltt = static_cast<time_t>(tmp - valid_lft);
+    } else {
+        cltt = time(NULL);
+    }
+
+    bool fqdn_fwd = false;
+    if (lease_info->contains("fqdn-fwd")) {
+        fqdn_fwd = getBoolean(lease_info, "fqdn-fwd");
+    }
+    bool fqdn_rev = false;
+    if (lease_info->contains("fqdn-rev")) {
+        fqdn_rev = getBoolean(lease_info, "fqdn-rev");
+    }
+    string hostname;
+    if (lease_info->contains("hostname")) {
+        hostname = getString(lease_info, "hostname");
+    }
+    if (hostname.empty() && (fqdn_fwd || fqdn_rev)) {
+        isc_throw(BadValue, "No hostname specified and either forward or reverse"
+                  " fqdn was set to true.");
+    }
+
+    uint32_t state = 0;
+    if (lease_info->contains("state")) {
+        state = getUint8(lease_info, "state");
+    }
+
+    // Let's fabricate some data and we're ready to go.
+    uint32_t t1 = subnet->getT1();
+    uint32_t t2 = subnet->getT2();
+
+    Lease4Ptr l(new Lease4(addr, hwaddr_ptr, client_id, valid_lft, t1, t2,
+                           cltt, subnet_id,
+                           fqdn_fwd, fqdn_rev, hostname));
+    l->state_ = state;
+    return (l);
+}
+
+Lease6Ptr
+Lease6Parser::parse(ConstSrvConfigPtr& cfg,
+                    const ConstElementPtr& lease_info) {
+    if (!lease_info) {
+        isc_throw(BadValue, "lease information missing");
+    }
+
+    // These are mandatory parameters.
+    IOAddress addr = getIOAddress(lease_info, "ip-address");
+    SubnetID subnet_id = getUint32(lease_info, "subnet-id");
+
+    if (addr.isV4()) {
+        isc_throw(BadValue, "Non-IPv6 address specified: " << addr);
+    }
+
+    // Not a most straightforward conversion, but it works.
+    string duid_txt = getString(lease_info, "duid");
+    DUID duid = DUID::fromText(duid_txt);
+    DuidPtr duid_ptr = DuidPtr(new DUID(duid));
+
+    Subnet6Ptr subnet = cfg->getCfgSubnets6()->getSubnet(subnet_id);
+    if (!subnet) {
+        isc_throw(BadValue, "Invalid subnet-id: No IPv6 subnet with subnet-id="
+                  << subnet_id << " currently configured.");
+    }
+
+    Lease::Type type = Lease::TYPE_NA;
+    uint8_t prefix_len = 128;
+    if (lease_info->contains("type")) {
+        string txt = getString(lease_info, "type");
+        if (txt == "IA_NA") {
+            type = Lease::TYPE_NA;
+        } else if (txt == "IA_TA") {
+            type = Lease::TYPE_TA;
+        } else if (txt == "IA_PD") {
+            type = Lease::TYPE_PD;
+
+            prefix_len = getUint8(lease_info, "prefix-len");
+        } else {
+            isc_throw(BadValue, "Incorrect lease type: " << txt << ", the only "
+                      "supported values are: na, ta and pd");
+        }
+    }
+
+    uint32_t iaid = getUint32(lease_info, "iaid");
+
+    // Hw-address is optional in v6 leases.
+    HWAddrPtr hwaddr_ptr;
+    if (lease_info->contains("hw-address")) {
+        string hwaddr_txt = getString(lease_info, "hw-address");
+        HWAddr hwaddr = HWAddr::fromText(hwaddr_txt);
+        hwaddr_ptr = HWAddrPtr(new HWAddr(hwaddr));
+    }
+
+    // These parameters are optional. If not specified, we'll derive them
+    // from the current subnet configuration, if possible.
+    uint32_t valid_lft = 0;
+    if (lease_info->contains("valid-lft")) {
+        valid_lft = getUint32(lease_info, "valid-lft");
+    } else {
+        valid_lft = subnet->getValid();
+    }
+
+    // These parameters are optional. If not specified, we'll derive them
+    // from the current subnet configuration, if possible.
+    uint32_t pref_lft = 0;
+    if (lease_info->contains("preferred-lft")) {
+        pref_lft = getUint32(lease_info, "preferred-lft");
+    } else {
+        pref_lft = subnet->getValid();
+    }
+
+    /// Let's calculate client last transmission time (cltt). If expiration
+    /// timestamp is specified explicitly, we will use that. Note there are
+    /// no checks whether this is in the past. There may be valid cases when
+    /// user wants to insert expired leases, e.g. when migrating from one
+    /// DHCP server to another and wants to migrate the database as is, without
+    /// disarding any leases.
+    time_t cltt;
+    if (lease_info->contains("expire")) {
+        int64_t tmp = getUint32(lease_info, "expire");
+        cltt = static_cast<time_t>(tmp - valid_lft);
+    } else {
+        cltt = time(NULL);
+    }
+
+    bool fqdn_fwd = false;
+    if (lease_info->contains("fqdn-fwd")) {
+        fqdn_fwd = getBoolean(lease_info, "fqdn-fwd");
+    }
+    bool fqdn_rev = false;
+    if (lease_info->contains("fqdn-rev")) {
+        fqdn_rev = getBoolean(lease_info, "fqdn-rev");
+    }
+    string hostname;
+    if (lease_info->contains("hostname")) {
+        hostname = getString(lease_info, "hostname");
+    }
+    if (hostname.empty() && (fqdn_fwd || fqdn_rev)) {
+        isc_throw(BadValue, "No hostname specified and either forward or reverse"
+                  " fqdn was set to true.");
+    }
+
+    uint32_t state = 0;
+    if (lease_info->contains("state")) {
+        state = getUint8(lease_info, "state");
+    }
+
+    // Let's fabricate some data and we're ready to go.
+    uint32_t t1 = subnet->getT1();
+    uint32_t t2 = subnet->getT2();
 
 
+    Lease6Ptr l(new Lease6(type, addr, duid_ptr, iaid, pref_lft, valid_lft, t1, t2,
+                           subnet_id, fqdn_fwd, fqdn_rev, hostname,
+                           hwaddr_ptr, prefix_len));
+    l->cltt_ = cltt;
+    l->state_ = state;
+    return (l);
+}
 
 
-    
+};
+};

+ 74 - 6
src/hooks/dhcp/lease_cmds/lease_parser.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -10,28 +10,96 @@
 #include <cc/data.h>
 #include <cc/data.h>
 #include <cc/simple_parser.h>
 #include <cc/simple_parser.h>
 #include <dhcpsrv/lease.h>
 #include <dhcpsrv/lease.h>
+#include <dhcpsrv/srv_config.h>
 
 
 namespace isc {
 namespace isc {
 namespace lease_cmds {
 namespace lease_cmds {
 
 
-/// @brief Parser for a single Lease information.
+/// @brief Base class for Lease4 and Lease6 parsers
 class LeaseParser : public isc::data::SimpleParser {
 class LeaseParser : public isc::data::SimpleParser {
+protected:
+
+    /// @brief Returns an address from JSON structure
+    ///
+    /// @param scope a map the element will be searched at
+    /// @param name key name to be searched for
+    /// @return IOAddress representation
+    isc::asiolink::IOAddress getIOAddress(const isc::data::ConstElementPtr& scope,
+                                          const std::string& name);
 };
 };
 
 
+/// @brief Parser for Lease4 structure
+///
+/// It expects the data in the following format:
+/// {
+///     "ip-address": "192.0.2.1",
+///     "hw-address": "00:01:02:03:04:05",
+///     "client-id": "this-is-a-client",
+///     "valid-lft": 3600,
+///     "cltt": 12345678,
+///     "expire": 1499282530,
+///     "subnet-id": 1,
+///     "fdqn-fwd": true,
+///     "fqdn-rev": true,
+///     "hostname": "myhost.example.org",
+///     "state": 0
+/// }
 class Lease4Parser : public LeaseParser {
 class Lease4Parser : public LeaseParser {
 public:
 public:
-    virtual isc::dhcp::Lease4Ptr parse(const isc::data::ConstElementPtr& lease_info);
+
+    /// @brief Parses Element tree and tries to convert to Lease4
+    ///
+    /// See @ref Lease6Parser class description for expected format.
+    ///
+    /// @param cfg Currently running config (used for sanity checks and defaults)
+    /// @param lease_info structure to be parsed
+    /// @return A pointer to Lease4
+    /// @throw BadValue if any of the parameters is invalid
+    /// @throw DhcpConfigError if mandatory parameter is missing
+    virtual isc::dhcp::Lease4Ptr parse(isc::dhcp::ConstSrvConfigPtr& cfg,
+                                       const isc::data::ConstElementPtr& lease_info);
+
+    /// @brief virtual dtor (does nothing)
     virtual ~Lease4Parser() {}
     virtual ~Lease4Parser() {}
 };
 };
 
 
+/// @brief Parser for Lease6 structure
+///
+/// {
+///     "address": "2001:db8::1",
+///     "duid": "00:01:02:03:04:05",
+///     "type": "IA_NA",
+///     "cltt": 12345678,
+///     "preferred-lft": 3600,
+///     "valid-lft": 3600,
+///     "expire": 1499282530,
+///     "subnet-id": 1,
+///     "fdqn-fwd": true,
+///     "fqdn-rev": true,
+///     "hostname": "myhost.example.org",
+///     "state": 0
+/// }
+
+/// It expects the input data to use the following format:
 class Lease6Parser : public LeaseParser {
 class Lease6Parser : public LeaseParser {
 public:
 public:
-    virtual isc::dhcp::Lease6Ptr parse(const isc::data::ConstElementPtr& lease_info);
+    /// @brief Parses Element tree and tries to convert to Lease4
+    ///
+    /// See @ref Lease6Parser class description for expected format.
+    ///
+    /// @param cfg Currently running config (used for sanity checks and defaults)
+    /// @param lease_info structure to be parsed
+    /// @return A pointer to Lease4
+    /// @throw BadValue if any of the parameters is invalid
+    /// @throw DhcpConfigError if mandatory parameter is missing
+    virtual isc::dhcp::Lease6Ptr parse(isc::dhcp::ConstSrvConfigPtr& cfg,
+                                       const isc::data::ConstElementPtr& lease_info);
+
+    /// @brief virtual dtor (does nothing)
     virtual ~Lease6Parser() {}
     virtual ~Lease6Parser() {}
 };
 };
-    
+
 }; // end of isc::dhcp namespace
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 }; // end of isc namespace
 
 
 #endif
 #endif
-    

+ 5 - 0
src/hooks/dhcp/lease_cmds/tests/.gitignore

@@ -0,0 +1,5 @@
+host_cmds_unittests
+host_cmds_unittests.log
+host_cmds_unittests.trs
+test-suite.log
+*~

+ 17 - 0
src/hooks/dhcp/lease_cmds/version.cc

@@ -0,0 +1,17 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <hooks/hooks.h>
+
+extern "C" {
+
+/// @brief returns Kea hooks version.
+int version() {
+    return (KEA_HOOKS_VERSION);
+}
+
+}