|
| 1 | +import yaml |
| 2 | +from kubetester import create_or_update_secret, run_periodically, try_load |
| 3 | +from kubetester.certs import ( |
| 4 | + create_agent_tls_certs, |
| 5 | + create_tls_certs, |
| 6 | + create_x509_mongodb_tls_certs, |
| 7 | +) |
| 8 | +from kubetester.kubetester import KubernetesTester |
| 9 | +from kubetester.kubetester import fixture as yaml_fixture |
| 10 | +from kubetester.mongodb import MongoDB |
| 11 | +from kubetester.mongodb_search import MongoDBSearch |
| 12 | +from kubetester.mongodb_user import MongoDBUser |
| 13 | +from kubetester.omtester import skip_if_cloud_manager |
| 14 | +from kubetester.phase import Phase |
| 15 | +from pytest import fixture, mark |
| 16 | +from tests import test_logger |
| 17 | +from tests.common.search import movies_search_helper |
| 18 | +from tests.common.search.search_tester import SearchTester |
| 19 | +from tests.conftest import get_default_operator, get_issuer_ca_filepath |
| 20 | +from tests.search.om_deployment import get_ops_manager |
| 21 | + |
| 22 | +logger = test_logger.get_test_logger(__name__) |
| 23 | + |
| 24 | +ADMIN_USER_NAME = "mdb-admin-user" |
| 25 | +ADMIN_USER_PASSWORD = f"{ADMIN_USER_NAME}-password" |
| 26 | + |
| 27 | +MONGOT_USER_NAME = "search-sync-source" |
| 28 | +MONGOT_USER_PASSWORD = f"{MONGOT_USER_NAME}-password" |
| 29 | + |
| 30 | +USER_NAME = "mdb-user" |
| 31 | +USER_PASSWORD = f"{USER_NAME}-password" |
| 32 | + |
| 33 | +MDB_RESOURCE_NAME = "mdb-ent-tls" |
| 34 | + |
| 35 | +# MongoDBSearch TLS configuration |
| 36 | +MDBS_TLS_SECRET_NAME = "mdbs-tls-secret" |
| 37 | + |
| 38 | + |
| 39 | +@fixture(scope="function") |
| 40 | +def mdb(namespace: str, issuer_ca_configmap: str) -> MongoDB: |
| 41 | + resource = MongoDB.from_yaml( |
| 42 | + yaml_fixture("enterprise-replicaset-sample-mflix.yaml"), |
| 43 | + name=MDB_RESOURCE_NAME, |
| 44 | + namespace=namespace, |
| 45 | + ) |
| 46 | + |
| 47 | + if try_load(resource): |
| 48 | + return resource |
| 49 | + |
| 50 | + resource.configure(om=get_ops_manager(namespace), project_name=MDB_RESOURCE_NAME) |
| 51 | + resource.configure_custom_tls(issuer_ca_configmap, "certs") |
| 52 | + resource["spec"]["security"]["authentication"] = { |
| 53 | + "enabled": True, |
| 54 | + "modes": ["X509", "SCRAM"], |
| 55 | + "agents": {"mode": "X509"}, |
| 56 | + "internalCluster": "X509", |
| 57 | + } |
| 58 | + |
| 59 | + return resource |
| 60 | + |
| 61 | + |
| 62 | +@fixture(scope="function") |
| 63 | +def mdbs(namespace: str) -> MongoDBSearch: |
| 64 | + resource = MongoDBSearch.from_yaml(yaml_fixture("search-minimal.yaml"), namespace=namespace, name=MDB_RESOURCE_NAME) |
| 65 | + |
| 66 | + if try_load(resource): |
| 67 | + return resource |
| 68 | + |
| 69 | + # Add TLS configuration to MongoDBSearch |
| 70 | + if "spec" not in resource: |
| 71 | + resource["spec"] = {} |
| 72 | + |
| 73 | + resource["spec"]["security"] = {"tls": {"certificateKeySecretRef": {"name": MDBS_TLS_SECRET_NAME}}} |
| 74 | + |
| 75 | + return resource |
| 76 | + |
| 77 | + |
| 78 | +@fixture(scope="function") |
| 79 | +def admin_user(namespace: str) -> MongoDBUser: |
| 80 | + resource = MongoDBUser.from_yaml( |
| 81 | + yaml_fixture("mongodbuser-mdb-admin.yaml"), namespace=namespace, name=ADMIN_USER_NAME |
| 82 | + ) |
| 83 | + |
| 84 | + if try_load(resource): |
| 85 | + return resource |
| 86 | + |
| 87 | + resource["spec"]["mongodbResourceRef"]["name"] = MDB_RESOURCE_NAME |
| 88 | + resource["spec"]["username"] = resource.name |
| 89 | + resource["spec"]["passwordSecretKeyRef"]["name"] = f"{resource.name}-password" |
| 90 | + |
| 91 | + return resource |
| 92 | + |
| 93 | + |
| 94 | +@fixture(scope="function") |
| 95 | +def user(namespace: str) -> MongoDBUser: |
| 96 | + resource = MongoDBUser.from_yaml(yaml_fixture("mongodbuser-mdb-user.yaml"), namespace=namespace, name=USER_NAME) |
| 97 | + |
| 98 | + if try_load(resource): |
| 99 | + return resource |
| 100 | + |
| 101 | + resource["spec"]["mongodbResourceRef"]["name"] = MDB_RESOURCE_NAME |
| 102 | + resource["spec"]["username"] = resource.name |
| 103 | + resource["spec"]["passwordSecretKeyRef"]["name"] = f"{resource.name}-password" |
| 104 | + |
| 105 | + return resource |
| 106 | + |
| 107 | + |
| 108 | +@fixture(scope="function") |
| 109 | +def mongot_user(namespace: str, mdbs: MongoDBSearch) -> MongoDBUser: |
| 110 | + resource = MongoDBUser.from_yaml( |
| 111 | + yaml_fixture("mongodbuser-search-sync-source-user.yaml"), |
| 112 | + namespace=namespace, |
| 113 | + name=f"{mdbs.name}-{MONGOT_USER_NAME}", |
| 114 | + ) |
| 115 | + |
| 116 | + if try_load(resource): |
| 117 | + return resource |
| 118 | + |
| 119 | + resource["spec"]["mongodbResourceRef"]["name"] = MDB_RESOURCE_NAME |
| 120 | + resource["spec"]["username"] = MONGOT_USER_NAME |
| 121 | + resource["spec"]["passwordSecretKeyRef"]["name"] = f"{resource.name}-password" |
| 122 | + |
| 123 | + return resource |
| 124 | + |
| 125 | + |
| 126 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 127 | +def test_install_operator(namespace: str, operator_installation_config: dict[str, str]): |
| 128 | + operator = get_default_operator(namespace, operator_installation_config=operator_installation_config) |
| 129 | + operator.assert_is_running() |
| 130 | + |
| 131 | + |
| 132 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 133 | +@skip_if_cloud_manager |
| 134 | +def test_create_ops_manager(namespace: str): |
| 135 | + ops_manager = get_ops_manager(namespace) |
| 136 | + ops_manager.update() |
| 137 | + ops_manager.om_status().assert_reaches_phase(Phase.Running, timeout=1200) |
| 138 | + ops_manager.appdb_status().assert_reaches_phase(Phase.Running, timeout=600) |
| 139 | + |
| 140 | + |
| 141 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 142 | +def test_install_tls_secrets_and_configmaps(namespace: str, mdb: MongoDB, mdbs: MongoDBSearch, issuer: str): |
| 143 | + create_agent_tls_certs(issuer, namespace, mdb.name, "certs") |
| 144 | + create_x509_mongodb_tls_certs(issuer, namespace, mdb.name, f"certs-{mdb.name}-clusterfile") |
| 145 | + create_x509_mongodb_tls_certs(issuer, namespace, mdb.name, f"certs-{mdb.name}-cert", mdb.get_members()) |
| 146 | + |
| 147 | + search_service_name = f"{mdbs.name}-search-svc" |
| 148 | + create_tls_certs( |
| 149 | + issuer, |
| 150 | + namespace, |
| 151 | + f"{mdbs.name}-search", |
| 152 | + replicas=1, |
| 153 | + service_name=search_service_name, |
| 154 | + additional_domains=[f"{search_service_name}.{namespace}.svc.cluster.local"], |
| 155 | + secret_name=MDBS_TLS_SECRET_NAME, |
| 156 | + ) |
| 157 | + |
| 158 | + |
| 159 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 160 | +def test_create_database_resource(mdb: MongoDB): |
| 161 | + mdb.update() |
| 162 | + mdb.assert_reaches_phase(Phase.Running, timeout=300) |
| 163 | + |
| 164 | + |
| 165 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 166 | +def test_create_users( |
| 167 | + namespace: str, admin_user: MongoDBUser, user: MongoDBUser, mongot_user: MongoDBUser, mdb: MongoDB |
| 168 | +): |
| 169 | + create_or_update_secret( |
| 170 | + namespace, name=admin_user["spec"]["passwordSecretKeyRef"]["name"], data={"password": ADMIN_USER_PASSWORD} |
| 171 | + ) |
| 172 | + admin_user.update() |
| 173 | + admin_user.assert_reaches_phase(Phase.Updated, timeout=300) |
| 174 | + |
| 175 | + create_or_update_secret( |
| 176 | + namespace, name=user["spec"]["passwordSecretKeyRef"]["name"], data={"password": USER_PASSWORD} |
| 177 | + ) |
| 178 | + user.update() |
| 179 | + user.assert_reaches_phase(Phase.Updated, timeout=300) |
| 180 | + |
| 181 | + create_or_update_secret( |
| 182 | + namespace, name=mongot_user["spec"]["passwordSecretKeyRef"]["name"], data={"password": MONGOT_USER_PASSWORD} |
| 183 | + ) |
| 184 | + mongot_user.update() |
| 185 | + mongot_user.assert_reaches_phase(Phase.Updated, timeout=300) |
| 186 | + |
| 187 | + |
| 188 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 189 | +def test_create_search_resource(mdbs: MongoDBSearch): |
| 190 | + mdbs.update() |
| 191 | + mdbs.assert_reaches_phase(Phase.Running, timeout=300) |
| 192 | + |
| 193 | + |
| 194 | +# After picking up MongoDBSearch CR, MongoDB reconciler will add mongod parameters to each process. |
| 195 | +# Due to how MongoDB reconciler works (blocking on waiting for agents and not changing the status to pending) |
| 196 | +# the phase won't be updated to Pending and we need to wait by checking agents' status directly in OM. |
| 197 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 198 | +def test_wait_for_agents_ready(mdb: MongoDB): |
| 199 | + mdb.get_om_tester().wait_agents_ready() |
| 200 | + mdb.assert_reaches_phase(Phase.Running, timeout=300) |
| 201 | + |
| 202 | + |
| 203 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 204 | +def test_wait_for_mongod_parameters(mdb: MongoDB): |
| 205 | + # After search CR is deployed, MongoDB controller will pick it up |
| 206 | + # and start adding search-related parameters to the automation config. |
| 207 | + def check_mongod_parameters(): |
| 208 | + parameters_are_set = True |
| 209 | + pod_parameters = [] |
| 210 | + for idx in range(mdb.get_members()): |
| 211 | + mongod_config = yaml.safe_load( |
| 212 | + KubernetesTester.run_command_in_pod_container( |
| 213 | + f"{mdb.name}-{idx}", mdb.namespace, ["cat", "/data/automation-mongod.conf"] |
| 214 | + ) |
| 215 | + ) |
| 216 | + set_parameter = mongod_config.get("setParameter", {}) |
| 217 | + parameters_are_set = parameters_are_set and ( |
| 218 | + "mongotHost" in set_parameter and "searchIndexManagementHostAndPort" in set_parameter |
| 219 | + ) |
| 220 | + pod_parameters.append(f"pod {idx} setParameter: {set_parameter}") |
| 221 | + |
| 222 | + return parameters_are_set, f'Not all pods have mongot parameters set:\n{"\n".join(pod_parameters)}' |
| 223 | + |
| 224 | + run_periodically(check_mongod_parameters, timeout=600) |
| 225 | + |
| 226 | + |
| 227 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 228 | +def test_search_restore_sample_database(mdb: MongoDB): |
| 229 | + get_admin_sample_movies_helper(mdb).restore_sample_database() |
| 230 | + |
| 231 | + |
| 232 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 233 | +def test_search_create_search_index(mdb: MongoDB): |
| 234 | + get_user_sample_movies_helper(mdb).create_search_index() |
| 235 | + |
| 236 | + |
| 237 | +@mark.e2e_search_enterprise_x509_cluster_auth |
| 238 | +def test_search_assert_search_query(mdb: MongoDB): |
| 239 | + get_user_sample_movies_helper(mdb).assert_search_query(retry_timeout=60) |
| 240 | + |
| 241 | + |
| 242 | +def get_connection_string(mdb: MongoDB, user_name: str, user_password: str) -> str: |
| 243 | + return f"mongodb://{user_name}:{user_password}@{mdb.name}-0.{mdb.name}-svc.{mdb.namespace}.svc.cluster.local:27017/?replicaSet={mdb.name}" |
| 244 | + |
| 245 | + |
| 246 | +def get_admin_sample_movies_helper(mdb): |
| 247 | + return movies_search_helper.SampleMoviesSearchHelper( |
| 248 | + SearchTester( |
| 249 | + get_connection_string(mdb, ADMIN_USER_NAME, ADMIN_USER_PASSWORD), |
| 250 | + use_ssl=True, |
| 251 | + ca_path=get_issuer_ca_filepath(), |
| 252 | + ) |
| 253 | + ) |
| 254 | + |
| 255 | + |
| 256 | +def get_user_sample_movies_helper(mdb): |
| 257 | + return movies_search_helper.SampleMoviesSearchHelper( |
| 258 | + SearchTester( |
| 259 | + get_connection_string(mdb, USER_NAME, USER_PASSWORD), use_ssl=True, ca_path=get_issuer_ca_filepath() |
| 260 | + ) |
| 261 | + ) |
0 commit comments