Skip to content

Commit 369a510

Browse files
committed
5.13.0
1 parent a314f04 commit 369a510

61 files changed

Lines changed: 1355 additions & 662 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

documentation/docs/reference/api.md

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ Once generated, copy the key and keep it safe. This key is used to authenticate
3737

3838
``<SNAPSHOT_ID>`` can be retrieved from the URL when you browse a snapshot from the repositories list or from the API when you list snapshots of a repository.
3939

40+
### Global query parameters
41+
42+
- ``normalize`` (optional): when set on a request, all keys in the JSON response are converted to lowercase recursively.
43+
44+
Example:
45+
46+
```bash
47+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/?normalize"
48+
```
49+
4050

4151
### Source repositories
4252

@@ -396,8 +406,8 @@ Once generated, copy the key and keep it safe. This key is used to authenticate
396406
<tr>
397407
<td>/hosts/package/<code>&lt;PACKAGE&gt;</code>/<code>&lt;VERSION?&gt;</code><br><code>GET</code></td>
398408
<td><code>&lt;APIKEY&gt;</code></td>
399-
<td><code>package</code> (required, in URL)<br><code>version</code> (optional, in URL)<br><code>strict</code> (optional, query parameter)<br><code>strict-name</code> (optional, query parameter)<br><code>strict-version</code> (optional, query parameter)</td>
400-
<td>List hosts that have the specified package installed, optionally filtered by version. By default, package name and version matching can be non-strict. Use <code>strict</code> to enable strict matching for both package name and version, or use <code>strict-name</code> and <code>strict-version</code> independently.</td>
409+
<td><code>package</code> (required, in URL)<br><code>version</code> (optional, in URL)<br><code>strict</code> (optional, query parameter)<br><code>strict-name</code> (optional, query parameter)<br><code>strict-version</code> (optional, query parameter)<br><code>absent</code> (optional, query parameter)</td>
410+
<td>List hosts that have the specified package installed, optionally filtered by version. By default, package name and version matching can be non-strict. Use <code>strict</code> to enable strict matching for both package name and version, or use <code>strict-name</code> and <code>strict-version</code> independently. Set <code>absent</code> to list hosts where the package (and optional version) is not installed.</td>
401411
<td markdown="block">
402412
```bash
403413
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" https://repomanager.mydomain.net/api/v2/hosts/package/nginx
@@ -418,13 +428,21 @@ Once generated, copy the key and keep it safe. This key is used to authenticate
418428
```bash
419429
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/package/nginx/1.24.0-1?strict-version"
420430
```
431+
Return hosts where package is absent:
432+
```bash
433+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/package/nginx?absent"
434+
```
435+
Return hosts where exact package version is absent:
436+
```bash
437+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/package/nginx/1.24.0-1?absent&strict"
438+
```
421439
</td>
422440
</tr>
423441
<tr>
424442
<td>/hosts/uptodate<br><code>GET</code></td>
425443
<td><code>&lt;APIKEY&gt;</code></td>
426444
<td></td>
427-
<td>List all up-to-date hosts (hosts with no or few available updates based on configured threshold)</td>
445+
<td>List hosts with no available updates (<code>0</code> pending updates).</td>
428446
<td markdown="block">
429447
```bash
430448
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" https://repomanager.mydomain.net/api/v2/hosts/uptodate
@@ -434,12 +452,46 @@ Once generated, copy the key and keep it safe. This key is used to authenticate
434452
<tr>
435453
<td>/hosts/outdated<br><code>GET</code></td>
436454
<td><code>&lt;APIKEY&gt;</code></td>
437-
<td></td>
438-
<td>List all outdated hosts (hosts with available updates exceeding the configured threshold)</td>
455+
<td><code>packages</code> (optional, query parameter)</td>
456+
<td>List hosts with at least one available update (<code>&gt;= 1</code> pending update). Set the <code>packages</code> query parameter to include the list of available updates for each host.</td>
439457
<td markdown="block">
440458
```bash
441459
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" https://repomanager.mydomain.net/api/v2/hosts/outdated
442460
```
461+
Including the list of available updates:
462+
```bash
463+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/outdated?packages"
464+
```
465+
</td>
466+
</tr>
467+
<tr>
468+
<td>/hosts/compliant<br><code>GET</code></td>
469+
<td><code>&lt;APIKEY&gt;</code></td>
470+
<td><code>packages</code> (optional, query parameter)</td>
471+
<td>List hosts compliant with all configured compliance criteria (pending updates threshold, latest update recency, and optional reboot-required check). Set the <code>packages</code> query parameter to include the list of available updates for each host.</td>
472+
<td markdown="block">
473+
```bash
474+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" https://repomanager.mydomain.net/api/v2/hosts/compliant
475+
```
476+
Including the list of available updates:
477+
```bash
478+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/compliant?packages"
479+
```
480+
</td>
481+
</tr>
482+
<tr>
483+
<td>/hosts/non-compliant<br><code>GET</code></td>
484+
<td><code>&lt;APIKEY&gt;</code></td>
485+
<td><code>packages</code> (optional, query parameter)</td>
486+
<td>List hosts not compliant with at least one configured compliance criterion. Set the <code>packages</code> query parameter to include the list of available updates for each host.</td>
487+
<td markdown="block">
488+
```bash
489+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" https://repomanager.mydomain.net/api/v2/hosts/non-compliant
490+
```
491+
Including the list of available updates:
492+
```bash
493+
curl --fail-with-body -L -s -X GET -H "Authorization: Bearer <APIKEY>" "https://repomanager.mydomain.net/api/v2/hosts/non-compliant?packages"
494+
```
443495
</td>
444496
</tr>
445497
</tbody>
@@ -574,11 +626,11 @@ Mainly used by the `linupdate` agent, these endpoints allow to register a host t
574626
<tr>
575627
<td>/host/status<br><code>PUT</code></td>
576628
<td><code>&lt;HOST_ID&gt;</code> and <code>&lt;HOST_TOKEN&gt;</code></td>
577-
<td><code>hostname</code> (optional)<br><code>os</code> (optional)<br><code>os_version</code> (optional)<br><code>os_family</code> (optional)<br><code>type</code> (=virtualization type) (optional)<br><code>kernel</code> (optional)<br><code>arch</code> (optional)<br><code>profile</code> (optional)<br><code>env</code> (optional)<br><code>agent_status</code> (optional)<br><code>linupdate_version</code> (optional)<br><code>reboot_required</code> (optional)</td>
629+
<td><code>hostname</code> (optional)<br><code>os</code> (optional)<br><code>os_version</code> (optional)<br><code>os_family</code> (optional)<br><code>type</code> (=virtualization type) (optional)<br><code>kernel</code> (optional)<br><code>arch</code> (optional)<br><code>profile</code> (optional)<br><code>env</code> (optional)<br><code>agent_status</code> (optional)<br><code>agent_version</code> (optional)<br><code>reboot_required</code> (optional)</td>
578630
<td>Send host general information to Repomanager</td>
579631
<td markdown="block">
580632
```bash
581-
curl --fail-with-body --post301 -L -s -X PUT -H "Authorization: Host <HOST_ID>:<HOST_TOKEN>" -H "Content-Type: application/json" -d '{"hostname":"myfqdn.localhost","os":"ubuntu","os_version":"22.04","os_family":"Debian","type":"Bare metal","kernel":"5.15.0-89-generic","arch":"x86_64","profile":"PC","env":"prod","agent_status":"running","linupdate_version":"2.2.2","reboot_required":"false"}' https://repomanager.mydomain.net/api/v2/host/status
633+
curl --fail-with-body --post301 -L -s -X PUT -H "Authorization: Host <HOST_ID>:<HOST_TOKEN>" -H "Content-Type: application/json" -d '{"hostname":"myfqdn.localhost","os":"ubuntu","os_version":"22.04","os_family":"Debian","type":"Bare metal","kernel":"5.15.0-89-generic","arch":"x86_64","profile":"PC","env":"prod","agent_status":"running","agent_version":"2.2.2","reboot_required":"false"}' https://repomanager.mydomain.net/api/v2/host/status
582634
```
583635
</td>
584636
</tr>

www/controllers/Api/Api.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ private static function returnSuccess(array $results): void
177177
// TODO: remove 'return' key in favor of 'rc' key in future major release
178178
$results['return'] = $results['rc'];
179179
$results['note'] = "The 'return' key is deprecated and will be removed in a future major release (replaced by 'rc' key)";
180+
181+
// If the "normalize" query parameter is set, convert all result keys to lowercase
182+
if (isset($_GET['normalize'])) {
183+
$results = Serializer::normalize($results);
184+
}
185+
180186
http_response_code((int) $results['rc']);
181187
echo json_encode($results);
182188
exit;

www/controllers/Api/Host/Host.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,16 @@ public function execute(): array
247247
}
248248

249249
// If linupdate version has been specified then update it in database
250-
if (!empty($this->data['linupdate_version'])) {
250+
if (!empty($this->data['linupdate_version']) or !empty($this->data['agent_version'])) {
251+
// TODO: temporary
252+
# Use agent_version later
253+
if (!empty($this->data['linupdate_version'])) {
254+
$version = $this->data['linupdate_version'];
255+
} else {
256+
$version = $this->data['agent_version'];
257+
}
251258
try {
252-
$hostUpdateController->updateLinupdateVersion($this->hostId, $this->data['linupdate_version']);
259+
$hostUpdateController->updateAgentVersion($this->hostId, $version);
253260
$message[] = "Linupdate version updated successfully.";
254261
} catch (Exception $e) {
255262
throw new Exception('Linupdate version update has failed.');

www/controllers/Api/Hosts/Hosts.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,27 +99,48 @@ public function execute(): array
9999
$strictVersion = true;
100100
}
101101

102+
// If the "absent" query parameter is set, return hosts on which the package is NOT installed
103+
$absent = isset($_GET['absent']);
104+
102105
if (empty($this->uri[5])) {
103106
throw new Exception('You must specify a package');
104107
}
105108

106-
return ['results' => $hostListingController->getByPackage($this->uri[5], $version, $strictName, $strictVersion)];
109+
return ['results' => $hostListingController->getByPackage($this->uri[5], $version, $strictName, $strictVersion, $absent)];
107110
}
108111

109112
/**
110-
* List up-to-date hosts
113+
* List up-to-date hosts (0 available updates)
111114
* https://repomanager.mydomain.net/api/v2/hosts/uptodate
112115
*/
113116
if ($this->uri[4] == 'uptodate' and $this->method == 'GET') {
114117
return ['results' => $hostListingController->getUpToDate()];
115118
}
116119

117120
/**
118-
* List outdated hosts
121+
* List compliant hosts (all compliance criteria)
122+
* https://repomanager.mydomain.net/api/v2/hosts/compliant
123+
*/
124+
if ($this->uri[4] == 'compliant' and $this->method == 'GET') {
125+
return ['results' => $hostListingController->getCompliant(isset($_GET['packages']))];
126+
}
127+
128+
/**
129+
* List outdated hosts (at least 1 available update)
119130
* https://repomanager.mydomain.net/api/v2/hosts/outdated
120131
*/
121132
if ($this->uri[4] == 'outdated' and $this->method == 'GET') {
122-
return ['results' => $hostListingController->getOutdated()];
133+
// Also get the list of available updates if the "packages" query parameter is set
134+
return ['results' => $hostListingController->getOutdated(isset($_GET['packages']))];
135+
}
136+
137+
/**
138+
* List non-compliant hosts (all compliance criteria)
139+
* https://repomanager.mydomain.net/api/v2/hosts/non-compliant
140+
*/
141+
if ($this->uri[4] == 'non-compliant' and $this->method == 'GET') {
142+
// Also get the list of available updates if the "packages" query parameter is set
143+
return ['results' => $hostListingController->getNonCompliant(isset($_GET['packages']))];
123144
}
124145
}
125146

www/controllers/Api/Serializer.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Controllers\Api;
4+
5+
class Serializer
6+
{
7+
/**
8+
* Recursively normalize the keys of an array to lowercase
9+
* so that the API always returns a consistent key format, no matter
10+
* whether the data comes from the database (PascalCase columns) or
11+
* is built by the backend (lowercase keys).
12+
*/
13+
public static function normalize($data)
14+
{
15+
// Only arrays have keys to normalize, return scalars as-is
16+
if (!is_array($data)) {
17+
return $data;
18+
}
19+
20+
$result = [];
21+
22+
foreach ($data as $key => $value) {
23+
// Recursively normalize nested arrays
24+
$value = self::normalize($value);
25+
26+
// Numeric keys (sequential lists) are kept as-is
27+
if (is_int($key)) {
28+
$result[$key] = $value;
29+
continue;
30+
}
31+
32+
$result[strtolower($key)] = $value;
33+
}
34+
35+
return $result;
36+
}
37+
}

www/controllers/Filesystem/Directory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Directory
1010
* Return an array with the list of founded directories in specified directory path
1111
* Directory name can be filtered with a regex
1212
*/
13-
public static function findRecursive(string $directoryPath, string $directoryNameRegex = null, bool $returnFullPath = true) : array
13+
public static function findRecursive(string $directoryPath, string $directoryNameRegex = '', bool $returnFullPath = true) : array
1414
{
1515
$foundedDirs = [];
1616

www/controllers/Host/Export.php

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ public function export(array $hosts): string
1818
throw new Exception('No hosts provided for export');
1919
}
2020

21-
/**
22-
* First check that hosts Id are valid and exist
23-
*/
21+
// First check that hosts Id are valid and exist
2422
foreach ($hosts as $id) {
2523
if (!is_numeric($id)) {
2624
throw new Exception('Invalid host Id: ' . $id);
@@ -31,9 +29,7 @@ public function export(array $hosts): string
3129
}
3230
}
3331

34-
/**
35-
* Generate the CSV header
36-
*/
32+
// Generate the CSV header
3733
$csv[] = [
3834
'Id',
3935
'Hostname',
@@ -53,9 +49,7 @@ public function export(array $hosts): string
5349
'Reboot required',
5450
];
5551

56-
/**
57-
* For each host, get its information and add it to the CSV array
58-
*/
52+
// For each host, get its information and add it to the CSV array
5953
foreach ($hosts as $id) {
6054
$data = $this->get($id);
6155

@@ -74,14 +68,12 @@ public function export(array $hosts): string
7468
$data['Online_status'],
7569
$data['Online_status_date'],
7670
$data['Online_status_time'],
77-
$data['Linupdate_version'],
71+
$data['Agent_version'],
7872
$data['Reboot_required'],
7973
];
8074
}
8175

82-
/**
83-
* Encode to JSON and return the CSV data
84-
*/
76+
// Encode to JSON and return the CSV data
8577
try {
8678
return json_encode($csv, JSON_THROW_ON_ERROR);
8779
} catch (JsonException $e) {

0 commit comments

Comments
 (0)