Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into lucas/diff-incr-backups
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasgameiroborges committed Jun 4, 2024
2 parents b9597f0 + 16d10d8 commit f1b4706
Show file tree
Hide file tree
Showing 15 changed files with 158 additions and 55 deletions.
18 changes: 11 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ on:
jobs:
lint:
name: Lint
uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v13.1.2
uses: canonical/data-platform-workflows/.github/workflows/lint.yaml@v13.2.0

unit-test:
name: Unit test charm
Expand All @@ -42,7 +42,7 @@ jobs:

build:
name: Build charm
uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v13.1.2
uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v13.2.0
with:
cache: true

Expand All @@ -53,21 +53,25 @@ jobs:
juju:
- agent: 2.9.49 # renovate: latest juju 2
libjuju: ==2.9.49.0 # renovate: latest libjuju 2
allure: false
allure_on_amd64: false
- agent: 3.1.8 # renovate: latest juju 3
allure: true
name: Integration test charm | ${{ matrix.juju.agent }}
allure_on_amd64: true
architecture:
- amd64
- arm64
name: Integration test charm | ${{ matrix.juju.agent }} | ${{ matrix.architecture }}
needs:
- lint
- unit-test
- build
uses: canonical/data-platform-workflows/.github/workflows/integration_test_charm.yaml@v13.1.2
uses: canonical/data-platform-workflows/.github/workflows/integration_test_charm.yaml@v13.2.0
with:
artifact-prefix: ${{ needs.build.outputs.artifact-prefix }}
architecture: ${{ matrix.architecture }}
cloud: lxd
juju-agent-version: ${{ matrix.juju.agent }}
libjuju-version-constraint: ${{ matrix.juju.libjuju }}
_beta_allure_report: ${{ matrix.juju.allure }}
_beta_allure_report: ${{ matrix.juju.allure_on_amd64 && matrix.architecture == 'amd64' }}
secrets:
integration-test: |
{
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ jobs:

build:
name: Build charm
uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v13.1.2
uses: canonical/data-platform-workflows/.github/workflows/build_charm.yaml@v13.2.0

release:
name: Release charm
needs:
- ci-tests
- build
uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v13.1.2
uses: canonical/data-platform-workflows/.github/workflows/release_charm.yaml@v13.2.0
with:
channel: 14/edge
artifact-prefix: ${{ needs.build.outputs.artifact-prefix }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync_issue_to_jira.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
sync:
name: Sync GitHub issue to Jira
uses: canonical/data-platform-workflows/.github/workflows/sync_issue_to_jira.yaml@v13.1.2
uses: canonical/data-platform-workflows/.github/workflows/sync_issue_to_jira.yaml@v13.2.0
with:
jira-base-url: https://warthogs.atlassian.net
jira-project-key: DPE
Expand Down
25 changes: 7 additions & 18 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ optional = true

[tool.poetry.group.integration.dependencies]
pytest = "^8.2.0"
pytest-github-secrets = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.2", subdirectory = "python/pytest_plugins/github_secrets"}
pytest-github-secrets = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.2.0", subdirectory = "python/pytest_plugins/github_secrets"}
pytest-operator = "^0.35.0"
pytest-operator-cache = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.2", subdirectory = "python/pytest_plugins/pytest_operator_cache"}
pytest-operator-groups = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.1.2", subdirectory = "python/pytest_plugins/pytest_operator_groups"}
pytest-operator-cache = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.2.0", subdirectory = "python/pytest_plugins/pytest_operator_cache"}
pytest-operator-groups = {git = "https://github.com/canonical/data-platform-workflows", tag = "v13.2.0", subdirectory = "python/pytest_plugins/pytest_operator_groups"}
# renovate caret doesn't work: https://github.com/renovatebot/renovate/issues/26940
juju = "<=3.4.0.0"
boto3 = "*"
Expand Down
21 changes: 21 additions & 0 deletions src/backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ def _are_backup_settings_ok(self) -> Tuple[bool, Optional[str]]:

return True, None

@property
def _can_initialise_stanza(self) -> bool:
"""Validates whether this unit can initialise a stanza."""
# Don't allow stanza initialisation if this unit hasn't started the database
# yet and either hasn't joined the peer relation yet or hasn't configured TLS
# yet while other unit already has TLS enabled.
if not self.charm._patroni.member_started and (
(len(self.charm._peers.data.keys()) == 2)
or (
"tls" not in self.charm.unit_peer_data
and any("tls" in unit_data for _, unit_data in self.charm._peers.data.items())
)
):
return False
return True

def _can_unit_perform_backup(self) -> Tuple[bool, Optional[str]]:
"""Validates whether this unit can perform a backup."""
if self.charm.is_blocked:
Expand Down Expand Up @@ -530,6 +546,11 @@ def _on_s3_credential_changed(self, event: CredentialsChangedEvent):
logger.debug("Cannot set pgBackRest configurations, missing configurations.")
return

if not self._can_initialise_stanza:
logger.debug("Cannot initialise stanza yet.")
event.defer()
return

# Verify the s3 relation only on the primary.
if not self.charm.is_primary:
return
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/architecture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.
import subprocess

architecture = subprocess.run(
["dpkg", "--print-architecture"], capture_output=True, check=True, encoding="utf-8"
).stdout.strip()
8 changes: 7 additions & 1 deletion tests/integration/ha_tests/test_async_replication.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# See LICENSE file for licensing details.
import contextlib
import logging
import subprocess
from asyncio import gather
from typing import Optional

Expand All @@ -12,7 +13,7 @@
from pytest_operator.plugin import OpsTest
from tenacity import Retrying, stop_after_delay, wait_fixed

from .. import markers
from .. import architecture, markers
from ..helpers import (
APPLICATION_NAME,
DATABASE_APP_NAME,
Expand Down Expand Up @@ -70,6 +71,11 @@ async def second_model(ops_test: OpsTest, first_model, request) -> Model:
second_model_name = f"{first_model.info.name}-other"
if second_model_name not in await ops_test._controller.list_models():
await ops_test._controller.add_model(second_model_name)
subprocess.run(["juju", "switch", second_model_name], check=True)
subprocess.run(
["juju", "set-model-constraints", f"arch={architecture.architecture}"], check=True
)
subprocess.run(["juju", "switch", first_model.info.name], check=True)
second_model = Model()
await second_model.connect(model_name=second_model_name)
yield second_model
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/ha_tests/test_upgrade_from_stable.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest
from pytest_operator.plugin import OpsTest

from .. import markers
from ..helpers import (
APPLICATION_NAME,
DATABASE_APP_NAME,
Expand All @@ -26,6 +27,7 @@


@pytest.mark.group(1)
@markers.amd64_only # TODO: remove after arm64 stable release
@pytest.mark.abort_on_fail
async def test_deploy_stable(ops_test: OpsTest) -> None:
"""Simple test to ensure that the PostgreSQL and application charms get deployed."""
Expand Down Expand Up @@ -77,6 +79,7 @@ async def test_deploy_stable(ops_test: OpsTest) -> None:


@pytest.mark.group(1)
@markers.amd64_only # TODO: remove after arm64 stable release
@pytest.mark.abort_on_fail
async def test_pre_upgrade_check(ops_test: OpsTest) -> None:
"""Test that the pre-upgrade-check action runs successfully."""
Expand All @@ -95,6 +98,7 @@ async def test_pre_upgrade_check(ops_test: OpsTest) -> None:


@pytest.mark.group(1)
@markers.amd64_only # TODO: remove after arm64 stable release
@pytest.mark.abort_on_fail
async def test_upgrade_from_stable(ops_test: OpsTest):
"""Test updating from stable channel."""
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@

import pytest

from . import architecture
from .juju_ import juju_major_version

juju2 = pytest.mark.skipif(juju_major_version != 2, reason="Requires juju 2")
juju3 = pytest.mark.skipif(juju_major_version != 3, reason="Requires juju 3")
juju_secrets = pytest.mark.skipif(juju_major_version < 3, reason="Requires juju secrets")
amd64_only = pytest.mark.skipif(
architecture.architecture != "amd64", reason="Requires amd64 architecture"
)
arm64_only = pytest.mark.skipif(
architecture.architecture != "arm64", reason="Requires arm64 architecture"
)
2 changes: 2 additions & 0 deletions tests/integration/new_relations/test_new_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import yaml
from pytest_operator.plugin import OpsTest

from .. import markers
from ..helpers import CHARM_SERIES, assert_sync_standbys, get_leader_unit, scale_application
from ..juju_ import juju_major_version
from .helpers import (
Expand Down Expand Up @@ -583,6 +584,7 @@ async def test_invalid_extra_user_roles(ops_test: OpsTest):


@pytest.mark.group(1)
@markers.amd64_only # nextcloud charm not available for arm64
async def test_nextcloud_db_blocked(ops_test: OpsTest, charm: str) -> None:
async with ops_test.fast_forward():
# Deploy Nextcloud.
Expand Down
27 changes: 17 additions & 10 deletions tests/integration/test_backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pytest_operator.plugin import OpsTest
from tenacity import Retrying, stop_after_attempt, wait_exponential

from . import architecture
from .helpers import (
CHARM_SERIES,
DATABASE_APP_NAME,
Expand All @@ -31,13 +32,19 @@
FAILED_TO_INITIALIZE_STANZA_ERROR_MESSAGE = "failed to initialize stanza, check your S3 settings"
S3_INTEGRATOR_APP_NAME = "s3-integrator"
if juju_major_version < 3:
TLS_CERTIFICATES_APP_NAME = "tls-certificates-operator"
TLS_CHANNEL = "legacy/stable"
TLS_CONFIG = {"generate-self-signed-certificates": "true", "ca-common-name": "Test CA"}
tls_certificates_app_name = "tls-certificates-operator"
if architecture.architecture == "arm64":
tls_channel = "legacy/edge"
else:
tls_channel = "legacy/stable"
tls_config = {"generate-self-signed-certificates": "true", "ca-common-name": "Test CA"}
else:
TLS_CERTIFICATES_APP_NAME = "self-signed-certificates"
TLS_CHANNEL = "latest/stable"
TLS_CONFIG = {"ca-common-name": "Test CA"}
tls_certificates_app_name = "self-signed-certificates"
if architecture.architecture == "arm64":
tls_channel = "latest/edge"
else:
tls_channel = "latest/stable"
tls_config = {"ca-common-name": "Test CA"}

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -96,7 +103,7 @@ async def test_backup(ops_test: OpsTest, cloud_configs: Tuple[Dict, Dict], charm
"""Build and deploy two units of PostgreSQL and then test the backup and restore actions."""
# Deploy S3 Integrator and TLS Certificates Operator.
await ops_test.model.deploy(S3_INTEGRATOR_APP_NAME)
await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, config=TLS_CONFIG, channel=TLS_CHANNEL)
await ops_test.model.deploy(tls_certificates_app_name, config=tls_config, channel=tls_channel)

for cloud, config in cloud_configs[0].items():
# Deploy and relate PostgreSQL to S3 integrator (one database app for each cloud for now
Expand All @@ -111,7 +118,7 @@ async def test_backup(ops_test: OpsTest, cloud_configs: Tuple[Dict, Dict], charm
config={"profile": "testing"},
)
await ops_test.model.relate(database_app_name, S3_INTEGRATOR_APP_NAME)
await ops_test.model.relate(database_app_name, TLS_CERTIFICATES_APP_NAME)
await ops_test.model.relate(database_app_name, tls_certificates_app_name)

# Configure and set access and secret keys.
logger.info(f"configuring S3 integrator for {cloud}")
Expand Down Expand Up @@ -304,7 +311,7 @@ async def test_backup(ops_test: OpsTest, cloud_configs: Tuple[Dict, Dict], charm
if cloud == list(cloud_configs[0].keys())[0]:
# Remove the relation to the TLS certificates operator.
await ops_test.model.applications[database_app_name].remove_relation(
f"{database_app_name}:certificates", f"{TLS_CERTIFICATES_APP_NAME}:certificates"
f"{database_app_name}:certificates", f"{tls_certificates_app_name}:certificates"
)
await ops_test.model.wait_for_idle(
apps=[database_app_name], status="active", timeout=1000
Expand Down Expand Up @@ -359,7 +366,7 @@ async def test_backup(ops_test: OpsTest, cloud_configs: Tuple[Dict, Dict], charm
await ops_test.model.remove_application(database_app_name, block_until_done=True)

# Remove the TLS operator.
await ops_test.model.remove_application(TLS_CERTIFICATES_APP_NAME, block_until_done=True)
await ops_test.model.remove_application(tls_certificates_app_name, block_until_done=True)


@pytest.mark.group(1)
Expand Down
Loading

0 comments on commit f1b4706

Please sign in to comment.