[cli] add lease info to srp server host and srp server service (#12589)

This commit adds lease and remaining lease information to the output
of `srp server host` and `srp server service` CLI commands.

The information includes:
- `lease`: The total lease time in seconds.
- `key-lease`: The total key lease time in seconds.
- `remaining lease`: The remaining lease time in seconds (with
  millisecond precision).
- `remaining key-lease`: The remaining key lease time in seconds
  (with millisecond precision).

A new utility method `OutputMsecDurationInSec()` is added to `Utils`
class to format durations in milliseconds as seconds with a
fractional part.

The SRP server host and service output parsers in
`tests/scripts/thread-cert/node.py`, `tests/toranj/cli/cli.py`, and
`tools/otci/otci/otci.py` are updated to correctly handle the new
fields for both active and deleted entries.
This commit is contained in:
Abtin Keshavarzian
2026-03-02 20:03:14 -06:00
committed by GitHub
parent d5b5f863d7
commit cf1d23c11e
8 changed files with 132 additions and 30 deletions
+12
View File
@@ -165,9 +165,17 @@ Print information of all registered hosts.
srp-api-test-1.default.service.arpa.
deleted: false
addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
lease: 7200
key-lease: 1209600
remaining lease: 6345.459
remaining key-lease: 1208734.459
srp-api-test-0.default.service.arpa.
deleted: false
addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
lease: 3600
key-lease: 1209600
remaining lease: 2600.012
remaining key-lease: 1208600.012
Done
```
@@ -241,6 +249,8 @@ srp-api-test-1._ipps._tcp.default.service.arpa.
ttl: 7200
lease: 7200
key-lease: 1209600
remaining lease: 6345.459
remaining key-lease: 1208734.459
TXT: [616263, xyz=585960]
host: srp-api-test-1.default.service.arpa.
addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
@@ -253,6 +263,8 @@ srp-api-test-0._ipps._tcp.default.service.arpa.
ttl: 3600
lease: 3600
key-lease: 1209600
remaining lease: 2600.012
remaining key-lease: 1208600.012
TXT: [616263, xyz=585960]
host: srp-api-test-0.default.service.arpa.
addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
+49 -20
View File
@@ -378,32 +378,35 @@ template <> otError SrpServer::Process<Cmd("host")>(Arg aArgs[])
host = nullptr;
while ((host = otSrpServerGetNextHost(GetInstancePtr(), host)) != nullptr)
{
const otIp6Address *addresses;
uint8_t addressesNum;
bool isDeleted = otSrpServerHostIsDeleted(host);
const otIp6Address *addresses;
uint8_t addressesNum;
bool isDeleted = otSrpServerHostIsDeleted(host);
otSrpServerLeaseInfo leaseInfo;
OutputLine("%s", otSrpServerHostGetFullName(host));
OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
if (isDeleted)
if (!isDeleted)
{
continue;
}
OutputSpaces(kIndentSize);
OutputFormat("addresses: [");
OutputSpaces(kIndentSize);
OutputFormat("addresses: [");
addresses = otSrpServerHostGetAddresses(host, &addressesNum);
addresses = otSrpServerHostGetAddresses(host, &addressesNum);
for (uint8_t i = 0; i < addressesNum; ++i)
{
OutputIp6Address(addresses[i]);
if (i < addressesNum - 1)
for (uint8_t i = 0; i < addressesNum; ++i)
{
OutputFormat(", ");
OutputIp6Address(addresses[i]);
if (i < addressesNum - 1)
{
OutputFormat(", ");
}
}
OutputLine("]");
}
OutputLine("]");
otSrpServerHostGetLeaseInfo(host, &leaseInfo);
OutputLeaseInfo(leaseInfo, isDeleted);
}
exit:
@@ -430,6 +433,27 @@ void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost)
OutputFormat("]");
}
void SrpServer::OutputLeaseInfo(const otSrpServerLeaseInfo &aLeaseInfo, bool aIsDeleted)
{
if (!aIsDeleted)
{
OutputLine(kIndentSize, "lease: %lu", ToUlong(aLeaseInfo.mLease / 1000));
}
OutputLine(kIndentSize, "key-lease: %lu", ToUlong(aLeaseInfo.mKeyLease / 1000));
if (!aIsDeleted)
{
OutputFormat(kIndentSize, "remaining lease: ");
OutputMsecDurationInSec(aLeaseInfo.mRemainingLease);
OutputNewLine();
}
OutputFormat(kIndentSize, "remaining key-lease: ");
OutputMsecDurationInSec(aLeaseInfo.mRemainingKeyLease);
OutputNewLine();
}
/**
* @cli srp server service
* @code
@@ -443,6 +467,8 @@ void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost)
* ttl: 7200
* lease: 7200
* key-lease: 1209600
* remaining lease: 6345.459
* remaining key-lease: 1208734.459
* TXT: [616263, xyz=585960]
* host: srp-api-test-1.default.service.arpa.
* addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
@@ -455,6 +481,8 @@ void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost)
* ttl: 3600
* lease: 3600
* key-lease: 1209600
* remaining lease: 2600.012
* remaining key-lease: 1208600.012
* TXT: [616263, xyz=585960]
* host: srp-api-test-0.default.service.arpa.
* addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
@@ -493,13 +521,14 @@ template <> otError SrpServer::Process<Cmd("service")>(Arg aArgs[])
OutputLine("%s", otSrpServerServiceGetInstanceName(service));
OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
otSrpServerServiceGetLeaseInfo(service, &leaseInfo);
if (isDeleted)
{
OutputLeaseInfo(leaseInfo, isDeleted);
continue;
}
otSrpServerServiceGetLeaseInfo(service, &leaseInfo);
OutputFormat(kIndentSize, "subtypes: ");
for (uint16_t index = 0;; index++)
@@ -523,8 +552,8 @@ template <> otError SrpServer::Process<Cmd("service")>(Arg aArgs[])
OutputLine(kIndentSize, "priority: %u", otSrpServerServiceGetPriority(service));
OutputLine(kIndentSize, "weight: %u", otSrpServerServiceGetWeight(service));
OutputLine(kIndentSize, "ttl: %lu", ToUlong(otSrpServerServiceGetTtl(service)));
OutputLine(kIndentSize, "lease: %lu", ToUlong(leaseInfo.mLease / 1000));
OutputLine(kIndentSize, "key-lease: %lu", ToUlong(leaseInfo.mKeyLease / 1000));
OutputLeaseInfo(leaseInfo, isDeleted);
txtData = otSrpServerServiceGetTxtData(service, &txtDataLength);
OutputFormat(kIndentSize, "TXT: ");
+1
View File
@@ -83,6 +83,7 @@ private:
template <CommandId kCommandId> otError Process(Arg aArgs[]);
void OutputHostAddresses(const otSrpServerHost *aHost);
void OutputLeaseInfo(const otSrpServerLeaseInfo &aLeaseInfo, bool aIsDeleted);
};
} // namespace Cli
+8
View File
@@ -160,6 +160,14 @@ void Utils::OutputUint64Line(uint64_t aUint64)
void Utils::OutputEnabledDisabledStatus(bool aEnabled) { OutputLine(aEnabled ? "Enabled" : "Disabled"); }
void Utils::OutputMsecDurationInSec(uint32_t aMsecDuration)
{
uint32_t durInSec = aMsecDuration / 1000;
uint32_t remainder = aMsecDuration % 1000;
OutputFormat("%lu.%03u", ToUlong(durInSec), static_cast<uint16_t>(remainder));
}
#if OPENTHREAD_FTD || OPENTHREAD_MTD
void Utils::OutputIp6Address(const otIp6Address &aAddress)
+9
View File
@@ -351,6 +351,15 @@ public:
*/
void OutputEnabledDisabledStatus(bool aEnabled);
/**
* Outputs a given duration interval in seconds including the msec remainder.
*
* The duration is outputted in seconds with msec remainder, e.g., 12.047.
*
* @param[in] aMsecDuration A duration interval in msec.
*/
void OutputMsecDurationInSec(uint32_t aMsecDuration);
#if OPENTHREAD_FTD || OPENTHREAD_MTD
/**
+23 -4
View File
@@ -1157,7 +1157,11 @@ class NodeImpl:
'fullname': 'my-host.default.service.arpa.',
'name': 'my-host',
'deleted': 'false',
'addresses': ['2001::1', '2001::2']
'addresses': ['2001::1', '2001::2'],
'lease': '7200',
'key-lease': '1209600',
'remaining lease': '6345.459',
'remaining key-lease': '1208734.459'
}]
"""
@@ -1173,6 +1177,10 @@ class NodeImpl:
host['deleted'] = lines.pop(0).strip().split(':')[1].strip()
if host['deleted'] == 'true':
for _ in range(2):
# `key-lease` and `remaining key-lease`
key_value = lines.pop(0).strip().split(':')
host[key_value[0].strip()] = key_value[1].strip()
host_list.append(host)
continue
@@ -1180,6 +1188,11 @@ class NodeImpl:
map(str.strip, addresses)
host['addresses'] = [addr.strip() for addr in addresses if addr]
for _ in range(4):
# `lease`, `key-lease`, `remaining lease` and `remaining key-lease`
key_value = lines.pop(0).strip().split(':')
host[key_value[0].strip()] = key_value[1].strip()
host_list.append(host)
return host_list
@@ -1210,7 +1223,9 @@ class NodeImpl:
'weight': '0',
'ttl': '7200',
'lease': '7200',
'key-lease': '7200',
'key-lease': '1209600',
'remaining lease': '6345.459',
'remaining key-lease': '1208734.459',
'TXT': ['abc=010203'],
'host_fullname': 'my-host.default.service.arpa.',
'host': 'my-host',
@@ -1235,11 +1250,15 @@ class NodeImpl:
service['deleted'] = lines.pop(0).strip().split(':')[1].strip()
if service['deleted'] == 'true':
for _ in range(2):
key_value = lines.pop(0).strip().split(':')
service[key_value[0].strip()] = key_value[1].strip()
service_list.append(service)
continue
# 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', and 'key-lease'
for i in range(0, 7):
# 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', 'key-lease',
# 'remaining lease', and `remaining key-lease`
for i in range(0, 9):
key_value = lines.pop(0).strip().split(':')
service[key_value[0].strip()] = key_value[1].strip()
+24 -6
View File
@@ -715,15 +715,18 @@ class Node(object):
self._cli_no_output('srp server lease', min_lease, max_lease, min_key_lease, max_key_lease)
def srp_server_get_hosts(self):
"""Returns the host list on the SRP server as a list of property
dictionary.
"""Returns the host list on the SRP server as a list of property dictionary.
Example output:
[{
'fullname': 'my-host.default.service.arpa.',
'name': 'my-host',
'deleted': 'false',
'addresses': ['2001::1', '2001::2']
'addresses': ['2001::1', '2001::2'],
'lease': '7200',
'key-lease': '1209600',
'remaining lease': '6345.459',
'remaining key-lease': '1208734.459'
}]
"""
outputs = self.cli('srp server host')
@@ -734,11 +737,19 @@ class Node(object):
host['name'] = host['fullname'].split('.')[0]
host['deleted'] = outputs.pop(0).strip().split(':')[1].strip()
if host['deleted'] == 'true':
for _ in range(2):
# `key-lease` and `remaining key-lease`
key_value = outputs.pop(0).strip().split(':')
host[key_value[0].strip()] = key_value[1].strip()
host_list.append(host)
continue
addresses = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
map(str.strip, addresses)
host['addresses'] = [addr for addr in addresses if addr]
for _ in range(4):
# `lease`, `key-lease`, `remaining lease`, and `remaining key-lease`
key_value = outputs.pop(0).strip().split(':')
host[key_value[0].strip()] = key_value[1].strip()
host_list.append(host)
return host_list
@@ -767,7 +778,9 @@ class Node(object):
'weight': '0',
'ttl': '7200',
'lease': '7200',
'key-lease', '1209600',
'key-lease': '1209600',
'remaining lease': '6322.418',
'remaining key-lease': '1109587.418',
'TXT': ['abc=010203'],
'host_fullname': 'my-host.default.service.arpa.',
'host': 'my-host',
@@ -786,10 +799,15 @@ class Node(object):
service['name'] = '.'.join(name_labels[1:3])
service['deleted'] = outputs.pop(0).strip().split(':')[1].strip()
if service['deleted'] == 'true':
for _ in range(2):
# `key-lease` and `remaining key-lease`
key_value = outputs.pop(0).strip().split(':')
service[key_value[0].strip()] = key_value[1].strip()
service_list.append(service)
continue
# 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', 'key-lease'
for i in range(0, 7):
# 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', 'key-lease',
# 'remaining lease', 'remaining key-lease'.
for i in range(0, 9):
key_value = outputs.pop(0).strip().split(':')
service[key_value[0].strip()] = key_value[1].strip()
txt_entries = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
+6
View File
@@ -1164,6 +1164,10 @@ class OTCI(object):
v = v[1:-1]
info['addresses'] = list(map(Ip6Addr, v.split(', ')))
elif k in ('lease', 'key-lease', 'remaining lease', 'remaining key-lease'):
info[k] = v
else:
raise UnexpectedCommandOutput(output)
@@ -1195,6 +1199,8 @@ class OTCI(object):
info[k] = list() if v == '(null)' else list(v.split(','))
elif k in ('port', 'weight', 'priority', 'ttl', 'lease', 'key-lease'):
info[k] = int(v)
elif k in ('remaining lease', 'remaining key-lease'):
info[k] = v
elif k in ('host',):
info[k] = v
elif k == 'TXT':