// Copyright (C) 2018-2023 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/**

@page libdhcp_stat_cmds Kea Stat Commands Hooks Library

@section libdhcp_stat_cmdsIntro Introduction

Welcome to Kea Stat Commands Hooks Library. This documentation is addressed to
developers who are interested in the internal operation of the Stat Commands
library. This file provides information needed to understand and perhaps extend
this library.

This documentation is stand-alone: you should have read and understood the <a
href="https://reports.kea.isc.org/dev_guide/">Kea Developer's Guide</a> and in
particular its section about hooks.

@section stat_cmds Stat Commands Overview

Stat Commands (or stat_cmds) is a Hook library that can be loaded by
either kea-dhcp4 and kea-dhcp6 servers to extend them with additional
statistics mechanisms.

The initial purpose of this library is provide supplemental commands for
obtaining accurate lease statistics in deployments that share lease storage
between multiple Kea DHCP servers. It is likely that additional statistics
related commands will be added to this library in future releases as use
cases for them arise.

The library is structured around command handlers. When the library is
loaded it registers handlers for new commands.  When a command
is issued (be it directly via control channel or indirectly via REST
interface from control agent), the code receives a JSON command with
parameters.  The command is routed the appropriate handler, its parameters
are parsed and command executed accordingly.  Lastly, a response is
constructed and shipped back to the client.

This lease statistics commands interact with both the isc::dhcp::StatsMgr
and the isc::dhcp::LeaseMgr instance.  At the time of writing this text
(May, 2018), Kea supports four types of lease managers: memfile, MySQL or
PostgreSQL. The lease statistics commands provided by this library provide a
unified interface supported by all four of these backends.

As with other hooks, this one keeps its code in a separate namespace which
corresponds to the file name of the library: isc::stat_cmds.

For background on the design and design choices please refer to: <a
href="https://gitlab.isc.org/isc-projects/kea/wikis/designs/shared-lease-storage-statistics">Shared Lease Stats Design</a>

@section stat_cmdsCode Stat Commands Code Overview

Library operation starts with Kea calling the load() function (file
stat_cmds_callouts.cc).  This function registers the command callout
functions for each of the libraries commands. For a list,
see @ref isc::stat_cmds::StatCmds class documentation.  This class uses
the Pimpl design pattern, and thus the actual implementation is hidden
in @ref isc::stat_cmds::LeaseStatCmdsImpl.

Unlike similar libraries, the Pimpl class is differentiated from the
the StatCmds class by the prefix "Lease" and it is instantiated in the outer
handler (e.g. @ref isc::stat_cmds::StatCmds::statLease4GetHandler) rather than
the StatCmds constructor.  This was done in the event that commands, unrelated
to lease statistics, are added to this library and that would be better served
by Pimpl derivations specific to them.

@subsection stat_cmdsLeaseStatCode Lease Stat Commands Code Overview

There are two shared lease statistic commands, "stat-lease4-get" and "stat-lease6-get".
Both of these support the same input parameters and have their own command handlers:

- @ref isc::stat_cmds::LeaseStatCmdsImpl::statLease4GetHandler (stat-lease4-get)
- @ref isc::stat_cmds::LeaseStatCmdsImpl::statLease6GetHandler (stat-lease6-get)

Briefly, the commands are intended to fetch the lease statistics per subnet
for the range of subnets described by the input parameters.  JSON text structure
of the commands is as follows:

DHCPv4 command:

@code
{
    "command": "stat-lease4-get",
    "arguments": {
        "subnet-id": x
        "subnet-range": {
            "first-subnet-id": x,
            "last-subnet-id": y
        }
    }
}

    where subnet-id and subnet-range are optional and mutually exclusive
@endcode

DHCPv6 command:

@code
{
    "command": "stat-lease6-get",
    "arguments": {
        "subnet-id": x
        "subnet-range": {
            "first-subnet-id": x,
            "last-subnet-id": y
        }
    }
}

    where subnet-id and subnet-range are optional and mutually exclusive
@endcode



Command handling
for both commands is symmetrical consists of the following steps:

-# The input parameters (if any) are parsed.  Invalid values or
combinations if detected result in generating a CONTROL_RESULT_ERROR
response to the client.  (See @ref isc::stat_cmds::LeaseStatCmdsImpl::getParameters
and @ref isc::stat_cmds::LeaseStatCmdsImpl::Parameters)

-# The parameters are used to identify the range of configured subnets
to include in the response.  This is done by querying subnet configuration
housed by @ref isc::dhcp::CfgMgr. If the range contains no known subnets then a
CONTROL_RESULT_EMPTY response is sent back to the client.

-# The initial result-set response is constructed.  Essentially this is
an @ref isc::data::Element tree, which converted to JSON would appear as follows:

@code
    "result-set": {
        "timestamp": "2018-03-22 09:43:30.815371",
        "columns": ["<label-1>, <label-2>, ... ],
        "rows": []
    }
@endcode

-# The actual lease statistics are then retrieved from @ref isc::dhcp::LeaseMgr instance
by invoking of the three functions based on the input parameters:

DHCPv4 functions:

- @ref isc::dhcp::LeaseMgr::startLeaseStatsQuery4
- @ref isc::dhcp::LeaseMgr::startSubnetLeaseStatsQuery4
- @ref isc::dhcp::LeaseMgr::startSubnetRangeLeaseStatsQuery4

DHCPv6 functions:

- @ref isc::dhcp::LeaseMgr::startLeaseStatsQuery6
- @ref isc::dhcp::LeaseMgr::startSubnetLeaseStatsQuery6
- @ref isc::dhcp::LeaseMgr::startSubnetRangeLeaseStatsQuery6

-# Iterate over the range of qualifying subnets adding a row of statistics for
each subnet to the result-set.  Each row combines the subnet total(s) from isc::dhcp::StatsMgr
with the type and state counts from the lease query results. For subnets with no query
data (i.e. no leases), their rows have non-zero values for totals only.

-# Finally, a CONTROL_RESULT_SUCCESS response is generated containing the populated result-set.

A DHCPv4 response might look like this:

@code
        {
        "result-set\": {
           "columns\": [
                "subnet-id", "total-addresses",
                "cumulative-assigned-addresses",
                "assigned-addresses", "declined-addresses"
           ],
           "rows\": [
               [ 30, 256, 300, 100, 2 ],
               [ 40,  16, 5, 0, 0 ],
               [ 50, 256, 100, 35, 0 ]
           ],
           timestamp\": \"2018-05-04 15:03:37.000000\" }
        }
@endcode

and DHCPv6 response might look like this:

@code
        {
        "result-set": {
           "columns": [
                "subnet-id", "total-nas", "cumulative-assigned-nas",
                "assigned-nas", "declined-addresses", "total-pds",
                "cumulative-assigned-pds", "assigned-pds"
           ],
           "rows": [
               [ 30, 16, 20, 6, 0, 65536, 1000, 400 ],
               [ 40, 16777216, 1100000, 989837, 0, 0, 0, 0 ]
           ],
           "timestamp": "2018-05-04 15:03:37.000000" }
        }
@endcode

@section stat_cmdsMTCompatibility Multi-Threading Compatibility

The Stat Commands Hook library is compatible with multi-threading.
All commands are executed inside a critical section, i.e. with threads stopped.
It makes sense to not have lease state changes when retrieving lease counts.

*/
