Skip to content

Commit 3af250c

Browse files
Lifkajesuslinares
authored andcommitted
Fix agents purge (#82)
1 parent 1c356b8 commit 3af250c

File tree

7 files changed

+205
-94
lines changed

7 files changed

+205
-94
lines changed

CHANGELOG.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,26 @@ All notable changes to this project will be documented in this file.
1010
* `GET/cluster/nodes/:node_name`.
1111
- A parameter in request `GET/rules` to filter by GDPR requirements ([#78](https://github.com/wazuh/wazuh-api/pull/78)).
1212
- Parameters in `GET/cluster/nodes`: `search`, `sort`, `offset`, `limit`, `select`. And a new filter: `type`.
13-
- A parameter in request `GET/agents` to filter agents by cluster nodes.
13+
- Parameters in request `GET/agents`:
14+
* `node_name`: Filters agents by cluster nodes.
15+
- `older_than`: Filters by agents not connected in a specific time ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
16+
- `status`: Filters agents with a specific status ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
17+
- New filters in request `DELETE/agents`:
18+
- `older_than`: Filters by agents not connected in a specific time ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
19+
- `status`: Filters agents with a specific status ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
20+
1421
### Changed
15-
- Output of `GET/nodes`: Added a new attribute `version`.
22+
- Output of `GET/nodes`: Added new attribute `version`.
23+
- Output of `DELETE/agents`: Added new attribute `older_than`.
24+
- Filter `status` in `GET/agents` can filter by several status separated by commas ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
1625

1726
### Removed
1827
- The following requests have been removed:
1928
- `GET/cluster/agents`: Duplicated request (`GET/agents`).
2029
- `GET/cluster/node`: Duplicated request (`GET/cluster/config`).
2130
- `GET/cluster/files`: It will not be available in this version of the cluster.
31+
- `POST/agents/purge`: Replaced by `DELETE/agents` ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
32+
- `GET/agents/purgeable`: Replaced by `GET/agents` ([#82](https://github.com/wazuh/wazuh-api/pull/82)).
2233

2334
## [v3.2.2]
2435
### Added

controllers/agents.js

Lines changed: 33 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ var router = require('express').Router();
2121
* @apiParam {Number} [limit=500] Maximum number of elements to return.
2222
* @apiParam {String} [sort] Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order.
2323
* @apiParam {String} [search] Looks for elements with the specified string.
24-
* @apiParam {String="active","pending","never connected", "disconnected"} [status] Filters by agent status.
24+
* @apiParam {String="active", "pending", "neverconnected", "disconnected"} [status] Filters by agent status. Use commas to enter multiple statuses.
25+
* @apiParam {String} older_than Filters out disconnected agents for longer than specified. Time in seconds | "[n_days]d" | "[n_hours]h" | "[n_minutes]m" | "[n_seconds]s". For never connected agents, uses the register date.
2526
* @apiParam {String} [os.platform] Filters by OS platform.
2627
* @apiParam {String} [os.version] Filters by OS version.
2728
* @apiParam {String} [manager] Filters by manager hostname to which agents are connected.
@@ -41,9 +42,10 @@ router.get('/', cache(), function(req, res) {
4142
var data_request = {'function': '/agents', 'arguments': {}};
4243
var filters = {'offset': 'numbers', 'limit': 'numbers', 'sort':'sort_param',
4344
'select':'select_param', 'search':'search_param',
44-
'status':'alphanumeric_param', 'os.platform':'alphanumeric_param',
45+
'status':'alphanumeric_param', 'os.platform':'alphanumeric_param',
4546
'os.version':'alphanumeric_param', 'manager':'alphanumeric_param',
46-
'version':'alphanumeric_param', 'node': 'alphanumeric_param'};
47+
'version':'alphanumeric_param', 'node': 'alphanumeric_param',
48+
'older_than':'timeframe_type'};
4749

4850
if (!filter.check(req.query, filters, req, res)) // Filter with error
4951
return;
@@ -70,6 +72,8 @@ router.get('/', cache(), function(req, res) {
7072
data_request['arguments']['node_name'] = req.query['node'];
7173
if ('version' in req.query)
7274
data_request['arguments']['version'] = req.query['version'];
75+
if ('older_than' in req.query)
76+
data_request['arguments']['older_than'] = req.query['older_than'];
7377

7478
execute.exec(python_bin, [wazuh_control], data_request, function (data) { res_h.send(req, res, data); });
7579
})
@@ -426,44 +430,6 @@ router.get('/outdated', cache(), function(req, res) {
426430
execute.exec(python_bin, [wazuh_control], data_request, function (data) { res_h.send(req, res, data); });
427431
})
428432

429-
/**
430-
* @api {get} /purgeable/:timeframe Get list of purgeable agents
431-
* @apiName GetAgentsPurgeable
432-
* @apiGroup Info
433-
*
434-
* @apiParam {String} timeframe Time from last connection in seconds or [n_days]d[n_hours]h[n_minutes]m[n_seconds]s.
435-
* @apiParam {Number} [offset] First element to return in the collection.
436-
* @apiParam {Number} [limit=500] Maximum number of elements to return.
437-
*
438-
* @apiDescription Returns a list of agents that can be purged.
439-
*
440-
* @apiExample {curl} Example usage*:
441-
* curl -u foo:bar -k -X GET "https://127.0.0.1:55000/agents/purgeable/1d5h?pretty"
442-
*
443-
*/
444-
router.get('/purgeable/:timeframe', cache(), function(req, res) {
445-
446-
logger.debug(req.connection.remoteAddress + " GET /agents/purgeable/:timeframe");
447-
448-
var data_request = {'function': '/agents/purgeable/:timeframe', 'arguments': {}};
449-
var filters = {'timeframe':'timeframe_type', 'offset': 'numbers', 'limit': 'numbers'};
450-
451-
if (!filter.check(req.params, filters, req, res)) // Filter with error
452-
return;
453-
454-
if ('timeframe' in req.params)
455-
data_request['arguments']['timeframe'] = req.params.timeframe;
456-
else
457-
res_h.bad_request(req, res, 604, "Missing field: 'timeframe'");
458-
459-
if ('offset' in req.query)
460-
data_request['arguments']['offset'] = req.query.offset;
461-
462-
if ('limit' in req.query)
463-
data_request['arguments']['limit'] = req.query.limit;
464-
465-
execute.exec(python_bin, [wazuh_control], data_request, function (data) { res_h.send(req, res, data); });
466-
})
467433

468434
/**
469435
* @api {get} /agents/name/:agent_name Get an agent by its name
@@ -942,14 +908,16 @@ router.delete('/groups/:group_id', function(req, res) {
942908
})
943909

944910
/**
945-
* @api {delete} /agents Delete a list of agents
911+
* @api {delete} /agents Delete agents
946912
* @apiName DeleteAgents
947913
* @apiGroup Delete
948914
*
949915
* @apiParam {String[]} ids Array of agent ID's.
950916
* @apiParam {Boolean} purge Delete an agent from the key store.
917+
* @apiParam {String="active", "pending", "neverconnected", "disconnected"} [status] Filters by agent status. Use commas to enter multiple statuses.
918+
* @apiParam {String} older_than Filters out disconnected agents for longer than specified. Time in seconds | "[n_days]d" | "[n_hours]h" | "[n_minutes]m" | "[n_seconds]s". For never connected agents, uses the register date.
951919
*
952-
* @apiDescription Removes a list of agents. The Wazuh API must be restarted after removing an agent.
920+
* @apiDescription Removes agents, using a list of them or a criterion based on the status or time of the last connection. The Wazuh API must be restarted after removing an agent.
953921
*
954922
* @apiExample {curl} Example usage:
955923
* curl -u foo:bar -k -X DELETE -H "Content-Type:application/json" -d '{"ids":["003","005"]}' "https://127.0.0.1:55000/agents?pretty"
@@ -958,18 +926,33 @@ router.delete('/groups/:group_id', function(req, res) {
958926
router.delete('/', function(req, res) {
959927
logger.debug(req.connection.remoteAddress + " DELETE /agents");
960928

961-
var data_request = {'function': 'DELETE/agents/', 'arguments': {}};
929+
var data_request = { 'function': 'DELETE/agents/', 'arguments': {} };
930+
var filter_body = { 'ids': 'array_numbers', 'purge': 'boolean' };
931+
var filter_query = { 'older_than': 'timeframe_type', 'status': 'alphanumeric_param'};
932+
933+
if (!filter.check(req.body, filter_body, req, res)) // Filter with error
934+
return;
935+
936+
if (!filter.check(req.query, filter_query, req, res)) // Filter with error
937+
return;
962938

963-
if (!filter.check(req.body, {'ids':'array_numbers', 'purge':'boolean'}, req, res)) // Filter with error
939+
if (!('ids' in req.body) && !('status' in req.query))
940+
res_h.bad_request(req, res, 604, "Missing field: You have to specified 'ids' or status.");
964941
return;
965942

966943
data_request['arguments']['purge'] = 'purge' in req.body && (req.body['purge'] == true || req.body['purge'] == 'true');
967944

968-
if ('ids' in req.body){
969-
data_request['arguments']['agent_id'] = req.body.ids;
970-
execute.exec(python_bin, [wazuh_control], data_request, function (data) { res_h.send(req, res, data); });
971-
}else
972-
res_h.bad_request(req, res, 604, "Missing field: 'ids'");
945+
if ('ids' in req.body)
946+
data_request['arguments']['list_agent_ids'] = req.body.ids;
947+
948+
if ('older_than' in req.query)
949+
data_request['arguments']['older_than'] = req.query.older_than;
950+
951+
if ('status' in req.query)
952+
data_request['arguments']['status'] = req.query.status;
953+
954+
955+
execute.exec(python_bin, [wazuh_control], data_request, function (data) { res_h.send(req, res, data); });
973956
})
974957

975958

@@ -1098,37 +1081,4 @@ router.post('/insert', function(req, res) {
10981081
res_h.bad_request(req, res, 604, "Missing fields. Mandatory fields: id, name, ip, key");
10991082
})
11001083

1101-
/**
1102-
* @api {post} /agents/purge Purge old agents from manager
1103-
* @apiName PostAgentsPurge
1104-
* @apiGroup Purge
1105-
*
1106-
* @apiParam {String} timeframe Time from last connection in seconds or [n_days]d[n_hours]h[n_minutes]m[n_seconds]s.
1107-
* @apiParam {Boolean} verbose Return information about agents purged.
1108-
*
1109-
* @apiDescription Deletes all agents that did not connect in the last timeframe seconds.
1110-
*
1111-
* @apiExample {curl} Example usage*:
1112-
* curl -u foo:bar -k -X POST -H "Content-Type:application/json" -d '{"timeframe":"1d5h","verbose":true}' "https://127.0.0.1:55000/agents/purge?pretty"
1113-
*
1114-
*/
1115-
router.post('/purge', function(req, res) {
1116-
logger.debug(req.connection.remoteAddress + " POST /agents/purge");
1117-
1118-
var data_request = {'function': 'POST/agents/purge', 'arguments': {}};
1119-
var filters = {'timeframe':'timeframe_type', 'verbose':'boolean'};
1120-
1121-
if (!filter.check(req.body, filters, req, res)) // Filter with error
1122-
return;
1123-
1124-
if ('verbose' in req.body)
1125-
data_request['arguments']['verbose'] = req.body.verbose;
1126-
1127-
if ('timeframe' in req.body){
1128-
data_request['arguments']['timeframe'] = req.body.timeframe;
1129-
execute.exec(python_bin, [wazuh_control], data_request, function (data) { res_h.send(req, res, data); });
1130-
}else
1131-
res_h.bad_request(req, res, 604, "Missing field: 'timeframe'");
1132-
})
1133-
11341084
module.exports = router;

helpers/errors.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ errors['ossec_key'] = 615;
4949
errors['616'] = "Param not valid. Valid characters: array of numbers";
5050
errors['array_numbers'] = 616;
5151
errors['timeframe_type'] = 617;
52-
errors['617'] = "Param not valid. Valid characters: \"[0-9]d[0-9]h[0-9]m[0-9]s\" or 0-9"
52+
errors['617'] = "Param not valid. Valid characters: [0-9]d|[0-9]h|[0-9]m|[0-9]s|0-9"
5353
errors['boolean'] = 618;
5454
errors['618'] = "Param not valid. Valid characters: true or false"
5555

helpers/input_validation.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ exports.ips = function(ip) {
7272

7373
exports.alphanumeric_param = function(param) {
7474
if (typeof param != 'undefined'){
75-
var regex = /^[a-zA-Z0-9_\-\.\+\s]+$/;
75+
var regex = /^[a-zA-Z0-9_,\-\.\+\s]+$/;
7676
return regex.test(param);
7777
}
7878
else
@@ -136,7 +136,7 @@ exports.ossec_key = function(param) {
136136
// [n_days]d[n_hours]h[n_minutes]m[n_seconds]s
137137
exports.timeframe_type = function(param) {
138138
if (typeof param != 'undefined'){
139-
var regex = /^((\d{1,}[d]){0,1}(\d{1,}[h]){0,1}(\d{1,}[m]){0,1}(\d{1,}[s]){0,1}){1}$|^\d{1,}$/;
139+
var regex = /^(\d{1,}[d|h|m|s]?){1}$/;
140140
return regex.test(param);
141141
}
142142
else

models/wazuh-api.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def usage():
191191
'POST/agents/insert': Agent.insert_agent,
192192
'DELETE/agents/groups': Agent.remove_group,
193193
'DELETE/agents/:agent_id': Agent.remove_agent,
194-
'DELETE/agents/': Agent.remove_agent,
194+
'DELETE/agents/': Agent.remove_agents,
195195

196196
# Groups
197197
'/agents/groups': Agent.get_all_groups,
@@ -204,8 +204,6 @@ def usage():
204204
'PUT/agents/groups/:group_id': Agent.create_group,
205205
'DELETE/agents/groups/:group_id':Agent.remove_group,
206206
'DELETE/agents/:agent_id/group':Agent.unset_group,
207-
'POST/agents/purge': Agent.purge_agents,
208-
'/agents/purgeable/:timeframe': Agent.get_purgeable_agents_json,
209207

210208
# Decoders
211209
'/decoders': Decoder.get_decoders,

test/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
## Requirements
44

55
* API installed and configurated (Configure API: https and auth (foo:bar)).
6-
* Packages npm installed: `glob`, `supertest`, `mocha`, `should`, `moment` and `getos`.
6+
* Packages npm installed: `glob`, `supertest`, `mocha`, `should`, `moment`, `sleep` and `getos`.
77

8-
``` npm install glob supertest mocha should moment getos ```
8+
```
9+
npm install mocha -g
10+
npm install glob supertest mocha should moment getos sleep
11+
```
912
1013
* Cluster configurated and running with 2 connected nodes: `master` and `client`.
1114
* A connected agent with id `001`.

0 commit comments

Comments
 (0)