howler-client 3.1.0.dev340__tar.gz → 3.1.0.dev345__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/PKG-INFO +1 -1
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/hit.py +44 -10
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/user.py +26 -8
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/case.py +61 -17
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/ingest.py +18 -5
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/pyproject.toml +1 -1
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/LICENSE +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/README.md +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/__init__.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/client.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/__init__.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/dict_utils.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/utils.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/connection.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/logger.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/__init__.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/comment.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/help.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/__init__.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/chunk.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/facet.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/fields.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/grouped.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/histogram.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/stats.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/stream.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/__init__.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/search.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/utils/__init__.py +0 -0
- {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/utils/json_encoders.py +0 -0
|
@@ -77,6 +77,7 @@ class Hit(object):
|
|
|
77
77
|
map: dict[str, list[str]],
|
|
78
78
|
documents: list[dict[str, Any]],
|
|
79
79
|
ignore_extra_values: bool = False,
|
|
80
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
80
81
|
) -> list[dict[str, str | list[str] | None]]:
|
|
81
82
|
"""Create hits for a given tool using the raw documents and a map of the document fields to howler's fields.
|
|
82
83
|
|
|
@@ -86,6 +87,8 @@ class Hit(object):
|
|
|
86
87
|
the values are a list of flattened path for Howler's fields where the data will be copied into
|
|
87
88
|
documents (list[dict[str, Any]]): The data to ingest into howler, in the tool's raw document format
|
|
88
89
|
ignore_extra_values (bool, optional): Whether to allow extra fields, or raise an error. Defaults to False.
|
|
90
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
91
|
+
Defaults to False.
|
|
89
92
|
|
|
90
93
|
Returns:
|
|
91
94
|
list[dict[str, str | list[str] | None]]: One entry per document, each with keys ``id``, ``error``,
|
|
@@ -103,7 +106,7 @@ class Hit(object):
|
|
|
103
106
|
|
|
104
107
|
try:
|
|
105
108
|
result = self._connection.post(
|
|
106
|
-
api_path("tools", tool_name, "hits", ignore_extra_values=ignore_extra_values),
|
|
109
|
+
api_path("tools", tool_name, "hits", ignore_extra_values=ignore_extra_values, refresh=refresh),
|
|
107
110
|
json=data,
|
|
108
111
|
)
|
|
109
112
|
except ClientError as e:
|
|
@@ -155,6 +158,7 @@ class Hit(object):
|
|
|
155
158
|
self: Self,
|
|
156
159
|
data: dict[str, Any] | list[dict[str, Any]],
|
|
157
160
|
ignore_extra_values: bool = False,
|
|
161
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
158
162
|
) -> CreateHitsResponse | None:
|
|
159
163
|
"""Create one or many hits using the howler schema.
|
|
160
164
|
|
|
@@ -162,6 +166,8 @@ class Hit(object):
|
|
|
162
166
|
data (dict[str, Any] | list[dict[str, Any]]): The hit or list of hits to create
|
|
163
167
|
ignore_extra_values (bool, optional): Whtether to ignore extra values, or throw an exception.
|
|
164
168
|
Defaults to False.
|
|
169
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
170
|
+
Defaults to False.
|
|
165
171
|
|
|
166
172
|
Returns:
|
|
167
173
|
CreateHitsResponse | None: Created and invalid hits with warnings, or ``None`` when no
|
|
@@ -217,7 +223,7 @@ class Hit(object):
|
|
|
217
223
|
return None
|
|
218
224
|
|
|
219
225
|
result = self._connection.post(
|
|
220
|
-
api_path("hit", ignore_extra_values=ignore_extra_values),
|
|
226
|
+
api_path("hit", ignore_extra_values=ignore_extra_values, refresh=refresh),
|
|
221
227
|
data=json.dumps(final_hit_list, cls=DatetimeEncoder),
|
|
222
228
|
headers={"Content-Type": "application/json"},
|
|
223
229
|
)
|
|
@@ -231,7 +237,12 @@ class Hit(object):
|
|
|
231
237
|
|
|
232
238
|
return result
|
|
233
239
|
|
|
234
|
-
def overwrite(
|
|
240
|
+
def overwrite(
|
|
241
|
+
self: Self,
|
|
242
|
+
hit_id: str,
|
|
243
|
+
new_hit_data: dict[str, Any],
|
|
244
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
245
|
+
):
|
|
235
246
|
"""Overwrite a hit.
|
|
236
247
|
|
|
237
248
|
This is different from updating a hit, as you simply provide a partial hit object
|
|
@@ -246,9 +257,14 @@ class Hit(object):
|
|
|
246
257
|
if not isinstance(new_hit_data, dict):
|
|
247
258
|
raise TypeError("New hit data must be of type dict.")
|
|
248
259
|
|
|
249
|
-
return self._connection.put(api_path(f"hit/{hit_id}/overwrite"), json=new_hit_data)
|
|
260
|
+
return self._connection.put(api_path(f"hit/{hit_id}/overwrite", refresh=refresh), json=new_hit_data)
|
|
250
261
|
|
|
251
|
-
def update(
|
|
262
|
+
def update(
|
|
263
|
+
self: Self,
|
|
264
|
+
hit_id: str,
|
|
265
|
+
updates: list[tuple[str, str, Any]],
|
|
266
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
267
|
+
):
|
|
252
268
|
"""Update a hit.
|
|
253
269
|
|
|
254
270
|
Args:
|
|
@@ -256,6 +272,8 @@ class Hit(object):
|
|
|
256
272
|
updates (list[tuple[str, str, Any]]): A list of updates to run. The first entry in the tuple must be a valid
|
|
257
273
|
update operation (see UPDATE_OPERATIONS), the second a key for a howler hit, and the third the value
|
|
258
274
|
to use in the operation.
|
|
275
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
276
|
+
Defaults to False.
|
|
259
277
|
|
|
260
278
|
Raises:
|
|
261
279
|
ClientError: Updates provided were invalid
|
|
@@ -273,9 +291,14 @@ class Hit(object):
|
|
|
273
291
|
400,
|
|
274
292
|
)
|
|
275
293
|
|
|
276
|
-
return self._connection.put(api_path(f"hit/{hit_id}/update"), json=updates)
|
|
294
|
+
return self._connection.put(api_path(f"hit/{hit_id}/update", refresh=refresh), json=updates)
|
|
277
295
|
|
|
278
|
-
def update_by_query(
|
|
296
|
+
def update_by_query(
|
|
297
|
+
self: Self,
|
|
298
|
+
query: str,
|
|
299
|
+
updates: list[tuple[str, str, Any]],
|
|
300
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
301
|
+
):
|
|
279
302
|
"""Update a set of hits by query.
|
|
280
303
|
|
|
281
304
|
Args:
|
|
@@ -283,6 +306,8 @@ class Hit(object):
|
|
|
283
306
|
updates (list[tuple[str, str, Any]]): A list of updates to run. The first entry in the tuple must be a valid
|
|
284
307
|
update operation (see UPDATE_OPERATIONS), the second a key for a howler hit, and the third the value
|
|
285
308
|
to use in the operation.
|
|
309
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
310
|
+
Defaults to False.
|
|
286
311
|
|
|
287
312
|
Raises:
|
|
288
313
|
ClientError: Updates provided were invalid
|
|
@@ -299,15 +324,24 @@ class Hit(object):
|
|
|
299
324
|
400,
|
|
300
325
|
)
|
|
301
326
|
|
|
302
|
-
return self._connection.put(
|
|
327
|
+
return self._connection.put(
|
|
328
|
+
api_path("hit/update", refresh=refresh), json={"query": query, "operations": updates}
|
|
329
|
+
)
|
|
303
330
|
|
|
304
|
-
def delete(
|
|
331
|
+
def delete(
|
|
332
|
+
self: Self, hit_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
333
|
+
) -> dict[Literal["success"], bool]:
|
|
305
334
|
"""Delete a list of hits by id
|
|
306
335
|
|
|
336
|
+
Args:
|
|
337
|
+
hit_ids (list[str]): List of hit ids to delete
|
|
338
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
339
|
+
Defaults to False.
|
|
340
|
+
|
|
307
341
|
Returns:
|
|
308
342
|
dict[Literal["success"], bool]: Whether the delete operation was successful
|
|
309
343
|
"""
|
|
310
344
|
if not isinstance(hit_ids, list):
|
|
311
345
|
hit_ids = [hit_ids]
|
|
312
346
|
|
|
313
|
-
return self._connection.delete(api_path("hit"), json=hit_ids)
|
|
347
|
+
return self._connection.delete(api_path("hit", refresh=refresh), json=hit_ids)
|
|
@@ -26,28 +26,39 @@ class User(object):
|
|
|
26
26
|
"""
|
|
27
27
|
return self._connection.get(api_path("user", username))
|
|
28
28
|
|
|
29
|
-
def add(
|
|
29
|
+
def add(
|
|
30
|
+
self: Self,
|
|
31
|
+
username: str,
|
|
32
|
+
user_data: dict[str, Any],
|
|
33
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
34
|
+
) -> dict[Literal["success"], bool]:
|
|
30
35
|
"""Add a user to the system
|
|
31
36
|
|
|
32
37
|
Args:
|
|
33
38
|
username (str): Name of the user to add to the system
|
|
34
39
|
user_data (dict[str, Any]): Profile data of the user to add
|
|
40
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
41
|
+
Defaults to False.
|
|
35
42
|
|
|
36
43
|
Returns:
|
|
37
44
|
dict[Literal["success"], bool]: Whether creating the user succeeded
|
|
38
45
|
"""
|
|
39
|
-
return self._connection.post(api_path("user", username), json=user_data)
|
|
46
|
+
return self._connection.post(api_path("user", username, refresh=refresh), json=user_data)
|
|
40
47
|
|
|
41
|
-
def delete(
|
|
48
|
+
def delete(
|
|
49
|
+
self: Self, username: str, refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
50
|
+
) -> dict[Literal["success"], bool]:
|
|
42
51
|
"""Remove the account specified by the username.
|
|
43
52
|
|
|
44
53
|
Args:
|
|
45
|
-
str: Name of the user to remove from the system
|
|
54
|
+
username (str): Name of the user to remove from the system
|
|
55
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
56
|
+
Defaults to False.
|
|
46
57
|
|
|
47
58
|
Returns:
|
|
48
59
|
dict[Literal["success"], bool]: Whether the delete succeeded
|
|
49
60
|
"""
|
|
50
|
-
return self._connection.delete(api_path("user", username))
|
|
61
|
+
return self._connection.delete(api_path("user", username, refresh=refresh))
|
|
51
62
|
|
|
52
63
|
def list(
|
|
53
64
|
self: Self,
|
|
@@ -60,7 +71,7 @@ class User(object):
|
|
|
60
71
|
"""List users of the system
|
|
61
72
|
|
|
62
73
|
Args:
|
|
63
|
-
query (
|
|
74
|
+
query (str, optional): Filter to apply to the user list. Defaults to "*:*".
|
|
64
75
|
rows (int, optional): Total number of users returned. Defaults to 10.
|
|
65
76
|
offset (int, optional): Offset in the user index. Defaults to 0.
|
|
66
77
|
sort (str, optional): Sort order. Defaults to "uname asc".
|
|
@@ -80,17 +91,24 @@ class User(object):
|
|
|
80
91
|
)
|
|
81
92
|
)
|
|
82
93
|
|
|
83
|
-
def update(
|
|
94
|
+
def update(
|
|
95
|
+
self: Self,
|
|
96
|
+
username: str,
|
|
97
|
+
user_data: dict[str, Any],
|
|
98
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
99
|
+
) -> dict[Literal["success"], bool]:
|
|
84
100
|
"""Update a user profile in the system.
|
|
85
101
|
|
|
86
102
|
Args:
|
|
87
103
|
username (str): Name of the user to update in the system
|
|
88
104
|
user_data (dict[str, Any]): Profile data of the user to update
|
|
105
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
106
|
+
Defaults to False.
|
|
89
107
|
|
|
90
108
|
Returns:
|
|
91
109
|
dict[Literal["success"], bool]: Whether the update succeeded
|
|
92
110
|
"""
|
|
93
|
-
return self._connection.put(api_path("user", username), json=user_data)
|
|
111
|
+
return self._connection.put(api_path("user", username, refresh=refresh), json=user_data)
|
|
94
112
|
|
|
95
113
|
def whoami(self: Self) -> dict[str, Any]:
|
|
96
114
|
"Return the currently logged in user"
|
|
@@ -42,36 +42,46 @@ class Case(object):
|
|
|
42
42
|
"""
|
|
43
43
|
return self._connection.post(api_path_v2("case/"), json=case_data)
|
|
44
44
|
|
|
45
|
-
def update(
|
|
45
|
+
def update(
|
|
46
|
+
self: Self, case_id: str, updates: dict[str, Any], refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
47
|
+
) -> dict[str, Any]:
|
|
46
48
|
"""Update fields on an existing case.
|
|
47
49
|
|
|
48
50
|
Args:
|
|
49
51
|
case_id: ID of the case to update.
|
|
50
52
|
updates: Dictionary of fields to update.
|
|
53
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
54
|
+
Defaults to False.
|
|
51
55
|
|
|
52
56
|
Returns:
|
|
53
57
|
The updated case data.
|
|
54
58
|
"""
|
|
55
|
-
return self._connection.put(api_path_v2("case", case_id), json=updates)
|
|
59
|
+
return self._connection.put(api_path_v2("case", case_id, refresh=refresh), json=updates)
|
|
56
60
|
|
|
57
|
-
def delete(self: Self, case_ids: list[str]) -> None:
|
|
61
|
+
def delete(self: Self, case_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False) -> None:
|
|
58
62
|
"""Delete one or more cases.
|
|
59
63
|
|
|
60
64
|
Args:
|
|
61
65
|
case_ids: List of case IDs to delete.
|
|
66
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
67
|
+
Defaults to False.
|
|
62
68
|
"""
|
|
63
|
-
return self._connection.delete(api_path_v2("case/"), json=case_ids)
|
|
69
|
+
return self._connection.delete(api_path_v2("case/", refresh=refresh), json=case_ids)
|
|
64
70
|
|
|
65
|
-
def hide(
|
|
71
|
+
def hide(
|
|
72
|
+
self: Self, case_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
73
|
+
) -> dict[Literal["success"], bool]:
|
|
66
74
|
"""Hide one or more cases.
|
|
67
75
|
|
|
68
76
|
Args:
|
|
69
77
|
case_ids: List of case IDs to hide.
|
|
78
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
79
|
+
Defaults to False.
|
|
70
80
|
|
|
71
81
|
Returns:
|
|
72
82
|
Whether the operation succeeded.
|
|
73
83
|
"""
|
|
74
|
-
return self._connection.post(api_path_v2("case/hide"), json=case_ids)
|
|
84
|
+
return self._connection.post(api_path_v2("case/hide", refresh=refresh), json=case_ids)
|
|
75
85
|
|
|
76
86
|
def append_item(
|
|
77
87
|
self: Self,
|
|
@@ -81,6 +91,7 @@ class Case(object):
|
|
|
81
91
|
path: str | None = None,
|
|
82
92
|
name: str | None = None,
|
|
83
93
|
parent: str | None = None,
|
|
94
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
84
95
|
) -> dict[str, Any]:
|
|
85
96
|
"""Append an item to a case.
|
|
86
97
|
|
|
@@ -92,6 +103,8 @@ class Case(object):
|
|
|
92
103
|
name: Optional display name for the item. Defaults to ``value``.
|
|
93
104
|
parent: Optional parent folder item ID. If both ``path`` and ``parent``
|
|
94
105
|
are provided, the API resolves and applies ``path``.
|
|
106
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
107
|
+
Defaults to False.
|
|
95
108
|
|
|
96
109
|
Returns:
|
|
97
110
|
The updated case data.
|
|
@@ -107,71 +120,102 @@ class Case(object):
|
|
|
107
120
|
payload["path"] = path
|
|
108
121
|
|
|
109
122
|
return self._connection.post(
|
|
110
|
-
api_path_v2("case", case_id, "items"),
|
|
123
|
+
api_path_v2("case", case_id, "items", refresh=refresh),
|
|
111
124
|
json=payload,
|
|
112
125
|
)
|
|
113
126
|
|
|
114
|
-
def delete_items(
|
|
127
|
+
def delete_items(
|
|
128
|
+
self: Self, case_id: str, item_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
129
|
+
) -> dict[str, Any]:
|
|
115
130
|
"""Remove items from a case.
|
|
116
131
|
|
|
117
132
|
Args:
|
|
118
133
|
case_id: ID of the case.
|
|
119
134
|
item_ids: List of item IDs to remove.
|
|
135
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
136
|
+
Defaults to False.
|
|
120
137
|
|
|
121
138
|
Returns:
|
|
122
139
|
The updated case data.
|
|
123
140
|
"""
|
|
124
|
-
return self._connection.delete(api_path_v2("case", case_id, "items"), json={"ids": item_ids})
|
|
141
|
+
return self._connection.delete(api_path_v2("case", case_id, "items", refresh=refresh), json={"ids": item_ids})
|
|
125
142
|
|
|
126
|
-
def rename_item(
|
|
143
|
+
def rename_item(
|
|
144
|
+
self: Self,
|
|
145
|
+
case_id: str,
|
|
146
|
+
item_id: str,
|
|
147
|
+
new_name: str,
|
|
148
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
149
|
+
) -> dict[str, Any]:
|
|
127
150
|
"""Rename an item within a case.
|
|
128
151
|
|
|
129
152
|
Args:
|
|
130
153
|
case_id: ID of the case.
|
|
131
154
|
item_id: ID identifying the item to rename.
|
|
132
155
|
new_name: New display name for the item.
|
|
156
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
157
|
+
Defaults to False.
|
|
133
158
|
|
|
134
159
|
Returns:
|
|
135
160
|
The updated case data.
|
|
136
161
|
"""
|
|
137
162
|
return self._connection.put(
|
|
138
|
-
api_path_v2("case", case_id, "items"),
|
|
163
|
+
api_path_v2("case", case_id, "items", refresh=refresh),
|
|
139
164
|
json={"id": item_id, "name": new_name},
|
|
140
165
|
)
|
|
141
166
|
|
|
142
|
-
def add_rule(
|
|
167
|
+
def add_rule(
|
|
168
|
+
self: Self,
|
|
169
|
+
case_id: str,
|
|
170
|
+
rule_data: dict[str, Any],
|
|
171
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
172
|
+
) -> dict[str, Any]:
|
|
143
173
|
"""Add a correlation rule to a case.
|
|
144
174
|
|
|
145
175
|
Args:
|
|
146
176
|
case_id: ID of the case.
|
|
147
177
|
rule_data: Rule definition (must include ``query``, ``destination``, ``author``).
|
|
178
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
179
|
+
Defaults to False.
|
|
148
180
|
|
|
149
181
|
Returns:
|
|
150
182
|
The updated case data.
|
|
151
183
|
"""
|
|
152
|
-
return self._connection.post(api_path_v2("case", case_id, "rules"), json=rule_data)
|
|
184
|
+
return self._connection.post(api_path_v2("case", case_id, "rules", refresh=refresh), json=rule_data)
|
|
153
185
|
|
|
154
|
-
def delete_rule(
|
|
186
|
+
def delete_rule(
|
|
187
|
+
self: Self, case_id: str, rule_id: str, refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
188
|
+
) -> dict[str, Any]:
|
|
155
189
|
"""Delete a correlation rule from a case.
|
|
156
190
|
|
|
157
191
|
Args:
|
|
158
192
|
case_id: ID of the case.
|
|
159
193
|
rule_id: ID of the rule to delete.
|
|
194
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
195
|
+
Defaults to False.
|
|
160
196
|
|
|
161
197
|
Returns:
|
|
162
198
|
The updated case data.
|
|
163
199
|
"""
|
|
164
|
-
return self._connection.delete(api_path_v2("case", case_id, "rules", rule_id))
|
|
200
|
+
return self._connection.delete(api_path_v2("case", case_id, "rules", rule_id, refresh=refresh))
|
|
165
201
|
|
|
166
|
-
def update_rule(
|
|
202
|
+
def update_rule(
|
|
203
|
+
self: Self,
|
|
204
|
+
case_id: str,
|
|
205
|
+
rule_id: str,
|
|
206
|
+
rule_data: dict[str, Any],
|
|
207
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
208
|
+
) -> dict[str, Any]:
|
|
167
209
|
"""Update a correlation rule on a case.
|
|
168
210
|
|
|
169
211
|
Args:
|
|
170
212
|
case_id: ID of the case.
|
|
171
213
|
rule_id: ID of the rule to update.
|
|
172
214
|
rule_data: Updated rule fields.
|
|
215
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
216
|
+
Defaults to False.
|
|
173
217
|
|
|
174
218
|
Returns:
|
|
175
219
|
The updated case data.
|
|
176
220
|
"""
|
|
177
|
-
return self._connection.put(api_path_v2("case", case_id, "rules", rule_id), json=rule_data)
|
|
221
|
+
return self._connection.put(api_path_v2("case", case_id, "rules", rule_id, refresh=refresh), json=rule_data)
|
|
@@ -42,12 +42,15 @@ class Ingest(object):
|
|
|
42
42
|
self: Self,
|
|
43
43
|
index: str,
|
|
44
44
|
data: Union[dict[str, Any], list[dict[str, Any]]],
|
|
45
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
45
46
|
) -> list[str]:
|
|
46
47
|
"""Create one or more records in the given index.
|
|
47
48
|
|
|
48
49
|
Args:
|
|
49
50
|
index: Target index (``hit`` or ``event``).
|
|
50
51
|
data: A single record dict or a list of record dicts.
|
|
52
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
53
|
+
Defaults to False.
|
|
51
54
|
|
|
52
55
|
Returns:
|
|
53
56
|
List of created record IDs.
|
|
@@ -56,22 +59,26 @@ class Ingest(object):
|
|
|
56
59
|
data = [data]
|
|
57
60
|
|
|
58
61
|
return self._connection.post(
|
|
59
|
-
api_path_v2("ingest", index),
|
|
62
|
+
api_path_v2("ingest", index, refresh=refresh),
|
|
60
63
|
data=json.dumps(data),
|
|
61
64
|
headers={"Content-Type": "application/json"},
|
|
62
65
|
)
|
|
63
66
|
|
|
64
|
-
def delete(
|
|
67
|
+
def delete(
|
|
68
|
+
self: Self, indexes: str, ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
|
|
69
|
+
) -> dict[str, Any]:
|
|
65
70
|
"""Delete records across one or more indexes.
|
|
66
71
|
|
|
67
72
|
Args:
|
|
68
73
|
indexes: Comma-separated index names (e.g. ``"hit"`` or ``"hit,event"``).
|
|
69
74
|
ids: List of record IDs to delete.
|
|
75
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
76
|
+
Defaults to False.
|
|
70
77
|
|
|
71
78
|
Returns:
|
|
72
79
|
Dictionary with deletion results.
|
|
73
80
|
"""
|
|
74
|
-
return self._connection.delete(api_path_v2("ingest", indexes), json=ids)
|
|
81
|
+
return self._connection.delete(api_path_v2("ingest", indexes, refresh=refresh), json=ids)
|
|
75
82
|
|
|
76
83
|
def validate(
|
|
77
84
|
self: Self,
|
|
@@ -102,6 +109,7 @@ class Ingest(object):
|
|
|
102
109
|
record_id: str,
|
|
103
110
|
new_data: dict[str, Any],
|
|
104
111
|
replace: bool = False,
|
|
112
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
105
113
|
) -> dict[str, Any]:
|
|
106
114
|
"""Overwrite (patch) a single record.
|
|
107
115
|
|
|
@@ -110,6 +118,8 @@ class Ingest(object):
|
|
|
110
118
|
record_id: ID of the record to overwrite.
|
|
111
119
|
new_data: Partial record data to merge.
|
|
112
120
|
replace: If ``True``, lists are replaced instead of merged.
|
|
121
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
122
|
+
Defaults to False.
|
|
113
123
|
|
|
114
124
|
Returns:
|
|
115
125
|
The updated record data.
|
|
@@ -119,7 +129,7 @@ class Ingest(object):
|
|
|
119
129
|
|
|
120
130
|
return self._connection.request(
|
|
121
131
|
self._connection.session.patch,
|
|
122
|
-
api_path_v2("ingest", index, record_id, "overwrite", replace=replace if replace else None),
|
|
132
|
+
api_path_v2("ingest", index, record_id, "overwrite", replace=replace if replace else None, refresh=refresh),
|
|
123
133
|
lambda resp: resp.json()["api_response"],
|
|
124
134
|
json=new_data,
|
|
125
135
|
)
|
|
@@ -129,6 +139,7 @@ class Ingest(object):
|
|
|
129
139
|
indexes: str,
|
|
130
140
|
query: str,
|
|
131
141
|
operations: list[tuple[str, str, Any]],
|
|
142
|
+
refresh: bool | Literal["true", "false", "wait_for"] = False,
|
|
132
143
|
) -> dict[Literal["success"], bool]:
|
|
133
144
|
"""Bulk update records matching a query.
|
|
134
145
|
|
|
@@ -138,6 +149,8 @@ class Ingest(object):
|
|
|
138
149
|
operations: List of ``(operation, key, value)`` tuples.
|
|
139
150
|
Valid operations: SET, INC, DEC, MAX, MIN, APPEND,
|
|
140
151
|
APPEND_IF_MISSING, REMOVE, DELETE.
|
|
152
|
+
refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
|
|
153
|
+
Defaults to False.
|
|
141
154
|
|
|
142
155
|
Returns:
|
|
143
156
|
Whether the operation succeeded.
|
|
@@ -155,6 +168,6 @@ class Ingest(object):
|
|
|
155
168
|
)
|
|
156
169
|
|
|
157
170
|
return self._connection.put(
|
|
158
|
-
api_path_v2("ingest", indexes, "update"),
|
|
171
|
+
api_path_v2("ingest", indexes, "update", refresh=refresh),
|
|
159
172
|
json={"query": query, "operations": operations},
|
|
160
173
|
)
|
|
@@ -91,7 +91,7 @@ suppress-none-returning = true
|
|
|
91
91
|
[tool.poetry]
|
|
92
92
|
package-mode = true
|
|
93
93
|
name = "howler-client"
|
|
94
|
-
version = "3.1.0.
|
|
94
|
+
version = "3.1.0.dev345"
|
|
95
95
|
description = "The Howler client library facilitates issuing requests to Howler"
|
|
96
96
|
authors = [
|
|
97
97
|
"Canadian Centre for Cyber Security <howler@cyber.gc.ca>",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/dict_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/__init__.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/chunk.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/facet.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/fields.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/grouped.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/histogram.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/stats.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/stream.py
RENAMED
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/utils/json_encoders.py
RENAMED
|
File without changes
|