mongo-charms-single-kernel 1.8.7__py3-none-any.whl → 1.8.9__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.

Files changed (31) hide show
  1. {mongo_charms_single_kernel-1.8.7.dist-info → mongo_charms_single_kernel-1.8.9.dist-info}/METADATA +1 -1
  2. {mongo_charms_single_kernel-1.8.7.dist-info → mongo_charms_single_kernel-1.8.9.dist-info}/RECORD +30 -28
  3. single_kernel_mongo/config/literals.py +8 -3
  4. single_kernel_mongo/config/models.py +12 -0
  5. single_kernel_mongo/config/relations.py +2 -1
  6. single_kernel_mongo/config/statuses.py +127 -20
  7. single_kernel_mongo/core/operator.py +68 -1
  8. single_kernel_mongo/core/structured_config.py +2 -0
  9. single_kernel_mongo/core/workload.py +10 -4
  10. single_kernel_mongo/events/cluster.py +5 -0
  11. single_kernel_mongo/events/sharding.py +3 -1
  12. single_kernel_mongo/events/tls.py +183 -157
  13. single_kernel_mongo/exceptions.py +0 -8
  14. single_kernel_mongo/lib/charms/operator_libs_linux/v1/systemd.py +288 -0
  15. single_kernel_mongo/lib/charms/tls_certificates_interface/v4/tls_certificates.py +1995 -0
  16. single_kernel_mongo/managers/cluster.py +70 -28
  17. single_kernel_mongo/managers/config.py +14 -8
  18. single_kernel_mongo/managers/mongo.py +1 -1
  19. single_kernel_mongo/managers/mongodb_operator.py +53 -56
  20. single_kernel_mongo/managers/mongos_operator.py +18 -20
  21. single_kernel_mongo/managers/sharding.py +154 -127
  22. single_kernel_mongo/managers/tls.py +223 -206
  23. single_kernel_mongo/state/charm_state.py +39 -16
  24. single_kernel_mongo/state/cluster_state.py +8 -0
  25. single_kernel_mongo/state/config_server_state.py +9 -0
  26. single_kernel_mongo/state/tls_state.py +39 -12
  27. single_kernel_mongo/templates/enable-transparent-huge-pages.service.j2 +14 -0
  28. single_kernel_mongo/utils/helpers.py +4 -19
  29. single_kernel_mongo/lib/charms/tls_certificates_interface/v3/tls_certificates.py +0 -2123
  30. {mongo_charms_single_kernel-1.8.7.dist-info → mongo_charms_single_kernel-1.8.9.dist-info}/WHEEL +0 -0
  31. {mongo_charms_single_kernel-1.8.7.dist-info → mongo_charms_single_kernel-1.8.9.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
- mongos_has_tls, config_server_has_tls = self.tls_status()
257
- match (mongos_has_tls, config_server_has_tls):
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.is_waiting_to_request_certs():
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 is_ca_compatible(self) -> bool:
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 is_waiting_to_request_certs(self) -> bool:
449
- """Returns True if mongos has been waiting for config server in order to request certs."""
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
- # our CA is none until certs have been requested. We cannot request certs until integrated
455
- # to config-server.
456
- return not mongos_tls_ca
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
- def tls_status(self) -> tuple[bool, bool]:
459
- """Returns the TLS integration status for mongos and config-server."""
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.tls_relation is not None
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 get_tls_statuses(self) -> StatusObject | None:
468
- """Return statuses relevant to TLS."""
469
- mongos_has_tls, config_server_has_tls = self.tls_status()
470
- match (mongos_has_tls, config_server_has_tls):
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
- return MongosStatuses.MISSING_TLS_REL.value
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
- return MongosStatuses.INVALID_TLS_REL.value
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
- if not self.is_ca_compatible():
509
+
510
+ if not is_ca_compatible:
478
511
  logger.error(
479
- "mongos is integrated to a different CA than the config server. Please use the same CA for all cluster components."
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.CA_MISMATCH.value
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
@@ -269,7 +269,7 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
269
269
  self.binding_ips,
270
270
  self.port_parameter,
271
271
  self.auth_parameter,
272
- self.tls_parameters,
272
+ self.client_tls_parameters,
273
273
  self.log_options,
274
274
  self.audit_options,
275
275
  self.ldap_parameters,
@@ -332,16 +332,20 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
332
332
  def auth_parameter(self) -> dict[str, Any]:
333
333
  """The auth mode."""
334
334
  cmd = {"security": {"authorization": "enabled"}} if self.auth else {}
335
- if self.state.tls.internal_enabled and self.state.tls.external_enabled:
335
+ if self.state.tls.peer_enabled:
336
336
  return always_merger.merge(
337
337
  cmd,
338
338
  {
339
339
  "security": {"clusterAuthMode": "x509"},
340
340
  "net": {
341
341
  "tls": {
342
+ "mode": "preferTLS",
342
343
  "allowInvalidCertificates": True,
343
- "clusterCAFile": f"{self.workload.paths.int_ca_file}",
344
+ "certificateKeyFile": f"{self.workload.paths.int_pem_file}",
345
+ "CAFile": f"{self.workload.paths.int_ca_file}",
346
+ "disabledProtocols": "TLS1_0,TLS1_1",
344
347
  "clusterFile": f"{self.workload.paths.int_pem_file}",
348
+ "clusterCAFile": f"{self.workload.paths.int_ca_file}",
345
349
  "clusterAuthX509": {
346
350
  "attributes": f"O={self.state.get_subject_name()}",
347
351
  },
@@ -360,10 +364,11 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
360
364
  )
361
365
 
362
366
  @property
363
- def tls_parameters(self) -> dict[str, Any]:
364
- """The TLS external parameters."""
365
- if self.state.tls.external_enabled:
366
- return {
367
+ def client_tls_parameters(self) -> dict[str, Any]:
368
+ """The client TLS parameters."""
369
+ params = {}
370
+ if self.state.tls.client_enabled:
371
+ params = {
367
372
  "net": {
368
373
  "tls": {
369
374
  "CAFile": f"{self.workload.paths.ext_ca_file}",
@@ -373,7 +378,8 @@ class MongoConfigManager(FileBasedConfigManager, ABC):
373
378
  }
374
379
  },
375
380
  }
376
- return {}
381
+
382
+ return params
377
383
 
378
384
  @property
379
385
  @abstractmethod
@@ -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 du to ReplicaSetNoPrimary
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:
@@ -13,10 +13,7 @@ import charm_refresh
13
13
  from data_platform_helpers.advanced_statuses.models import StatusObject
14
14
  from data_platform_helpers.advanced_statuses.protocol import ManagerStatusProtocol
15
15
  from data_platform_helpers.advanced_statuses.types import Scope as DPHScope
16
- from data_platform_helpers.version_check import (
17
- CrossAppVersionChecker,
18
- get_charm_revision,
19
- )
16
+ from data_platform_helpers.version_check import CrossAppVersionChecker, get_charm_revision
20
17
  from ops.framework import Object
21
18
  from ops.model import Container, ModelError, SecretNotFoundError, Unit
22
19
  from pymongo.errors import OperationFailure, PyMongoError, ServerSelectionTimeoutError
@@ -25,7 +22,6 @@ from typing_extensions import override
25
22
 
26
23
  from single_kernel_mongo.config.literals import (
27
24
  FEATURE_VERSION,
28
- OS_REQUIREMENTS,
29
25
  CharmKind,
30
26
  MongoPorts,
31
27
  Scope,
@@ -37,7 +33,10 @@ from single_kernel_mongo.config.models import (
37
33
  PasswordManagementContext,
38
34
  PasswordManagementState,
39
35
  )
40
- from single_kernel_mongo.config.relations import ExternalRequirerRelations, RelationNames
36
+ from single_kernel_mongo.config.relations import (
37
+ ExternalRequirerRelations,
38
+ RelationNames,
39
+ )
41
40
  from single_kernel_mongo.config.statuses import (
42
41
  BackupStatuses,
43
42
  CharmStatuses,
@@ -51,19 +50,14 @@ from single_kernel_mongo.core.kubernetes_upgrades_v3 import KubernetesMongoDBRef
51
50
  from single_kernel_mongo.core.machine_upgrades_v3 import MachineMongoDBRefresh
52
51
  from single_kernel_mongo.core.operator import OperatorProtocol
53
52
  from single_kernel_mongo.core.secrets import generate_secret_label
54
- from single_kernel_mongo.core.structured_config import MongoDBRoles
53
+ from single_kernel_mongo.core.structured_config import MongoDBCharmConfig, MongoDBRoles
55
54
  from single_kernel_mongo.core.version_checker import VersionChecker
56
- from single_kernel_mongo.events.backups import (
57
- BackupEventsHandler,
58
- )
55
+ from single_kernel_mongo.events.backups import BackupEventsHandler
59
56
  from single_kernel_mongo.events.cluster import ClusterConfigServerEventHandler
60
57
  from single_kernel_mongo.events.database import DatabaseEventsHandler
61
58
  from single_kernel_mongo.events.ldap import LDAPEventHandler
62
59
  from single_kernel_mongo.events.primary_action import PrimaryActionHandler
63
- from single_kernel_mongo.events.sharding import (
64
- ConfigServerEventHandler,
65
- ShardEventHandler,
66
- )
60
+ from single_kernel_mongo.events.sharding import ConfigServerEventHandler, ShardEventHandler
67
61
  from single_kernel_mongo.events.tls import TLSEventsHandler
68
62
  from single_kernel_mongo.exceptions import (
69
63
  BalancerNotEnabledError,
@@ -103,10 +97,7 @@ from single_kernel_mongo.managers.tls import TLSManager
103
97
  from single_kernel_mongo.managers.upgrade_v3 import MongoDBUpgradesManager
104
98
  from single_kernel_mongo.managers.upgrade_v3_status import MongoDBUpgradesStatusManager
105
99
  from single_kernel_mongo.state.charm_state import CharmState
106
- from single_kernel_mongo.utils.helpers import (
107
- is_valid_ldap_options,
108
- is_valid_ldapusertodnmapping,
109
- )
100
+ from single_kernel_mongo.utils.helpers import is_valid_ldap_options, is_valid_ldapusertodnmapping
110
101
  from single_kernel_mongo.utils.mongo_connection import MongoConnection, NotReadyError
111
102
  from single_kernel_mongo.utils.mongodb_users import (
112
103
  BackupUser,
@@ -179,12 +170,7 @@ class MongoDBOperator(OperatorProtocol, Object):
179
170
  self.state,
180
171
  container,
181
172
  )
182
- self.tls_manager = TLSManager(
183
- self,
184
- self.workload,
185
- self.state,
186
- self.substrate,
187
- )
173
+ self.tls_manager = TLSManager(self, self.workload, self.state)
188
174
  self.mongo_manager = MongoManager(
189
175
  self,
190
176
  self.workload,
@@ -340,15 +326,15 @@ class MongoDBOperator(OperatorProtocol, Object):
340
326
  return
341
327
  logger.info("Restarting workloads")
342
328
  # always apply the current charm revision's config
343
- self.dependent._configure_workloads()
344
- self.dependent.start_charm_services()
329
+ self._configure_workloads()
330
+ self.start_charm_services()
345
331
 
346
332
  self.state.unit_peer_data.current_revision = self.cross_app_version_checker.version
347
333
 
348
- if self.dependent.name == CharmKind.MONGOD:
349
- self.dependent._restart_related_services()
334
+ if self.name == CharmKind.MONGOD:
335
+ self._restart_related_services()
350
336
 
351
- if self.dependent.mongo_manager.mongod_ready():
337
+ if self.mongo_manager.mongod_ready():
352
338
  try:
353
339
  self.upgrades_manager.wait_for_cluster_healthy()
354
340
  refresh.next_unit_allowed_to_refresh = True
@@ -357,7 +343,8 @@ class MongoDBOperator(OperatorProtocol, Object):
357
343
  return
358
344
 
359
345
  @property
360
- def config(self):
346
+ @override
347
+ def config(self) -> MongoDBCharmConfig:
361
348
  """Returns the actual config."""
362
349
  return self.charm.parsed_config
363
350
 
@@ -405,6 +392,7 @@ class MongoDBOperator(OperatorProtocol, Object):
405
392
  return (
406
393
  self,
407
394
  self.mongo_manager,
395
+ self.tls_manager,
408
396
  self.shard_manager,
409
397
  self.config_server_manager,
410
398
  self.backup_manager,
@@ -499,7 +487,9 @@ class MongoDBOperator(OperatorProtocol, Object):
499
487
  except (NotReadyError, PyMongoError, WorkloadExecError) as e:
500
488
  logger.error(f"Deferring on start: error={e}")
501
489
  self.state.statuses.add(
502
- MongodStatuses.WAITING_REPL_SET_INIT.value, scope="unit", component=self.name
490
+ MongodStatuses.WAITING_REPL_SET_INIT.value,
491
+ scope="unit",
492
+ component=self.name,
503
493
  )
504
494
  raise
505
495
 
@@ -891,22 +881,17 @@ class MongoDBOperator(OperatorProtocol, Object):
891
881
  @override
892
882
  def update_status(self) -> None:
893
883
  """Status update Handler."""
894
- # TODO update the usage of this once the spec is approved and we have a consistent way of
895
- # handling statuses
896
884
  if self.basic_statuses():
897
885
  logger.info("Early return invalid statuses.")
898
886
  return
899
887
 
888
+ if self.state.is_role(MongoDBRoles.SHARD) and self._should_skip_because_of_incomplete_tls():
889
+ return
890
+
900
891
  if self.cluster_version_checker.get_cluster_mismatched_revision_status():
901
892
  logger.info("Early return, cluster mismatch version.")
902
893
  return
903
894
 
904
- if self.state.is_role(MongoDBRoles.SHARD):
905
- shard_has_tls, config_server_has_tls = self.shard_manager.tls_status()
906
- if config_server_has_tls and not shard_has_tls:
907
- logger.info("Shard is missing TLS.")
908
- return
909
-
910
895
  if not self.mongo_manager.mongod_ready():
911
896
  logger.info("Mongod not ready.")
912
897
  return
@@ -1013,19 +998,6 @@ class MongoDBOperator(OperatorProtocol, Object):
1013
998
  logger.exception(f"Failed to open port: {e}")
1014
999
  raise
1015
1000
 
1016
- def _set_os_config(self) -> None:
1017
- """Sets sysctl config for mongodb."""
1018
- try:
1019
- self.sysctl_config.configure(OS_REQUIREMENTS)
1020
- except (sysctl.ApplyError, sysctl.ValidationError, sysctl.CommandError) as e:
1021
- # we allow events to continue in the case that we are not able to correctly configure
1022
- # sysctl config, since we can still run the workload with wrong sysctl parameters
1023
- # even if it is not optimal.
1024
- logger.error(f"Error setting values on sysctl: {e.message}")
1025
- # containers share the kernel with the host system, and some sysctl parameters are
1026
- # set at kernel level.
1027
- logger.warning("sysctl params cannot be set. Is the machine running on a container?")
1028
-
1029
1001
  @property
1030
1002
  def primary_unit_name(self) -> str | None:
1031
1003
  """Retrieves the primary unit with the primary replica."""
@@ -1080,7 +1052,9 @@ class MongoDBOperator(OperatorProtocol, Object):
1080
1052
  except WorkloadServiceError as e:
1081
1053
  logger.error("An exception occurred when starting mongod agent, error: %s.", str(e))
1082
1054
  self.charm.state.statuses.add(
1083
- MongoDBStatuses.WAITING_FOR_MONGODB_START.value, scope="unit", component=self.name
1055
+ MongoDBStatuses.WAITING_FOR_MONGODB_START.value,
1056
+ scope="unit",
1057
+ component=self.name,
1084
1058
  )
1085
1059
  raise
1086
1060
 
@@ -1100,7 +1074,9 @@ class MongoDBOperator(OperatorProtocol, Object):
1100
1074
  self.backup_manager.configure_and_restart()
1101
1075
  except WorkloadServiceError:
1102
1076
  self.state.statuses.add(
1103
- BackupStatuses.WAITING_FOR_PBM_START.value, scope="unit", component=self.name
1077
+ BackupStatuses.WAITING_FOR_PBM_START.value,
1078
+ scope="unit",
1079
+ component=self.name,
1104
1080
  )
1105
1081
  raise
1106
1082
 
@@ -1141,7 +1117,10 @@ class MongoDBOperator(OperatorProtocol, Object):
1141
1117
  logger.error("Charm is in sharding mode. Does not support %s interface.", rel_name)
1142
1118
  return MongoDBStatuses.INVALID_CFG_SRV_ON_SHARD_REL.value
1143
1119
  if self.state.is_role(MongoDBRoles.CONFIG_SERVER) and rel_name == RelationNames.SHARDING:
1144
- logger.error("Charm is in config-server mode. Does not support %s interface.", rel_name)
1120
+ logger.error(
1121
+ "Charm is in config-server mode. Does not support %s interface.",
1122
+ rel_name,
1123
+ )
1145
1124
  return MongoDBStatuses.INVALID_SHARD_ON_CFG_SRV_REL.value
1146
1125
  if not self.state.is_role(MongoDBRoles.CONFIG_SERVER) and rel_name == RelationNames.CLUSTER:
1147
1126
  logger.error("Charm is not a config-server, cannot integrate mongos")
@@ -1161,7 +1140,9 @@ class MongoDBOperator(OperatorProtocol, Object):
1161
1140
  self.build_local_tls_directory()
1162
1141
 
1163
1142
  # Push TLS files if necessary
1164
- self.tls_manager.push_tls_files_to_workload()
1143
+ for internal in [True, False]:
1144
+ self.tls_manager.push_tls_files_to_workload(internal)
1145
+
1165
1146
  self.ldap_manager.save_certificates(self.state.ldap.chain)
1166
1147
 
1167
1148
  # Update licenses
@@ -1379,3 +1360,19 @@ class MongoDBOperator(OperatorProtocol, Object):
1379
1360
  scope="app",
1380
1361
  component=self.name,
1381
1362
  )
1363
+
1364
+ def _should_skip_because_of_incomplete_tls(self) -> bool:
1365
+ """Checks if the update status hook needs skipping due to an incomplete TLS integration."""
1366
+ shard_has_peer_tls, config_server_has_peer_tls = (
1367
+ self.shard_manager.shard_and_config_server_peer_tls_status()
1368
+ )
1369
+ if config_server_has_peer_tls and not shard_has_peer_tls:
1370
+ logger.info("Shard is missing peer TLS.")
1371
+ return True
1372
+ shard_has_client_tls, config_server_has_client_tls = (
1373
+ self.shard_manager.shard_and_config_server_client_tls_status()
1374
+ )
1375
+ if config_server_has_client_tls and not shard_has_client_tls:
1376
+ logger.info("Shard is missing client TLS.")
1377
+ return True
1378
+ return False
@@ -46,6 +46,7 @@ from single_kernel_mongo.exceptions import (
46
46
  from single_kernel_mongo.lib.charms.data_platform_libs.v0.data_interfaces import (
47
47
  DatabaseProviderData,
48
48
  )
49
+ from single_kernel_mongo.lib.charms.operator_libs_linux.v0 import sysctl
49
50
  from single_kernel_mongo.managers.cluster import ClusterRequirer
50
51
  from single_kernel_mongo.managers.config import MongosConfigManager
51
52
  from single_kernel_mongo.managers.k8s import K8sManager
@@ -103,12 +104,7 @@ class MongosOperator(OperatorProtocol, Object):
103
104
  self.state,
104
105
  self.substrate,
105
106
  )
106
- self.tls_manager = TLSManager(
107
- self,
108
- self.workload,
109
- self.state,
110
- self.substrate,
111
- )
107
+ self.tls_manager = TLSManager(self, self.workload, self.state)
112
108
  self.cluster_manager = ClusterRequirer(
113
109
  self, self.workload, self.state, self.substrate, RelationNames.CLUSTER
114
110
  )
@@ -152,6 +148,7 @@ class MongosOperator(OperatorProtocol, Object):
152
148
  ExternalRequirerRelations.LDAP,
153
149
  ExternalRequirerRelations.LDAP_CERT,
154
150
  )
151
+ self.sysctl_config = sysctl.Config(name=self.charm.app.name)
155
152
 
156
153
  pod_name = self.model.unit.name.replace("/", "-")
157
154
  self.k8s = K8sManager(pod_name, self.model.name)
@@ -199,9 +196,10 @@ class MongosOperator(OperatorProtocol, Object):
199
196
  @property
200
197
  def components(self) -> tuple[ManagerStatusProtocol, ...]:
201
198
  """The ordered list of components for this operator."""
202
- return (self, self.ldap_manager, self.upgrades_status_manager)
199
+ return (self, self.tls_manager, self.ldap_manager, self.upgrades_status_manager)
203
200
 
204
201
  @property
202
+ @override
205
203
  def config(self) -> MongosCharmConfig:
206
204
  """Returns the actual config."""
207
205
  return self.charm.parsed_config
@@ -220,8 +218,8 @@ class MongosOperator(OperatorProtocol, Object):
220
218
  # Instantiate the local directory for k8s
221
219
  self.build_local_tls_directory()
222
220
 
223
- # Push certificates
224
- self.tls_manager.push_tls_files_to_workload()
221
+ for internal in [True, False]:
222
+ self.tls_manager.push_tls_files_to_workload(internal)
225
223
 
226
224
  # Save LDAP certificates
227
225
  self.ldap_manager.save_certificates(self.state.ldap.chain)
@@ -299,8 +297,7 @@ class MongosOperator(OperatorProtocol, Object):
299
297
  component=self.name,
300
298
  )
301
299
  self.update_k8s_external_services()
302
-
303
- self.tls_manager.update_tls_sans()
300
+ self.tls_events.refresh_certificates()
304
301
  self.share_connection_info()
305
302
 
306
303
  @override
@@ -343,7 +340,7 @@ class MongosOperator(OperatorProtocol, Object):
343
340
  # our SANS as necessary.
344
341
  # The connection info will be updated when we receive the new certificates.
345
342
  if self.substrate == Substrates.K8S:
346
- self.tls_manager.update_tls_sans()
343
+ self.tls_events.refresh_certificates()
347
344
 
348
345
  @override
349
346
  def new_peer(self) -> None:
@@ -388,11 +385,10 @@ class MongosOperator(OperatorProtocol, Object):
388
385
  self.mongos_config_manager.configure_and_restart(force=force)
389
386
  except WorkloadServiceError as e:
390
387
  logger.error("An exception occurred when starting mongos agent, error: %s.", str(e))
391
- self.charm.status_handler.set_running_status(
388
+ self.charm.state.statuses.add(
392
389
  MongosStatuses.WAITING_FOR_MONGOS_START.value,
393
390
  scope="unit",
394
- statuses_state=self.state.statuses,
395
- component_name=self.name,
391
+ component=self.name,
396
392
  )
397
393
  raise
398
394
 
@@ -577,8 +573,9 @@ class MongosOperator(OperatorProtocol, Object):
577
573
  )
578
574
  return False
579
575
 
580
- if status := self.cluster_manager.get_tls_statuses():
581
- logger.info(f"Invalid TLS integration: {status.message}")
576
+ if statuses := self.cluster_manager.tls_statuses():
577
+ for status in statuses:
578
+ logger.info(f"Invalid TLS integration: {status.message}")
582
579
  return False
583
580
 
584
581
  if not self.is_mongos_running():
@@ -616,10 +613,11 @@ class MongosOperator(OperatorProtocol, Object):
616
613
  # don't bother checking remaining statuses if no config-server is present
617
614
  return charm_statuses
618
615
 
619
- if status := self.cluster_manager.get_tls_statuses():
620
- logger.info(f"Invalid TLS integration: {status.message}")
616
+ if statuses := self.cluster_manager.tls_statuses():
617
+ for status in statuses:
618
+ logger.info(f"Invalid TLS integration: {status.message}")
621
619
  # if TLS is misconfigured we will get redherrings on the remaining messages
622
- charm_statuses.append(status)
620
+ charm_statuses += statuses
623
621
  return charm_statuses
624
622
 
625
623
  if self.state.mongos_cluster_relation and not self.state.cluster.config_server_uri: