1- import os
2- import tempfile
1+ from typing import Optional , Self
32
43import kubetester
5- import requests
6- from kubetester .helm import process_run_and_check
74from kubetester .mongotester import MongoTester
85from pymongo .operations import SearchIndexModel
96from tests import test_logger
7+ from tests .common .mongodb_tools_pod .mongodb_tools_pod import ToolsPod
108
119logger = test_logger .get_test_logger (__name__ )
1210
@@ -16,23 +14,100 @@ def __init__(
1614 self ,
1715 connection_string : str ,
1816 use_ssl : bool = False ,
19- ca_path : str | None = None ,
17+ ca_path : Optional [ str ] = None ,
2018 ):
2119 super ().__init__ (connection_string , use_ssl , ca_path )
2220
23- def mongorestore_from_url (self , archive_url : str , ns_include : str , mongodb_tools_dir : str = "" ):
24- logger .debug (f"running mongorestore from { archive_url } " )
25- with tempfile .NamedTemporaryFile (delete = False ) as sample_file :
26- resp = requests .get (archive_url )
27- size = sample_file .write (resp .content )
28- logger .debug (f"Downloaded sample file from { archive_url } to { sample_file .name } (size: { size } )" )
29- mongorestore_path = os .path .join (mongodb_tools_dir , "mongorestore" )
30- mongorestore_cmd = f"{ mongorestore_path } --archive={ sample_file .name } --verbose=1 --drop --nsInclude { ns_include } --uri={ self .cnx_string } "
31- if self .default_opts .get ("tls" , False ):
32- mongorestore_cmd += " --ssl"
33- if ca_path := self .default_opts .get ("tlsCAFile" ):
34- mongorestore_cmd += " --sslCAFile=" + ca_path
35- process_run_and_check (mongorestore_cmd .split (), capture_output = True )
21+ @classmethod
22+ def for_replicaset (
23+ cls ,
24+ mdb ,
25+ user_name : str ,
26+ password : str ,
27+ use_ssl : bool = False ,
28+ ca_path : Optional [str ] = None ,
29+ ) -> Self :
30+ """Create SearchTester for a replica set MongoDB resource.
31+
32+ Args:
33+ mdb: MongoDB or MongoDBCommunity resource with name and namespace attributes
34+ user_name: Username for authentication
35+ password: Password for authentication
36+ use_ssl: Whether to use TLS/SSL connection
37+ ca_path: Path to CA certificate file (required if use_ssl=True)
38+
39+ Returns:
40+ SearchTester instance configured for the replica set
41+ """
42+ conn_str = (
43+ f"mongodb://{ user_name } :{ password } @"
44+ f"{ mdb .name } -0.{ mdb .name } -svc.{ mdb .namespace } .svc.cluster.local:27017/"
45+ f"?replicaSet={ mdb .name } "
46+ )
47+ return cls (conn_str , use_ssl = use_ssl , ca_path = ca_path )
48+
49+ @classmethod
50+ def for_sharded (
51+ cls ,
52+ mdb ,
53+ user_name : str ,
54+ password : str ,
55+ use_ssl : bool = False ,
56+ ca_path : Optional [str ] = None ,
57+ ) -> Self :
58+ """Create SearchTester for a sharded MongoDB resource (connects to mongos).
59+
60+ Args:
61+ mdb: MongoDB resource with name and namespace attributes (sharded cluster)
62+ user_name: Username for authentication
63+ password: Password for authentication
64+ use_ssl: Whether to use TLS/SSL connection
65+ ca_path: Path to CA certificate file (required if use_ssl=True)
66+
67+ Returns:
68+ SearchTester instance configured for the sharded cluster via mongos
69+ """
70+ conn_str = (
71+ f"mongodb://{ user_name } :{ password } @"
72+ f"{ mdb .name } -mongos-0.{ mdb .name } -svc.{ mdb .namespace } .svc.cluster.local:27017/"
73+ f"?authSource=admin"
74+ )
75+ return cls (conn_str , use_ssl = use_ssl , ca_path = ca_path )
76+
77+ def mongorestore_from_url (self , archive_url : str , ns_include : str , tools_pod : ToolsPod ):
78+ """Run mongorestore from a URL using the tools pod.
79+
80+ Args:
81+ archive_url: URL to download the archive from
82+ ns_include: Namespace include pattern for mongorestore
83+ tools_pod: ToolsPod instance to run the command in
84+ """
85+ logger .debug (f"running mongorestore from { archive_url } via tools pod" )
86+ archive_path = "/tmp/sample.archive"
87+
88+ # Download the archive directly in the pod using curl
89+ tools_pod .run_command (["curl" , "-o" , archive_path , "-L" , archive_url ])
90+
91+ # Build mongorestore command
92+ mongorestore_cmd = [
93+ "mongorestore" ,
94+ f"--archive={ archive_path } " ,
95+ "--verbose=1" ,
96+ "--drop" ,
97+ "--nsInclude" ,
98+ ns_include ,
99+ f"--uri={ self .cnx_string } " ,
100+ ]
101+
102+ if self .default_opts .get ("tls" , False ):
103+ mongorestore_cmd .append ("--ssl" )
104+ if ca_path := self .default_opts .get ("tlsCAFile" ):
105+ # Copy CA cert to pod and use it
106+ pod_ca_path = "/tmp/ca.crt"
107+ tools_pod .copy_file_to_pod (ca_path , pod_ca_path )
108+ mongorestore_cmd .append (f"--sslCAFile={ pod_ca_path } " )
109+
110+ tools_pod .run_command (mongorestore_cmd )
36111
37112 def create_search_index (self , database_name : str , collection_name : str ):
38113 database = self .client [database_name ]
@@ -87,9 +162,19 @@ def search_indexes_ready(self, database_name: str, collection_name: str):
87162 return False
88163
89164 for idx in search_indexes :
90- if idx .get ("status" ) != "READY" :
91- logger .debug (f"{ database_name } /{ collection_name } : search index { idx } is not ready" )
92- return False
165+ status = idx .get ("status" )
166+ queryable = idx .get ("queryable" )
167+ if status == "READY" or queryable is True :
168+ continue
169+ if status is None and queryable is None and idx .get ("latestDefinition" ) is not None :
170+ logger .debug (
171+ f"{ database_name } /{ collection_name } : search index { idx .get ('name' )} has no status but has latestDefinition, considering ready"
172+ )
173+ continue
174+ logger .debug (
175+ f"{ database_name } /{ collection_name } : search index { idx } is not ready (status={ status } , queryable={ queryable } )"
176+ )
177+ return False
93178 return True
94179
95180 def get_search_indexes (self , database_name , collection_name ):
0 commit comments