Skip to content

Commit 0aec546

Browse files
committed
E2E testing
1 parent 32db1b2 commit 0aec546

File tree

12 files changed

+569
-160
lines changed

12 files changed

+569
-160
lines changed

.evergreen-tasks.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ tasks:
254254
commands:
255255
- func: "e2e_test"
256256

257+
- name: e2e_mongodb_custom_roles
258+
tags: [ "patch-run" ]
259+
commands:
260+
- func: "e2e_test"
261+
257262
- name: e2e_replica_set_recovery
258263
tags: [ "patch-run" ]
259264
commands:
@@ -644,7 +649,7 @@ tasks:
644649
commands:
645650
- func: "e2e_test"
646651

647-
- name: e2e_replica_set_custom_roles
652+
- name: e2e_replica_set_ldap_custom_roles
648653
tags: [ "patch-run" ]
649654
commands:
650655
- func: "e2e_test"

.evergreen.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ task_groups:
728728
- e2e_replica_set_ldap_user_to_dn_mapping
729729
# e2e_replica_set_ldap_agent_auth
730730
- e2e_replica_set_ldap_agent_client_certs
731-
- e2e_replica_set_custom_roles
731+
- e2e_replica_set_ldap_custom_roles
732732
- e2e_replica_set_update_roles_no_privileges
733733
- e2e_replica_set_ldap_group_dn
734734
- e2e_replica_set_ldap_group_dn_with_x509_agent
@@ -905,6 +905,7 @@ task_groups:
905905
- e2e_tls_x509_configure_all_options_sc
906906
- e2e_tls_x509_sc
907907
- e2e_meko_mck_upgrade
908+
- e2e_mongodb_custom_roles
908909

909910
<<: *teardown_group
910911

docker/mongodb-kubernetes-tests/kubeobject/customobject.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def _reload_if_needed(self):
145145
self.reload()
146146

147147
@classmethod
148-
def from_yaml(cls, yaml_file, name=None, namespace=None):
148+
def from_yaml(cls, yaml_file, name=None, namespace=None, cluster_scoped=False):
149149
"""Creates a `CustomObject` from a yaml file. In this case, `name` and
150150
`namespace` are optional in this function's signature, because they
151151
might be passed as part of the `yaml_file` document.
@@ -161,22 +161,23 @@ def from_yaml(cls, yaml_file, name=None, namespace=None):
161161
"or exist in the `metadata` section of the yaml document."
162162
)
163163

164-
if (namespace is None or namespace == "") and "namespace" not in doc["metadata"]:
165-
raise ValueError(
166-
"`namespace` needs to be passed as part of the function call "
167-
"or exist in the `metadata` section of the yaml document."
168-
)
164+
if not cluster_scoped:
165+
if (namespace is None or namespace == "") and "namespace" not in doc["metadata"]:
166+
raise ValueError(
167+
"`namespace` needs to be passed as part of the function call "
168+
"or exist in the `metadata` section of the yaml document."
169+
)
170+
171+
if namespace is None:
172+
namespace = doc["metadata"]["namespace"]
173+
else:
174+
doc["metadata"]["namespace"] = namespace
169175

170176
if name is None:
171177
name = doc["metadata"]["name"]
172178
else:
173179
doc["metadata"]["name"] = name
174180

175-
if namespace is None:
176-
namespace = doc["metadata"]["namespace"]
177-
else:
178-
doc["metadata"]["namespace"] = namespace
179-
180181
kind = doc["kind"]
181182
api_version = doc["apiVersion"]
182183
if "/" in api_version:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from typing import Optional
2+
3+
from kubeobject import CustomObject
4+
from kubetester.mongodb import MongoDBCommon, Phase, in_desired_state
5+
6+
ClusterMongoDBRoleKind = "ClusterMongoDBRole"
7+
8+
9+
class ClusterMongoDBRole(CustomObject, MongoDBCommon):
10+
def __init__(self, *args, **kwargs):
11+
with_defaults = {
12+
"plural": "clustermongodbroles",
13+
"kind": "ClusterMongoDBRole",
14+
"group": "mongodb.com",
15+
"version": "v1",
16+
}
17+
with_defaults.update(kwargs)
18+
super(ClusterMongoDBRole, self).__init__(*args, **with_defaults)
19+
20+
def get_name(self) -> str:
21+
return self["metadata"]["name"]
22+
23+
def get_role_name(self):
24+
return self["spec"]["role"]
25+
26+
def get_role(self):
27+
return self["spec"]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
apiVersion: mongodb.com/v1
2+
kind: ClusterMongoDBRole
3+
metadata:
4+
name: test-customrole
5+
spec:
6+
role: "test-customrole"
7+
db: "admin"
8+
roles:
9+
- db: "admin"
10+
role: "root"
11+
privileges:
12+
- resource:
13+
db: "admin"
14+
collection: "system.users"
15+
actions:
16+
- "find"
17+
- "update"
18+
- resource:
19+
db: "admin"
20+
collection: "system.roles"
21+
actions:
22+
- "find"
23+
- "update"
24+
authenticationRestrictions:
25+
- clientSource:
26+
- "127.0.0.0/8"
27+
serverAddress:
28+
- "10.0.0.0/8"
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
from kubetester import (
2+
create_or_update_configmap,
3+
find_fixture,
4+
random_k8s_name,
5+
read_configmap,
6+
try_load,
7+
wait_until,
8+
)
9+
from kubetester.mongodb import MongoDB, Phase
10+
from kubetester.mongodb_multi import MongoDBMulti
11+
from kubetester.mongodb_role import ClusterMongoDBRole, ClusterMongoDBRoleKind
12+
from pytest import fixture, mark
13+
from tests.multicluster.conftest import cluster_spec_list
14+
15+
16+
@fixture(scope="module")
17+
def project_name_prefix(namespace: str) -> str:
18+
return random_k8s_name(f"{namespace}-project-")
19+
20+
21+
@fixture(scope="module")
22+
def first_project(namespace: str, project_name_prefix: str) -> str:
23+
cm = read_configmap(namespace=namespace, name="my-project")
24+
project_name = f"{project_name_prefix}-first"
25+
return create_or_update_configmap(
26+
namespace=namespace,
27+
name=project_name,
28+
data={
29+
"baseUrl": cm["baseUrl"],
30+
"projectName": project_name,
31+
"orgId": cm["orgId"],
32+
},
33+
)
34+
35+
36+
@fixture(scope="module")
37+
def second_project(namespace: str, project_name_prefix: str) -> str:
38+
cm = read_configmap(namespace=namespace, name="my-project")
39+
project_name = f"{project_name_prefix}-second"
40+
return create_or_update_configmap(
41+
namespace=namespace,
42+
name=project_name,
43+
data={
44+
"baseUrl": cm["baseUrl"],
45+
"projectName": project_name,
46+
"orgId": cm["orgId"],
47+
},
48+
)
49+
50+
51+
@fixture(scope="module")
52+
def third_project(namespace: str, project_name_prefix: str) -> str:
53+
cm = read_configmap(namespace=namespace, name="my-project")
54+
project_name = f"{project_name_prefix}-third"
55+
return create_or_update_configmap(
56+
namespace=namespace,
57+
name=project_name,
58+
data={
59+
"baseUrl": cm["baseUrl"],
60+
"projectName": project_name,
61+
"orgId": cm["orgId"],
62+
},
63+
)
64+
65+
66+
@fixture(scope="module")
67+
def mongodb_role():
68+
resource = ClusterMongoDBRole.from_yaml(
69+
find_fixture("cluster-mongodb-role.yaml"), namespace="", cluster_scoped=True
70+
)
71+
72+
if try_load(resource):
73+
return resource
74+
75+
return resource.update()
76+
77+
78+
@fixture(scope="module")
79+
def replica_set(namespace: str, mongodb_role: ClusterMongoDBRole, first_project: str) -> MongoDB:
80+
resource = MongoDB.from_yaml(find_fixture("replica-set-scram.yaml"), namespace=namespace)
81+
82+
if try_load(resource):
83+
return resource
84+
85+
resource["spec"]["members"] = 1
86+
resource["spec"]["security"]["roleRefs"] = [
87+
{
88+
"name": mongodb_role.get_name(),
89+
"kind": ClusterMongoDBRoleKind,
90+
}
91+
]
92+
resource["spec"]["opsManager"]["configMapRef"]["name"] = first_project
93+
94+
return resource
95+
96+
97+
@fixture(scope="module")
98+
def sharded_cluster(namespace: str, mongodb_role: ClusterMongoDBRole, second_project: str) -> MongoDB:
99+
resource = MongoDB.from_yaml(find_fixture("sharded-cluster-scram-sha-1.yaml"), namespace=namespace)
100+
101+
if try_load(resource):
102+
return resource
103+
104+
resource["spec"]["mongodsPerShardCount"] = 1
105+
resource["spec"]["mongosCount"] = 1
106+
resource["spec"]["configServerCount"] = 1
107+
108+
resource["spec"]["security"]["roleRefs"] = [
109+
{
110+
"name": mongodb_role.get_name(),
111+
"kind": ClusterMongoDBRoleKind,
112+
}
113+
]
114+
resource["spec"]["opsManager"]["configMapRef"]["name"] = second_project
115+
116+
return resource
117+
118+
119+
@fixture(scope="module")
120+
def mc_replica_set(namespace: str, mongodb_role: ClusterMongoDBRole, third_project: str) -> MongoDBMulti:
121+
resource = MongoDBMulti.from_yaml(find_fixture("mongodb-multi.yaml"), namespace=namespace)
122+
123+
if try_load(resource):
124+
return resource
125+
126+
resource["spec"]["security"] = {
127+
"roleRefs": [
128+
{
129+
"name": mongodb_role.get_name(),
130+
"kind": ClusterMongoDBRoleKind,
131+
}
132+
]
133+
}
134+
resource["spec"]["opsManager"]["configMapRef"]["name"] = third_project
135+
resource["spec"]["clusterSpecList"] = cluster_spec_list(["kind-e2e-cluster-1"], [1])
136+
137+
return resource
138+
139+
140+
@mark.e2e_mongodb_custom_roles
141+
def test_create_resources(
142+
mongodb_role: ClusterMongoDBRole, replica_set: MongoDB, sharded_cluster: MongoDB, mc_replica_set: MongoDBMulti
143+
):
144+
replica_set.update()
145+
sharded_cluster.update()
146+
mc_replica_set.update()
147+
148+
replica_set.assert_reaches_phase(Phase.Running, timeout=400)
149+
sharded_cluster.assert_reaches_phase(Phase.Running, timeout=400)
150+
mc_replica_set.assert_reaches_phase(Phase.Running, timeout=400)
151+
152+
153+
@mark.e2e_mongodb_custom_roles
154+
def test_automation_config_has_roles(
155+
replica_set: MongoDB, sharded_cluster: MongoDB, mc_replica_set: MongoDBMulti, mongodb_role: ClusterMongoDBRole
156+
):
157+
rs_tester = replica_set.get_automation_config_tester()
158+
rs_tester.assert_has_expected_number_of_roles(expected_roles=1)
159+
rs_tester.assert_expected_role(role_index=0, expected_value=mongodb_role.get_role())
160+
161+
sc_tester = sharded_cluster.get_automation_config_tester()
162+
sc_tester.assert_has_expected_number_of_roles(expected_roles=1)
163+
sc_tester.assert_expected_role(role_index=0, expected_value=mongodb_role.get_role())
164+
165+
mcrs_tester = mc_replica_set.get_automation_config_tester()
166+
mcrs_tester.assert_has_expected_number_of_roles(expected_roles=1)
167+
mcrs_tester.assert_expected_role(role_index=0, expected_value=mongodb_role.get_role())
168+
169+
170+
@mark.e2e_mongodb_custom_roles
171+
def test_changing_role(
172+
replica_set: MongoDB, sharded_cluster: MongoDB, mc_replica_set: MongoDBMulti, mongodb_role: ClusterMongoDBRole
173+
):
174+
rs_version = replica_set.get_automation_config_tester().automation_config["version"]
175+
sc_version = sharded_cluster.get_automation_config_tester().automation_config["version"]
176+
mcrs_version = mc_replica_set.get_automation_config_tester().automation_config["version"]
177+
178+
mongodb_role["spec"]["roles"][0]["role"] = "readWrite"
179+
mongodb_role.update()
180+
181+
wait_until(lambda: replica_set.get_automation_config_tester().reached_version(rs_version + 1), timeout=120)
182+
wait_until(lambda: sharded_cluster.get_automation_config_tester().reached_version(sc_version + 1), timeout=120)
183+
wait_until(lambda: mc_replica_set.get_automation_config_tester().reached_version(mcrs_version + 1), timeout=120)
184+
185+
replica_set.get_automation_config_tester().assert_expected_role(
186+
role_index=0, expected_value=mongodb_role.get_role()
187+
)
188+
sharded_cluster.get_automation_config_tester().assert_expected_role(
189+
role_index=0, expected_value=mongodb_role.get_role()
190+
)
191+
mc_replica_set.get_automation_config_tester().assert_expected_role(
192+
role_index=0, expected_value=mongodb_role.get_role()
193+
)
194+
195+
196+
@mark.e2e_mongodb_custom_roles
197+
def test_deleting_role_does_not_remove_access(
198+
mongodb_role: ClusterMongoDBRole, replica_set: MongoDB, sharded_cluster: MongoDB, mc_replica_set: MongoDBMulti
199+
):
200+
mongodb_role.delete()
201+
202+
assert try_load(mongodb_role) == False
203+
204+
replica_set.assert_reaches_phase(
205+
phase=Phase.Failed, msg_regexp=f"ClusterMongoDBRole '{mongodb_role.get_name()}' not found"
206+
)
207+
sharded_cluster.assert_reaches_phase(
208+
phase=Phase.Failed, msg_regexp=f"ClusterMongoDBRole '{mongodb_role.get_name()}' not found"
209+
)
210+
mc_replica_set.assert_reaches_phase(
211+
phase=Phase.Failed, msg_regexp=f"ClusterMongoDBRole '{mongodb_role.get_name()}' not found"
212+
)
213+
214+
# The role should still exist in the automation config
215+
replica_set.get_automation_config_tester().assert_has_expected_number_of_roles(expected_roles=1)
216+
sharded_cluster.get_automation_config_tester().assert_has_expected_number_of_roles(expected_roles=1)
217+
mc_replica_set.get_automation_config_tester().assert_has_expected_number_of_roles(expected_roles=1)
218+
219+
220+
@mark.e2e_mongodb_custom_roles
221+
def test_removing_role_from_resources(replica_set: MongoDB, sharded_cluster: MongoDB, mc_replica_set: MongoDBMulti):
222+
sc_version = sharded_cluster.get_automation_config_tester().automation_config["version"]
223+
mcrs_version = mc_replica_set.get_automation_config_tester().automation_config["version"]
224+
225+
sharded_cluster["spec"]["security"]["roleRefs"] = None
226+
sharded_cluster.update()
227+
228+
mc_replica_set["spec"]["security"]["roleRefs"] = None
229+
mc_replica_set.update()
230+
231+
wait_until(lambda: sharded_cluster.get_automation_config_tester().reached_version(sc_version + 1), timeout=120)
232+
wait_until(lambda: mc_replica_set.get_automation_config_tester().reached_version(mcrs_version + 1), timeout=120)
233+
234+
sharded_cluster.get_automation_config_tester().assert_has_expected_number_of_roles(expected_roles=0)
235+
mc_replica_set.get_automation_config_tester().assert_has_expected_number_of_roles(expected_roles=0)
236+
237+
238+
@mark.e2e_mongodb_custom_roles
239+
def test_install_operator_with_clustermongodbroles_disabled(multi_cluster_operator_no_clustermongodbroles):
240+
multi_cluster_operator_no_clustermongodbroles.assert_is_running()
241+
242+
243+
@mark.e2e_mongodb_custom_roles
244+
def test_replicaset_is_failed(replica_set: MongoDB):
245+
replica_set.assert_reaches_phase(
246+
Phase.Failed,
247+
msg_regexp="RoleRefs are not supported when ClusterMongoDBRoles are disabled. Please enable ClusterMongoDBRoles in the operator configuration.",
248+
)
249+
250+
251+
@mark.e2e_mongodb_custom_roles
252+
def test_replicaset_is_reconciled_without_rolerefs(replica_set: MongoDB):
253+
rs_version = replica_set.get_automation_config_tester().automation_config["version"]
254+
replica_set["spec"]["security"]["roleRefs"] = None
255+
replica_set.update()
256+
257+
replica_set.assert_reaches_phase(Phase.Running)
258+
wait_until(lambda: replica_set.get_automation_config_tester().reached_version(rs_version + 1), timeout=120)
259+
260+
replica_set.get_automation_config_tester().assert_has_expected_number_of_roles(expected_roles=0)

0 commit comments

Comments
 (0)