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-2406] Fix pod deletion #134

Merged
merged 2 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from ops.pebble import ConnectionError, Layer, PathError, ServiceStatus

from constants import (
AUTH_FILE_DATABAG_KEY,
AUTH_FILE_PATH,
CLIENT_RELATION_NAME,
EXTENSIONS_BLOCKING_MESSAGE,
Expand Down Expand Up @@ -58,7 +59,9 @@ def __init__(self, *args):

self.framework.observe(self.on.config_changed, self._on_config_changed)
self.framework.observe(self.on.pgbouncer_pebble_ready, self._on_pgbouncer_pebble_ready)
self.framework.observe(self.on.start, self._on_start)
self.framework.observe(self.on.update_status, self._on_update_status)
self.framework.observe(self.on.upgrade_charm, self._on_upgrade_charm)

self.peers = Peers(self)
self.backend = BackendDatabaseRequires(self)
Expand Down Expand Up @@ -279,6 +282,15 @@ def _pgbouncer_layer(self) -> Layer:
}
)

def _on_start(self, _) -> None:
"""Re-render the auth file, which is lost if the host machine is restarted."""
self.render_auth_file_if_available()

def render_auth_file_if_available(self):
"""Render the auth file if it's available in the secret store."""
if auth_file := self.get_secret("app", AUTH_FILE_DATABAG_KEY):
self.render_auth_file(auth_file)

def _on_update_status(self, _) -> None:
"""Update Status hook.
Expand Down Expand Up @@ -315,6 +327,10 @@ def update_status(self):
logger.error(not_running)
self.unit.status = WaitingStatus(not_running)

def _on_upgrade_charm(self, _) -> None:
"""Re-render the auth file, which is lost in a pod reschedule."""
self.render_auth_file_if_available()

def reload_pgbouncer(self) -> None:
"""Reloads pgbouncer application.
Expand Down
12 changes: 11 additions & 1 deletion tests/integration/relations/pgbouncer_provider/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ async def build_connection_string(
*,
relation_id: str = None,
read_only_endpoint: bool = False,
database: str = None,
) -> str:
"""Build a PostgreSQL connection string.
Expand All @@ -140,12 +141,14 @@ async def build_connection_string(
relation_id: id of the relation to get connection data from
read_only_endpoint: whether to choose the read-only endpoint
instead of the read/write endpoint
database: optional database to be used in the connection string
Returns:
a PostgreSQL connection string
"""
# Get the connection data exposed to the application through the relation.
database = f'{application_name.replace("-", "_")}_{relation_name.replace("-", "_")}'
if database is None:
database = f'{application_name.replace("-", "_")}_{relation_name.replace("-", "_")}'
username = await get_application_relation_data(
ops_test, application_name, relation_name, "username", relation_id
)
Expand Down Expand Up @@ -197,3 +200,10 @@ async def check_new_relation(
assert (
test_data in json.loads(run_query["results"])[0]
), f"smoke check failed. Query output: {run_query}"


async def delete_pod(ops_test: OpsTest, unit_name: str) -> None:
"""Delete a pod."""
model = ops_test.model.info
client = AsyncClient(namespace=model.name)
await client.delete(Pod, name=unit_name.replace("/", "-"))
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import logging
from pathlib import Path

import psycopg2
import pytest
import yaml
from pytest_operator.plugin import OpsTest
Expand All @@ -29,6 +30,7 @@
from .helpers import (
build_connection_string,
check_new_relation,
delete_pod,
get_application_relation_data,
run_sql_on_application_charm,
)
Expand Down Expand Up @@ -442,3 +444,25 @@ async def test_relation_with_data_integrator(ops_test: OpsTest):
await ops_test.model.add_relation(f"{PGB}:database", DATA_INTEGRATOR_APP_NAME)
async with ops_test.fast_forward():
await ops_test.model.wait_for_idle(status="active")


async def test_connection_is_possible_after_pod_deletion(ops_test: OpsTest) -> None:
"""Tests that the connection is possible after the pod is deleted."""
# Delete the pod.
unit = ops_test.model.applications[PGB].units[0]
await delete_pod(ops_test, unit.name)
await ops_test.model.wait_for_idle(status="active", idle_period=3)

# Test the connection.
connection_string = await build_connection_string(
ops_test, DATA_INTEGRATOR_APP_NAME, relation_name="postgresql", database="test-database"
)
connection_string += " port=6432"
connection = None
try:
connection = psycopg2.connect(connection_string)
except psycopg2.Error:
assert False, "failed to connect to PgBouncer after deleting it's pod"
finally:
if connection is not None:
connection.close()