iris-devtester 1.8.1__py3-none-any.whl → 1.9.1__py3-none-any.whl
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.
- iris_devtester/__init__.py +3 -2
- iris_devtester/cli/__init__.py +4 -2
- iris_devtester/cli/__main__.py +1 -1
- iris_devtester/cli/connection_commands.py +31 -51
- iris_devtester/cli/container.py +42 -113
- iris_devtester/cli/container_commands.py +6 -4
- iris_devtester/cli/fixture_commands.py +97 -73
- iris_devtester/config/auto_discovery.py +8 -20
- iris_devtester/config/container_config.py +24 -35
- iris_devtester/config/container_state.py +19 -43
- iris_devtester/config/discovery.py +10 -10
- iris_devtester/config/presets.py +3 -10
- iris_devtester/config/yaml_loader.py +3 -2
- iris_devtester/connections/__init__.py +25 -30
- iris_devtester/connections/connection.py +4 -3
- iris_devtester/connections/dbapi.py +5 -1
- iris_devtester/connections/jdbc.py +2 -6
- iris_devtester/connections/manager.py +1 -1
- iris_devtester/connections/retry.py +2 -5
- iris_devtester/containers/__init__.py +6 -6
- iris_devtester/containers/cpf_manager.py +13 -12
- iris_devtester/containers/iris_container.py +268 -436
- iris_devtester/containers/models.py +18 -43
- iris_devtester/containers/monitor_utils.py +1 -3
- iris_devtester/containers/monitoring.py +31 -46
- iris_devtester/containers/performance.py +5 -5
- iris_devtester/containers/validation.py +27 -60
- iris_devtester/containers/wait_strategies.py +13 -4
- iris_devtester/fixtures/__init__.py +14 -13
- iris_devtester/fixtures/creator.py +127 -555
- iris_devtester/fixtures/loader.py +221 -78
- iris_devtester/fixtures/manifest.py +8 -6
- iris_devtester/fixtures/obj_export.py +45 -35
- iris_devtester/fixtures/validator.py +4 -7
- iris_devtester/integrations/langchain.py +2 -6
- iris_devtester/ports/registry.py +5 -4
- iris_devtester/testing/__init__.py +3 -0
- iris_devtester/testing/fixtures.py +10 -1
- iris_devtester/testing/helpers.py +5 -12
- iris_devtester/testing/models.py +3 -2
- iris_devtester/testing/schema_reset.py +1 -3
- iris_devtester/utils/__init__.py +20 -5
- iris_devtester/utils/container_port.py +2 -6
- iris_devtester/utils/container_status.py +2 -6
- iris_devtester/utils/dbapi_compat.py +29 -14
- iris_devtester/utils/enable_callin.py +5 -7
- iris_devtester/utils/health_checks.py +18 -33
- iris_devtester/utils/iris_container_adapter.py +27 -26
- iris_devtester/utils/password.py +673 -0
- iris_devtester/utils/progress.py +1 -1
- iris_devtester/utils/test_connection.py +4 -6
- {iris_devtester-1.8.1.dist-info → iris_devtester-1.9.1.dist-info}/METADATA +7 -7
- iris_devtester-1.9.1.dist-info/RECORD +66 -0
- {iris_devtester-1.8.1.dist-info → iris_devtester-1.9.1.dist-info}/WHEEL +1 -1
- iris_devtester/utils/password_reset.py +0 -594
- iris_devtester/utils/password_verification.py +0 -350
- iris_devtester/utils/unexpire_passwords.py +0 -168
- iris_devtester-1.8.1.dist-info/RECORD +0 -68
- {iris_devtester-1.8.1.dist-info → iris_devtester-1.9.1.dist-info}/entry_points.txt +0 -0
- {iris_devtester-1.8.1.dist-info → iris_devtester-1.9.1.dist-info}/licenses/LICENSE +0 -0
- {iris_devtester-1.8.1.dist-info → iris_devtester-1.9.1.dist-info}/top_level.txt +0 -0
iris_devtester/__init__.py
CHANGED
|
@@ -26,14 +26,15 @@ LangChain Integration:
|
|
|
26
26
|
... # Build your RAG app...
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
|
-
__version__ = "1.
|
|
29
|
+
__version__ = "1.9.1"
|
|
30
30
|
__author__ = "InterSystems Community"
|
|
31
31
|
__license__ = "MIT"
|
|
32
32
|
|
|
33
|
+
from iris_devtester.config import IRISConfig
|
|
34
|
+
|
|
33
35
|
# Convenience imports for common usage
|
|
34
36
|
from iris_devtester.connections import get_connection
|
|
35
37
|
from iris_devtester.containers import IRISContainer
|
|
36
|
-
from iris_devtester.config import IRISConfig
|
|
37
38
|
|
|
38
39
|
# Optional LangChain integration (requires langchain-iris)
|
|
39
40
|
try:
|
iris_devtester/cli/__init__.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""CLI commands for iris-devtester."""
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
|
+
|
|
4
5
|
from iris_devtester import __version__
|
|
5
|
-
|
|
6
|
-
from .container import container_group as container
|
|
6
|
+
|
|
7
7
|
from .connection_commands import test_connection
|
|
8
|
+
from .container import container_group as container
|
|
9
|
+
from .fixture_commands import fixture
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
@click.group()
|
iris_devtester/cli/__main__.py
CHANGED
|
@@ -13,45 +13,17 @@ from iris_devtester.utils.iris_container_adapter import IRISContainerManager
|
|
|
13
13
|
|
|
14
14
|
@click.command(name="test-connection")
|
|
15
15
|
@click.option(
|
|
16
|
-
"--config",
|
|
17
|
-
type=click.Path(exists=True),
|
|
18
|
-
help="Path to iris-config.yml configuration file"
|
|
16
|
+
"--config", type=click.Path(exists=True), help="Path to iris-config.yml configuration file"
|
|
19
17
|
)
|
|
20
18
|
@click.option(
|
|
21
|
-
"--container",
|
|
22
|
-
type=str,
|
|
23
|
-
help="Container name to test connection against (default: iris_db)"
|
|
24
|
-
)
|
|
25
|
-
@click.option(
|
|
26
|
-
"--host",
|
|
27
|
-
type=str,
|
|
28
|
-
help="IRIS host (overrides config/container)"
|
|
29
|
-
)
|
|
30
|
-
@click.option(
|
|
31
|
-
"--port",
|
|
32
|
-
type=int,
|
|
33
|
-
help="IRIS SuperServer port (overrides config/container)"
|
|
34
|
-
)
|
|
35
|
-
@click.option(
|
|
36
|
-
"--namespace",
|
|
37
|
-
type=str,
|
|
38
|
-
help="IRIS namespace (default: USER)"
|
|
39
|
-
)
|
|
40
|
-
@click.option(
|
|
41
|
-
"--username",
|
|
42
|
-
type=str,
|
|
43
|
-
help="Username (default: _SYSTEM)"
|
|
44
|
-
)
|
|
45
|
-
@click.option(
|
|
46
|
-
"--password",
|
|
47
|
-
type=str,
|
|
48
|
-
help="Password (default: SYS)"
|
|
49
|
-
)
|
|
50
|
-
@click.option(
|
|
51
|
-
"--verbose", "-v",
|
|
52
|
-
is_flag=True,
|
|
53
|
-
help="Show detailed connection diagnostics"
|
|
19
|
+
"--container", type=str, help="Container name to test connection against (default: iris_db)"
|
|
54
20
|
)
|
|
21
|
+
@click.option("--host", type=str, help="IRIS host (overrides config/container)")
|
|
22
|
+
@click.option("--port", type=int, help="IRIS SuperServer port (overrides config/container)")
|
|
23
|
+
@click.option("--namespace", type=str, help="IRIS namespace (default: USER)")
|
|
24
|
+
@click.option("--username", type=str, help="Username (default: _SYSTEM)")
|
|
25
|
+
@click.option("--password", type=str, help="Password (default: SYS)")
|
|
26
|
+
@click.option("--verbose", "-v", is_flag=True, help="Show detailed connection diagnostics")
|
|
55
27
|
@click.pass_context
|
|
56
28
|
def test_connection(ctx, config, container, host, port, namespace, username, password, verbose):
|
|
57
29
|
"""
|
|
@@ -108,7 +80,9 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
108
80
|
if docker_container:
|
|
109
81
|
docker_container.reload()
|
|
110
82
|
if verbose:
|
|
111
|
-
click.echo(
|
|
83
|
+
click.echo(
|
|
84
|
+
f" → Found container: {container_name} (status: {docker_container.status})"
|
|
85
|
+
)
|
|
112
86
|
|
|
113
87
|
# Get port mapping
|
|
114
88
|
port_bindings = docker_container.attrs.get("NetworkSettings", {}).get("Ports", {})
|
|
@@ -175,12 +149,7 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
175
149
|
click.echo(f" → Connecting to SuperServer {conn_host}:{conn_port}...")
|
|
176
150
|
|
|
177
151
|
connection_string = f"{conn_host}:{conn_port}/{conn_namespace}"
|
|
178
|
-
conn = dbapi.connect(
|
|
179
|
-
connection_string,
|
|
180
|
-
conn_username,
|
|
181
|
-
conn_password,
|
|
182
|
-
timeout=5
|
|
183
|
-
)
|
|
152
|
+
conn = dbapi.connect(connection_string, conn_username, conn_password, timeout=5)
|
|
184
153
|
|
|
185
154
|
if verbose:
|
|
186
155
|
click.echo(" → Executing test query...")
|
|
@@ -204,6 +173,7 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
204
173
|
click.echo(f" ✗ DBAPI connection failed: {e}")
|
|
205
174
|
if verbose:
|
|
206
175
|
import traceback
|
|
176
|
+
|
|
207
177
|
click.echo(f"\n{traceback.format_exc()}")
|
|
208
178
|
|
|
209
179
|
# Test JDBC connection
|
|
@@ -216,7 +186,9 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
216
186
|
if not jpype.isJVMStarted():
|
|
217
187
|
if verbose:
|
|
218
188
|
click.echo(" → Starting JVM...")
|
|
219
|
-
jpype.startJVM(
|
|
189
|
+
jpype.startJVM(
|
|
190
|
+
jpype.getDefaultJVMPath(), "-Djava.class.path=./intersystems-jdbc-3.8.1.jar"
|
|
191
|
+
)
|
|
220
192
|
|
|
221
193
|
if verbose:
|
|
222
194
|
click.echo(f" → Connecting via JDBC to {conn_host}:{conn_port}...")
|
|
@@ -226,7 +198,7 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
226
198
|
"com.intersystems.jdbc.IRISDriver",
|
|
227
199
|
jdbc_url,
|
|
228
200
|
[conn_username, conn_password],
|
|
229
|
-
"./intersystems-jdbc-3.8.1.jar"
|
|
201
|
+
"./intersystems-jdbc-3.8.1.jar",
|
|
230
202
|
)
|
|
231
203
|
|
|
232
204
|
if verbose:
|
|
@@ -252,21 +224,26 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
252
224
|
click.echo(f" ✗ JDBC connection failed: {e}")
|
|
253
225
|
if verbose:
|
|
254
226
|
import traceback
|
|
227
|
+
|
|
255
228
|
click.echo(f"\n{traceback.format_exc()}")
|
|
256
229
|
|
|
257
230
|
# Summary
|
|
258
|
-
click.echo("\n" + "="*60)
|
|
231
|
+
click.echo("\n" + "=" * 60)
|
|
259
232
|
if dbapi_success or jdbc_success:
|
|
260
233
|
click.echo("✓ Connection test PASSED")
|
|
261
234
|
if dbapi_success and jdbc_success:
|
|
262
235
|
click.echo(" → Both DBAPI and JDBC working")
|
|
263
236
|
elif dbapi_success:
|
|
264
237
|
click.echo(" → DBAPI working (recommended)")
|
|
265
|
-
click.echo(
|
|
238
|
+
click.echo(
|
|
239
|
+
" → JDBC not available (install with: pip install iris-devtester[jdbc])"
|
|
240
|
+
)
|
|
266
241
|
else:
|
|
267
242
|
click.echo(" → JDBC working (slower fallback)")
|
|
268
|
-
click.echo(
|
|
269
|
-
|
|
243
|
+
click.echo(
|
|
244
|
+
" → DBAPI not available (install with: pip install intersystems-irispython)"
|
|
245
|
+
)
|
|
246
|
+
click.echo("=" * 60)
|
|
270
247
|
return # Success - exit with code 0
|
|
271
248
|
else:
|
|
272
249
|
click.echo("✗ Connection test FAILED")
|
|
@@ -282,8 +259,10 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
282
259
|
click.echo(" pip install iris-devtester[all]")
|
|
283
260
|
click.echo(" 4. Check firewall/network access to port")
|
|
284
261
|
click.echo("\nDocumentation:")
|
|
285
|
-
click.echo(
|
|
286
|
-
|
|
262
|
+
click.echo(
|
|
263
|
+
" https://github.com/intersystems-community/iris-devtester#connection-issues"
|
|
264
|
+
)
|
|
265
|
+
click.echo("=" * 60)
|
|
287
266
|
ctx.exit(1)
|
|
288
267
|
|
|
289
268
|
except ValueError as e:
|
|
@@ -295,6 +274,7 @@ def test_connection(ctx, config, container, host, port, namespace, username, pas
|
|
|
295
274
|
progress.print_error(f"Unexpected error: {e}")
|
|
296
275
|
if verbose:
|
|
297
276
|
import traceback
|
|
277
|
+
|
|
298
278
|
click.echo(f"\n{traceback.format_exc()}")
|
|
299
279
|
ctx.exit(1)
|
|
300
280
|
|
iris_devtester/cli/container.py
CHANGED
|
@@ -29,25 +29,17 @@ def container_group(ctx):
|
|
|
29
29
|
|
|
30
30
|
@container_group.command(name="up")
|
|
31
31
|
@click.option(
|
|
32
|
-
"--config",
|
|
33
|
-
type=click.Path(exists=True),
|
|
34
|
-
help="Path to iris-config.yml configuration file"
|
|
32
|
+
"--config", type=click.Path(exists=True), help="Path to iris-config.yml configuration file"
|
|
35
33
|
)
|
|
36
34
|
@click.option(
|
|
37
35
|
"--detach/--no-detach",
|
|
38
36
|
default=True,
|
|
39
|
-
help="Run container in background mode (default: detached)"
|
|
40
|
-
)
|
|
41
|
-
@click.option(
|
|
42
|
-
"--timeout",
|
|
43
|
-
type=int,
|
|
44
|
-
default=60,
|
|
45
|
-
help="Health check timeout in seconds (default: 60)"
|
|
37
|
+
help="Run container in background mode (default: detached)",
|
|
46
38
|
)
|
|
47
39
|
@click.option(
|
|
48
|
-
"--
|
|
49
|
-
help="Path to CPF merge file or raw CPF content"
|
|
40
|
+
"--timeout", type=int, default=60, help="Health check timeout in seconds (default: 60)"
|
|
50
41
|
)
|
|
42
|
+
@click.option("--cpf", help="Path to CPF merge file or raw CPF content")
|
|
51
43
|
@click.pass_context
|
|
52
44
|
def up(ctx, config, detach, timeout, cpf):
|
|
53
45
|
"""
|
|
@@ -122,7 +114,7 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
122
114
|
superserver_port=superserver_port,
|
|
123
115
|
webserver_port=webserver_port,
|
|
124
116
|
namespace=container_config.namespace,
|
|
125
|
-
password=container_config.password
|
|
117
|
+
password=container_config.password,
|
|
126
118
|
)
|
|
127
119
|
return
|
|
128
120
|
|
|
@@ -134,7 +126,9 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
134
126
|
# Create new container using Docker SDK (Feature 011 - T015: CLI mode persistence)
|
|
135
127
|
click.echo(f" → Edition: {container_config.edition}")
|
|
136
128
|
click.echo(f" → Image: {container_config.get_image_name()}")
|
|
137
|
-
click.echo(
|
|
129
|
+
click.echo(
|
|
130
|
+
f" → Ports: {container_config.superserver_port}, {container_config.webserver_port}"
|
|
131
|
+
)
|
|
138
132
|
if container_config.volumes:
|
|
139
133
|
click.echo(f" → Volumes: {len(container_config.volumes)} mount(s)")
|
|
140
134
|
|
|
@@ -151,16 +145,14 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
151
145
|
try:
|
|
152
146
|
existing_container = IRISContainerManager.create_from_config(
|
|
153
147
|
container_config,
|
|
154
|
-
use_testcontainers=False # CLI mode: manual lifecycle, no ryuk cleanup
|
|
148
|
+
use_testcontainers=False, # CLI mode: manual lifecycle, no ryuk cleanup
|
|
155
149
|
)
|
|
156
150
|
click.echo(f"✓ Container '{container_config.container_name}' created and started")
|
|
157
151
|
|
|
158
152
|
# Verify container persistence (Feature 011 - T015)
|
|
159
153
|
click.echo("⏳ Verifying container persistence...")
|
|
160
154
|
check = verify_container_persistence(
|
|
161
|
-
container_config.container_name,
|
|
162
|
-
container_config,
|
|
163
|
-
wait_seconds=2.0
|
|
155
|
+
container_config.container_name, container_config, wait_seconds=2.0
|
|
164
156
|
)
|
|
165
157
|
|
|
166
158
|
if not check.success:
|
|
@@ -180,9 +172,7 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
180
172
|
click.echo(f" {msg}")
|
|
181
173
|
|
|
182
174
|
state = health_checks.wait_for_healthy(
|
|
183
|
-
existing_container,
|
|
184
|
-
timeout=timeout,
|
|
185
|
-
progress_callback=progress_callback
|
|
175
|
+
existing_container, timeout=timeout, progress_callback=progress_callback
|
|
186
176
|
)
|
|
187
177
|
|
|
188
178
|
# Enable CallIn service (required for DBAPI)
|
|
@@ -215,7 +205,7 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
215
205
|
superserver_port=superserver_port,
|
|
216
206
|
webserver_port=webserver_port,
|
|
217
207
|
namespace=container_config.namespace,
|
|
218
|
-
password=container_config.password
|
|
208
|
+
password=container_config.password,
|
|
219
209
|
)
|
|
220
210
|
|
|
221
211
|
# Exit code 0 (success)
|
|
@@ -225,7 +215,6 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
225
215
|
raise
|
|
226
216
|
except ValueError as e:
|
|
227
217
|
|
|
228
|
-
|
|
229
218
|
# Configuration error (exit code 2)
|
|
230
219
|
progress.print_error(str(e))
|
|
231
220
|
ctx.exit(2)
|
|
@@ -244,13 +233,10 @@ def up(ctx, config, detach, timeout, cpf):
|
|
|
244
233
|
@click.option(
|
|
245
234
|
"--config",
|
|
246
235
|
type=click.Path(exists=True),
|
|
247
|
-
help="Path to configuration file (used if creating new container)"
|
|
236
|
+
help="Path to configuration file (used if creating new container)",
|
|
248
237
|
)
|
|
249
238
|
@click.option(
|
|
250
|
-
"--timeout",
|
|
251
|
-
type=int,
|
|
252
|
-
default=60,
|
|
253
|
-
help="Health check timeout in seconds (default: 60)"
|
|
239
|
+
"--timeout", type=int, default=60, help="Health check timeout in seconds (default: 60)"
|
|
254
240
|
)
|
|
255
241
|
@click.pass_context
|
|
256
242
|
def start(ctx, container_name, config, timeout):
|
|
@@ -308,15 +294,13 @@ def start(ctx, container_name, config, timeout):
|
|
|
308
294
|
try:
|
|
309
295
|
container = IRISContainerManager.create_from_config(
|
|
310
296
|
container_config,
|
|
311
|
-
use_testcontainers=False # CLI mode: manual lifecycle, no ryuk cleanup
|
|
297
|
+
use_testcontainers=False, # CLI mode: manual lifecycle, no ryuk cleanup
|
|
312
298
|
)
|
|
313
299
|
click.echo(f"✓ Container '{container_name}' created and started")
|
|
314
300
|
|
|
315
301
|
# Verify container persistence (Feature 011 - T015)
|
|
316
302
|
check = verify_container_persistence(
|
|
317
|
-
container_name,
|
|
318
|
-
container_config,
|
|
319
|
-
wait_seconds=2.0
|
|
303
|
+
container_name, container_config, wait_seconds=2.0
|
|
320
304
|
)
|
|
321
305
|
|
|
322
306
|
if not check.success:
|
|
@@ -354,10 +338,7 @@ def start(ctx, container_name, config, timeout):
|
|
|
354
338
|
@container_group.command(name="stop")
|
|
355
339
|
@click.argument("container_name", required=False, default="iris_db")
|
|
356
340
|
@click.option(
|
|
357
|
-
"--timeout",
|
|
358
|
-
type=int,
|
|
359
|
-
default=30,
|
|
360
|
-
help="Grace period before force kill (default: 30 seconds)"
|
|
341
|
+
"--timeout", type=int, default=30, help="Grace period before force kill (default: 30 seconds)"
|
|
361
342
|
)
|
|
362
343
|
@click.pass_context
|
|
363
344
|
def stop(ctx, container_name, timeout):
|
|
@@ -405,10 +386,7 @@ def stop(ctx, container_name, timeout):
|
|
|
405
386
|
@container_group.command(name="restart")
|
|
406
387
|
@click.argument("container_name", required=False, default="iris_db")
|
|
407
388
|
@click.option(
|
|
408
|
-
"--timeout",
|
|
409
|
-
type=int,
|
|
410
|
-
default=60,
|
|
411
|
-
help="Health check timeout in seconds (default: 60)"
|
|
389
|
+
"--timeout", type=int, default=60, help="Health check timeout in seconds (default: 60)"
|
|
412
390
|
)
|
|
413
391
|
@click.pass_context
|
|
414
392
|
def restart(ctx, container_name, timeout):
|
|
@@ -458,7 +436,7 @@ def restart(ctx, container_name, timeout):
|
|
|
458
436
|
"--format",
|
|
459
437
|
type=click.Choice(["text", "json"]),
|
|
460
438
|
default="text",
|
|
461
|
-
help="Output format (default: text)"
|
|
439
|
+
help="Output format (default: text)",
|
|
462
440
|
)
|
|
463
441
|
@click.pass_context
|
|
464
442
|
def status(ctx, container_name, format):
|
|
@@ -508,22 +486,9 @@ def status(ctx, container_name, format):
|
|
|
508
486
|
|
|
509
487
|
@container_group.command(name="logs")
|
|
510
488
|
@click.argument("container_name", required=False, default="iris_db")
|
|
511
|
-
@click.option(
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
help="Stream logs continuously (CTRL+C to exit)"
|
|
515
|
-
)
|
|
516
|
-
@click.option(
|
|
517
|
-
"--tail",
|
|
518
|
-
type=int,
|
|
519
|
-
default=100,
|
|
520
|
-
help="Number of lines to show (default: 100)"
|
|
521
|
-
)
|
|
522
|
-
@click.option(
|
|
523
|
-
"--since",
|
|
524
|
-
type=str,
|
|
525
|
-
help="Show logs since timestamp (ISO 8601 format)"
|
|
526
|
-
)
|
|
489
|
+
@click.option("--follow", "-f", is_flag=True, help="Stream logs continuously (CTRL+C to exit)")
|
|
490
|
+
@click.option("--tail", type=int, default=100, help="Number of lines to show (default: 100)")
|
|
491
|
+
@click.option("--since", type=str, help="Show logs since timestamp (ISO 8601 format)")
|
|
527
492
|
@click.pass_context
|
|
528
493
|
def logs(ctx, container_name, follow, tail, since):
|
|
529
494
|
"""
|
|
@@ -586,16 +551,8 @@ def logs(ctx, container_name, follow, tail, since):
|
|
|
586
551
|
|
|
587
552
|
@container_group.command(name="remove")
|
|
588
553
|
@click.argument("container_name", required=False, default="iris_db")
|
|
589
|
-
@click.option(
|
|
590
|
-
|
|
591
|
-
is_flag=True,
|
|
592
|
-
help="Force remove running container"
|
|
593
|
-
)
|
|
594
|
-
@click.option(
|
|
595
|
-
"--volumes", "-v",
|
|
596
|
-
is_flag=True,
|
|
597
|
-
help="Remove associated volumes (data loss!)"
|
|
598
|
-
)
|
|
554
|
+
@click.option("--force", "-f", is_flag=True, help="Force remove running container")
|
|
555
|
+
@click.option("--volumes", "-v", is_flag=True, help="Remove associated volumes (data loss!)")
|
|
599
556
|
@click.pass_context
|
|
600
557
|
def remove(ctx, container_name, force, volumes):
|
|
601
558
|
"""
|
|
@@ -631,9 +588,7 @@ def remove(ctx, container_name, force, volumes):
|
|
|
631
588
|
# Check if running without --force
|
|
632
589
|
container.reload()
|
|
633
590
|
if container.status == "running" and not force:
|
|
634
|
-
raise ValueError(
|
|
635
|
-
"Container is running. Stop it first or use --force to force removal."
|
|
636
|
-
)
|
|
591
|
+
raise ValueError("Container is running. Stop it first or use --force to force removal.")
|
|
637
592
|
|
|
638
593
|
# Remove container
|
|
639
594
|
click.echo(f"⚡ Removing container '{container_name}'...")
|
|
@@ -659,21 +614,10 @@ def remove(ctx, container_name, force, volumes):
|
|
|
659
614
|
|
|
660
615
|
@container_group.command(name="reset-password")
|
|
661
616
|
@click.argument("container_name")
|
|
617
|
+
@click.option("--user", default="_SYSTEM", help="Username to reset password for (default: _SYSTEM)")
|
|
618
|
+
@click.option("--password", default="SYS", help="New password (default: SYS)")
|
|
662
619
|
@click.option(
|
|
663
|
-
"--
|
|
664
|
-
default="_SYSTEM",
|
|
665
|
-
help="Username to reset password for (default: _SYSTEM)"
|
|
666
|
-
)
|
|
667
|
-
@click.option(
|
|
668
|
-
"--password",
|
|
669
|
-
default="SYS",
|
|
670
|
-
help="New password (default: SYS)"
|
|
671
|
-
)
|
|
672
|
-
@click.option(
|
|
673
|
-
"--port",
|
|
674
|
-
default=None,
|
|
675
|
-
type=int,
|
|
676
|
-
help="IRIS SuperServer port (auto-detected if not specified)"
|
|
620
|
+
"--port", default=None, type=int, help="IRIS SuperServer port (auto-detected if not specified)"
|
|
677
621
|
)
|
|
678
622
|
@click.pass_context
|
|
679
623
|
def reset_password_cmd(ctx, container_name, user, password, port):
|
|
@@ -695,8 +639,8 @@ def reset_password_cmd(ctx, container_name, user, password, port):
|
|
|
695
639
|
iris-devtester container reset-password my_iris --port 51972
|
|
696
640
|
"""
|
|
697
641
|
try:
|
|
698
|
-
from iris_devtester.utils.password_reset import reset_password
|
|
699
642
|
from iris_devtester.utils.container_port import get_container_port
|
|
643
|
+
from iris_devtester.utils.password import reset_password
|
|
700
644
|
|
|
701
645
|
# Auto-detect port if not specified (for random port containers like testcontainers)
|
|
702
646
|
if port is None:
|
|
@@ -707,14 +651,13 @@ def reset_password_cmd(ctx, container_name, user, password, port):
|
|
|
707
651
|
else:
|
|
708
652
|
port = 1972 # Default fallback
|
|
709
653
|
|
|
710
|
-
click.echo(
|
|
654
|
+
click.echo(
|
|
655
|
+
f"⚡ Resetting password for user '{user}' in container '{container_name}' on port {port}..."
|
|
656
|
+
)
|
|
711
657
|
|
|
712
658
|
# Call password reset utility
|
|
713
659
|
success, message = reset_password(
|
|
714
|
-
container_name=container_name,
|
|
715
|
-
username=user,
|
|
716
|
-
new_password=password,
|
|
717
|
-
port=port
|
|
660
|
+
container_name=container_name, username=user, new_password=password, port=port
|
|
718
661
|
)
|
|
719
662
|
|
|
720
663
|
if success:
|
|
@@ -738,20 +681,10 @@ def reset_password_cmd(ctx, container_name, user, password, port):
|
|
|
738
681
|
@container_group.command(name="test-connection")
|
|
739
682
|
@click.argument("container_name")
|
|
740
683
|
@click.option(
|
|
741
|
-
"--namespace",
|
|
742
|
-
default="USER",
|
|
743
|
-
help="IRIS namespace to test connection to (default: USER)"
|
|
744
|
-
)
|
|
745
|
-
@click.option(
|
|
746
|
-
"--username",
|
|
747
|
-
default="_SYSTEM",
|
|
748
|
-
help="Username for connection (default: _SYSTEM)"
|
|
749
|
-
)
|
|
750
|
-
@click.option(
|
|
751
|
-
"--password",
|
|
752
|
-
default="SYS",
|
|
753
|
-
help="Password for connection (default: SYS)"
|
|
684
|
+
"--namespace", default="USER", help="IRIS namespace to test connection to (default: USER)"
|
|
754
685
|
)
|
|
686
|
+
@click.option("--username", default="_SYSTEM", help="Username for connection (default: _SYSTEM)")
|
|
687
|
+
@click.option("--password", default="SYS", help="Password for connection (default: SYS)")
|
|
755
688
|
@click.pass_context
|
|
756
689
|
def test_connection_cmd(ctx, container_name, namespace, username, password):
|
|
757
690
|
"""
|
|
@@ -774,7 +707,9 @@ def test_connection_cmd(ctx, container_name, namespace, username, password):
|
|
|
774
707
|
from iris_devtester.config import IRISConfig
|
|
775
708
|
from iris_devtester.connections import get_connection
|
|
776
709
|
|
|
777
|
-
click.echo(
|
|
710
|
+
click.echo(
|
|
711
|
+
f"⚡ Testing connection to container '{container_name}' namespace '{namespace}'..."
|
|
712
|
+
)
|
|
778
713
|
|
|
779
714
|
# Get container to extract connection details
|
|
780
715
|
container = IRISContainerManager.get_existing(container_name)
|
|
@@ -799,7 +734,7 @@ def test_connection_cmd(ctx, container_name, namespace, username, password):
|
|
|
799
734
|
namespace=namespace,
|
|
800
735
|
username=username,
|
|
801
736
|
password=password,
|
|
802
|
-
driver="auto"
|
|
737
|
+
driver="auto",
|
|
803
738
|
)
|
|
804
739
|
|
|
805
740
|
# Try to connect
|
|
@@ -835,10 +770,7 @@ def test_connection_cmd(ctx, container_name, namespace, username, password):
|
|
|
835
770
|
@container_group.command(name="enable-callin")
|
|
836
771
|
@click.argument("container_name")
|
|
837
772
|
@click.option(
|
|
838
|
-
"--timeout",
|
|
839
|
-
type=int,
|
|
840
|
-
default=30,
|
|
841
|
-
help="Timeout in seconds for docker commands (default: 30)"
|
|
773
|
+
"--timeout", type=int, default=30, help="Timeout in seconds for docker commands (default: 30)"
|
|
842
774
|
)
|
|
843
775
|
@click.pass_context
|
|
844
776
|
def enable_callin(ctx, container_name, timeout):
|
|
@@ -861,10 +793,7 @@ def enable_callin(ctx, container_name, timeout):
|
|
|
861
793
|
click.echo(f"⚡ Enabling CallIn service in container '{container_name}'...")
|
|
862
794
|
|
|
863
795
|
# Call enable callin utility
|
|
864
|
-
success, message = enable_callin_service(
|
|
865
|
-
container_name=container_name,
|
|
866
|
-
timeout=timeout
|
|
867
|
-
)
|
|
796
|
+
success, message = enable_callin_service(container_name=container_name, timeout=timeout)
|
|
868
797
|
|
|
869
798
|
if success:
|
|
870
799
|
click.echo(f"✓ CallIn service enabled in container '{container_name}'")
|
|
@@ -12,11 +12,11 @@ Pattern: Follows fixture_commands.py Click structure.
|
|
|
12
12
|
|
|
13
13
|
import click
|
|
14
14
|
|
|
15
|
-
from iris_devtester.utils.
|
|
15
|
+
from iris_devtester.utils.container_port import get_container_port
|
|
16
|
+
from iris_devtester.utils.container_status import get_container_status
|
|
16
17
|
from iris_devtester.utils.enable_callin import enable_callin_service
|
|
18
|
+
from iris_devtester.utils.password import reset_password
|
|
17
19
|
from iris_devtester.utils.test_connection import test_connection
|
|
18
|
-
from iris_devtester.utils.container_status import get_container_status
|
|
19
|
-
from iris_devtester.utils.container_port import get_container_port
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
@click.group()
|
|
@@ -36,7 +36,9 @@ def container():
|
|
|
36
36
|
@click.argument("container_name")
|
|
37
37
|
@click.option("--user", default="_SYSTEM", help="Username to reset (default: _SYSTEM)")
|
|
38
38
|
@click.option("--password", default="SYS", help="New password (default: SYS)")
|
|
39
|
-
@click.option(
|
|
39
|
+
@click.option(
|
|
40
|
+
"--port", default=None, type=int, help="IRIS SuperServer port (auto-detected if not specified)"
|
|
41
|
+
)
|
|
40
42
|
def reset_password_command(container_name: str, user: str, password: str, port: int):
|
|
41
43
|
"""
|
|
42
44
|
Reset password for IRIS user.
|