Skip to content

Commit

Permalink
Merge pull request #40 from canonical/DPE-5645-update-libs
Browse files Browse the repository at this point in the history
[DPE-5645] update mongo* libs
  • Loading branch information
MiaAltieri authored Oct 8, 2024
2 parents 06d4443 + 280d0b6 commit 14cbfa5
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 49 deletions.
37 changes: 28 additions & 9 deletions lib/charms/mongodb/v0/config_server_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@

from charms.data_platform_libs.v0.data_interfaces import (
DatabaseProvides,
DatabaseRequestedEvent,
DatabaseRequires,
)
from charms.mongodb.v1.mongos import MongosConnection
from ops.charm import CharmBase, EventBase, RelationBrokenEvent
from ops.charm import CharmBase, EventBase, RelationBrokenEvent, RelationChangedEvent
from ops.framework import Object
from ops.model import (
ActiveStatus,
Expand Down Expand Up @@ -42,7 +43,7 @@

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 11
LIBPATCH = 13


class ClusterProvider(Object):
Expand All @@ -57,6 +58,9 @@ def __init__(
self.database_provides = DatabaseProvides(self.charm, relation_name=self.relation_name)

super().__init__(charm, self.relation_name)
self.framework.observe(
self.database_provides.on.database_requested, self._on_database_requested
)
self.framework.observe(
charm.on[self.relation_name].relation_changed, self._on_relation_changed
)
Expand Down Expand Up @@ -105,8 +109,14 @@ def is_valid_mongos_integration(self) -> bool:

return True

def _on_relation_changed(self, event) -> None:
"""Handles providing mongos with KeyFile and hosts."""
def _on_database_requested(self, event: DatabaseRequestedEvent | RelationChangedEvent) -> None:
"""Handles the database requested event.
The first time secrets are written to relations should be on this event.
Note: If secrets are written for the first time on other events we risk
the chance of writing secrets in plain sight.
"""
if not self.pass_hook_checks(event):
if not self.is_valid_mongos_integration():
self.charm.status.set_and_share_status(
Expand All @@ -116,12 +126,9 @@ def _on_relation_changed(self, event) -> None:
)
logger.info("Skipping relation joined event: hook checks did not pass")
return

config_server_db = self.generate_config_server_db()

# create user and set secrets for mongos relation
self.charm.client_relations.oversee_users(None, None)

relation_data = {
KEYFILE_KEY: self.charm.get_secret(
Config.Relations.APP_SCOPE, Config.Secrets.SECRET_KEYFILE_NAME
Expand All @@ -135,9 +142,20 @@ def _on_relation_changed(self, event) -> None:
)
if int_tls_ca:
relation_data[INT_TLS_CA_KEY] = int_tls_ca

self.database_provides.update_relation_data(event.relation.id, relation_data)

def _on_relation_changed(self, event: RelationChangedEvent) -> None:
"""Handles providing mongos with KeyFile and hosts."""
# First we need to ensure that the database requested event has run
# otherwise we risk the chance of writing secrets in plain sight.
if not self.database_provides.fetch_relation_field(event.relation.id, "database"):
logger.info("Database Requested has not run yet, skipping.")
event.defer()
return

# TODO : This workflow is a fix until we have time for a better and complete fix (DPE-5513)
self._on_database_requested(event)

def _on_relation_broken(self, event) -> None:
if self.charm.upgrade_in_progress:
logger.warning(
Expand Down Expand Up @@ -300,7 +318,8 @@ def _on_relation_changed(self, event) -> None:
return

self.charm.status.set_and_share_status(ActiveStatus())
self.charm.mongos_intialised = True
if self.charm.unit.is_leader():
self.charm.mongos_initialised = True

def _on_relation_broken(self, event: RelationBrokenEvent) -> None:
# Only relation_deparated events can check if scaling down
Expand Down
10 changes: 8 additions & 2 deletions lib/charms/mongodb/v0/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class NotReadyError(PyMongoError):

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1
LIBPATCH = 2

ADMIN_AUTH_SOURCE = "authSource=admin"
SYSTEM_DBS = ("admin", "local", "config")
Expand All @@ -40,6 +40,7 @@ class NotReadyError(PyMongoError):
{"role": "userAdminAnyDatabase", "db": "admin"},
{"role": "readWriteAnyDatabase", "db": "admin"},
{"role": "userAdmin", "db": "admin"},
{"role": "enableSharding", "db": "admin"},
],
"monitor": [
{"role": "explainRole", "db": "admin"},
Expand Down Expand Up @@ -127,7 +128,12 @@ def uri(self):

def supported_roles(config: MongoConfiguration):
"""Return the supported roles for the given configuration."""
return REGULAR_ROLES | {"default": [{"db": config.database, "role": "readWrite"}]}
return REGULAR_ROLES | {
"default": [
{"db": config.database, "role": "readWrite"},
{"db": config.database, "role": "enableSharding"},
]
}


class MongoConnection:
Expand Down
32 changes: 27 additions & 5 deletions lib/charms/mongodb/v1/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import secrets
import string
import subprocess
from typing import List
from typing import List, Mapping

from charms.mongodb.v1.mongodb import MongoConfiguration
from ops.model import ActiveStatus, MaintenanceStatus, StatusBase, WaitingStatus
Expand All @@ -23,7 +23,7 @@

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 8
LIBPATCH = 12

# path to store mongodb ketFile
KEY_FILE = "keyFile"
Expand Down Expand Up @@ -89,7 +89,7 @@ def get_create_user_cmd(config: MongoConfiguration, mongo_path=MONGO_SHELL) -> L
"mongodb://localhost/admin",
"--quiet",
"--eval",
"db.createUser({"
'"db.createUser({'
f" user: '{config.username}',"
" pwd: passwordPrompt(),"
" roles:["
Expand All @@ -99,7 +99,7 @@ def get_create_user_cmd(config: MongoConfiguration, mongo_path=MONGO_SHELL) -> L
" ],"
" mechanisms: ['SCRAM-SHA-256'],"
" passwordDigestor: 'server',"
"})",
'})"',
]


Expand All @@ -118,7 +118,7 @@ def get_mongos_args(
binding_ips = (
"--bind_ip_all"
if external_connectivity
else f"--bind_ip {MONGODB_COMMON_DIR}/var/mongodb-27018.sock"
else f"--bind_ip {MONGODB_COMMON_DIR}/var/mongodb-27018.sock --filePermissions 0766"
)

# mongos running on the config server communicates through localhost
Expand Down Expand Up @@ -320,3 +320,25 @@ def add_args_to_env(var: str, args: str):

with open(Config.ENV_VAR_PATH, "w") as service_file:
service_file.writelines(env_vars)


def safe_exec(
command: list[str] | str,
env: Mapping[str, str] | None = None,
working_dir: str | None = None,
) -> str:
"""Execs a command on the workload in a safe way."""
try:
output = subprocess.check_output(
command,
stderr=subprocess.PIPE,
universal_newlines=True,
shell=isinstance(command, str),
env=env,
cwd=working_dir,
)
logger.debug(f"{output=}")
return output
except subprocess.CalledProcessError as err:
logger.error(f"cmd failed - {err.cmd}, {err.stdout}, {err.stderr}")
raise
Loading

0 comments on commit 14cbfa5

Please sign in to comment.