solrctl 0.5.0__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.
- solrctl-0.5.0/LICENSE +21 -0
- solrctl-0.5.0/PKG-INFO +164 -0
- solrctl-0.5.0/README.md +130 -0
- solrctl-0.5.0/pyproject.toml +58 -0
- solrctl-0.5.0/setup.cfg +4 -0
- solrctl-0.5.0/src/solrctl/__init__.py +0 -0
- solrctl-0.5.0/src/solrctl/cli.py +231 -0
- solrctl-0.5.0/src/solrctl/client.py +473 -0
- solrctl-0.5.0/src/solrctl/flows/__init__.py +0 -0
- solrctl-0.5.0/src/solrctl/flows/swap_flow.py +136 -0
- solrctl-0.5.0/src/solrctl/tasks/__init__.py +0 -0
- solrctl-0.5.0/src/solrctl/tasks/alias_swap.py +82 -0
- solrctl-0.5.0/src/solrctl/tasks/cleanup.py +133 -0
- solrctl-0.5.0/src/solrctl/tasks/core_swap.py +76 -0
- solrctl-0.5.0/src/solrctl/utils/__init__.py +1 -0
- solrctl-0.5.0/src/solrctl/utils/setup_test_cores.py +197 -0
- solrctl-0.5.0/src/solrctl.egg-info/PKG-INFO +164 -0
- solrctl-0.5.0/src/solrctl.egg-info/SOURCES.txt +22 -0
- solrctl-0.5.0/src/solrctl.egg-info/dependency_links.txt +1 -0
- solrctl-0.5.0/src/solrctl.egg-info/entry_points.txt +2 -0
- solrctl-0.5.0/src/solrctl.egg-info/requires.txt +16 -0
- solrctl-0.5.0/src/solrctl.egg-info/top_level.txt +1 -0
- solrctl-0.5.0/tests/test_cli.py +273 -0
- solrctl-0.5.0/tests/test_client.py +343 -0
solrctl-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Baer, Sächsische Landesbibliothek - Staats- und Universitätsbibliothek Dresden (SLUB)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
solrctl-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: solrctl
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: CLI-Tool zur Verwaltung von Apache Solr 9.x – Cores tauschen, Status abfragen, Konfiguration einsehen
|
|
5
|
+
Author-email: Thomas Baer <thomas.baer@slub-dresden.de>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Intended Audience :: System Administrators
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: System :: Systems Administration
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: httpx>=0.27
|
|
20
|
+
Requires-Dist: pydantic>=2.7
|
|
21
|
+
Requires-Dist: click>=8.1
|
|
22
|
+
Requires-Dist: loguru>=0.7
|
|
23
|
+
Provides-Extra: prefect
|
|
24
|
+
Requires-Dist: prefect==3.6.19; extra == "prefect"
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0; extra == "prefect"
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=8.2; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-env>=1.1; extra == "dev"
|
|
30
|
+
Requires-Dist: respx>=0.21; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pysolr>=3.10; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# solrctl
|
|
36
|
+
|
|
37
|
+
CLI-Tool zur Verwaltung von Apache Solr 9.x – ohne Downtime Cores tauschen, Status abfragen, Konfiguration einsehen.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv tool install solrctl
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Oder aus dem Checkout:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv pip install -e .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## CLI-Befehle
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Solr erreichbar?
|
|
55
|
+
solrctl ping
|
|
56
|
+
|
|
57
|
+
# Cores anzeigen
|
|
58
|
+
solrctl core list
|
|
59
|
+
|
|
60
|
+
# Core-Infos (Pfade, Dokumentanzahl, Größe)
|
|
61
|
+
solrctl core info <name>
|
|
62
|
+
|
|
63
|
+
# solrconfig.xml abrufen
|
|
64
|
+
solrctl core config <name>
|
|
65
|
+
|
|
66
|
+
# Schema als XML abrufen
|
|
67
|
+
solrctl core schema <name>
|
|
68
|
+
|
|
69
|
+
# Core-Swap (unterbrechungsfrei)
|
|
70
|
+
solrctl core swap --source <neuer_core> --target <aktiver_core>
|
|
71
|
+
|
|
72
|
+
# Core löschen
|
|
73
|
+
solrctl core delete <name> [--delete-index]
|
|
74
|
+
|
|
75
|
+
# Alias-Operationen (SolrCloud)
|
|
76
|
+
solrctl alias list
|
|
77
|
+
solrctl alias swap --alias <name> --collection <ziel>
|
|
78
|
+
solrctl alias delete <name>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Alle Befehle akzeptieren globale Optionen:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
--solr-url Basis-URL der Solr-Instanz (Default: http://localhost:8983, Env: SOLR_URL)
|
|
85
|
+
--user Basic-Auth Benutzername (Env: SOLR_USER)
|
|
86
|
+
--password Basic-Auth Passwort (Env: SOLR_PASSWORD)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Voraussetzungen
|
|
90
|
+
|
|
91
|
+
- Python 3.11+
|
|
92
|
+
- Zugriff auf eine Solr 9.x Instanz (Standalone für Core-Befehle, SolrCloud für Alias-Befehle)
|
|
93
|
+
|
|
94
|
+
## Lokale Entwicklung
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Abhängigkeiten inkl. Dev- und Prefect-Extras installieren
|
|
98
|
+
uv sync --all-extras
|
|
99
|
+
|
|
100
|
+
# Tests ausführen
|
|
101
|
+
uv run pytest
|
|
102
|
+
|
|
103
|
+
# CLI lokal ausführen
|
|
104
|
+
uv run solrctl --help
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Docker-basiertes Test-Setup
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker compose up -d
|
|
111
|
+
solrctl --solr-url http://localhost:8983 ping
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Prefect-Integration
|
|
115
|
+
|
|
116
|
+
solrctl liefert optionale Prefect-Tasks und -Flows für automatisierte Pipelines. Die Prefect-Abhängigkeiten werden nicht standardmäßig installiert:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv pip install -e ".[prefect]"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Verfügbare Tasks und Flows:
|
|
123
|
+
|
|
124
|
+
| Modul | Beschreibung |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `solrctl.tasks.core_swap` | Task: Core-Swap mit Retries |
|
|
127
|
+
| `solrctl.tasks.alias_swap` | Task: Alias-Swap mit Retries |
|
|
128
|
+
| `solrctl.tasks.cleanup` | Task: Optionales Löschen alter Cores/Collections |
|
|
129
|
+
| `solrctl.flows.swap_flow` | Flow: Kompletter Swap inkl. optionalem Cleanup |
|
|
130
|
+
|
|
131
|
+
Lokaler Testlauf:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
uv run python -m solrctl.flows.swap_flow
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Projektstruktur
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
src/
|
|
141
|
+
solrctl/
|
|
142
|
+
cli.py # Click-CLI
|
|
143
|
+
client.py # SolrClient (HTTP-API-Wrapper)
|
|
144
|
+
tasks/ # Prefect-Tasks (optional)
|
|
145
|
+
alias_swap.py
|
|
146
|
+
core_swap.py
|
|
147
|
+
cleanup.py
|
|
148
|
+
flows/ # Prefect-Flows (optional)
|
|
149
|
+
swap_flow.py
|
|
150
|
+
tests/
|
|
151
|
+
docs/
|
|
152
|
+
idea.md
|
|
153
|
+
plan.md
|
|
154
|
+
technical.md
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Weitere Dokumentation
|
|
158
|
+
|
|
159
|
+
- [`docs/plan.md`](docs/plan.md) – Ausführungsplan und aktueller Status
|
|
160
|
+
- [`docs/technical.md`](docs/technical.md) – Architekturentscheidungen
|
|
161
|
+
|
|
162
|
+
## KI-Unterstützung
|
|
163
|
+
|
|
164
|
+
Dieses Projekt wurde mit Unterstützung von KI-Tools (Large Language Models) entwickelt. Code-Struktur, Implementierung und Dokumentation wurden dabei unterstützt durch automatiserte Vorschläge. Alle Entscheidungen wurden vom Entwickler geprüft und bestätigt. Transparenz über den Entwicklungsprozess ist uns wichtig.
|
solrctl-0.5.0/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# solrctl
|
|
2
|
+
|
|
3
|
+
CLI-Tool zur Verwaltung von Apache Solr 9.x – ohne Downtime Cores tauschen, Status abfragen, Konfiguration einsehen.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv tool install solrctl
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Oder aus dem Checkout:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv pip install -e .
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## CLI-Befehle
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Solr erreichbar?
|
|
21
|
+
solrctl ping
|
|
22
|
+
|
|
23
|
+
# Cores anzeigen
|
|
24
|
+
solrctl core list
|
|
25
|
+
|
|
26
|
+
# Core-Infos (Pfade, Dokumentanzahl, Größe)
|
|
27
|
+
solrctl core info <name>
|
|
28
|
+
|
|
29
|
+
# solrconfig.xml abrufen
|
|
30
|
+
solrctl core config <name>
|
|
31
|
+
|
|
32
|
+
# Schema als XML abrufen
|
|
33
|
+
solrctl core schema <name>
|
|
34
|
+
|
|
35
|
+
# Core-Swap (unterbrechungsfrei)
|
|
36
|
+
solrctl core swap --source <neuer_core> --target <aktiver_core>
|
|
37
|
+
|
|
38
|
+
# Core löschen
|
|
39
|
+
solrctl core delete <name> [--delete-index]
|
|
40
|
+
|
|
41
|
+
# Alias-Operationen (SolrCloud)
|
|
42
|
+
solrctl alias list
|
|
43
|
+
solrctl alias swap --alias <name> --collection <ziel>
|
|
44
|
+
solrctl alias delete <name>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Alle Befehle akzeptieren globale Optionen:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
--solr-url Basis-URL der Solr-Instanz (Default: http://localhost:8983, Env: SOLR_URL)
|
|
51
|
+
--user Basic-Auth Benutzername (Env: SOLR_USER)
|
|
52
|
+
--password Basic-Auth Passwort (Env: SOLR_PASSWORD)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Voraussetzungen
|
|
56
|
+
|
|
57
|
+
- Python 3.11+
|
|
58
|
+
- Zugriff auf eine Solr 9.x Instanz (Standalone für Core-Befehle, SolrCloud für Alias-Befehle)
|
|
59
|
+
|
|
60
|
+
## Lokale Entwicklung
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Abhängigkeiten inkl. Dev- und Prefect-Extras installieren
|
|
64
|
+
uv sync --all-extras
|
|
65
|
+
|
|
66
|
+
# Tests ausführen
|
|
67
|
+
uv run pytest
|
|
68
|
+
|
|
69
|
+
# CLI lokal ausführen
|
|
70
|
+
uv run solrctl --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Docker-basiertes Test-Setup
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
docker compose up -d
|
|
77
|
+
solrctl --solr-url http://localhost:8983 ping
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Prefect-Integration
|
|
81
|
+
|
|
82
|
+
solrctl liefert optionale Prefect-Tasks und -Flows für automatisierte Pipelines. Die Prefect-Abhängigkeiten werden nicht standardmäßig installiert:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv pip install -e ".[prefect]"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Verfügbare Tasks und Flows:
|
|
89
|
+
|
|
90
|
+
| Modul | Beschreibung |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `solrctl.tasks.core_swap` | Task: Core-Swap mit Retries |
|
|
93
|
+
| `solrctl.tasks.alias_swap` | Task: Alias-Swap mit Retries |
|
|
94
|
+
| `solrctl.tasks.cleanup` | Task: Optionales Löschen alter Cores/Collections |
|
|
95
|
+
| `solrctl.flows.swap_flow` | Flow: Kompletter Swap inkl. optionalem Cleanup |
|
|
96
|
+
|
|
97
|
+
Lokaler Testlauf:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
uv run python -m solrctl.flows.swap_flow
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Projektstruktur
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
src/
|
|
107
|
+
solrctl/
|
|
108
|
+
cli.py # Click-CLI
|
|
109
|
+
client.py # SolrClient (HTTP-API-Wrapper)
|
|
110
|
+
tasks/ # Prefect-Tasks (optional)
|
|
111
|
+
alias_swap.py
|
|
112
|
+
core_swap.py
|
|
113
|
+
cleanup.py
|
|
114
|
+
flows/ # Prefect-Flows (optional)
|
|
115
|
+
swap_flow.py
|
|
116
|
+
tests/
|
|
117
|
+
docs/
|
|
118
|
+
idea.md
|
|
119
|
+
plan.md
|
|
120
|
+
technical.md
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Weitere Dokumentation
|
|
124
|
+
|
|
125
|
+
- [`docs/plan.md`](docs/plan.md) – Ausführungsplan und aktueller Status
|
|
126
|
+
- [`docs/technical.md`](docs/technical.md) – Architekturentscheidungen
|
|
127
|
+
|
|
128
|
+
## KI-Unterstützung
|
|
129
|
+
|
|
130
|
+
Dieses Projekt wurde mit Unterstützung von KI-Tools (Large Language Models) entwickelt. Code-Struktur, Implementierung und Dokumentation wurden dabei unterstützt durch automatiserte Vorschläge. Alle Entscheidungen wurden vom Entwickler geprüft und bestätigt. Transparenz über den Entwicklungsprozess ist uns wichtig.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "solrctl"
|
|
7
|
+
version = "0.5.0"
|
|
8
|
+
description = "CLI-Tool zur Verwaltung von Apache Solr 9.x – Cores tauschen, Status abfragen, Konfiguration einsehen"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Thomas Baer", email = "thomas.baer@slub-dresden.de"},
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: System Administrators",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: System :: Systems Administration",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"httpx>=0.27",
|
|
28
|
+
"pydantic>=2.7",
|
|
29
|
+
"click>=8.1",
|
|
30
|
+
"loguru>=0.7",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
prefect = [
|
|
35
|
+
"prefect==3.6.19",
|
|
36
|
+
"python-dotenv>=1.0",
|
|
37
|
+
]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=8.2",
|
|
40
|
+
"pytest-asyncio>=0.23",
|
|
41
|
+
"pytest-env>=1.1",
|
|
42
|
+
"respx>=0.21",
|
|
43
|
+
"pytest-cov>=5.0",
|
|
44
|
+
"pysolr>=3.10",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
solrctl = "solrctl.cli:main"
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.packages.find]
|
|
51
|
+
where = ["src"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
asyncio_mode = "auto"
|
|
55
|
+
testpaths = ["tests"]
|
|
56
|
+
env = [
|
|
57
|
+
"PREFECT_API_URL=",
|
|
58
|
+
]
|
solrctl-0.5.0/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""solrctl CLI – Verwaltung von Solr-Cores und Aliases."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from loguru import logger
|
|
7
|
+
|
|
8
|
+
from solrctl.client import SolrClient, SolrClientError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SolrContext:
|
|
12
|
+
"""Hält den SolrClient für die Laufzeit des CLI-Aufrufs."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, solr_url: str, auth: tuple[str, str] | None) -> None:
|
|
15
|
+
self.client = SolrClient(solr_url, auth=auth)
|
|
16
|
+
|
|
17
|
+
def close(self) -> None:
|
|
18
|
+
self.client.close()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
pass_solr_ctx = click.make_pass_decorator(SolrContext)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _handle_error(exc: SolrClientError) -> None:
|
|
25
|
+
click.secho(f"Fehler: {exc}", fg="red", err=True)
|
|
26
|
+
raise SystemExit(1)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@click.group()
|
|
30
|
+
@click.option(
|
|
31
|
+
"--solr-url",
|
|
32
|
+
envvar="SOLR_URL",
|
|
33
|
+
default="http://localhost:8983",
|
|
34
|
+
show_default=True,
|
|
35
|
+
help="Basis-URL der Solr-Instanz.",
|
|
36
|
+
)
|
|
37
|
+
@click.option(
|
|
38
|
+
"--user", envvar="SOLR_USER", default=None, help="Basic-Auth Benutzername."
|
|
39
|
+
)
|
|
40
|
+
@click.option(
|
|
41
|
+
"--password", envvar="SOLR_PASSWORD", default=None, help="Basic-Auth Passwort."
|
|
42
|
+
)
|
|
43
|
+
@click.pass_context
|
|
44
|
+
def cli(
|
|
45
|
+
ctx: click.Context, solr_url: str, user: str | None, password: str | None
|
|
46
|
+
) -> None:
|
|
47
|
+
"""solrctl – Verwaltung von Solr-Cores und Aliases."""
|
|
48
|
+
auth = (user, password) if user and password else None
|
|
49
|
+
ctx.obj = SolrContext(solr_url, auth)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@cli.command()
|
|
53
|
+
@pass_solr_ctx
|
|
54
|
+
def ping(ctx: SolrContext) -> None:
|
|
55
|
+
"""Prüft, ob Solr erreichbar ist."""
|
|
56
|
+
if ctx.client.ping():
|
|
57
|
+
click.echo("Solr erreichbar.")
|
|
58
|
+
else:
|
|
59
|
+
click.secho("Solr NICHT erreichbar.", fg="red", err=True)
|
|
60
|
+
raise SystemExit(1)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# ── core ──────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@cli.group()
|
|
67
|
+
def core() -> None:
|
|
68
|
+
"""Standalone Core-Operationen."""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@core.command("list")
|
|
72
|
+
@pass_solr_ctx
|
|
73
|
+
def core_list(ctx: SolrContext) -> None:
|
|
74
|
+
"""Listet alle vorhandenen Cores auf."""
|
|
75
|
+
try:
|
|
76
|
+
cores = ctx.client.list_cores()
|
|
77
|
+
except SolrClientError as exc:
|
|
78
|
+
_handle_error(exc)
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
if not cores:
|
|
82
|
+
click.echo("Keine Cores gefunden.")
|
|
83
|
+
return
|
|
84
|
+
for name in cores:
|
|
85
|
+
click.echo(name)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@core.command()
|
|
89
|
+
@click.option("--source", required=True, help="Name des neuen Cores (frische Daten).")
|
|
90
|
+
@click.option(
|
|
91
|
+
"--target", required=True, help="Name des aktiven Cores (wird getauscht)."
|
|
92
|
+
)
|
|
93
|
+
@pass_solr_ctx
|
|
94
|
+
def swap(ctx: SolrContext, source: str, target: str) -> None:
|
|
95
|
+
"""Tauscht zwei Solr-Cores (CoreAdmin SWAP-Action)."""
|
|
96
|
+
logger.info("Swap: '{}' <-> '{}'", target, source)
|
|
97
|
+
try:
|
|
98
|
+
ctx.client.swap_cores(target, source)
|
|
99
|
+
click.secho(f"Swap erfolgreich: '{target}' <-> '{source}'.", fg="green")
|
|
100
|
+
except SolrClientError as exc:
|
|
101
|
+
_handle_error(exc)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@core.command()
|
|
105
|
+
@click.argument("name")
|
|
106
|
+
@click.option("--delete-index", is_flag=True, help="Index-Daten auf Disk löschen.")
|
|
107
|
+
@pass_solr_ctx
|
|
108
|
+
def delete(ctx: SolrContext, name: str, delete_index: bool) -> None:
|
|
109
|
+
"""Löscht (unload) einen Solr-Core."""
|
|
110
|
+
try:
|
|
111
|
+
ctx.client.unload_core(name, delete_index=delete_index)
|
|
112
|
+
click.secho(f"Core '{name}' gelöscht.", fg="green")
|
|
113
|
+
except SolrClientError as exc:
|
|
114
|
+
_handle_error(exc)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@core.command("info")
|
|
118
|
+
@click.argument("name")
|
|
119
|
+
@pass_solr_ctx
|
|
120
|
+
def core_info(ctx: SolrContext, name: str) -> None:
|
|
121
|
+
"""Zeigt detaillierte Informationen zu einem Core an."""
|
|
122
|
+
try:
|
|
123
|
+
info = ctx.client.get_core_info(name)
|
|
124
|
+
except SolrClientError as exc:
|
|
125
|
+
_handle_error(exc)
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
click.echo(f"Core: {info.get('name', name)}")
|
|
129
|
+
click.echo(f"InstanceDir: {info.get('instanceDir')}")
|
|
130
|
+
click.echo(f"DataDir: {info.get('dataDir')}")
|
|
131
|
+
click.echo(f"Config: {info.get('config')}")
|
|
132
|
+
click.echo(f"Schema: {info.get('schema')}")
|
|
133
|
+
click.echo(f"StartTime: {info.get('startTime')}")
|
|
134
|
+
uptime = info.get("uptime", 0)
|
|
135
|
+
click.echo(f"Uptime: {uptime // 1000}s")
|
|
136
|
+
|
|
137
|
+
index = info.get("index", {})
|
|
138
|
+
if index:
|
|
139
|
+
click.echo()
|
|
140
|
+
click.secho("Index:", bold=True)
|
|
141
|
+
click.echo(f" numDocs: {index.get('numDocs')}")
|
|
142
|
+
click.echo(f" maxDoc: {index.get('maxDoc')}")
|
|
143
|
+
click.echo(f" deletedDocs: {index.get('deletedDocs')}")
|
|
144
|
+
click.echo(f" segments: {index.get('segmentCount')}")
|
|
145
|
+
click.echo(f" size: {index.get('size')}")
|
|
146
|
+
click.echo(f" lastModified: {index.get('lastModified')}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@core.command("config")
|
|
150
|
+
@click.argument("name")
|
|
151
|
+
@pass_solr_ctx
|
|
152
|
+
def core_config(ctx: SolrContext, name: str) -> None:
|
|
153
|
+
"""Gibt die solrconfig.xml eines Cores als XML aus."""
|
|
154
|
+
try:
|
|
155
|
+
config_xml = ctx.client.get_core_config(name)
|
|
156
|
+
except SolrClientError as exc:
|
|
157
|
+
_handle_error(exc)
|
|
158
|
+
return
|
|
159
|
+
click.echo(config_xml)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@core.command("schema")
|
|
163
|
+
@click.argument("name")
|
|
164
|
+
@pass_solr_ctx
|
|
165
|
+
def core_schema(ctx: SolrContext, name: str) -> None:
|
|
166
|
+
"""Gibt das Schema eines Cores als XML aus."""
|
|
167
|
+
try:
|
|
168
|
+
schema_xml = ctx.client.get_core_schema(name)
|
|
169
|
+
except SolrClientError as exc:
|
|
170
|
+
_handle_error(exc)
|
|
171
|
+
return
|
|
172
|
+
click.echo(schema_xml)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# ── alias ─────────────────────────────────────────────────────────
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@cli.group()
|
|
179
|
+
def alias() -> None:
|
|
180
|
+
"""SolrCloud Alias-Operationen."""
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@alias.command("list")
|
|
184
|
+
@pass_solr_ctx
|
|
185
|
+
def alias_list(ctx: SolrContext) -> None:
|
|
186
|
+
"""Listet alle Aliases auf."""
|
|
187
|
+
try:
|
|
188
|
+
aliases = ctx.client.list_aliases()
|
|
189
|
+
except SolrClientError as exc:
|
|
190
|
+
_handle_error(exc)
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
if not aliases:
|
|
194
|
+
click.echo("Keine Aliases gefunden.")
|
|
195
|
+
return
|
|
196
|
+
for alias_name, collection in aliases.items():
|
|
197
|
+
click.echo(f"{alias_name} -> {collection}")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@alias.command()
|
|
201
|
+
@click.option("--alias", required=True, help="Name des Alias.")
|
|
202
|
+
@click.option("--collection", required=True, help="Ziel-Collection.")
|
|
203
|
+
@pass_solr_ctx
|
|
204
|
+
def swap(ctx: SolrContext, alias: str, collection: str) -> None:
|
|
205
|
+
"""Setzt einen Alias auf eine neue Collection um."""
|
|
206
|
+
try:
|
|
207
|
+
ctx.client.create_or_update_alias(alias, collection)
|
|
208
|
+
click.secho(f"Alias '{alias}' -> '{collection}' gesetzt.", fg="green")
|
|
209
|
+
except SolrClientError as exc:
|
|
210
|
+
_handle_error(exc)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@alias.command()
|
|
214
|
+
@click.argument("name")
|
|
215
|
+
@pass_solr_ctx
|
|
216
|
+
def delete(ctx: SolrContext, name: str) -> None:
|
|
217
|
+
"""Löscht einen Alias."""
|
|
218
|
+
try:
|
|
219
|
+
ctx.client.delete_alias(name)
|
|
220
|
+
click.secho(f"Alias '{name}' gelöscht.", fg="green")
|
|
221
|
+
except SolrClientError as exc:
|
|
222
|
+
_handle_error(exc)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def main() -> None:
|
|
226
|
+
"""Einstiegspunkt für die CLI."""
|
|
227
|
+
cli()
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if __name__ == "__main__":
|
|
231
|
+
main()
|