|
7 | 7 | from ocp_resources.deployment import Deployment |
8 | 8 | from ocp_resources.namespace import Namespace |
9 | 9 | from ocp_resources.service import Service |
| 10 | +from ocp_resources.secret import Secret |
10 | 11 |
|
11 | 12 |
|
12 | 13 | MILVUS_IMAGE = os.getenv( |
|
30 | 31 | PGVECTOR_USER = os.getenv("LLS_VECTOR_IO_PGVECTOR_USER", "vector_user") |
31 | 32 | PGVECTOR_PASSWORD = os.getenv("LLS_VECTOR_IO_PGVECTOR_PASSWORD", "yourpassword") |
32 | 33 |
|
| 34 | +QDRANT_IMAGE = os.getenv( |
| 35 | + "LLS_VECTOR_IO_QDRANT_IMAGE", |
| 36 | + ( |
| 37 | + "docker.io/qdrant/qdrant@sha256:" |
| 38 | + "26509b92c44ded1ad344e18a005383c20bb3fbf9dbf4d337265a230b2aa89e79" # pragma: allowlist secret" |
| 39 | + ), |
| 40 | +) |
| 41 | + |
33 | 42 |
|
34 | 43 | @pytest.fixture(scope="class") |
35 | 44 | def vector_io_provider_deployment_config_factory( |
@@ -66,6 +75,10 @@ def vector_io_provider_deployment_config_factory( |
66 | 75 | * PGVECTOR_USER: Database user |
67 | 76 | * PGVECTOR_PASSWORD: Database password |
68 | 77 | * PGVECTOR_DB: Database name |
| 78 | + - "qdrant-remote": |
| 79 | + * ENABLE_QDRANT: enable qdrant provider |
| 80 | + * QDRANT_API_KEY: Qdrant API key |
| 81 | + * QDRANT_URL: Qdrant service URL with protocol (e.g., "http://vector-io-qdrant-service:6333") |
69 | 82 |
|
70 | 83 | Example: |
71 | 84 | def test_with_milvus(vector_io_provider_deployment_config_factory): |
@@ -98,6 +111,14 @@ def _factory(provider_name: str) -> list[Dict[str, str]]: |
98 | 111 | env_vars.append({"name": "PGVECTOR_USER", "value": PGVECTOR_USER}) |
99 | 112 | env_vars.append({"name": "PGVECTOR_PASSWORD", "value": PGVECTOR_PASSWORD}) |
100 | 113 | env_vars.append({"name": "PGVECTOR_DB", "value": "pgvector"}) |
| 114 | + elif provider_name == "qdrant-remote": |
| 115 | + request.getfixturevalue(argname="qdrant_service") |
| 116 | + env_vars.append({"name": "ENABLE_QDRANT", "value": "true"}) |
| 117 | + env_vars.append({"name": "QDRANT_URL", "value": "http://vector-io-qdrant-service:6333"}) |
| 118 | + env_vars.append({ |
| 119 | + "name": "QDRANT_API_KEY", |
| 120 | + "valueFrom": {"secretKeyRef": {"name": "qdrant-secret", "key": "api-key"}}, |
| 121 | + }) |
101 | 122 |
|
102 | 123 | return env_vars |
103 | 124 |
|
@@ -350,3 +371,116 @@ def get_pgvector_deployment_template() -> Dict[str, Any]: |
350 | 371 | "volumes": [{"name": "pgdata", "emptyDir": {}}], |
351 | 372 | }, |
352 | 373 | } |
| 374 | + |
| 375 | + |
| 376 | +@pytest.fixture(scope="class") |
| 377 | +def qdrant_deployment( |
| 378 | + unprivileged_client: DynamicClient, |
| 379 | + unprivileged_model_namespace: Namespace, |
| 380 | + qdrant_secret: Secret, |
| 381 | +) -> Generator[Deployment, Any, Any]: |
| 382 | + """Deploy a Qdrant instance for vector I/O provider testing.""" |
| 383 | + with Deployment( |
| 384 | + client=unprivileged_client, |
| 385 | + namespace=unprivileged_model_namespace.name, |
| 386 | + name="vector-io-qdrant-deployment", |
| 387 | + min_ready_seconds=5, |
| 388 | + replicas=1, |
| 389 | + selector={"matchLabels": {"app": "qdrant"}}, |
| 390 | + strategy={"type": "Recreate"}, |
| 391 | + template=get_qdrant_deployment_template(), |
| 392 | + teardown=True, |
| 393 | + ) as deployment: |
| 394 | + deployment.wait_for_replicas(deployed=True, timeout=240) |
| 395 | + yield deployment |
| 396 | + |
| 397 | + |
| 398 | +@pytest.fixture(scope="class") |
| 399 | +def qdrant_service( |
| 400 | + unprivileged_client: DynamicClient, |
| 401 | + unprivileged_model_namespace: Namespace, |
| 402 | + qdrant_deployment: Deployment, |
| 403 | +) -> Generator[Service, Any, Any]: |
| 404 | + """Create a service for the Qdrant deployment.""" |
| 405 | + with Service( |
| 406 | + client=unprivileged_client, |
| 407 | + namespace=unprivileged_model_namespace.name, |
| 408 | + name="vector-io-qdrant-service", |
| 409 | + ports=[ |
| 410 | + { |
| 411 | + "name": "http", |
| 412 | + "port": 6333, |
| 413 | + "targetPort": 6333, |
| 414 | + }, |
| 415 | + { |
| 416 | + "name": "grpc", |
| 417 | + "port": 6334, |
| 418 | + "targetPort": 6334, |
| 419 | + }, |
| 420 | + ], |
| 421 | + selector={"app": "qdrant"}, |
| 422 | + wait_for_resource=True, |
| 423 | + ) as service: |
| 424 | + yield service |
| 425 | + |
| 426 | + |
| 427 | +@pytest.fixture(scope="class") |
| 428 | +def qdrant_secret( |
| 429 | + unprivileged_client: DynamicClient, |
| 430 | + unprivileged_model_namespace: Namespace, |
| 431 | +) -> Generator[Secret, Any, Any]: |
| 432 | + """Return a Kubernetes Secret for Qdrant""" |
| 433 | + with Secret( |
| 434 | + client=unprivileged_client, |
| 435 | + namespace=unprivileged_model_namespace.name, |
| 436 | + name="qdrant-secret", |
| 437 | + type="Opaque", |
| 438 | + string_data={"api-key": "yourapikey"}, |
| 439 | + ) as secret: |
| 440 | + yield secret |
| 441 | + |
| 442 | + |
| 443 | +def get_qdrant_deployment_template() -> Dict[str, Any]: |
| 444 | + """Return a Kubernetes deployment for Qdrant""" |
| 445 | + return { |
| 446 | + "metadata": {"labels": {"app": "qdrant"}}, |
| 447 | + "spec": { |
| 448 | + "securityContext": {"runAsNonRoot": True, "seccompProfile": {"type": "RuntimeDefault"}}, |
| 449 | + "containers": [ |
| 450 | + { |
| 451 | + "name": "qdrant", |
| 452 | + "image": QDRANT_IMAGE, |
| 453 | + "ports": [ |
| 454 | + { |
| 455 | + "containerPort": 6333, |
| 456 | + "name": "http", |
| 457 | + }, |
| 458 | + { |
| 459 | + "containerPort": 6334, |
| 460 | + "name": "grpc", |
| 461 | + }, |
| 462 | + ], |
| 463 | + "env": [ |
| 464 | + { |
| 465 | + "name": "QDRANT__SERVICE__API_KEY", |
| 466 | + "valueFrom": { |
| 467 | + "secretKeyRef": { |
| 468 | + "name": "qdrant-secret", |
| 469 | + "key": "api-key", |
| 470 | + }, |
| 471 | + }, |
| 472 | + }, |
| 473 | + ], |
| 474 | + "volumeMounts": [ |
| 475 | + {"name": "qdrant-storage", "mountPath": "/qdrant/storage"}, |
| 476 | + { |
| 477 | + "name": "qdrant-storage", |
| 478 | + "mountPath": "/qdrant/snapshots", |
| 479 | + "subPath": "snapshots", |
| 480 | + }, |
| 481 | + ], |
| 482 | + }, |
| 483 | + ], |
| 484 | + "volumes": [{"name": "qdrant-storage", "emptyDir": {}}], |
| 485 | + }, |
| 486 | + } |
0 commit comments