Skip to content

Commit

Permalink
Clean remote application when disabling observability
Browse files Browse the repository at this point in the history
Clean remote applications coming from observability model when disabling
observability plugin.

LP: 2063183
  • Loading branch information
gboutry committed Apr 24, 2024
1 parent 515ebb9 commit 3a4f31c
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
52 changes: 51 additions & 1 deletion sunbeam-python/sunbeam/plugins/observability/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from sunbeam.clusterd.service import ClusterServiceUnavailableException
from sunbeam.commands.juju import JujuStepHelper
from sunbeam.commands.k8s import CREDENTIAL_SUFFIX, K8SHelper
from sunbeam.commands.openstack import PatchLoadBalancerServicesStep
from sunbeam.commands.openstack import OPENSTACK_MODEL, PatchLoadBalancerServicesStep
from sunbeam.commands.terraform import TerraformException, TerraformInitStep
from sunbeam.jobs.common import (
BaseStep,
Expand Down Expand Up @@ -178,6 +178,52 @@ def run(self, status: Optional[Status] = None) -> Result:
return Result(ResultType.COMPLETED)


class RemoveSaasApplicationsStep(BaseStep):
"""Removes SAAS offers from given model."""

def __init__(self, jhelper: JujuHelper, model: str, offering_model: str):
super().__init__(
f"Purge SAAS Offers: {model}", f"Purging SAAS Offers from {model}"
)
self.jhelper = jhelper
self.model = model
self.offering_model = offering_model
self._remote_app_to_delete = []

def is_skip(self, status: Status | None = None) -> Result:
model = run_sync(self.jhelper.get_model(self.model))
remote_application = model.remote_applications
LOG.debug("Remote applications found: %s", ", ".join(remote_application.keys()))
if not remote_application:
return Result(ResultType.SKIPPED, "No remote applications found")

for name, remote_app in remote_application.items():
if not remote_app:
continue
offer = remote_app.offer_url
LOG.debug("Processing offer: %s", offer)
model_name = offer.split("/", 1)[1].split(".", 1)[0]
if model_name == self.offering_model:
self._remote_app_to_delete.append(name)

if len(self._remote_app_to_delete) == 0:
return Result(ResultType.SKIPPED, "No remote applications to remove")

return Result(ResultType.COMPLETED)

def run(self, status: Optional[Status] = None) -> Result:
"""Execute configuration using terraform."""
if not self._remote_app_to_delete:
return Result(ResultType.COMPLETED)

model = run_sync(self.jhelper.get_model(self.model))

for saas in self._remote_app_to_delete:
LOG.debug("Removing remote application %s", saas)
run_sync(model.remove_saas(saas))
return Result(ResultType.COMPLETED)


class DeployGrafanaAgentStep(BaseStep, JujuStepHelper):
"""Deploy Grafana Agent using Terraform"""

Expand Down Expand Up @@ -515,11 +561,15 @@ def run_disable_plans(self):
agent_grafana_k8s_plan = [
TerraformInitStep(self.manifest.get_tfhelper(self.tfplan)),
DisableOpenStackApplicationStep(jhelper, self),
RemoveSaasApplicationsStep(jhelper, OPENSTACK_MODEL, OBSERVABILITY_MODEL),
]

grafana_agent_plan = [
TerraformInitStep(self.manifest.get_tfhelper(self.tfplan_grafana_agent)),
RemoveGrafanaAgentStep(self, jhelper),
RemoveSaasApplicationsStep(
jhelper, self.deployment.infrastructure_model, OBSERVABILITY_MODEL
),
]

cos_plan = [
Expand Down
44 changes: 43 additions & 1 deletion sunbeam-python/tests/unit/sunbeam/plugins/test_observability.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

import asyncio
from unittest.mock import AsyncMock, patch
from unittest.mock import AsyncMock, Mock, patch

import pytest

Expand Down Expand Up @@ -222,3 +222,45 @@ def test_run_waiting_timed_out(self, jhelper, observabilityplugin):
jhelper.wait_application_gone.assert_called_once()
assert result.result_type == ResultType.FAILED
assert result.message == "timed out"


class TestRemoveSaasApplicationsStep:
def test_is_skip(self, jhelper):
jhelper.get_model.return_value = AsyncMock(
remote_applications={
"test-1": Mock(offer_url="admin/offering_model.test-1")
}
)
step = observability_plugin.RemoveSaasApplicationsStep(
jhelper, "test", "offering_model"
)
result = step.is_skip()
assert result.result_type == ResultType.COMPLETED

def test_is_skip_no_remote_app(self, jhelper):
jhelper.get_model.return_value = AsyncMock(remote_applications={})
step = observability_plugin.RemoveSaasApplicationsStep(
jhelper, "test", "offering_model"
)
result = step.is_skip()
assert result.result_type == ResultType.SKIPPED

def test_is_skip_no_saas_app(self, jhelper):
jhelper.get_model.return_value = AsyncMock(
remote_applications={
"test-1": Mock(offer_url="admin/offering_model.test-1")
}
)
step = observability_plugin.RemoveSaasApplicationsStep(
jhelper, "test", "offering_model-no-apps"
)
result = step.is_skip()
assert result.result_type == ResultType.SKIPPED

def test_run(self, jhelper):
step = observability_plugin.RemoveSaasApplicationsStep(
jhelper, "test", "offering_model"
)
step._remote_app_to_delete = ["test-1"]
result = step.run()
assert result.result_type == ResultType.COMPLETED

0 comments on commit 3a4f31c

Please sign in to comment.