mongo-charms-single-kernel 1.8.8__py3-none-any.whl → 1.8.10__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.
Potentially problematic release.
This version of mongo-charms-single-kernel might be problematic. Click here for more details.
- {mongo_charms_single_kernel-1.8.8.dist-info → mongo_charms_single_kernel-1.8.10.dist-info}/METADATA +1 -1
- {mongo_charms_single_kernel-1.8.8.dist-info → mongo_charms_single_kernel-1.8.10.dist-info}/RECORD +30 -30
- single_kernel_mongo/config/literals.py +12 -5
- single_kernel_mongo/config/relations.py +2 -1
- single_kernel_mongo/config/statuses.py +127 -20
- single_kernel_mongo/core/operator.py +7 -0
- single_kernel_mongo/core/structured_config.py +2 -0
- single_kernel_mongo/core/workload.py +10 -4
- single_kernel_mongo/events/cluster.py +5 -0
- single_kernel_mongo/events/sharding.py +3 -1
- single_kernel_mongo/events/tls.py +183 -157
- single_kernel_mongo/exceptions.py +0 -8
- single_kernel_mongo/lib/charms/tls_certificates_interface/v4/tls_certificates.py +1995 -0
- single_kernel_mongo/managers/cluster.py +70 -28
- single_kernel_mongo/managers/config.py +24 -14
- single_kernel_mongo/managers/mongo.py +12 -12
- single_kernel_mongo/managers/mongodb_operator.py +58 -34
- single_kernel_mongo/managers/mongos_operator.py +16 -20
- single_kernel_mongo/managers/sharding.py +172 -136
- single_kernel_mongo/managers/tls.py +223 -206
- single_kernel_mongo/managers/upgrade_v3.py +6 -6
- single_kernel_mongo/state/charm_state.py +54 -31
- single_kernel_mongo/state/cluster_state.py +8 -0
- single_kernel_mongo/state/config_server_state.py +15 -6
- single_kernel_mongo/state/models.py +2 -2
- single_kernel_mongo/state/tls_state.py +39 -12
- single_kernel_mongo/utils/helpers.py +4 -19
- single_kernel_mongo/utils/mongodb_users.py +20 -20
- single_kernel_mongo/lib/charms/tls_certificates_interface/v3/tls_certificates.py +0 -2123
- {mongo_charms_single_kernel-1.8.8.dist-info → mongo_charms_single_kernel-1.8.10.dist-info}/WHEEL +0 -0
- {mongo_charms_single_kernel-1.8.8.dist-info → mongo_charms_single_kernel-1.8.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -105,6 +105,9 @@ class ClusterProvider(Object):
|
|
|
105
105
|
if int_tls_ca := self.state.tls.get_secret(label_name=SECRET_CA_LABEL, internal=True):
|
|
106
106
|
relation_data[ClusterStateKeys.INT_CA_SECRET.value] = int_tls_ca
|
|
107
107
|
|
|
108
|
+
if ext_tls_ca := self.state.tls.get_secret(label_name=SECRET_CA_LABEL, internal=False):
|
|
109
|
+
relation_data[ClusterStateKeys.EXT_CA_SECRET.value] = ext_tls_ca
|
|
110
|
+
|
|
108
111
|
if hashed_data := self.dependent.ldap_manager.get_hash():
|
|
109
112
|
relation_data[ClusterStateKeys.LDAP_HASH.value] = hashed_data
|
|
110
113
|
|
|
@@ -253,19 +256,19 @@ class ClusterRequirer(Object):
|
|
|
253
256
|
|
|
254
257
|
def assert_pass_hook_checks(self) -> None:
|
|
255
258
|
"""Runs pre-hook checks, raises if one fails."""
|
|
256
|
-
|
|
257
|
-
match (
|
|
259
|
+
mongos_peer_tls, config_server_peer_tls = self.mongos_and_config_server_peer_tls_status()
|
|
260
|
+
match (mongos_peer_tls, config_server_peer_tls):
|
|
258
261
|
case False, True:
|
|
259
262
|
raise DeferrableFailedHookChecksError(
|
|
260
|
-
"Config-Server uses TLS but mongos does not. Please synchronise encryption method."
|
|
263
|
+
"Config-Server uses peer TLS but mongos does not. Please synchronise encryption method."
|
|
261
264
|
)
|
|
262
265
|
case True, False:
|
|
263
266
|
raise DeferrableFailedHookChecksError(
|
|
264
|
-
"Mongos uses TLS but config-server does not. Please synchronise encryption method."
|
|
267
|
+
"Mongos uses peer TLS but config-server does not. Please synchronise encryption method."
|
|
265
268
|
)
|
|
266
269
|
case _:
|
|
267
270
|
pass
|
|
268
|
-
if self.
|
|
271
|
+
if self.dependent.tls_manager.is_waiting_for_a_cert():
|
|
269
272
|
raise DeferrableFailedHookChecksError(
|
|
270
273
|
"Mongos was waiting for config-server to enable TLS. Wait for TLS to be enabled until starting mongos."
|
|
271
274
|
)
|
|
@@ -431,10 +434,10 @@ class ClusterRequirer(Object):
|
|
|
431
434
|
with MongoConnection(self.state.mongo_config) as mongo:
|
|
432
435
|
mongo.drop_user(mongo.config.username)
|
|
433
436
|
|
|
434
|
-
def
|
|
435
|
-
"""Returns true if both the mongos and the config-server use the same CA.
|
|
437
|
+
def is_peer_ca_compatible(self) -> bool:
|
|
438
|
+
"""Returns true if both the mongos and the config-server use the same peer CA.
|
|
436
439
|
|
|
437
|
-
Using the same CA is a requirement for sharded clusters.
|
|
440
|
+
Using the same peer CA is a requirement for sharded clusters.
|
|
438
441
|
"""
|
|
439
442
|
if not self.state.mongos_cluster_relation:
|
|
440
443
|
return True
|
|
@@ -445,38 +448,77 @@ class ClusterRequirer(Object):
|
|
|
445
448
|
|
|
446
449
|
return config_server_tls_ca == mongos_tls_ca
|
|
447
450
|
|
|
448
|
-
def
|
|
449
|
-
"""Returns
|
|
450
|
-
if not self.state.tls_relation:
|
|
451
|
-
return False
|
|
452
|
-
mongos_tls_ca = self.state.tls.get_secret(internal=True, label_name=SECRET_CA_LABEL)
|
|
451
|
+
def is_client_ca_compatible(self) -> bool:
|
|
452
|
+
"""Returns true if both the mongos and the config-server use the same client CA.
|
|
453
453
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
454
|
+
Using the same client CA is a requirement for sharded clusters.
|
|
455
|
+
"""
|
|
456
|
+
if not self.state.mongos_cluster_relation:
|
|
457
|
+
return True
|
|
458
|
+
config_server_tls_ca = self.state.cluster.external_ca_secret
|
|
459
|
+
mongos_tls_ca = self.state.tls.get_secret(internal=False, label_name=SECRET_CA_LABEL)
|
|
460
|
+
if not config_server_tls_ca or not mongos_tls_ca:
|
|
461
|
+
return True
|
|
457
462
|
|
|
458
|
-
|
|
459
|
-
|
|
463
|
+
return config_server_tls_ca == mongos_tls_ca
|
|
464
|
+
|
|
465
|
+
def mongos_and_config_server_peer_tls_status(self) -> tuple[bool, bool]:
|
|
466
|
+
"""Returns the peer TLS integration status for mongos and config-server."""
|
|
460
467
|
if self.state.mongos_cluster_relation:
|
|
461
|
-
mongos_has_tls = self.state.
|
|
468
|
+
mongos_has_tls = self.state.peer_tls_relation is not None
|
|
462
469
|
config_server_has_tls = self.state.cluster.internal_ca_secret is not None
|
|
463
470
|
return mongos_has_tls, config_server_has_tls
|
|
464
471
|
|
|
465
472
|
return False, False
|
|
466
473
|
|
|
467
|
-
def
|
|
468
|
-
"""
|
|
469
|
-
|
|
470
|
-
|
|
474
|
+
def mongos_and_config_server_client_tls_status(self) -> tuple[bool, bool]:
|
|
475
|
+
"""Returns the client TLS integration status for mongos and config-server."""
|
|
476
|
+
if self.state.mongos_cluster_relation:
|
|
477
|
+
mongos_has_tls = self.state.client_tls_relation is not None
|
|
478
|
+
config_server_has_tls = self.state.cluster.external_ca_secret is not None
|
|
479
|
+
return mongos_has_tls, config_server_has_tls
|
|
480
|
+
|
|
481
|
+
return False, False
|
|
482
|
+
|
|
483
|
+
def get_tls_status(self, internal: bool):
|
|
484
|
+
"""Computes the TLS status for the scope.
|
|
485
|
+
|
|
486
|
+
Args:
|
|
487
|
+
internal: (bool) if true, represents the internal TLS, otherwise external TLS.
|
|
488
|
+
"""
|
|
489
|
+
if internal:
|
|
490
|
+
shard_tls, config_server_tls = self.mongos_and_config_server_peer_tls_status()
|
|
491
|
+
is_ca_compatible = self.is_peer_ca_compatible()
|
|
492
|
+
else:
|
|
493
|
+
shard_tls, config_server_tls = self.mongos_and_config_server_client_tls_status()
|
|
494
|
+
is_ca_compatible = self.is_client_ca_compatible()
|
|
495
|
+
|
|
496
|
+
match (shard_tls, config_server_tls):
|
|
471
497
|
case False, True:
|
|
472
|
-
|
|
498
|
+
logger.warning(
|
|
499
|
+
"Config-Server uses peer TLS but mongos does not. Please synchronise encryption method."
|
|
500
|
+
)
|
|
501
|
+
return MongosStatuses.missing_tls(internal=internal)
|
|
473
502
|
case True, False:
|
|
474
|
-
|
|
503
|
+
logger.warning(
|
|
504
|
+
"Mongos uses peer TLS but config-server does not. Please synchronise encryption method."
|
|
505
|
+
)
|
|
506
|
+
return MongosStatuses.invalid_tls(internal=internal)
|
|
475
507
|
case _:
|
|
476
508
|
pass
|
|
477
|
-
|
|
509
|
+
|
|
510
|
+
if not is_ca_compatible:
|
|
478
511
|
logger.error(
|
|
479
|
-
"
|
|
512
|
+
"Mongos is integrated to a different CA than the config server. Please use the same CA for all cluster components."
|
|
480
513
|
)
|
|
481
|
-
return MongosStatuses.
|
|
514
|
+
return MongosStatuses.incompatible_ca(internal=internal)
|
|
515
|
+
|
|
482
516
|
return None
|
|
517
|
+
|
|
518
|
+
def tls_statuses(self) -> list[StatusObject]:
|
|
519
|
+
"""Return statuses relevant to TLS."""
|
|
520
|
+
statuses = []
|
|
521
|
+
for internal in True, False:
|
|
522
|
+
if status := self.get_tls_status(internal=internal):
|
|
523
|
+
statuses.append(status)
|
|
524
|
+
return statuses
|
|
@@ -28,7 +28,11 @@ from single_kernel_mongo.core.structured_config import MongoConfigModel, MongoDB
|
|
|
28
28
|
from single_kernel_mongo.core.workload import WorkloadBase
|
|
29
29
|
from single_kernel_mongo.exceptions import WorkloadServiceError
|
|
30
30
|
from single_kernel_mongo.state.charm_state import CharmState
|
|
31
|
-
from single_kernel_mongo.utils.mongodb_users import
|
|
31
|
+
from single_kernel_mongo.utils.mongodb_users import (
|
|
32
|
+
CharmedBackupUser,
|
|
33
|
+
CharmedLogRotateUser,
|
|
34
|
+
CharmedStatsUser,
|
|
35
|
+
)
|
|
32
36
|
from single_kernel_mongo.workload import (
|
|
33
37
|
get_logrotate_workload_for_substrate,
|
|
34
38
|
get_mongodb_exporter_workload_for_substrate,
|
|
@@ -135,7 +139,7 @@ class BackupConfigManager(CommonConfigManager):
|
|
|
135
139
|
logger.info("Not starting PBM yet. Shard not added to config-server")
|
|
136
140
|
return
|
|
137
141
|
|
|
138
|
-
if not self.state.get_user_password(
|
|
142
|
+
if not self.state.get_user_password(CharmedBackupUser):
|
|
139
143
|
logger.info("No password found.")
|
|
140
144
|
return
|
|
141
145
|
|
|
@@ -184,7 +188,7 @@ class LogRotateConfigManager(CommonConfigManager):
|
|
|
184
188
|
logger.info("DB is not initialised.")
|
|
185
189
|
return
|
|
186
190
|
|
|
187
|
-
if not self.state.get_user_password(
|
|
191
|
+
if not self.state.get_user_password(CharmedLogRotateUser):
|
|
188
192
|
logger.info("No password found.")
|
|
189
193
|
return
|
|
190
194
|
|
|
@@ -224,17 +228,17 @@ class MongoDBExporterConfigManager(CommonConfigManager):
|
|
|
224
228
|
|
|
225
229
|
@override
|
|
226
230
|
def build_parameters(self) -> list[list[str]]:
|
|
227
|
-
return [[self.state.
|
|
231
|
+
return [[self.state.stats_config.uri]]
|
|
228
232
|
|
|
229
233
|
def configure_and_restart(self):
|
|
230
234
|
"""Exposes the endpoint to mongodb_exporter."""
|
|
231
235
|
if not self.state.db_initialised:
|
|
232
236
|
return
|
|
233
237
|
|
|
234
|
-
if not self.state.get_user_password(
|
|
238
|
+
if not self.state.get_user_password(CharmedStatsUser):
|
|
235
239
|
return
|
|
236
240
|
|
|
237
|
-
if not self.workload.active() or self.get_environment() != self.state.
|
|
241
|
+
if not self.workload.active() or self.get_environment() != self.state.stats_config.uri:
|
|
238
242
|
try:
|
|
239
243
|
# Always enable the service
|
|
240
244
|
self.workload.stop()
|
|
@@ -269,7 +273,7 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
|
|
|
269
273
|
self.binding_ips,
|
|
270
274
|
self.port_parameter,
|
|
271
275
|
self.auth_parameter,
|
|
272
|
-
self.
|
|
276
|
+
self.client_tls_parameters,
|
|
273
277
|
self.log_options,
|
|
274
278
|
self.audit_options,
|
|
275
279
|
self.ldap_parameters,
|
|
@@ -332,16 +336,20 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
|
|
|
332
336
|
def auth_parameter(self) -> dict[str, Any]:
|
|
333
337
|
"""The auth mode."""
|
|
334
338
|
cmd = {"security": {"authorization": "enabled"}} if self.auth else {}
|
|
335
|
-
if self.state.tls.
|
|
339
|
+
if self.state.tls.peer_enabled:
|
|
336
340
|
return always_merger.merge(
|
|
337
341
|
cmd,
|
|
338
342
|
{
|
|
339
343
|
"security": {"clusterAuthMode": "x509"},
|
|
340
344
|
"net": {
|
|
341
345
|
"tls": {
|
|
346
|
+
"mode": "preferTLS",
|
|
342
347
|
"allowInvalidCertificates": True,
|
|
343
|
-
"
|
|
348
|
+
"certificateKeyFile": f"{self.workload.paths.int_pem_file}",
|
|
349
|
+
"CAFile": f"{self.workload.paths.int_ca_file}",
|
|
350
|
+
"disabledProtocols": "TLS1_0,TLS1_1",
|
|
344
351
|
"clusterFile": f"{self.workload.paths.int_pem_file}",
|
|
352
|
+
"clusterCAFile": f"{self.workload.paths.int_ca_file}",
|
|
345
353
|
"clusterAuthX509": {
|
|
346
354
|
"attributes": f"O={self.state.get_subject_name()}",
|
|
347
355
|
},
|
|
@@ -360,10 +368,11 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
|
|
|
360
368
|
)
|
|
361
369
|
|
|
362
370
|
@property
|
|
363
|
-
def
|
|
364
|
-
"""The TLS
|
|
365
|
-
|
|
366
|
-
|
|
371
|
+
def client_tls_parameters(self) -> dict[str, Any]:
|
|
372
|
+
"""The client TLS parameters."""
|
|
373
|
+
params = {}
|
|
374
|
+
if self.state.tls.client_enabled:
|
|
375
|
+
params = {
|
|
367
376
|
"net": {
|
|
368
377
|
"tls": {
|
|
369
378
|
"CAFile": f"{self.workload.paths.ext_ca_file}",
|
|
@@ -373,7 +382,8 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
|
|
|
373
382
|
}
|
|
374
383
|
},
|
|
375
384
|
}
|
|
376
|
-
|
|
385
|
+
|
|
386
|
+
return params
|
|
377
387
|
|
|
378
388
|
@property
|
|
379
389
|
@abstractmethod
|
|
@@ -52,11 +52,11 @@ from single_kernel_mongo.utils.mongo_config import (
|
|
|
52
52
|
from single_kernel_mongo.utils.mongo_connection import MongoConnection, NotReadyError
|
|
53
53
|
from single_kernel_mongo.utils.mongodb_users import (
|
|
54
54
|
OPERATOR_ROLE,
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
CharmedBackupUser,
|
|
56
|
+
CharmedLogRotateUser,
|
|
57
|
+
CharmedOperatorUser,
|
|
58
|
+
CharmedStatsUser,
|
|
57
59
|
MongoDBUser,
|
|
58
|
-
MonitorUser,
|
|
59
|
-
OperatorUser,
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
if TYPE_CHECKING:
|
|
@@ -138,12 +138,12 @@ class MongoManager(Object, ManagerStatusProtocol):
|
|
|
138
138
|
|
|
139
139
|
def initialise_charm_admin_users(self) -> None:
|
|
140
140
|
"""First initialisation of each user."""
|
|
141
|
-
self.
|
|
142
|
-
self.initialise_user(
|
|
143
|
-
self.initialise_user(
|
|
144
|
-
self.initialise_user(
|
|
141
|
+
self.initialise_charmed_operator_user()
|
|
142
|
+
self.initialise_user(CharmedStatsUser)
|
|
143
|
+
self.initialise_user(CharmedBackupUser)
|
|
144
|
+
self.initialise_user(CharmedLogRotateUser)
|
|
145
145
|
|
|
146
|
-
def
|
|
146
|
+
def initialise_charmed_operator_user(self):
|
|
147
147
|
"""Creates initial admin user for MongoDB.
|
|
148
148
|
|
|
149
149
|
Initial admin user can be created only through localhost connection.
|
|
@@ -154,7 +154,7 @@ class MongoManager(Object, ManagerStatusProtocol):
|
|
|
154
154
|
It is needed to install mongodb-clients inside charm container to make
|
|
155
155
|
this function work correctly.
|
|
156
156
|
"""
|
|
157
|
-
if self.state.app_peer_data.is_user_created(
|
|
157
|
+
if self.state.app_peer_data.is_user_created(CharmedOperatorUser.username):
|
|
158
158
|
return
|
|
159
159
|
config = self.state.mongo_config
|
|
160
160
|
cmd = [
|
|
@@ -169,7 +169,7 @@ class MongoManager(Object, ManagerStatusProtocol):
|
|
|
169
169
|
'})"',
|
|
170
170
|
]
|
|
171
171
|
self.workload.run_bin_command("mongodb://localhost/admin", cmd, input=config.password)
|
|
172
|
-
self.state.app_peer_data.set_user_created(
|
|
172
|
+
self.state.app_peer_data.set_user_created(CharmedOperatorUser.username)
|
|
173
173
|
|
|
174
174
|
def initialise_user(self, user: MongoDBUser):
|
|
175
175
|
"""Creates a user and sets its role on the MongoDB database."""
|
|
@@ -530,7 +530,7 @@ class MongoManager(Object, ManagerStatusProtocol):
|
|
|
530
530
|
return charm_statuses
|
|
531
531
|
|
|
532
532
|
except ServerSelectionTimeoutError as e:
|
|
533
|
-
# Usually it is
|
|
533
|
+
# Usually it is due to ReplicaSetNoPrimary
|
|
534
534
|
logger.debug(f"Got error {e} while checking replica set status")
|
|
535
535
|
return [MongodStatuses.WAITING_ELECTION.value]
|
|
536
536
|
except AutoReconnect as e:
|
|
@@ -33,7 +33,10 @@ from single_kernel_mongo.config.models import (
|
|
|
33
33
|
PasswordManagementContext,
|
|
34
34
|
PasswordManagementState,
|
|
35
35
|
)
|
|
36
|
-
from single_kernel_mongo.config.relations import
|
|
36
|
+
from single_kernel_mongo.config.relations import (
|
|
37
|
+
ExternalRequirerRelations,
|
|
38
|
+
RelationNames,
|
|
39
|
+
)
|
|
37
40
|
from single_kernel_mongo.config.statuses import (
|
|
38
41
|
BackupStatuses,
|
|
39
42
|
CharmStatuses,
|
|
@@ -47,7 +50,7 @@ from single_kernel_mongo.core.kubernetes_upgrades_v3 import KubernetesMongoDBRef
|
|
|
47
50
|
from single_kernel_mongo.core.machine_upgrades_v3 import MachineMongoDBRefresh
|
|
48
51
|
from single_kernel_mongo.core.operator import OperatorProtocol
|
|
49
52
|
from single_kernel_mongo.core.secrets import generate_secret_label
|
|
50
|
-
from single_kernel_mongo.core.structured_config import MongoDBRoles
|
|
53
|
+
from single_kernel_mongo.core.structured_config import MongoDBCharmConfig, MongoDBRoles
|
|
51
54
|
from single_kernel_mongo.core.version_checker import VersionChecker
|
|
52
55
|
from single_kernel_mongo.events.backups import BackupEventsHandler
|
|
53
56
|
from single_kernel_mongo.events.cluster import ClusterConfigServerEventHandler
|
|
@@ -97,12 +100,12 @@ from single_kernel_mongo.state.charm_state import CharmState
|
|
|
97
100
|
from single_kernel_mongo.utils.helpers import is_valid_ldap_options, is_valid_ldapusertodnmapping
|
|
98
101
|
from single_kernel_mongo.utils.mongo_connection import MongoConnection, NotReadyError
|
|
99
102
|
from single_kernel_mongo.utils.mongodb_users import (
|
|
100
|
-
|
|
103
|
+
CharmedBackupUser,
|
|
104
|
+
CharmedLogRotateUser,
|
|
105
|
+
CharmedOperatorUser,
|
|
106
|
+
CharmedStatsUser,
|
|
101
107
|
InternalUsers,
|
|
102
|
-
LogRotateUser,
|
|
103
108
|
MongoDBUser,
|
|
104
|
-
MonitorUser,
|
|
105
|
-
OperatorUser,
|
|
106
109
|
get_user_from_username,
|
|
107
110
|
validate_charm_user_password_config,
|
|
108
111
|
)
|
|
@@ -167,12 +170,7 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
167
170
|
self.state,
|
|
168
171
|
container,
|
|
169
172
|
)
|
|
170
|
-
self.tls_manager = TLSManager(
|
|
171
|
-
self,
|
|
172
|
-
self.workload,
|
|
173
|
-
self.state,
|
|
174
|
-
self.substrate,
|
|
175
|
-
)
|
|
173
|
+
self.tls_manager = TLSManager(self, self.workload, self.state)
|
|
176
174
|
self.mongo_manager = MongoManager(
|
|
177
175
|
self,
|
|
178
176
|
self.workload,
|
|
@@ -345,7 +343,8 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
345
343
|
return
|
|
346
344
|
|
|
347
345
|
@property
|
|
348
|
-
|
|
346
|
+
@override
|
|
347
|
+
def config(self) -> MongoDBCharmConfig:
|
|
349
348
|
"""Returns the actual config."""
|
|
350
349
|
return self.charm.parsed_config
|
|
351
350
|
|
|
@@ -393,6 +392,7 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
393
392
|
return (
|
|
394
393
|
self,
|
|
395
394
|
self.mongo_manager,
|
|
395
|
+
self.tls_manager,
|
|
396
396
|
self.shard_manager,
|
|
397
397
|
self.config_server_manager,
|
|
398
398
|
self.backup_manager,
|
|
@@ -487,7 +487,9 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
487
487
|
except (NotReadyError, PyMongoError, WorkloadExecError) as e:
|
|
488
488
|
logger.error(f"Deferring on start: error={e}")
|
|
489
489
|
self.state.statuses.add(
|
|
490
|
-
MongodStatuses.WAITING_REPL_SET_INIT.value,
|
|
490
|
+
MongodStatuses.WAITING_REPL_SET_INIT.value,
|
|
491
|
+
scope="unit",
|
|
492
|
+
component=self.name,
|
|
491
493
|
)
|
|
492
494
|
raise
|
|
493
495
|
|
|
@@ -717,10 +719,10 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
717
719
|
|
|
718
720
|
Adds the unit as a replica to the MongoDB replica set.
|
|
719
721
|
"""
|
|
720
|
-
# Changing the
|
|
721
|
-
# units receiving a relation changed event. We must update
|
|
722
|
-
# and pbm URI if the password changes so that COS/pbm can
|
|
723
|
-
# work.
|
|
722
|
+
# Changing the charmed-stats or the charmed-backup password will lead
|
|
723
|
+
# to non-leader units receiving a relation changed event. We must update
|
|
724
|
+
# the monitor and pbm URI if the password changes so that COS/pbm can
|
|
725
|
+
# continue to work.
|
|
724
726
|
if self.state.db_initialised and self.workload.active():
|
|
725
727
|
self.mongodb_exporter_config_manager.configure_and_restart()
|
|
726
728
|
self.backup_manager.configure_and_restart()
|
|
@@ -879,22 +881,17 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
879
881
|
@override
|
|
880
882
|
def update_status(self) -> None:
|
|
881
883
|
"""Status update Handler."""
|
|
882
|
-
# TODO update the usage of this once the spec is approved and we have a consistent way of
|
|
883
|
-
# handling statuses
|
|
884
884
|
if self.basic_statuses():
|
|
885
885
|
logger.info("Early return invalid statuses.")
|
|
886
886
|
return
|
|
887
887
|
|
|
888
|
+
if self.state.is_role(MongoDBRoles.SHARD) and self._should_skip_because_of_incomplete_tls():
|
|
889
|
+
return
|
|
890
|
+
|
|
888
891
|
if self.cluster_version_checker.get_cluster_mismatched_revision_status():
|
|
889
892
|
logger.info("Early return, cluster mismatch version.")
|
|
890
893
|
return
|
|
891
894
|
|
|
892
|
-
if self.state.is_role(MongoDBRoles.SHARD):
|
|
893
|
-
shard_has_tls, config_server_has_tls = self.shard_manager.tls_status()
|
|
894
|
-
if config_server_has_tls and not shard_has_tls:
|
|
895
|
-
logger.info("Shard is missing TLS.")
|
|
896
|
-
return
|
|
897
|
-
|
|
898
895
|
if not self.mongo_manager.mongod_ready():
|
|
899
896
|
logger.info("Mongod not ready.")
|
|
900
897
|
return
|
|
@@ -915,16 +912,18 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
915
912
|
def update_single_user_password(self, user: MongoDBUser, new_password: str) -> None:
|
|
916
913
|
"""Set password in Mongod and restart the appropriate services."""
|
|
917
914
|
self.mongo_manager.set_user_password(user, new_password)
|
|
918
|
-
if user ==
|
|
915
|
+
if user == CharmedBackupUser:
|
|
919
916
|
# Update and restart PBM Agent.
|
|
920
917
|
self.backup_manager.configure_and_restart()
|
|
921
|
-
if user ==
|
|
918
|
+
if user == CharmedStatsUser:
|
|
922
919
|
# Update and restart mongodb exporter.
|
|
923
920
|
self.mongodb_exporter_config_manager.configure_and_restart()
|
|
924
|
-
if user ==
|
|
921
|
+
if user == CharmedLogRotateUser:
|
|
925
922
|
# Update and restart logrotate.
|
|
926
923
|
self.logrotate_config_manager.configure_and_restart()
|
|
927
|
-
if user in (
|
|
924
|
+
if user in (CharmedOperatorUser, CharmedBackupUser) and self.state.is_role(
|
|
925
|
+
MongoDBRoles.CONFIG_SERVER
|
|
926
|
+
):
|
|
928
927
|
self.config_server_manager.update_credentials(
|
|
929
928
|
user.password_key_name,
|
|
930
929
|
new_password,
|
|
@@ -1055,7 +1054,9 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
1055
1054
|
except WorkloadServiceError as e:
|
|
1056
1055
|
logger.error("An exception occurred when starting mongod agent, error: %s.", str(e))
|
|
1057
1056
|
self.charm.state.statuses.add(
|
|
1058
|
-
MongoDBStatuses.WAITING_FOR_MONGODB_START.value,
|
|
1057
|
+
MongoDBStatuses.WAITING_FOR_MONGODB_START.value,
|
|
1058
|
+
scope="unit",
|
|
1059
|
+
component=self.name,
|
|
1059
1060
|
)
|
|
1060
1061
|
raise
|
|
1061
1062
|
|
|
@@ -1075,7 +1076,9 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
1075
1076
|
self.backup_manager.configure_and_restart()
|
|
1076
1077
|
except WorkloadServiceError:
|
|
1077
1078
|
self.state.statuses.add(
|
|
1078
|
-
BackupStatuses.WAITING_FOR_PBM_START.value,
|
|
1079
|
+
BackupStatuses.WAITING_FOR_PBM_START.value,
|
|
1080
|
+
scope="unit",
|
|
1081
|
+
component=self.name,
|
|
1079
1082
|
)
|
|
1080
1083
|
raise
|
|
1081
1084
|
|
|
@@ -1116,7 +1119,10 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
1116
1119
|
logger.error("Charm is in sharding mode. Does not support %s interface.", rel_name)
|
|
1117
1120
|
return MongoDBStatuses.INVALID_CFG_SRV_ON_SHARD_REL.value
|
|
1118
1121
|
if self.state.is_role(MongoDBRoles.CONFIG_SERVER) and rel_name == RelationNames.SHARDING:
|
|
1119
|
-
logger.error(
|
|
1122
|
+
logger.error(
|
|
1123
|
+
"Charm is in config-server mode. Does not support %s interface.",
|
|
1124
|
+
rel_name,
|
|
1125
|
+
)
|
|
1120
1126
|
return MongoDBStatuses.INVALID_SHARD_ON_CFG_SRV_REL.value
|
|
1121
1127
|
if not self.state.is_role(MongoDBRoles.CONFIG_SERVER) and rel_name == RelationNames.CLUSTER:
|
|
1122
1128
|
logger.error("Charm is not a config-server, cannot integrate mongos")
|
|
@@ -1136,7 +1142,9 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
1136
1142
|
self.build_local_tls_directory()
|
|
1137
1143
|
|
|
1138
1144
|
# Push TLS files if necessary
|
|
1139
|
-
|
|
1145
|
+
for internal in [True, False]:
|
|
1146
|
+
self.tls_manager.push_tls_files_to_workload(internal)
|
|
1147
|
+
|
|
1140
1148
|
self.ldap_manager.save_certificates(self.state.ldap.chain)
|
|
1141
1149
|
|
|
1142
1150
|
# Update licenses
|
|
@@ -1354,3 +1362,19 @@ class MongoDBOperator(OperatorProtocol, Object):
|
|
|
1354
1362
|
scope="app",
|
|
1355
1363
|
component=self.name,
|
|
1356
1364
|
)
|
|
1365
|
+
|
|
1366
|
+
def _should_skip_because_of_incomplete_tls(self) -> bool:
|
|
1367
|
+
"""Checks if the update status hook needs skipping due to an incomplete TLS integration."""
|
|
1368
|
+
shard_has_peer_tls, config_server_has_peer_tls = (
|
|
1369
|
+
self.shard_manager.shard_and_config_server_peer_tls_status()
|
|
1370
|
+
)
|
|
1371
|
+
if config_server_has_peer_tls and not shard_has_peer_tls:
|
|
1372
|
+
logger.info("Shard is missing peer TLS.")
|
|
1373
|
+
return True
|
|
1374
|
+
shard_has_client_tls, config_server_has_client_tls = (
|
|
1375
|
+
self.shard_manager.shard_and_config_server_client_tls_status()
|
|
1376
|
+
)
|
|
1377
|
+
if config_server_has_client_tls and not shard_has_client_tls:
|
|
1378
|
+
logger.info("Shard is missing client TLS.")
|
|
1379
|
+
return True
|
|
1380
|
+
return False
|
|
@@ -104,12 +104,7 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
104
104
|
self.state,
|
|
105
105
|
self.substrate,
|
|
106
106
|
)
|
|
107
|
-
self.tls_manager = TLSManager(
|
|
108
|
-
self,
|
|
109
|
-
self.workload,
|
|
110
|
-
self.state,
|
|
111
|
-
self.substrate,
|
|
112
|
-
)
|
|
107
|
+
self.tls_manager = TLSManager(self, self.workload, self.state)
|
|
113
108
|
self.cluster_manager = ClusterRequirer(
|
|
114
109
|
self, self.workload, self.state, self.substrate, RelationNames.CLUSTER
|
|
115
110
|
)
|
|
@@ -201,9 +196,10 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
201
196
|
@property
|
|
202
197
|
def components(self) -> tuple[ManagerStatusProtocol, ...]:
|
|
203
198
|
"""The ordered list of components for this operator."""
|
|
204
|
-
return (self, self.ldap_manager, self.upgrades_status_manager)
|
|
199
|
+
return (self, self.tls_manager, self.ldap_manager, self.upgrades_status_manager)
|
|
205
200
|
|
|
206
201
|
@property
|
|
202
|
+
@override
|
|
207
203
|
def config(self) -> MongosCharmConfig:
|
|
208
204
|
"""Returns the actual config."""
|
|
209
205
|
return self.charm.parsed_config
|
|
@@ -222,8 +218,8 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
222
218
|
# Instantiate the local directory for k8s
|
|
223
219
|
self.build_local_tls_directory()
|
|
224
220
|
|
|
225
|
-
|
|
226
|
-
|
|
221
|
+
for internal in [True, False]:
|
|
222
|
+
self.tls_manager.push_tls_files_to_workload(internal)
|
|
227
223
|
|
|
228
224
|
# Save LDAP certificates
|
|
229
225
|
self.ldap_manager.save_certificates(self.state.ldap.chain)
|
|
@@ -301,8 +297,7 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
301
297
|
component=self.name,
|
|
302
298
|
)
|
|
303
299
|
self.update_k8s_external_services()
|
|
304
|
-
|
|
305
|
-
self.tls_manager.update_tls_sans()
|
|
300
|
+
self.tls_events.refresh_certificates()
|
|
306
301
|
self.share_connection_info()
|
|
307
302
|
|
|
308
303
|
@override
|
|
@@ -345,7 +340,7 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
345
340
|
# our SANS as necessary.
|
|
346
341
|
# The connection info will be updated when we receive the new certificates.
|
|
347
342
|
if self.substrate == Substrates.K8S:
|
|
348
|
-
self.
|
|
343
|
+
self.tls_events.refresh_certificates()
|
|
349
344
|
|
|
350
345
|
@override
|
|
351
346
|
def new_peer(self) -> None:
|
|
@@ -390,11 +385,10 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
390
385
|
self.mongos_config_manager.configure_and_restart(force=force)
|
|
391
386
|
except WorkloadServiceError as e:
|
|
392
387
|
logger.error("An exception occurred when starting mongos agent, error: %s.", str(e))
|
|
393
|
-
self.charm.
|
|
388
|
+
self.charm.state.statuses.add(
|
|
394
389
|
MongosStatuses.WAITING_FOR_MONGOS_START.value,
|
|
395
390
|
scope="unit",
|
|
396
|
-
|
|
397
|
-
component_name=self.name,
|
|
391
|
+
component=self.name,
|
|
398
392
|
)
|
|
399
393
|
raise
|
|
400
394
|
|
|
@@ -579,8 +573,9 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
579
573
|
)
|
|
580
574
|
return False
|
|
581
575
|
|
|
582
|
-
if
|
|
583
|
-
|
|
576
|
+
if statuses := self.cluster_manager.tls_statuses():
|
|
577
|
+
for status in statuses:
|
|
578
|
+
logger.info(f"Invalid TLS integration: {status.message}")
|
|
584
579
|
return False
|
|
585
580
|
|
|
586
581
|
if not self.is_mongos_running():
|
|
@@ -618,10 +613,11 @@ class MongosOperator(OperatorProtocol, Object):
|
|
|
618
613
|
# don't bother checking remaining statuses if no config-server is present
|
|
619
614
|
return charm_statuses
|
|
620
615
|
|
|
621
|
-
if
|
|
622
|
-
|
|
616
|
+
if statuses := self.cluster_manager.tls_statuses():
|
|
617
|
+
for status in statuses:
|
|
618
|
+
logger.info(f"Invalid TLS integration: {status.message}")
|
|
623
619
|
# if TLS is misconfigured we will get redherrings on the remaining messages
|
|
624
|
-
charm_statuses
|
|
620
|
+
charm_statuses += statuses
|
|
625
621
|
return charm_statuses
|
|
626
622
|
|
|
627
623
|
if self.state.mongos_cluster_relation and not self.state.cluster.config_server_uri:
|