Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DPE-2646] - POC Rotate password #261

Merged
merged 33 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ac24eed
charm can start as shard or config server
MiaAltieri Sep 13, 2023
f8ff8a1
mongos, shard, and config server all start without error
MiaAltieri Sep 14, 2023
9b64f31
use correct snap
MiaAltieri Sep 15, 2023
c167fad
Merge branch 'main' into start-shard-config-mongos
MiaAltieri Sep 15, 2023
11f3c65
fmt + lint
MiaAltieri Sep 15, 2023
4bf9d5f
update error processing
MiaAltieri Sep 15, 2023
e924c00
bump lib patch
MiaAltieri Sep 15, 2023
51a22ec
Merge branch 'main' into start-shard-config-mongos
MiaAltieri Sep 15, 2023
d1f0a0d
enable auth
MiaAltieri Sep 18, 2023
06af49a
mongos should be run on 0.0.0.0
MiaAltieri Sep 19, 2023
363db5f
addressing PR comments
MiaAltieri Sep 19, 2023
c4c0c27
Merge branch 'main' into start-shard-config-mongos
MiaAltieri Sep 19, 2023
ac78ed3
PR comments
MiaAltieri Sep 19, 2023
49cba1b
Merge branch 'main' into start-shard-config-mongos
MiaAltieri Sep 19, 2023
563f049
correct ip binding
MiaAltieri Sep 19, 2023
67964c7
Merge branch 'start-shard-config-mongos' into start-mongos-auth
MiaAltieri Sep 19, 2023
e8aaeb5
mongos and config server now start correctly, and mongos has auth ena…
MiaAltieri Sep 19, 2023
0598dde
cleaning up code
MiaAltieri Sep 19, 2023
7c64ce0
fix unit tests
MiaAltieri Sep 19, 2023
666f3dc
Merge branch '6/edge' into start-mongos-auth
MiaAltieri Sep 20, 2023
58d91fa
don't publish 6/edge changes to 5/edge
MiaAltieri Sep 20, 2023
80c8bf9
revert changes on init admin user
MiaAltieri Sep 20, 2023
02fcf7c
add new lib
MiaAltieri Sep 20, 2023
ff83789
set up basic relation structure
MiaAltieri Sep 20, 2023
426cff8
operator password and keyfile now shared from config server
MiaAltieri Sep 21, 2023
af99322
fixes + working with replicas now
MiaAltieri Sep 21, 2023
caef63d
add docstrings
MiaAltieri Sep 21, 2023
38b7b8f
unit, lint, fmt
MiaAltieri Sep 21, 2023
766a59b
simplify function for tox
MiaAltieri Sep 21, 2023
e6dff94
Merge branch '6/edge' into share-secrets
MiaAltieri Sep 21, 2023
a9f6cd6
personal nits
MiaAltieri Sep 21, 2023
baee949
rotate password
MiaAltieri Sep 22, 2023
a24c021
Merge branch '6/edge' into rotate-password
MiaAltieri Oct 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Testing high availability on a production cluster can be done with:
tox run -e ha-integration -- --model=<model_name>
```

Note if you'd like to test storage re-use in ha-testing, your storage must not be of the type `rootfs`. `rootfs` storage is tied to the machine lifecycle and does not stick around after unit removal. `rootfs` storage is used by default with `tox run -e ha-integration`. To test ha-testing for storage re-use:
Note if you'd like to test storage reuse in ha-testing, your storage must not be of the type `rootfs`. `rootfs` storage is tied to the machine lifecycle and does not stick around after unit removal. `rootfs` storage is used by default with `tox run -e ha-integration`. To test ha-testing for storage reuse:
```shell
juju create-storage-pool mongodb-ebs ebs volume-type=standard # create a storage pool
juju deploy ./*charm --storage mongodb=mongodb-ebs,7G,1 # deploy 1 or more units of application with said storage pool
Expand Down
2 changes: 1 addition & 1 deletion lib/charms/mongodb/v0/mongodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def create_role(self, role_name: str, privileges: dict, roles: dict = []):

Args:
role_name: name of the role to be added.
privileges: privledges to be associated with the role.
privileges: privileges to be associated with the role.
roles: List of roles from which this role inherits privileges.
"""
try:
Expand Down
4 changes: 2 additions & 2 deletions lib/charms/mongodb/v0/mongodb_backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ def _try_to_restore(self, backup_id: str) -> None:

If PBM is resyncing, the function will retry to create backup
(up to BACKUP_RESTORE_MAX_ATTEMPTS times) with BACKUP_RESTORE_ATTEMPT_COOLDOWN
time between attepts.
time between attempts.

If PMB returen any other error, the function will raise RestoreError.
"""
Expand Down Expand Up @@ -541,7 +541,7 @@ def _try_to_backup(self):

If PBM is resyncing, the function will retry to create backup
(up to BACKUP_RESTORE_MAX_ATTEMPTS times)
with BACKUP_RESTORE_ATTEMPT_COOLDOWN time between attepts.
with BACKUP_RESTORE_ATTEMPT_COOLDOWN time between attempts.

If PMB returen any other error, the function will raise BackupError.
"""
Expand Down
6 changes: 5 additions & 1 deletion lib/charms/mongodb/v0/shards_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ def _on_relation_joined(self, event):
)

# TODO Future PR, add shard to config server
# TODO Follow up PR, handle rotating passwords

def update_credentials(self, key: str, value: str) -> None:
"""Sends new credentials, for a key value pair across all shards."""
for relation in self.charm.model.relations[self.relation_name]:
self._update_relation_data(relation.id, {key: value})

def _update_relation_data(self, relation_id: int, data: dict) -> None:
"""Updates a set of key-value pairs in the relation.
Expand Down
44 changes: 30 additions & 14 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,19 +575,8 @@ def _on_get_password(self, event: ActionEvent) -> None:

def _on_set_password(self, event: ActionEvent) -> None:
"""Set the password for the admin user."""
if self.is_role(Config.Role.SHARD):
event.fail("Cannot set password on shard, please set password on config-server.")
return

# changing the backup password while a backup/restore is in progress can be disastrous
pbm_status = self.backups._get_pbm_status()
if isinstance(pbm_status, MaintenanceStatus):
event.fail("Cannot change password while a backup/restore is in progress.")
return

# only leader can write the new password into peer relation.
if not self.unit.is_leader():
event.fail("The action can be run only on leader unit.")
# check conditions for setting the password and fail if necessary
if not self.pass_pre_set_password_checks(event):
return

username = self._get_user_or_fail_event(
Expand Down Expand Up @@ -615,6 +604,14 @@ def _on_set_password(self, event: ActionEvent) -> None:
if username == MonitorUser.get_username():
self._connect_mongodb_exporter()

# rotate password to shards
# TODO in the future support rotating passwords of pbm across shards
if username == OperatorUser.get_username():
self.shard_relations.update_credentials(
MongoDBUser.get_password_key_name_for_user(username),
new_password,
)

event.set_results(
{Config.Actions.PASSWORD_PARAM_NAME: new_password, "secret-id": secret_id}
)
Expand Down Expand Up @@ -782,6 +779,25 @@ def _get_user_or_fail_event(self, event: ActionEvent, default_username: str) ->
return
return username

def pass_pre_set_password_checks(self, event: ActionEvent) -> bool:
"""Checks conditions for setting the password and fail if necessary."""
if self.is_role(Config.Role.SHARD):
event.fail("Cannot set password on shard, please set password on config-server.")
return

# changing the backup password while a backup/restore is in progress can be disastrous
pbm_status = self.backups._get_pbm_status()
if isinstance(pbm_status, MaintenanceStatus):
event.fail("Cannot change password while a backup/restore is in progress.")
return

# only leader can write the new password into peer relation.
if not self.unit.is_leader():
event.fail("The action can be run only on leader unit.")
return

return True

def _check_or_set_user_password(self, user: MongoDBUser) -> None:
key = user.get_password_key_name()
if not self.get_secret(APP_SCOPE, key):
Expand Down Expand Up @@ -1242,7 +1258,7 @@ def _juju_secret_set(self, scope: Scopes, key: str, value: str) -> str:

secret = self.secrets[scope].get(Config.Secrets.SECRET_LABEL)

# It's not the first secret for the scope, we can re-use the existing one
# It's not the first secret for the scope, we can reuse the existing one
# that was fetched in the previous call, as fetching secrets from juju is
# slow
if secret:
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/ha_tests/test_ha.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ async def test_storage_re_use(ops_test, continuous_writes):
app = await helpers.app_name(ops_test)
if helpers.storage_type(ops_test, app) == "rootfs":
pytest.skip(
"re-use of storage can only be used on deployments with persistent storage not on rootfs deployments"
"reuse of storage can only be used on deployments with persistent storage not on rootfs deployments"
)

# removing the only replica can be disastrous
Expand All @@ -117,7 +117,7 @@ async def test_storage_re_use(ops_test, continuous_writes):

assert await helpers.reused_storage(
ops_test, new_unit.public_address, removal_time
), "attached storage not properly re-used by MongoDB."
), "attached storage not properly reused by MongoDB."

# verify that the no writes were skipped
total_expected_writes = await helpers.stop_continous_writes(ops_test)
Expand Down Expand Up @@ -501,7 +501,7 @@ async def test_full_cluster_crash(ops_test: OpsTest, continuous_writes, reset_re
)

# This test serves to verify behavior when all replicas are down at the same time that when
# they come back online they operate as expected. This check verifies that we meet the criterea
# they come back online they operate as expected. This check verifies that we meet the criteria
# of all replicas being down at the same time.
assert await helpers.all_db_processes_down(ops_test), "Not all units down at the same time."

Expand Down Expand Up @@ -549,7 +549,7 @@ async def test_full_cluster_restart(ops_test: OpsTest, continuous_writes, reset_
)

# This test serves to verify behavior when all replicas are down at the same time that when
# they come back online they operate as expected. This check verifies that we meet the criterea
# they come back online they operate as expected. This check verifies that we meet the criteria
# of all replicas being down at the same time.
assert await helpers.all_db_processes_down(ops_test), "Not all units down at the same time."

Expand Down