elastro-client 1.2.2__tar.gz → 1.2.4__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.
- {elastro_client-1.2.2 → elastro_client-1.2.4}/MANIFEST.in +2 -1
- {elastro_client-1.2.2/elastro_client.egg-info → elastro_client-1.2.4}/PKG-INFO +54 -7
- {elastro_client-1.2.2 → elastro_client-1.2.4}/README.md +47 -5
- elastro_client-1.2.4/docs/commands_reference.md +101 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/__init__.py +1 -1
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/aggregations.py +14 -18
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/query_builder.py +22 -13
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/scroll.py +41 -30
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/art.py +4 -1
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/cli.py +68 -37
- elastro_client-1.2.4/elastro/cli/commands/__init__.py +48 -0
- elastro_client-1.2.4/elastro/cli/commands/cluster.py +111 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/config.py +50 -36
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/datastream.py +31 -13
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/document.py +93 -48
- elastro_client-1.2.4/elastro/cli/commands/gui.py +38 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/ilm.py +95 -65
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/index.py +205 -44
- elastro_client-1.2.4/elastro/cli/commands/index_recipes.py +193 -0
- elastro_client-1.2.4/elastro/cli/commands/ingest.py +92 -0
- elastro_client-1.2.4/elastro/cli/commands/security.py +92 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/snapshot.py +97 -60
- elastro_client-1.2.4/elastro/cli/commands/tasks.py +97 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/template.py +91 -39
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/utils.py +76 -30
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/completion.py +24 -19
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/output.py +20 -17
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/config/__init__.py +7 -1
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/config/defaults.py +10 -23
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/config/loader.py +37 -20
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/client.py +51 -26
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/datastream.py +50 -41
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/document.py +73 -40
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/document_bulk.py +6 -19
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/errors.py +9 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/ilm.py +14 -14
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/index.py +16 -15
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/logger.py +9 -9
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/query_builder.py +35 -33
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/snapshot.py +45 -36
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/validation.py +81 -22
- elastro_client-1.2.4/elastro/gui/assets/index-7HiKWxC0.js +293 -0
- elastro_client-1.2.4/elastro/gui/assets/index-BGQLoyNJ.css +1 -0
- elastro_client-1.2.4/elastro/gui/elastro.svg +10 -0
- elastro_client-1.2.4/elastro/gui/favicon.ico +0 -0
- elastro_client-1.2.4/elastro/gui/index.html +17 -0
- elastro_client-1.2.4/elastro/gui/vite.svg +1 -0
- elastro_client-1.2.4/elastro/server.py +524 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/aliases.py +37 -22
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/health.py +33 -27
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/snapshots.py +105 -80
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/templates.py +19 -8
- {elastro_client-1.2.2 → elastro_client-1.2.4/elastro_client.egg-info}/PKG-INFO +54 -7
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/SOURCES.txt +14 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/requires.txt +2 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/client.py +25 -29
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/config_usage.py +17 -24
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/datastreams.py +93 -110
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/debug_connection.py +52 -25
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/document_operations.py +36 -42
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/index_management.py +34 -53
- {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/search.py +102 -139
- {elastro_client-1.2.2 → elastro_client-1.2.4}/pyproject.toml +34 -6
- elastro_client-1.2.4/requirements.txt +58 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/setup.py +1 -1
- elastro_client-1.2.4/tests/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/conftest.py +5 -5
- elastro_client-1.2.4/tests/fixtures/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/fixtures/datastream_fixtures.py +18 -32
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/fixtures/document_fixtures.py +20 -40
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/fixtures/index_fixtures.py +8 -16
- elastro_client-1.2.4/tests/integration/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_aggregations_integration.py +66 -108
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_client_integration.py +40 -40
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_datastream_integration.py +27 -29
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_docs_quickstart.py +14 -13
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_document_integration.py +65 -75
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_index_integration.py +22 -21
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_query_builder_integration.py +42 -42
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_scroll_integration.py +55 -61
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_workflow_integration.py +69 -95
- elastro_client-1.2.4/tests/manual/test_es.py +5 -0
- elastro_client-1.2.4/tests/unit/__init__.py +1 -0
- elastro_client-1.2.4/tests/unit/advanced/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/advanced/test_aggregations.py +36 -77
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/advanced/test_query_builder.py +85 -136
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/advanced/test_scroll.py +56 -107
- elastro_client-1.2.4/tests/unit/config/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/config/test_defaults.py +38 -17
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/config/test_loader.py +94 -93
- elastro_client-1.2.4/tests/unit/core/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_client.py +85 -85
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_datastream.py +168 -108
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_document.py +124 -247
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_document_bulk.py +56 -46
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_errors.py +1 -1
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_index.py +173 -140
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_validation.py +18 -46
- elastro_client-1.2.4/tests/unit/utils/__init__.py +1 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_aliases.py +75 -74
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_health.py +121 -129
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_snapshots.py +110 -115
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_templates.py +93 -58
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/verify_api_actions.py +10 -9
- {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/verify_cli_e2e.py +149 -95
- elastro_client-1.2.2/elastro/cli/commands/__init__.py +0 -32
- elastro_client-1.2.2/requirements.txt +0 -6
- elastro_client-1.2.2/tests/__init__.py +0 -1
- elastro_client-1.2.2/tests/fixtures/__init__.py +0 -1
- elastro_client-1.2.2/tests/integration/__init__.py +0 -1
- elastro_client-1.2.2/tests/manual/test_es.py +0 -1
- elastro_client-1.2.2/tests/unit/__init__.py +0 -1
- elastro_client-1.2.2/tests/unit/advanced/__init__.py +0 -1
- elastro_client-1.2.2/tests/unit/config/__init__.py +0 -1
- elastro_client-1.2.2/tests/unit/core/__init__.py +0 -1
- elastro_client-1.2.2/tests/unit/utils/__init__.py +0 -1
- {elastro_client-1.2.2 → elastro_client-1.2.4}/.coveragerc +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/LICENSE +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/advanced_features.md +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/api_reference.md +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/cli_usage.md +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/getting_started.md +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/roadmap.md +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/troubleshooting.md +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/__init__.py +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/__init__.py +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/__init__.py +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/py.typed +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/__init__.py +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/dependency_links.txt +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/entry_points.txt +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/top_level.txt +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/pytest.ini +0 -0
- {elastro_client-1.2.2 → elastro_client-1.2.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elastro-client
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: A comprehensive Python library for Elasticsearch management with both programmatic and CLI interfaces
|
|
5
5
|
Author: Austin Jorgensen
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,11 +9,14 @@ Project-URL: Repository, https://github.com/Fremen-Labs/elastro
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.9
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
15
|
Classifier: Operating System :: OS Independent
|
|
13
16
|
Classifier: Development Status :: 3 - Alpha
|
|
14
17
|
Classifier: Intended Audience :: Developers
|
|
15
18
|
Classifier: Topic :: Database
|
|
16
|
-
Requires-Python:
|
|
19
|
+
Requires-Python: <3.14,>=3.9
|
|
17
20
|
Description-Content-Type: text/markdown
|
|
18
21
|
License-File: LICENSE
|
|
19
22
|
Requires-Dist: elasticsearch<9.0.0,>=8.18.0
|
|
@@ -24,6 +27,8 @@ Requires-Dist: pyyaml>=6.0
|
|
|
24
27
|
Requires-Dist: colorlog>=6.0.0
|
|
25
28
|
Requires-Dist: rich>=10.0.0
|
|
26
29
|
Requires-Dist: rich-click>=1.7.0
|
|
30
|
+
Requires-Dist: fastapi>=0.111.0
|
|
31
|
+
Requires-Dist: uvicorn>=0.30.0
|
|
27
32
|
Provides-Extra: test
|
|
28
33
|
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
29
34
|
Requires-Dist: pytest-cov>=3.0.0; extra == "test"
|
|
@@ -68,18 +73,42 @@ The library offers both a programmatic API and a command-line interface for seam
|
|
|
68
73
|
|
|
69
74
|
## Installation
|
|
70
75
|
|
|
76
|
+
### Global CLI Installation (Recommended)
|
|
77
|
+
|
|
78
|
+
To heavily simplify installation across all operating systems and elegantly check your Python compatibility, run our automated `install.sh` via curl:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Safely check your python version and install the elastro CLI globally
|
|
82
|
+
curl -sSfL https://raw.githubusercontent.com/Fremen-Labs/elastro/main/install.sh | bash
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Alternatively, if you already have pipx installed and your Python version is compatible (>=3.9, <3.14):
|
|
86
|
+
|
|
71
87
|
```bash
|
|
72
|
-
|
|
88
|
+
# Manual installation via pipx
|
|
89
|
+
pipx install elastro-client
|
|
90
|
+
|
|
91
|
+
# Upgrade later
|
|
92
|
+
pipx upgrade elastro-client
|
|
73
93
|
```
|
|
74
94
|
|
|
75
|
-
|
|
95
|
+
### Library Installation (For Development)
|
|
96
|
+
|
|
97
|
+
If you are using Elastro as a library in your Python project:
|
|
76
98
|
|
|
77
99
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
100
|
+
# Using a virtual environment
|
|
101
|
+
python3 -m venv venv
|
|
102
|
+
source venv/bin/activate
|
|
103
|
+
pip install elastro-client
|
|
81
104
|
```
|
|
82
105
|
|
|
106
|
+
### Troubleshooting: "externally-managed-environment"
|
|
107
|
+
|
|
108
|
+
If you see an `externally-managed-environment` error when running `pip install`, it means your OS (like macOS with Homebrew) prevents system-wide package installation.
|
|
109
|
+
|
|
110
|
+
**Solution:** Use `pipx` (above) or a virtual environment. Do not use `--break-system-packages` unless you are certain of the consequences.
|
|
111
|
+
|
|
83
112
|
## Basic Usage
|
|
84
113
|
|
|
85
114
|
### Client Connection
|
|
@@ -169,6 +198,9 @@ print(results)
|
|
|
169
198
|
# Initialize configuration
|
|
170
199
|
elastro config init
|
|
171
200
|
|
|
201
|
+
# Launch the Elastro Local Web GUI
|
|
202
|
+
elastro gui
|
|
203
|
+
|
|
172
204
|
# Create an index
|
|
173
205
|
elastro index create products --shards 3 --replicas 1
|
|
174
206
|
|
|
@@ -186,6 +218,21 @@ elastro doc index products --id 1 --file ./product.json
|
|
|
186
218
|
|
|
187
219
|
# Search documents
|
|
188
220
|
elastro doc search products --term category=laptop
|
|
221
|
+
|
|
222
|
+
# View cluster health and routing allocation
|
|
223
|
+
elastro cluster health
|
|
224
|
+
elastro cluster allocation
|
|
225
|
+
|
|
226
|
+
# Manage ingest pipelines
|
|
227
|
+
elastro ingest list
|
|
228
|
+
elastro ingest simulate my-pipeline --docs ./docs.json
|
|
229
|
+
|
|
230
|
+
# Manage native realm security users and roles
|
|
231
|
+
elastro security users list
|
|
232
|
+
elastro security roles create my-role --privileges "monitor,manage"
|
|
233
|
+
|
|
234
|
+
# View long-running cluster tasks
|
|
235
|
+
elastro tasks list --detailed
|
|
189
236
|
```
|
|
190
237
|
|
|
191
238
|
### ILM (Index Lifecycle Management)
|
|
@@ -30,18 +30,42 @@ The library offers both a programmatic API and a command-line interface for seam
|
|
|
30
30
|
|
|
31
31
|
## Installation
|
|
32
32
|
|
|
33
|
+
### Global CLI Installation (Recommended)
|
|
34
|
+
|
|
35
|
+
To heavily simplify installation across all operating systems and elegantly check your Python compatibility, run our automated `install.sh` via curl:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Safely check your python version and install the elastro CLI globally
|
|
39
|
+
curl -sSfL https://raw.githubusercontent.com/Fremen-Labs/elastro/main/install.sh | bash
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Alternatively, if you already have pipx installed and your Python version is compatible (>=3.9, <3.14):
|
|
43
|
+
|
|
33
44
|
```bash
|
|
34
|
-
|
|
45
|
+
# Manual installation via pipx
|
|
46
|
+
pipx install elastro-client
|
|
47
|
+
|
|
48
|
+
# Upgrade later
|
|
49
|
+
pipx upgrade elastro-client
|
|
35
50
|
```
|
|
36
51
|
|
|
37
|
-
|
|
52
|
+
### Library Installation (For Development)
|
|
53
|
+
|
|
54
|
+
If you are using Elastro as a library in your Python project:
|
|
38
55
|
|
|
39
56
|
```bash
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
# Using a virtual environment
|
|
58
|
+
python3 -m venv venv
|
|
59
|
+
source venv/bin/activate
|
|
60
|
+
pip install elastro-client
|
|
43
61
|
```
|
|
44
62
|
|
|
63
|
+
### Troubleshooting: "externally-managed-environment"
|
|
64
|
+
|
|
65
|
+
If you see an `externally-managed-environment` error when running `pip install`, it means your OS (like macOS with Homebrew) prevents system-wide package installation.
|
|
66
|
+
|
|
67
|
+
**Solution:** Use `pipx` (above) or a virtual environment. Do not use `--break-system-packages` unless you are certain of the consequences.
|
|
68
|
+
|
|
45
69
|
## Basic Usage
|
|
46
70
|
|
|
47
71
|
### Client Connection
|
|
@@ -131,6 +155,9 @@ print(results)
|
|
|
131
155
|
# Initialize configuration
|
|
132
156
|
elastro config init
|
|
133
157
|
|
|
158
|
+
# Launch the Elastro Local Web GUI
|
|
159
|
+
elastro gui
|
|
160
|
+
|
|
134
161
|
# Create an index
|
|
135
162
|
elastro index create products --shards 3 --replicas 1
|
|
136
163
|
|
|
@@ -148,6 +175,21 @@ elastro doc index products --id 1 --file ./product.json
|
|
|
148
175
|
|
|
149
176
|
# Search documents
|
|
150
177
|
elastro doc search products --term category=laptop
|
|
178
|
+
|
|
179
|
+
# View cluster health and routing allocation
|
|
180
|
+
elastro cluster health
|
|
181
|
+
elastro cluster allocation
|
|
182
|
+
|
|
183
|
+
# Manage ingest pipelines
|
|
184
|
+
elastro ingest list
|
|
185
|
+
elastro ingest simulate my-pipeline --docs ./docs.json
|
|
186
|
+
|
|
187
|
+
# Manage native realm security users and roles
|
|
188
|
+
elastro security users list
|
|
189
|
+
elastro security roles create my-role --privileges "monitor,manage"
|
|
190
|
+
|
|
191
|
+
# View long-running cluster tasks
|
|
192
|
+
elastro tasks list --detailed
|
|
151
193
|
```
|
|
152
194
|
|
|
153
195
|
### ILM (Index Lifecycle Management)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Elastro CLI Commands Reference
|
|
2
|
+
|
|
3
|
+
The Elastro CLI provides a robust feature set for managing your Elasticsearch cluster operations safely and efficiently. This guide details each primary command group, its associated subcommands, what they do, and why they are important for your workflow.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. `config`
|
|
8
|
+
**Purpose**: Manage local configuration and connection profiles.
|
|
9
|
+
**Why it's important**: Centralizing connection strings, credentials, and API keys ensures you don't accidentally leak secrets or push them to version control. It also enables rapid context-switching between dev, staging, and production environments.
|
|
10
|
+
|
|
11
|
+
- **`profile`**: Switch or define which configuration profile is actively used by Elastro.
|
|
12
|
+
- **`set`**: Set individual configuration values securely within the active profile.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 2. `gui`
|
|
17
|
+
**Purpose**: Launch the Elastro Local Web GUI.
|
|
18
|
+
**Why it's important**: Sometimes the CLI isn't enough to visualize complex index metrics or health statuses. The fully autonomous local GUI acts as a single pane of glass, allowing you to quickly spot cluster degradation (yellow/red indices) and manage your instances without deploying heavy Kibana stacks.
|
|
19
|
+
|
|
20
|
+
- **`elastro gui`**: Starts a secure, detached background server and immediately opens the web dashboard in your browser with a unique, one-time authentication token.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 3. `index`
|
|
25
|
+
**Purpose**: Manage Elasticsearch indices.
|
|
26
|
+
**Why it's important**: Indices are the foundational storage mechanism of Elasticsearch. Proper index management ensures that your data is correctly sharded, optimally routed, and easily purged.
|
|
27
|
+
|
|
28
|
+
- **`wizard`**: Interactive wizard for creating indices using "Certified Engineer" optimized recipes (highly recommended).
|
|
29
|
+
- **`list`** / **`find`**: Filter and list indices, displaying vital statistics like size, document counts, and health status.
|
|
30
|
+
- **`create`** / **`delete`**: Safely deploy mapped index schemas or purge indices entirely.
|
|
31
|
+
- **`get`** / **`exists`**: Query the exact structure, mappings, and existence of a target index.
|
|
32
|
+
- **`update`**: Inject dynamic settings updates into live indices.
|
|
33
|
+
- **`close`** / **`open`**: Freeze indices to save cluster memory footprint, and thaw them later for searching.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 4. `doc`
|
|
38
|
+
**Purpose**: Manage Elasticsearch documents.
|
|
39
|
+
**Why it's important**: While indexing logs via beats is common, debugging mapping errors or orchestrating CRUD operations manually is a critical administrative function. The `doc` commands let you easily ingest, query, and mutate specific records directly from the terminal.
|
|
40
|
+
|
|
41
|
+
- **`bulk`**: Perform high-throughput bulk insertion of documents from NDJSON payloads.
|
|
42
|
+
- **`search`**: Execute direct search queries against your indexes for ad-hoc debugging.
|
|
43
|
+
- **`index`**: Insert a new specific document or overwrite an existing one.
|
|
44
|
+
- **`get`**: Retrieve a document by its ID to examine its exact structured payload.
|
|
45
|
+
- **`update`**: Perform partial updates to an existing document without full replacement.
|
|
46
|
+
- **`delete`**: Remove an individual document.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 5. `datastream`
|
|
51
|
+
**Purpose**: Manage Elasticsearch datastreams.
|
|
52
|
+
**Why it's important**: Data streams are the modern, scalable approach to handling time-series data (like logs and metrics). Elastro abstracts the complexities of backing indices so you can manage the continuous stream elegantly.
|
|
53
|
+
|
|
54
|
+
- **`create`**: Establish a new datastream (requires a matching index template).
|
|
55
|
+
- **`list`** / **`get`** / **`exists`**: Discover and inspect streaming channels.
|
|
56
|
+
- **`stats`**: Retrieve detailed volumetric and performance statistics about your streams.
|
|
57
|
+
- **`delete`**: Teardown deprecated datastreams.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 6. `template`
|
|
62
|
+
**Purpose**: Manage index and component templates.
|
|
63
|
+
**Why it's important**: Templates guarantee that newly generated rolling indices (or datastreams) automatically inherit the correct shards, replicas, mappings, and lifecycles dynamically, avoiding manual intervention at runtime.
|
|
64
|
+
|
|
65
|
+
- **`wizard`**: An interactive wizard that makes assembling advanced index schemas from reusable component templates easy.
|
|
66
|
+
- **`create`**: Apply a template JSON manifest to the cluster.
|
|
67
|
+
- **`list`** / **`get`**: Inspect currently active templates.
|
|
68
|
+
- **`delete`**: Purge outdated templates.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 7. `ilm`
|
|
73
|
+
**Purpose**: Manage Index Lifecycle Management (ILM) policies.
|
|
74
|
+
**Why it's important**: Managing the cost of compute versus storage requires aging out data. ILM policies automate the transition of indices through Hot, Warm, Cold, and Delete phases automatically, saving enormous amounts of hardware resources.
|
|
75
|
+
|
|
76
|
+
- **`wizard`**: Interactively define retention durations, rollover sizes, and phase transitions to build robust lifecycle policies without writing complex JSON.
|
|
77
|
+
- **`create`**: Upload a customized JSON ILM policy.
|
|
78
|
+
- **`list`** / **`get`**: Inspect the policies currently governing your cluster data.
|
|
79
|
+
- **`delete`**: Remove an ILM policy.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 8. `snapshot`
|
|
84
|
+
**Purpose**: Manage Snapshots and Repositories.
|
|
85
|
+
**Why it's important**: Hardware failures, ransomware, or unexpected deletions happen. Standardized cluster snapshotting is the only reliable path to disaster recovery (DR).
|
|
86
|
+
|
|
87
|
+
- **`repo`**: Manage the snapshot storage backends (e.g., S3, Azure Blob, or local FS).
|
|
88
|
+
- **`create`**: Trigger a manual snapshot of the cluster or specific indices.
|
|
89
|
+
- **`list`**: View all historical snapshots held in a repository.
|
|
90
|
+
- **`restore`**: Recover your cluster state and data instantly from a previously saved snapshot.
|
|
91
|
+
- **`delete`**: Prune old snapshots to reclaim storage space.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 9. `utils`
|
|
96
|
+
**Purpose**: Miscellaneous utility commands.
|
|
97
|
+
**Why it's important**: Fast access to high-level cluster metrics and organizational operations for general system administration.
|
|
98
|
+
|
|
99
|
+
- **`health`**: Get a quick snapshot of the cluster's pulse (Green, Yellow, Red) and node availability.
|
|
100
|
+
- **`aliases`**: Inspect index aliases, showing how applications transparently route to underlying indices.
|
|
101
|
+
- **`templates`**: Manage legacy index templates (if supporting older Elasticsearch 7.x clusters).
|
|
@@ -14,8 +14,9 @@ class AggregationBuilder:
|
|
|
14
14
|
"""Initialize an empty aggregation builder."""
|
|
15
15
|
self._aggregations: Dict[str, Dict[str, Any]] = {}
|
|
16
16
|
|
|
17
|
-
def terms(
|
|
18
|
-
|
|
17
|
+
def terms(
|
|
18
|
+
self, name: str, field: str, size: int = 10, min_doc_count: Optional[int] = None
|
|
19
|
+
) -> "AggregationBuilder":
|
|
19
20
|
"""Add a terms aggregation.
|
|
20
21
|
|
|
21
22
|
Args:
|
|
@@ -34,8 +35,9 @@ class AggregationBuilder:
|
|
|
34
35
|
self._aggregations[name] = {"terms": agg}
|
|
35
36
|
return self
|
|
36
37
|
|
|
37
|
-
def date_histogram(
|
|
38
|
-
|
|
38
|
+
def date_histogram(
|
|
39
|
+
self, name: str, field: str, interval: str, format: Optional[str] = None
|
|
40
|
+
) -> "AggregationBuilder":
|
|
39
41
|
"""Add a date_histogram aggregation.
|
|
40
42
|
|
|
41
43
|
Args:
|
|
@@ -65,15 +67,12 @@ class AggregationBuilder:
|
|
|
65
67
|
Returns:
|
|
66
68
|
Self for method chaining
|
|
67
69
|
"""
|
|
68
|
-
self._aggregations[name] = {
|
|
69
|
-
"histogram": {
|
|
70
|
-
"field": field,
|
|
71
|
-
"interval": interval
|
|
72
|
-
}
|
|
73
|
-
}
|
|
70
|
+
self._aggregations[name] = {"histogram": {"field": field, "interval": interval}}
|
|
74
71
|
return self
|
|
75
72
|
|
|
76
|
-
def range(
|
|
73
|
+
def range(
|
|
74
|
+
self, name: str, field: str, ranges: List[Dict[str, Any]]
|
|
75
|
+
) -> "AggregationBuilder":
|
|
77
76
|
"""Add a range aggregation.
|
|
78
77
|
|
|
79
78
|
Args:
|
|
@@ -84,12 +83,7 @@ class AggregationBuilder:
|
|
|
84
83
|
Returns:
|
|
85
84
|
Self for method chaining
|
|
86
85
|
"""
|
|
87
|
-
self._aggregations[name] = {
|
|
88
|
-
"range": {
|
|
89
|
-
"field": field,
|
|
90
|
-
"ranges": ranges
|
|
91
|
-
}
|
|
92
|
-
}
|
|
86
|
+
self._aggregations[name] = {"range": {"field": field, "ranges": ranges}}
|
|
93
87
|
return self
|
|
94
88
|
|
|
95
89
|
def avg(self, name: str, field: str) -> "AggregationBuilder":
|
|
@@ -157,7 +151,9 @@ class AggregationBuilder:
|
|
|
157
151
|
self._aggregations[name] = {"cardinality": {"field": field}}
|
|
158
152
|
return self
|
|
159
153
|
|
|
160
|
-
def nested_agg(
|
|
154
|
+
def nested_agg(
|
|
155
|
+
self, parent_name: str, child_builder: "AggregationBuilder"
|
|
156
|
+
) -> "AggregationBuilder":
|
|
161
157
|
"""Add nested aggregations to a parent aggregation.
|
|
162
158
|
|
|
163
159
|
Args:
|
|
@@ -14,7 +14,13 @@ class QueryBuilder:
|
|
|
14
14
|
"""Initialize an empty query builder."""
|
|
15
15
|
self._query: Dict[str, Any] = {}
|
|
16
16
|
|
|
17
|
-
def match(
|
|
17
|
+
def match(
|
|
18
|
+
self,
|
|
19
|
+
field: str,
|
|
20
|
+
value: Any,
|
|
21
|
+
operator: str = "or",
|
|
22
|
+
fuzziness: Optional[str] = None,
|
|
23
|
+
) -> "QueryBuilder":
|
|
18
24
|
"""Create a match query.
|
|
19
25
|
|
|
20
26
|
Args:
|
|
@@ -26,7 +32,9 @@ class QueryBuilder:
|
|
|
26
32
|
Returns:
|
|
27
33
|
Self for method chaining
|
|
28
34
|
"""
|
|
29
|
-
match_query: Dict[str, Any] = {
|
|
35
|
+
match_query: Dict[str, Any] = {
|
|
36
|
+
"match": {field: {"query": value, "operator": operator}}
|
|
37
|
+
}
|
|
30
38
|
if fuzziness:
|
|
31
39
|
match_query["match"][field]["fuzziness"] = fuzziness
|
|
32
40
|
|
|
@@ -44,14 +52,7 @@ class QueryBuilder:
|
|
|
44
52
|
Returns:
|
|
45
53
|
Self for method chaining
|
|
46
54
|
"""
|
|
47
|
-
self._query = {
|
|
48
|
-
"match_phrase": {
|
|
49
|
-
field: {
|
|
50
|
-
"query": value,
|
|
51
|
-
"slop": slop
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
+
self._query = {"match_phrase": {field: {"query": value, "slop": slop}}}
|
|
55
56
|
return self
|
|
56
57
|
|
|
57
58
|
def term(self, field: str, value: Any) -> "QueryBuilder":
|
|
@@ -80,8 +81,14 @@ class QueryBuilder:
|
|
|
80
81
|
self._query = {"terms": {field: values}}
|
|
81
82
|
return self
|
|
82
83
|
|
|
83
|
-
def range(
|
|
84
|
-
|
|
84
|
+
def range(
|
|
85
|
+
self,
|
|
86
|
+
field: str,
|
|
87
|
+
gte: Optional[Any] = None,
|
|
88
|
+
lte: Optional[Any] = None,
|
|
89
|
+
gt: Optional[Any] = None,
|
|
90
|
+
lt: Optional[Any] = None,
|
|
91
|
+
) -> "QueryBuilder":
|
|
85
92
|
"""Create a range query.
|
|
86
93
|
|
|
87
94
|
Args:
|
|
@@ -188,7 +195,9 @@ class BoolQueryBuilder:
|
|
|
188
195
|
self._must.append(query)
|
|
189
196
|
return self
|
|
190
197
|
|
|
191
|
-
def must_not(
|
|
198
|
+
def must_not(
|
|
199
|
+
self, query: Union[QueryBuilder, Dict[str, Any]]
|
|
200
|
+
) -> "BoolQueryBuilder":
|
|
192
201
|
"""Add a must_not clause to the bool query.
|
|
193
202
|
|
|
194
203
|
Args:
|
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Callable, Dict, Generator, List, Optional, Union
|
|
4
4
|
from elasticsearch import Elasticsearch
|
|
5
|
+
from elasticsearch import Elasticsearch
|
|
6
|
+
from elastro.core.logger import get_logger
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
5
9
|
|
|
6
10
|
|
|
7
11
|
class ScrollHelper:
|
|
8
12
|
"""Helper for managing Elasticsearch scroll searches.
|
|
9
13
|
|
|
10
|
-
Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
15
|
+
that would otherwise exceed result size limits. This helper simplifies the
|
|
16
|
+
process of initializing and maintaining scroll contexts.
|
|
13
17
|
"""
|
|
14
18
|
|
|
15
19
|
def __init__(self, client: Elasticsearch) -> None:
|
|
@@ -20,9 +24,14 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
20
24
|
"""
|
|
21
25
|
self._client = client
|
|
22
26
|
|
|
23
|
-
def scroll(
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
def scroll(
|
|
28
|
+
self,
|
|
29
|
+
index: str,
|
|
30
|
+
query: Dict[str, Any],
|
|
31
|
+
scroll_timeout: str = "1m",
|
|
32
|
+
size: int = 1000,
|
|
33
|
+
source_fields: Optional[List[str]] = None,
|
|
34
|
+
) -> Generator[List[Dict[str, Any]], None, None]:
|
|
26
35
|
"""Perform a scroll search and yield batches of results.
|
|
27
36
|
|
|
28
37
|
Args:
|
|
@@ -40,11 +49,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
40
49
|
body["_source"] = source_fields
|
|
41
50
|
|
|
42
51
|
# Initialize scroll
|
|
43
|
-
resp = self._client.search(
|
|
44
|
-
index=index,
|
|
45
|
-
body=body,
|
|
46
|
-
scroll=scroll_timeout
|
|
47
|
-
)
|
|
52
|
+
resp = self._client.search(index=index, body=body, scroll=scroll_timeout)
|
|
48
53
|
|
|
49
54
|
# Get the scroll ID
|
|
50
55
|
scroll_id = resp.get("_scroll_id")
|
|
@@ -56,10 +61,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
56
61
|
yield batch
|
|
57
62
|
|
|
58
63
|
# Continue scrolling
|
|
59
|
-
resp = self._client.scroll(
|
|
60
|
-
scroll_id=scroll_id,
|
|
61
|
-
scroll=scroll_timeout
|
|
62
|
-
)
|
|
64
|
+
resp = self._client.scroll(scroll_id=scroll_id, scroll=scroll_timeout)
|
|
63
65
|
|
|
64
66
|
# Update scroll_id as it may change
|
|
65
67
|
scroll_id = resp.get("_scroll_id")
|
|
@@ -75,14 +77,18 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
75
77
|
if scroll_id:
|
|
76
78
|
try:
|
|
77
79
|
self._client.clear_scroll(scroll_id=scroll_id)
|
|
78
|
-
except Exception:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.warning(f"Failed to clear scroll context: {str(e)}")
|
|
82
|
+
|
|
83
|
+
def process_all(
|
|
84
|
+
self,
|
|
85
|
+
index: str,
|
|
86
|
+
query: Dict[str, Any],
|
|
87
|
+
processor: Callable[[Dict[str, Any]], None],
|
|
88
|
+
scroll_timeout: str = "1m",
|
|
89
|
+
size: int = 1000,
|
|
90
|
+
source_fields: Optional[List[str]] = None,
|
|
91
|
+
) -> int:
|
|
86
92
|
"""Process all matching documents with a callback function.
|
|
87
93
|
|
|
88
94
|
Args:
|
|
@@ -103,7 +109,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
103
109
|
query=query,
|
|
104
110
|
scroll_timeout=scroll_timeout,
|
|
105
111
|
size=size,
|
|
106
|
-
source_fields=source_fields
|
|
112
|
+
source_fields=source_fields,
|
|
107
113
|
):
|
|
108
114
|
for doc in batch:
|
|
109
115
|
processor(doc)
|
|
@@ -111,10 +117,15 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
111
117
|
|
|
112
118
|
return total_processed
|
|
113
119
|
|
|
114
|
-
def collect_all(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
def collect_all(
|
|
121
|
+
self,
|
|
122
|
+
index: str,
|
|
123
|
+
query: Dict[str, Any],
|
|
124
|
+
scroll_timeout: str = "1m",
|
|
125
|
+
size: int = 1000,
|
|
126
|
+
source_fields: Optional[List[str]] = None,
|
|
127
|
+
max_documents: Optional[int] = None,
|
|
128
|
+
) -> List[Dict[str, Any]]:
|
|
118
129
|
"""Collect all matching documents into a single list.
|
|
119
130
|
|
|
120
131
|
Warning: This can consume a lot of memory for large result sets.
|
|
@@ -130,7 +141,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
130
141
|
Returns:
|
|
131
142
|
List of all matching documents
|
|
132
143
|
"""
|
|
133
|
-
all_docs = []
|
|
144
|
+
all_docs: List[Dict[str, Any]] = []
|
|
134
145
|
docs_collected = 0
|
|
135
146
|
|
|
136
147
|
for batch in self.scroll(
|
|
@@ -138,7 +149,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
|
|
|
138
149
|
query=query,
|
|
139
150
|
scroll_timeout=scroll_timeout,
|
|
140
151
|
size=size,
|
|
141
|
-
source_fields=source_fields
|
|
152
|
+
source_fields=source_fields,
|
|
142
153
|
):
|
|
143
154
|
if max_documents is not None:
|
|
144
155
|
remaining = max_documents - docs_collected
|
|
@@ -14,10 +14,13 @@ ELASTRO_ART = r"""
|
|
|
14
14
|
```
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
def get_banner() -> str:
|
|
18
19
|
return ELASTRO_ART
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
|
|
22
|
+
def print_banner() -> None:
|
|
21
23
|
from rich.console import Console
|
|
24
|
+
|
|
22
25
|
console = Console()
|
|
23
26
|
console.print(ELASTRO_ART, style="bold blue")
|