Skip to content

Commit

Permalink
[DPE-5269] Add passwords to Syncobj and Patroni (#596)
Browse files Browse the repository at this point in the history
* Add passowrds to Syncobj and Patroni

* Pass pass

* Generate passwords during upgrade

* Get password

* Update tests

* Fix tests

* Try to regenerate secrets

* Check for peers availability before resetting the passes

* Update templates/patroni.yml.j2

Co-authored-by: Mykola Marzhan <[email protected]>

* Switch patroni user

* Only try to create secret on leader

* Add replication check logging

* Try to observe topology without auth

* Try to ignore upgrade replication error

* Ignore replication only when encrypting raft

* Cast version

* Enable arm upgrade from stable

---------

Co-authored-by: Mykola Marzhan <[email protected]>
  • Loading branch information
dragomirp and delgod authored Aug 29, 2024
1 parent 0c855f4 commit 1ed5706
Show file tree
Hide file tree
Showing 22 changed files with 256 additions and 72 deletions.
2 changes: 1 addition & 1 deletion actions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ get-password:
username:
type: string
description: The username, the default value 'operator'.
Possible values - operator, replication, rewind.
Possible values - operator, replication, rewind, patroni.
list-backups:
description: Lists backups in s3 storage.
pre-upgrade-check:
Expand Down
8 changes: 6 additions & 2 deletions lib/charms/grafana_agent/v0/cos_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
Using the `COSAgentProvider` object only requires instantiating it,
typically in the `__init__` method of your charm (the one which sends telemetry).
The constructor of `COSAgentProvider` has only one required and nine optional parameters:
The constructor of `COSAgentProvider` has only one required and ten optional parameters:
```python
def __init__(
Expand All @@ -36,6 +36,7 @@ def __init__(
log_slots: Optional[List[str]] = None,
dashboard_dirs: Optional[List[str]] = None,
refresh_events: Optional[List] = None,
tracing_protocols: Optional[List[str]] = None,
scrape_configs: Optional[Union[List[Dict], Callable]] = None,
):
```
Expand Down Expand Up @@ -65,6 +66,8 @@ def __init__(
- `refresh_events`: List of events on which to refresh relation data.
- `tracing_protocols`: List of requested tracing protocols that the charm requires to send traces.
- `scrape_configs`: List of standard scrape_configs dicts or a callable that returns the list in
case the configs need to be generated dynamically. The contents of this list will be merged
with the configs from `metrics_endpoints`.
Expand Down Expand Up @@ -108,6 +111,7 @@ def __init__(self, *args):
log_slots=["my-app:slot"],
dashboard_dirs=["./src/dashboards_1", "./src/dashboards_2"],
refresh_events=["update-status", "upgrade-charm"],
tracing_protocols=["otlp_http", "otlp_grpc"],
scrape_configs=[
{
"job_name": "custom_job",
Expand Down Expand Up @@ -249,7 +253,7 @@ class _MetricsEndpointDict(TypedDict):

LIBID = "dc15fa84cef84ce58155fb84f6c6213a"
LIBAPI = 0
LIBPATCH = 10
LIBPATCH = 11

PYDEPS = ["cosl", "pydantic"]

Expand Down
17 changes: 14 additions & 3 deletions lib/charms/tempo_k8s/v1/charm_tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ def _remove_stale_otel_sdk_packages():

_remove_stale_otel_sdk_packages()


import functools
import inspect
import logging
Expand Down Expand Up @@ -271,7 +270,7 @@ def _remove_stale_otel_sdk_packages():
# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version

LIBPATCH = 14
LIBPATCH = 15

PYDEPS = ["opentelemetry-exporter-otlp-proto-http==1.21.0"]

Expand All @@ -281,7 +280,6 @@ def _remove_stale_otel_sdk_packages():
# set this to 0 if you are debugging/developing this library source
dev_logger.setLevel(logging.CRITICAL)


_CharmType = Type[CharmBase] # the type CharmBase and any subclass thereof
_C = TypeVar("_C", bound=_CharmType)
_T = TypeVar("_T", bound=type)
Expand Down Expand Up @@ -333,9 +331,22 @@ def _get_tracer() -> Optional[Tracer]:
try:
return tracer.get()
except LookupError:
# fallback: this course-corrects for a user error where charm_tracing symbols are imported
# from different paths (typically charms.tempo_k8s... and lib.charms.tempo_k8s...)
try:
ctx: Context = copy_context()
if context_tracer := _get_tracer_from_context(ctx):
logger.warning(
"Tracer not found in `tracer` context var. "
"Verify that you're importing all `charm_tracing` symbols from the same module path. \n"
"For example, DO"
": `from charms.lib...charm_tracing import foo, bar`. \n"
"DONT: \n"
" \t - `from charms.lib...charm_tracing import foo` \n"
" \t - `from lib...charm_tracing import bar` \n"
"For more info: https://python-notes.curiousefficiency.org/en/latest/python"
"_concepts/import_traps.html#the-double-import-trap"
)
return context_tracer.get()
else:
return None
Expand Down
27 changes: 17 additions & 10 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@
MONITORING_SNAP_SERVICE,
MONITORING_USER,
PATRONI_CONF_PATH,
PATRONI_PASSWORD_KEY,
PEER,
POSTGRESQL_SNAP_NAME,
RAFT_PASSWORD_KEY,
REPLICATION_PASSWORD_KEY,
REWIND_PASSWORD_KEY,
SECRET_DELETED_LABEL,
Expand Down Expand Up @@ -109,6 +111,7 @@
EXTENSION_OBJECT_MESSAGE = "Cannot disable plugins: Existing objects depend on it. See logs"

Scopes = Literal[APP_SCOPE, UNIT_SCOPE]
PASSWORD_USERS = [*SYSTEM_USERS, "patroni"]


@trace_charm(
Expand Down Expand Up @@ -745,6 +748,8 @@ def _patroni(self) -> Patroni:
self._replication_password,
self.get_secret(APP_SCOPE, REWIND_PASSWORD_KEY),
bool(self.unit_peer_data.get("tls")),
self.get_secret(APP_SCOPE, RAFT_PASSWORD_KEY),
self.get_secret(APP_SCOPE, PATRONI_PASSWORD_KEY),
)

@property
Expand Down Expand Up @@ -893,14 +898,16 @@ def _on_install(self, event: InstallEvent) -> None:
def _on_leader_elected(self, event: LeaderElectedEvent) -> None:
"""Handle the leader-elected event."""
# The leader sets the needed passwords if they weren't set before.
if self.get_secret(APP_SCOPE, USER_PASSWORD_KEY) is None:
self.set_secret(APP_SCOPE, USER_PASSWORD_KEY, new_password())
if self.get_secret(APP_SCOPE, REPLICATION_PASSWORD_KEY) is None:
self.set_secret(APP_SCOPE, REPLICATION_PASSWORD_KEY, new_password())
if self.get_secret(APP_SCOPE, REWIND_PASSWORD_KEY) is None:
self.set_secret(APP_SCOPE, REWIND_PASSWORD_KEY, new_password())
if self.get_secret(APP_SCOPE, MONITORING_PASSWORD_KEY) is None:
self.set_secret(APP_SCOPE, MONITORING_PASSWORD_KEY, new_password())
for key in (
USER_PASSWORD_KEY,
REPLICATION_PASSWORD_KEY,
REWIND_PASSWORD_KEY,
MONITORING_PASSWORD_KEY,
RAFT_PASSWORD_KEY,
PATRONI_PASSWORD_KEY,
):
if self.get_secret(APP_SCOPE, key) is None:
self.set_secret(APP_SCOPE, key, new_password())

# Update the list of the current PostgreSQL hosts when a new leader is elected.
# Add this unit to the list of cluster members
Expand Down Expand Up @@ -1218,10 +1225,10 @@ def _on_get_password(self, event: ActionEvent) -> None:
If no user is provided, the password of the operator user is returned.
"""
username = event.params.get("username", USER)
if username not in SYSTEM_USERS:
if username not in PASSWORD_USERS:
event.fail(
f"The action can be run only for users used by the charm or Patroni:"
f" {', '.join(SYSTEM_USERS)} not {username}"
f" {', '.join(PASSWORD_USERS)} not {username}"
)
return
event.set_results({"password": self.get_secret(APP_SCOPE, f"{username}-password")})
Expand Down
Loading

0 comments on commit 1ed5706

Please sign in to comment.