mongo-charms-single-kernel 1.8.8__tar.gz → 1.8.9__tar.gz
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 → mongo_charms_single_kernel-1.8.9}/PKG-INFO +1 -1
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/pyproject.toml +2 -8
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/config/literals.py +7 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/config/relations.py +2 -1
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/config/statuses.py +127 -20
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/operator.py +7 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/structured_config.py +2 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/workload.py +10 -4
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/cluster.py +5 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/sharding.py +3 -1
- mongo_charms_single_kernel-1.8.9/single_kernel_mongo/events/tls.py +242 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/exceptions.py +0 -8
- mongo_charms_single_kernel-1.8.9/single_kernel_mongo/lib/charms/tls_certificates_interface/v4/tls_certificates.py +1995 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/cluster.py +70 -28
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/config.py +14 -8
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/mongo.py +1 -1
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/mongodb_operator.py +44 -22
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/mongos_operator.py +16 -20
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/sharding.py +154 -127
- mongo_charms_single_kernel-1.8.9/single_kernel_mongo/managers/tls.py +413 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/charm_state.py +39 -16
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/cluster_state.py +8 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/config_server_state.py +9 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/tls_state.py +39 -12
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/helpers.py +4 -19
- mongo_charms_single_kernel-1.8.8/single_kernel_mongo/events/tls.py +0 -216
- mongo_charms_single_kernel-1.8.8/single_kernel_mongo/lib/charms/tls_certificates_interface/v3/tls_certificates.py +0 -2123
- mongo_charms_single_kernel-1.8.8/single_kernel_mongo/managers/tls.py +0 -396
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/LICENSE +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/README.md +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/abstract_charm.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/config/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/config/models.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/abstract_upgrades_v3.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/k8s_workload.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/kubernetes_upgrades_v3.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/machine_upgrades_v3.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/secrets.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/version_checker.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/core/vm_workload.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/backups.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/database.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/ldap.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/lifecycle.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/events/primary_action.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/certificate_transfer_interface/v0/certificate_transfer.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/data_platform_libs/v0/data_interfaces.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/data_platform_libs/v0/s3.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/glauth_k8s/v0/ldap.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/grafana_agent/v0/cos_agent.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/grafana_k8s/v0/grafana_dashboard.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/loki_k8s/v0/loki_push_api.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/operator_libs_linux/v0/sysctl.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/operator_libs_linux/v1/systemd.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/operator_libs_linux/v2/snap.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/lib/charms/prometheus_k8s/v0/prometheus_scrape.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/backups.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/k8s.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/ldap.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/observability.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/upgrade_v3.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/managers/upgrade_v3_status.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/observability_rules/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/observability_rules/grafana_dashboards/MongoDB_Cluster_Summary.json +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/observability_rules/grafana_dashboards/MongoDB_ReplSet_Summary.json +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/observability_rules/k8s_prometheus_alert_rules/percona-mongodb-exporter.rule +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/observability_rules/loki/.gitkeep +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/observability_rules/vm_prometheus_alert_rules/percona-mongodb-exporter.yml +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/abstract_state.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/app_peer_state.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/ldap_state.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/models.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/state/unit_peer_state.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/templates/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/templates/enable-transparent-huge-pages.service.j2 +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/templates/ldap.conf.j2 +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/templates/logrotate.j2 +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/event_helpers.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/mongo_config.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/mongo_connection.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/mongo_error_codes.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/utils/mongodb_users.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/workload/__init__.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/workload/backup_workload.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/workload/log_rotate_workload.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/workload/mongodb_workload.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/workload/mongos_workload.py +0 -0
- {mongo_charms_single_kernel-1.8.8 → mongo_charms_single_kernel-1.8.9}/single_kernel_mongo/workload/monitor_workload.py +0 -0
|
@@ -38,9 +38,9 @@ dependencies = [
|
|
|
38
38
|
"boto3 (~=1.37.12)",
|
|
39
39
|
"mypy-boto3-s3 (~=1.37.0)",
|
|
40
40
|
"python-ldap",
|
|
41
|
-
"charm-refresh (>=3.1.0.2,<4.0.0.0)"
|
|
41
|
+
"charm-refresh (>=3.1.0.2,<4.0.0.0)"
|
|
42
42
|
]
|
|
43
|
-
version = "1.8.
|
|
43
|
+
version = "1.8.9"
|
|
44
44
|
|
|
45
45
|
[project.urls]
|
|
46
46
|
homepage = "https://github.com/canonical/mongo-single-kernel-library"
|
|
@@ -137,12 +137,6 @@ httpx = "*"
|
|
|
137
137
|
boto3 = "^1.37.12"
|
|
138
138
|
mypy-boto3-s3 = "^1.37.0"
|
|
139
139
|
|
|
140
|
-
[tool.poetry.group.build-refresh-version]
|
|
141
|
-
optional = true
|
|
142
|
-
|
|
143
|
-
[tool.poetry.group.build-refresh-version.dependencies]
|
|
144
|
-
charm-refresh-build-version = "^0.4.0"
|
|
145
|
-
|
|
146
140
|
[tool.ruff]
|
|
147
141
|
target-version = "py310"
|
|
148
142
|
line-length = 100
|
|
@@ -35,7 +35,8 @@ class Scopes(str, Enum):
|
|
|
35
35
|
class ExternalRequirerRelations(str, Enum):
|
|
36
36
|
"""The relations we require externally."""
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
CLIENT_TLS = "client-certificates"
|
|
39
|
+
PEER_TLS = "peer-certificates"
|
|
39
40
|
S3_CREDENTIALS = "s3-credentials"
|
|
40
41
|
LDAP = "ldap"
|
|
41
42
|
LDAP_CERT = "ldap-certificate-transfer"
|
|
@@ -118,24 +118,45 @@ class MongosStatuses(Enum):
|
|
|
118
118
|
check="Config validation failed.",
|
|
119
119
|
action="Set the expose-external config to a valid value: `nodeport` or `none`.",
|
|
120
120
|
)
|
|
121
|
-
|
|
121
|
+
MISSING_PEER_TLS_REL = StatusObject(
|
|
122
122
|
status="blocked",
|
|
123
|
-
message="TLS must be enabled in mongos, since it is enabled on the config-server in the cluster relation.",
|
|
124
|
-
short_message="Missing certificates relation.",
|
|
123
|
+
message="Peer TLS must be enabled in mongos, since it is enabled on the config-server in the cluster relation.",
|
|
124
|
+
short_message="Missing peer-certificates relation.",
|
|
125
125
|
check="Relation validation failed.",
|
|
126
|
-
action="Add the certificates relation
|
|
126
|
+
action="Add the peer-certificates relation to mongos.",
|
|
127
127
|
)
|
|
128
|
-
|
|
128
|
+
INVALID_PEER_TLS_REL = StatusObject(
|
|
129
129
|
status="blocked",
|
|
130
|
-
message="TLS must be disabled in mongos, since it is disabled on the config-server in the cluster relation.",
|
|
131
|
-
short_message="Invalid certificates relation.",
|
|
130
|
+
message="Peer TLS must be disabled in mongos, since it is disabled on the config-server in the cluster relation.",
|
|
131
|
+
short_message="Invalid peer-certificates relation.",
|
|
132
132
|
check="Relation validation failed.",
|
|
133
|
-
action="Remove the certificates relation
|
|
133
|
+
action="Remove the peer-certificates relation from this application.",
|
|
134
134
|
)
|
|
135
|
-
|
|
135
|
+
MISSING_CLIENT_TLS_REL = StatusObject(
|
|
136
136
|
status="blocked",
|
|
137
|
-
message="
|
|
138
|
-
short_message="
|
|
137
|
+
message="Client TLS must be enabled in mongos, since it is enabled on the config-server in the cluster relation.",
|
|
138
|
+
short_message="Missing client-certificates relation.",
|
|
139
|
+
check="Relation validation failed.",
|
|
140
|
+
action="Add the client-certificates relation to mongos.",
|
|
141
|
+
)
|
|
142
|
+
INVALID_CLIENT_TLS_REL = StatusObject(
|
|
143
|
+
status="blocked",
|
|
144
|
+
message="Client TLS must be disabled in mongos, since it is disabled on the config-server in the cluster relation.",
|
|
145
|
+
short_message="Invalid client-certificates relation.",
|
|
146
|
+
check="Relation validation failed.",
|
|
147
|
+
action="Remove the client-certificates relation from this application.",
|
|
148
|
+
)
|
|
149
|
+
PEER_CA_MISMATCH = StatusObject(
|
|
150
|
+
status="blocked",
|
|
151
|
+
message="The mongos peer CA and Config-Server peer CA don't match.",
|
|
152
|
+
short_message="Peer CA mismatch.",
|
|
153
|
+
check="Relation validation failed.",
|
|
154
|
+
action="Verify the certificates relations. Use the same CA for all cluster components.",
|
|
155
|
+
)
|
|
156
|
+
CLIENT_CA_MISMATCH = StatusObject(
|
|
157
|
+
status="blocked",
|
|
158
|
+
message="The mongos client CA and Config-Server client CA don't match.",
|
|
159
|
+
short_message="Client CA mismatch.",
|
|
139
160
|
check="Relation validation failed.",
|
|
140
161
|
action="Verify the certificates relations. Use the same CA for all cluster components.",
|
|
141
162
|
)
|
|
@@ -153,6 +174,27 @@ class MongosStatuses(Enum):
|
|
|
153
174
|
status="maintenance", message="Starting mongos.", running="blocking"
|
|
154
175
|
)
|
|
155
176
|
|
|
177
|
+
@classmethod
|
|
178
|
+
def missing_tls(cls, internal: bool) -> StatusObject:
|
|
179
|
+
"""Correct status."""
|
|
180
|
+
if internal:
|
|
181
|
+
return cls.MISSING_PEER_TLS_REL.value
|
|
182
|
+
return cls.MISSING_CLIENT_TLS_REL.value
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def invalid_tls(cls, internal: bool) -> StatusObject:
|
|
186
|
+
"""Correct status."""
|
|
187
|
+
if internal:
|
|
188
|
+
return cls.INVALID_PEER_TLS_REL.value
|
|
189
|
+
return cls.INVALID_CLIENT_TLS_REL.value
|
|
190
|
+
|
|
191
|
+
@classmethod
|
|
192
|
+
def incompatible_ca(cls, internal: bool) -> StatusObject:
|
|
193
|
+
"""Correct status."""
|
|
194
|
+
if internal:
|
|
195
|
+
return cls.PEER_CA_MISMATCH.value
|
|
196
|
+
return cls.CLIENT_CA_MISMATCH.value
|
|
197
|
+
|
|
156
198
|
|
|
157
199
|
class CharmStatuses(Enum):
|
|
158
200
|
"""Charm Statuses."""
|
|
@@ -182,11 +224,28 @@ class CharmStatuses(Enum):
|
|
|
182
224
|
class TLSStatuses(Enum):
|
|
183
225
|
"""TLS statuses."""
|
|
184
226
|
|
|
185
|
-
|
|
186
|
-
|
|
227
|
+
INVALID_PEER_PRIVATE_KEY = StatusObject(
|
|
228
|
+
status="blocked",
|
|
229
|
+
message="Invalid peer private key",
|
|
230
|
+
check="Peer private key format validation failed",
|
|
231
|
+
action="Update the peer private key secret.",
|
|
232
|
+
)
|
|
233
|
+
INVALID_CLIENT_PRIVATE_KEY = StatusObject(
|
|
234
|
+
status="blocked",
|
|
235
|
+
message="Invalid client private key",
|
|
236
|
+
check="Client private key format validation failed.",
|
|
237
|
+
action="Update the client privatekey secret.",
|
|
238
|
+
)
|
|
239
|
+
DISABLING_PEER_TLS = StatusObject(
|
|
187
240
|
status="maintenance",
|
|
188
|
-
message="Disabling TLS...",
|
|
189
|
-
check="
|
|
241
|
+
message="Disabling peer TLS...",
|
|
242
|
+
check="Peer certificates relation (tls-certificates interface) removed.",
|
|
243
|
+
running="blocking",
|
|
244
|
+
)
|
|
245
|
+
DISABLING_CLIENT_TLS = StatusObject(
|
|
246
|
+
status="maintenance",
|
|
247
|
+
message="Disabling client TLS...",
|
|
248
|
+
check="Client certificates relation (tls-certificates interface) removed.",
|
|
190
249
|
running="blocking",
|
|
191
250
|
)
|
|
192
251
|
# Enabling TLS takes a while because we wait for multiple certs so it's
|
|
@@ -343,12 +402,39 @@ class ConfigServerStatuses(Enum):
|
|
|
343
402
|
class ShardStatuses(Enum):
|
|
344
403
|
"""Shard statuses."""
|
|
345
404
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
status="blocked", message="Shard has TLS enabled, but config-server does not."
|
|
405
|
+
MISSING_PEER_TLS_REL = StatusObject(
|
|
406
|
+
status="blocked", message="Shard requires peer TLS to be enabled."
|
|
349
407
|
)
|
|
350
|
-
|
|
351
|
-
status="blocked",
|
|
408
|
+
INVALID_PEER_TLS_REL = StatusObject(
|
|
409
|
+
status="blocked",
|
|
410
|
+
message="Peer TLS must be disabled in shard, since it is disabled in the related config-server.",
|
|
411
|
+
short_message="Invalid peer-certificates relation.",
|
|
412
|
+
check="Relation validation failed.",
|
|
413
|
+
action="Align the peer TLS configuration in all the cluster components: remove the peer-certificates relation from the shard.",
|
|
414
|
+
)
|
|
415
|
+
MISSING_CLIENT_TLS_REL = StatusObject(
|
|
416
|
+
status="blocked", message="Shard requires client TLS to be enabled."
|
|
417
|
+
)
|
|
418
|
+
INVALID_CLIENT_TLS_REL = StatusObject(
|
|
419
|
+
status="blocked",
|
|
420
|
+
message="Peer TLS must be disabled in shard, since it is disabled in the related config-server.",
|
|
421
|
+
short_message="Invalid client-certificates relation.",
|
|
422
|
+
check="Relation validation failed.",
|
|
423
|
+
action="Align the peer TLS configuration in all the cluster components: remove the client-certificates relation from the shard.",
|
|
424
|
+
)
|
|
425
|
+
PEER_CA_MISMATCH = StatusObject(
|
|
426
|
+
status="blocked",
|
|
427
|
+
message="Shard internal CA and Config-Server internal CA don't match.",
|
|
428
|
+
short_message="Peer CA mismatch.",
|
|
429
|
+
check="Relation validation failed.",
|
|
430
|
+
action="Verify the peer-certificates relations. Use the same CA for all cluster components.",
|
|
431
|
+
)
|
|
432
|
+
CLIENT_CA_MISMATCH = StatusObject(
|
|
433
|
+
status="blocked",
|
|
434
|
+
message="Shard client CA and Config-Server client CA don't match.",
|
|
435
|
+
short_message="Client CA mismatch.",
|
|
436
|
+
check="Relation validation failed.",
|
|
437
|
+
action="Verify the client-certificates relations. Use the same CA for all cluster components.",
|
|
352
438
|
)
|
|
353
439
|
|
|
354
440
|
MISSING_CONF_SERVER_REL = StatusObject(
|
|
@@ -399,6 +485,27 @@ class ShardStatuses(Enum):
|
|
|
399
485
|
message=f"Charm revision ({current_charms_version}{local_identifier}) is not up-to date with config-server.",
|
|
400
486
|
)
|
|
401
487
|
|
|
488
|
+
@classmethod
|
|
489
|
+
def missing_tls(cls, internal: bool) -> StatusObject:
|
|
490
|
+
"""Correct status."""
|
|
491
|
+
if internal:
|
|
492
|
+
return cls.MISSING_PEER_TLS_REL.value
|
|
493
|
+
return cls.MISSING_CLIENT_TLS_REL.value
|
|
494
|
+
|
|
495
|
+
@classmethod
|
|
496
|
+
def invalid_tls(cls, internal: bool) -> StatusObject:
|
|
497
|
+
"""Correct status."""
|
|
498
|
+
if internal:
|
|
499
|
+
return cls.INVALID_PEER_TLS_REL.value
|
|
500
|
+
return cls.INVALID_CLIENT_TLS_REL.value
|
|
501
|
+
|
|
502
|
+
@classmethod
|
|
503
|
+
def incompatible_ca(cls, internal: bool) -> StatusObject:
|
|
504
|
+
"""Correct status."""
|
|
505
|
+
if internal:
|
|
506
|
+
return cls.PEER_CA_MISMATCH.value
|
|
507
|
+
return cls.CLIENT_CA_MISMATCH.value
|
|
508
|
+
|
|
402
509
|
|
|
403
510
|
class MongodStatuses(Enum):
|
|
404
511
|
"""MongoD statuses."""
|
|
@@ -37,6 +37,7 @@ from single_kernel_mongo.config.literals import (
|
|
|
37
37
|
TrustStoreFiles,
|
|
38
38
|
)
|
|
39
39
|
from single_kernel_mongo.config.models import SNAP_NAME, THP_CONFIG, CharmSpec, LogRotateConfig
|
|
40
|
+
from single_kernel_mongo.core.structured_config import MongoConfigModel
|
|
40
41
|
from single_kernel_mongo.events.ldap import LDAPEventHandler
|
|
41
42
|
from single_kernel_mongo.exceptions import (
|
|
42
43
|
DeferrableFailedHookChecksError,
|
|
@@ -106,6 +107,12 @@ class OperatorProtocol(ABC, Object, ManagerStatusProtocol):
|
|
|
106
107
|
|
|
107
108
|
def __init__(self, dependent: AbstractMongoCharm): ...
|
|
108
109
|
|
|
110
|
+
@property
|
|
111
|
+
@abstractmethod
|
|
112
|
+
def config(self) -> MongoConfigModel:
|
|
113
|
+
"""The pydantic model of the config."""
|
|
114
|
+
...
|
|
115
|
+
|
|
109
116
|
@property
|
|
110
117
|
@abstractmethod
|
|
111
118
|
def components(self) -> tuple[ManagerStatusProtocol, ...]:
|
|
@@ -100,6 +100,8 @@ class MongoConfigModel(BaseConfigModel):
|
|
|
100
100
|
role: SerializeLiteralAsStr[MongoDBRoles]
|
|
101
101
|
ldap_user_to_dn_mapping: str | None = Field(default=None, alias="ldap-user-to-dn-mapping")
|
|
102
102
|
ldap_query_template: str | None = Field(default=None, alias="ldap-query-template")
|
|
103
|
+
tls_peer_private_key_id: str | None = Field(default=None, alias="tls-peer-private-key")
|
|
104
|
+
tls_client_private_key_id: str | None = Field(default=None, alias="tls-client-private-key")
|
|
103
105
|
|
|
104
106
|
@field_validator("expose_external", mode="before")
|
|
105
107
|
@classmethod
|
|
@@ -93,15 +93,21 @@ class MongoPaths:
|
|
|
93
93
|
return Path(f"{self.conf_path}/internal-ca.crt")
|
|
94
94
|
|
|
95
95
|
@property
|
|
96
|
-
def
|
|
97
|
-
"""Set of
|
|
96
|
+
def tls_peer_files(self) -> set[Path]:
|
|
97
|
+
"""Set of peer TLS files."""
|
|
98
98
|
return {
|
|
99
|
-
self.ext_pem_file,
|
|
100
|
-
self.ext_ca_file,
|
|
101
99
|
self.int_pem_file,
|
|
102
100
|
self.int_ca_file,
|
|
103
101
|
}
|
|
104
102
|
|
|
103
|
+
@property
|
|
104
|
+
def tls_client_files(self) -> set[Path]:
|
|
105
|
+
"""Set of client TLS files."""
|
|
106
|
+
return {
|
|
107
|
+
self.ext_pem_file,
|
|
108
|
+
self.ext_ca_file,
|
|
109
|
+
}
|
|
110
|
+
|
|
105
111
|
@property
|
|
106
112
|
def ldap_path(self) -> Path:
|
|
107
113
|
"""The LDAP conf path."""
|
|
@@ -136,6 +136,11 @@ class ClusterMongosEventHandler(Object):
|
|
|
136
136
|
def _on_relation_created(self, event: RelationCreatedEvent) -> None:
|
|
137
137
|
"""Relation created event handler."""
|
|
138
138
|
self.manager.set_relation_created_status()
|
|
139
|
+
# Edge condition: mongos was integrated with the certificates provider
|
|
140
|
+
# before being integrated with the config-server. We trigger the refresh
|
|
141
|
+
# of the certificates to use the config-server as CSR subject.
|
|
142
|
+
if self.manager.state.peer_tls_relation or self.manager.state.client_tls_relation:
|
|
143
|
+
self.dependent.tls_events.refresh_certificates()
|
|
139
144
|
|
|
140
145
|
def _on_database_created(self, event: DatabaseCreatedEvent) -> None:
|
|
141
146
|
"""Database Created event handler.
|
|
@@ -162,8 +162,10 @@ class ShardEventHandler(Object):
|
|
|
162
162
|
"""SecretChanged event handler, which is used to propagate the updated passwords."""
|
|
163
163
|
try:
|
|
164
164
|
self.manager.handle_secret_changed(event.secret.label or "")
|
|
165
|
-
except (NotReadyError, FailedToUpdateCredentialsError):
|
|
165
|
+
except (NotReadyError, FailedToUpdateCredentialsError, DeferrableFailedHookChecksError):
|
|
166
166
|
event.defer()
|
|
167
|
+
except NonDeferrableFailedHookChecksError as e:
|
|
168
|
+
logger.info(f"Skipping {str(type(event))}: {str(e)}")
|
|
167
169
|
except WaitingForSecretsError:
|
|
168
170
|
logger.info("Missing secrets, ignoring")
|
|
169
171
|
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright 2024 Canonical Ltd.
|
|
3
|
+
# See LICENSE file for licensing details.
|
|
4
|
+
|
|
5
|
+
"""Manager for handling TLS events."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from ops import ConfigChangedEvent
|
|
13
|
+
from ops.charm import RelationBrokenEvent, RelationCreatedEvent
|
|
14
|
+
from ops.framework import EventBase, EventSource, Object
|
|
15
|
+
|
|
16
|
+
from single_kernel_mongo.config.literals import CharmKind, TLSType
|
|
17
|
+
from single_kernel_mongo.config.relations import ExternalRequirerRelations
|
|
18
|
+
from single_kernel_mongo.config.statuses import (
|
|
19
|
+
MongosStatuses,
|
|
20
|
+
ShardStatuses,
|
|
21
|
+
TLSStatuses,
|
|
22
|
+
)
|
|
23
|
+
from single_kernel_mongo.core.structured_config import MongoDBRoles
|
|
24
|
+
from single_kernel_mongo.exceptions import DeferrableFailedHookChecksError
|
|
25
|
+
from single_kernel_mongo.lib.charms.tls_certificates_interface.v4.tls_certificates import (
|
|
26
|
+
CertificateAvailableEvent,
|
|
27
|
+
TLSCertificatesRequiresV4,
|
|
28
|
+
)
|
|
29
|
+
from single_kernel_mongo.state.tls_state import TlsManagementState
|
|
30
|
+
from single_kernel_mongo.utils.event_helpers import defer_event_with_info_log
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from single_kernel_mongo.abstract_charm import AbstractMongoCharm
|
|
34
|
+
from single_kernel_mongo.core.operator import OperatorProtocol
|
|
35
|
+
|
|
36
|
+
logger = logging.getLogger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class RefreshTLSCertificatesEvent(EventBase):
|
|
40
|
+
"""Event for refreshing TLS certificates."""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TLSEventsHandler(Object):
|
|
44
|
+
"""Event Handler for managing TLS events."""
|
|
45
|
+
|
|
46
|
+
refresh_tls_certificates_event = EventSource(RefreshTLSCertificatesEvent)
|
|
47
|
+
|
|
48
|
+
def __init__(self, dependent: OperatorProtocol):
|
|
49
|
+
super().__init__(parent=dependent, key="tls")
|
|
50
|
+
self.dependent = dependent
|
|
51
|
+
self.manager = self.dependent.tls_manager
|
|
52
|
+
self.charm: AbstractMongoCharm = dependent.charm
|
|
53
|
+
|
|
54
|
+
self.peer_certificate = TLSCertificatesRequiresV4(
|
|
55
|
+
charm=self.charm,
|
|
56
|
+
relationship_name=ExternalRequirerRelations.PEER_TLS.value,
|
|
57
|
+
certificate_requests=[self.manager.get_certificate_request_attributes()],
|
|
58
|
+
private_key=self.manager.state.tls.peer_private_key,
|
|
59
|
+
refresh_events=[self.refresh_tls_certificates_event],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
self.client_certificate = TLSCertificatesRequiresV4(
|
|
63
|
+
charm=self.charm,
|
|
64
|
+
relationship_name=ExternalRequirerRelations.CLIENT_TLS.value,
|
|
65
|
+
certificate_requests=[self.manager.get_certificate_request_attributes()],
|
|
66
|
+
private_key=self.manager.state.tls.client_private_key,
|
|
67
|
+
refresh_events=[self.refresh_tls_certificates_event],
|
|
68
|
+
)
|
|
69
|
+
for cert_requires in [self.peer_certificate, self.client_certificate]:
|
|
70
|
+
self.framework.observe(
|
|
71
|
+
cert_requires.on.certificate_available, self._on_certificate_available
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
for relation_name in [
|
|
75
|
+
ExternalRequirerRelations.PEER_TLS.value,
|
|
76
|
+
ExternalRequirerRelations.CLIENT_TLS.value,
|
|
77
|
+
]:
|
|
78
|
+
self.framework.observe(
|
|
79
|
+
self.charm.on[relation_name].relation_created,
|
|
80
|
+
self._on_tls_relation_created,
|
|
81
|
+
)
|
|
82
|
+
self.framework.observe(
|
|
83
|
+
self.charm.on[relation_name].relation_broken,
|
|
84
|
+
self._on_tls_relation_broken,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
self.framework.observe(self.charm.on.config_changed, self._on_config_changed)
|
|
88
|
+
self.framework.observe(self.charm.on.secret_changed, self._on_secret_changed)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def tls_mapping(self) -> dict[bool, TLSCertificatesRequiresV4]:
|
|
92
|
+
"""Mapping of boolean to a TLS requirer instance.
|
|
93
|
+
|
|
94
|
+
The boolean value is True if the requirer is for internal certificates,
|
|
95
|
+
and False for the client certificates.
|
|
96
|
+
"""
|
|
97
|
+
return {True: self.peer_certificate, False: self.client_certificate}
|
|
98
|
+
|
|
99
|
+
def _on_tls_relation_created(self, event: RelationCreatedEvent) -> None:
|
|
100
|
+
"""Handler for relation created."""
|
|
101
|
+
if self.manager.state.is_role(MongoDBRoles.MONGOS):
|
|
102
|
+
self.manager.state.statuses.delete(
|
|
103
|
+
MongosStatuses.MISSING_PEER_TLS_REL.value,
|
|
104
|
+
scope="unit",
|
|
105
|
+
component=self.dependent.name,
|
|
106
|
+
)
|
|
107
|
+
self.manager.state.statuses.delete(
|
|
108
|
+
MongosStatuses.MISSING_CLIENT_TLS_REL.value,
|
|
109
|
+
scope="unit",
|
|
110
|
+
component=self.dependent.name,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if self.manager.state.is_role(MongoDBRoles.SHARD):
|
|
114
|
+
self.manager.state.statuses.delete(
|
|
115
|
+
ShardStatuses.MISSING_PEER_TLS_REL.value,
|
|
116
|
+
scope="unit",
|
|
117
|
+
component=self.dependent.name,
|
|
118
|
+
)
|
|
119
|
+
self.manager.state.statuses.delete(
|
|
120
|
+
ShardStatuses.MISSING_CLIENT_TLS_REL.value,
|
|
121
|
+
scope="unit",
|
|
122
|
+
component=self.dependent.name,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def refresh_certificates(self) -> None:
|
|
126
|
+
"""Trigger refresh TLS certificates event."""
|
|
127
|
+
logger.info(f"Requesting refresh certificates for unit: {self.charm.unit.name}.")
|
|
128
|
+
self.refresh_tls_certificates_event.emit()
|
|
129
|
+
|
|
130
|
+
def _on_tls_relation_broken(self, event: RelationBrokenEvent) -> None:
|
|
131
|
+
"""Handle the relation broken event."""
|
|
132
|
+
state = self.manager.get_tls_management_state()
|
|
133
|
+
match state:
|
|
134
|
+
case TlsManagementState.UPGRADE_IN_PROGRESS:
|
|
135
|
+
defer_event_with_info_log(logger, event, str(type(event)), state.value)
|
|
136
|
+
return
|
|
137
|
+
case (
|
|
138
|
+
TlsManagementState.DB_NOT_INTIALIZED
|
|
139
|
+
| TlsManagementState.MONGOS_DB_NOT_INITIALIZED
|
|
140
|
+
):
|
|
141
|
+
logger.info("DB never initialised, removing the TLS relation.")
|
|
142
|
+
return
|
|
143
|
+
case _:
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
internal = event.relation.name == ExternalRequirerRelations.PEER_TLS.value
|
|
147
|
+
logger.debug(
|
|
148
|
+
f"Disabling {TLSType.PEER.value if internal else TLSType.CLIENT.value} TLS for unit: {self.charm.unit.name}"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
status = (
|
|
152
|
+
TLSStatuses.DISABLING_PEER_TLS.value
|
|
153
|
+
if internal
|
|
154
|
+
else TLSStatuses.DISABLING_CLIENT_TLS.value
|
|
155
|
+
)
|
|
156
|
+
self.charm.status_handler.set_running_status(status, scope="unit")
|
|
157
|
+
self.manager.disable_certificates_for_unit(internal)
|
|
158
|
+
# Recomputes the statuses for those components as the tls changes are impactful
|
|
159
|
+
self._recompute_statuses()
|
|
160
|
+
|
|
161
|
+
def _on_certificate_available(self, event: CertificateAvailableEvent) -> None:
|
|
162
|
+
"""Handler for the certificate available event.
|
|
163
|
+
|
|
164
|
+
This event is emitted by the TLS charm when a certificates is available.
|
|
165
|
+
"""
|
|
166
|
+
state = self.manager.get_tls_management_state()
|
|
167
|
+
match state:
|
|
168
|
+
case TlsManagementState.DB_NOT_INTIALIZED | TlsManagementState.UPGRADE_IN_PROGRESS:
|
|
169
|
+
defer_event_with_info_log(logger, event, str(type(event)), state.value)
|
|
170
|
+
return
|
|
171
|
+
case TlsManagementState.MONGOS_MISSING_CONFIG_SERVER:
|
|
172
|
+
logger.info(f"{state.value} Ignoring certificate.")
|
|
173
|
+
return
|
|
174
|
+
case _:
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
logger.info("Certificate available.")
|
|
178
|
+
|
|
179
|
+
cert = event.certificate
|
|
180
|
+
client_certificates, client_private_key = (
|
|
181
|
+
self.client_certificate.get_assigned_certificates()
|
|
182
|
+
)
|
|
183
|
+
peer_certificates, peer_private_key = self.peer_certificate.get_assigned_certificates()
|
|
184
|
+
|
|
185
|
+
if client_certificates and client_certificates[0].certificate == cert:
|
|
186
|
+
internal = False
|
|
187
|
+
provider_cert = client_certificates[0]
|
|
188
|
+
private_key = client_private_key.raw if client_private_key else None
|
|
189
|
+
elif peer_certificates and peer_certificates[0].certificate == cert:
|
|
190
|
+
internal = True
|
|
191
|
+
provider_cert = peer_certificates[0]
|
|
192
|
+
private_key = peer_private_key.raw if peer_private_key else None
|
|
193
|
+
else:
|
|
194
|
+
logger.error("Received certificate does not match any assigned certificates.")
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
logger.debug(
|
|
198
|
+
f"Received {TLSType.PEER.value if internal else TLSType.CLIENT.value} certificate."
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
self.manager.set_certificates(
|
|
202
|
+
secret_chain=[c.raw for c in provider_cert.chain],
|
|
203
|
+
certificate=provider_cert.certificate.raw,
|
|
204
|
+
csr=provider_cert.certificate_signing_request.raw,
|
|
205
|
+
ca=provider_cert.ca.raw,
|
|
206
|
+
private_key=private_key,
|
|
207
|
+
internal=internal,
|
|
208
|
+
)
|
|
209
|
+
if internal:
|
|
210
|
+
self.dependent.state.update_peer_ca_secrets(provider_cert.ca.raw)
|
|
211
|
+
else:
|
|
212
|
+
self.dependent.state.update_client_ca_secrets(provider_cert.ca.raw)
|
|
213
|
+
|
|
214
|
+
self.manager.enable_certificates_for_unit(internal)
|
|
215
|
+
self._recompute_statuses()
|
|
216
|
+
|
|
217
|
+
def _on_config_changed(self, event: ConfigChangedEvent) -> None:
|
|
218
|
+
"""On Config Changed, validate private keys and refresh certs if needed."""
|
|
219
|
+
try:
|
|
220
|
+
self.manager.update_private_keys()
|
|
221
|
+
except DeferrableFailedHookChecksError as e:
|
|
222
|
+
defer_event_with_info_log(logger, event, "set-private-key", f"{e}")
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
def _on_secret_changed(self, event: ConfigChangedEvent) -> None:
|
|
226
|
+
"""On Secret Changed, validate private keys and refresh certs if needed."""
|
|
227
|
+
try:
|
|
228
|
+
self.manager.update_private_keys()
|
|
229
|
+
except DeferrableFailedHookChecksError as e:
|
|
230
|
+
defer_event_with_info_log(logger, event, "set-private-key", f"{e}")
|
|
231
|
+
return
|
|
232
|
+
|
|
233
|
+
def _recompute_statuses(self):
|
|
234
|
+
"""Recomputes the statuses for those components as the tls changes are impactful."""
|
|
235
|
+
if self.dependent.name == CharmKind.MONGOD:
|
|
236
|
+
self.charm.status_handler._recompute_statuses_for_scope(
|
|
237
|
+
"unit", self.dependent.shard_manager
|
|
238
|
+
)
|
|
239
|
+
else:
|
|
240
|
+
self.charm.status_handler._recompute_statuses_for_scope("unit", self.dependent)
|
|
241
|
+
if self.charm.unit.is_leader():
|
|
242
|
+
self.charm.status_handler._recompute_statuses_for_scope("app", self.dependent)
|
|
@@ -134,14 +134,6 @@ class InvalidArgumentForActionError(Exception):
|
|
|
134
134
|
"""Raised when arguments for an action are invalid."""
|
|
135
135
|
|
|
136
136
|
|
|
137
|
-
class UnknownCertificateExpiringError(Exception):
|
|
138
|
-
"""Raised when an unknown certificate is expiring."""
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
class UnknownCertificateAvailableError(Exception):
|
|
142
|
-
"""Raised when an unknown certificate is available."""
|
|
143
|
-
|
|
144
|
-
|
|
145
137
|
class DatabaseRequestedHasNotRunYetError(Exception):
|
|
146
138
|
"""Raised when the database event has not run yet."""
|
|
147
139
|
|