From d780a340d3cca175114c895a2488a036898fbac1 Mon Sep 17 00:00:00 2001 From: Luca Zaninotto Date: Thu, 12 Dec 2024 16:10:46 +0100 Subject: [PATCH] chore(tenants): tenant cleanup Closes #504. Manages resource cleanup on tenant deletion, deleting base images, ephemeral images and system models images on remote storage. Signed-off-by: Luca Zaninotto --- .../lib/edgehog/base_images/base_images.ex | 5 +- backend/lib/edgehog/devices/devices.ex | 6 +- .../tenants/tenant/changes/handle_cleanup.ex | 87 +++++++++++++++++++ backend/lib/edgehog/tenants/tenant/tenant.ex | 10 ++- 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 backend/lib/edgehog/tenants/tenant/changes/handle_cleanup.ex diff --git a/backend/lib/edgehog/base_images/base_images.ex b/backend/lib/edgehog/base_images/base_images.ex index 3e07d0ba9..b800eed85 100644 --- a/backend/lib/edgehog/base_images/base_images.ex +++ b/backend/lib/edgehog/base_images/base_images.ex @@ -67,7 +67,10 @@ defmodule Edgehog.BaseImages do end resources do - resource BaseImage + resource BaseImage do + define :delete_base_image, action: :destroy + end + resource BaseImageCollection end end diff --git a/backend/lib/edgehog/devices/devices.ex b/backend/lib/edgehog/devices/devices.ex index 05448cd4b..40ce9da7f 100644 --- a/backend/lib/edgehog/devices/devices.ex +++ b/backend/lib/edgehog/devices/devices.ex @@ -86,7 +86,11 @@ defmodule Edgehog.Devices do resource Device resource HardwareType resource Edgehog.Devices.HardwareTypePartNumber - resource SystemModel + + resource SystemModel do + define :delete_system_model, action: :destroy + end + resource Edgehog.Devices.SystemModelPartNumber end end diff --git a/backend/lib/edgehog/tenants/tenant/changes/handle_cleanup.ex b/backend/lib/edgehog/tenants/tenant/changes/handle_cleanup.ex new file mode 100644 index 000000000..6ed8d6e48 --- /dev/null +++ b/backend/lib/edgehog/tenants/tenant/changes/handle_cleanup.ex @@ -0,0 +1,87 @@ +# +# This file is part of Edgehog. +# +# Copyright 2024 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +defmodule Edgehog.Tenants.Tenant.Changes.HandleCleanup do + @moduledoc false + use Ash.Resource.Change + + alias Edgehog.BaseImages + alias Edgehog.BaseImages.BaseImage + alias Edgehog.Devices + alias Edgehog.OSManagement.EphemeralImage + alias Edgehog.OSManagement.OTAOperation + + require Ash.Query + + @ephemeral_image_module Application.compile_env( + :edgehog, + :os_management_ephemeral_image_module, + EphemeralImage + ) + + @impl Ash.Resource.Change + def change(changeset, _opts, _context) do + Ash.Changeset.after_action(changeset, fn _changeset, tenant -> + try do + cleanup_system_models(tenant) + cleanup_base_images(tenant) + cleanup_ephimeral_images(tenant) + {:ok, tenant} + rescue + e -> {:error, e} + end + end) + end + + defp cleanup_base_images(tenant) do + base_images = + BaseImage + |> Ash.Query.filter(tenant_id == ^tenant.tenant_id) + |> Ash.read!(tenant: tenant) + + for image <- base_images do + BaseImages.delete_base_image!(image, tenant: tenant) + end + end + + defp cleanup_ephimeral_images(tenant) do + manual_otas = + OTAOperation + |> Ash.Query.filter(tenant_id == ^tenant.tenant_id) + |> Ash.Query.filter(manual?) + |> Ash.read!(tenant: tenant) + + for ota <- manual_otas do + # we do our best to cleanup + _ = @ephemeral_image_module.delete(tenant.tenant_id, ota.id, ota.base_image_url) + end + end + + defp cleanup_system_models(tenant) do + system_models = + Edgehog.Devices.SystemModel + |> Ash.Query.filter(tenant_id == ^tenant.tenant_id) + |> Ash.read!(tenant: tenant) + + for system_model <- system_models do + Devices.delete_system_model!(system_model, tenant: tenant) + end + end +end diff --git a/backend/lib/edgehog/tenants/tenant/tenant.ex b/backend/lib/edgehog/tenants/tenant/tenant.ex index 47d591151..dd95ada8a 100644 --- a/backend/lib/edgehog/tenants/tenant/tenant.ex +++ b/backend/lib/edgehog/tenants/tenant/tenant.ex @@ -31,6 +31,7 @@ defmodule Edgehog.Tenants.Tenant do alias Ash.Error.Invalid.TenantRequired alias Edgehog.Tenants.AstarteConfig alias Edgehog.Tenants.Tenant + alias Edgehog.Tenants.Tenant.Changes alias Edgehog.Validations require Ash.Query @@ -60,7 +61,7 @@ defmodule Edgehog.Tenants.Tenant do end actions do - defaults [:read, :destroy] + defaults [:read] create :create do primary? true @@ -99,6 +100,13 @@ defmodule Edgehog.Tenants.Tenant do run Tenant.ManualActions.ReconcilerAction end + + destroy :destroy do + description "Destroy tenant handling resource cleanup." + + require_atomic? false + change Changes.HandleCleanup + end end validations do