Skip to content

Commit 684b9b0

Browse files
committed
feat(backend): allow deletion of BaseImage used in completed campaign
Previously, a base image could not be deleted no matter what, if it had been used in an Update Campaign. This is problematic, for example, when the storage is full. It is reasonable to allow a Base Image to be deleted, even if in use by a Update Campaign, if that campaign is finished and does not need the image anymore. Closes #598 Signed-off-by: Damiano Mason <damiano.mason@secomind.com>
1 parent 3c7c8d7 commit 684b9b0

5 files changed

Lines changed: 194 additions & 83 deletions

File tree

backend/lib/edgehog/base_images/base_image/validations/base_image_not_in_use.ex

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
#
21
# This file is part of Edgehog.
32
#
4-
# Copyright 2025 SECO Mind Srl
3+
# Copyright 2025 - 2026 SECO Mind Srl
54
#
65
# Licensed under the Apache License, Version 2.0 (the "License");
76
# you may not use this file except in compliance with the License.
@@ -16,7 +15,6 @@
1615
# limitations under the License.
1716
#
1817
# SPDX-License-Identifier: Apache-2.0
19-
#
2018

2119
defmodule Edgehog.BaseImages.BaseImage.Validations.BaseImageNotInUse do
2220
@moduledoc false
@@ -42,6 +40,7 @@ defmodule Edgehog.BaseImages.BaseImage.Validations.BaseImageNotInUse do
4240
^resource.id
4341
)
4442
)
43+
|> Ash.Query.filter(status != :finished)
4544
|> Ash.Query.limit(1)
4645
|> Ash.read!()
4746

@@ -50,7 +49,7 @@ defmodule Edgehog.BaseImages.BaseImage.Validations.BaseImageNotInUse do
5049
:ok
5150

5251
[_] ->
53-
{:error, field: :id, message: "Base image is currently in use by at least one campaign"}
52+
{:error, field: :id, message: "Base image is currently in use by at least one running campaign"}
5453
end
5554
end
5655
end

backend/lib/edgehog/campaigns/campaign/campaign.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ defmodule Edgehog.Campaigns.Campaign do
7979
filter expr(status in [:idle, :in_progress, :pausing])
8080
end
8181

82+
# TODO: allow filtering per base_image_id
8283
read :update_campaigns do
8384
argument :types, {:array, :atom}
8485
multitenancy :allow_global

backend/lib/edgehog/campaigns/campaign_mechanism/firmware_upgrade/firmware_upgrade.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ defmodule Edgehog.Campaigns.CampaignMechanism.FirmwareUpgrade do
119119
belongs_to :base_image, Edgehog.BaseImages.BaseImage do
120120
description "The base image distributed by the update campaign."
121121
public? true
122-
allow_nil? false
123122
attribute_type :id
124123
end
125124
end

backend/test/edgehog_web/schema/mutation/delete_base_image_test.exs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,53 @@ defmodule EdgehogWeb.Schema.Mutation.DeleteBaseImageTest do
7878
assert %{fields: [:id], message: "could not be found"} = extract_error!(result)
7979
end
8080

81-
test "fails if the image is used in an Update Campaign", %{
81+
test "fails if the image is used in a running Update Campaign", %{
8282
tenant: tenant,
8383
base_image: base_image,
8484
id: id
85+
} do
86+
campaign =
87+
CampaignsFixtures.campaign_fixture(
88+
tenant: tenant,
89+
base_image_id: base_image.id,
90+
mechanism_type: :firmware_upgrade
91+
)
92+
93+
Edgehog.Campaigns.mark_campaign_in_progress(campaign)
94+
95+
result = delete_base_image_mutation(tenant: tenant, id: id)
96+
97+
assert %{
98+
fields: [:id],
99+
message: "Base image is currently in use by at least one running campaign"
100+
} =
101+
extract_error!(result)
102+
end
103+
104+
test "deletes an image if the image is used in a completed Update Campaign", %{
105+
tenant: tenant,
106+
base_image: fixture,
107+
id: id
85108
} do
86109
CampaignsFixtures.campaign_fixture(
87110
tenant: tenant,
88-
base_image_id: base_image.id,
111+
base_image_id: fixture.id,
89112
mechanism_type: :firmware_upgrade
90113
)
91114

92-
result = delete_base_image_mutation(tenant: tenant, id: id)
115+
expect(StorageMock, :delete, fn _ -> :ok end)
93116

94-
assert %{fields: [:id], message: "Base image is currently in use by at least one campaign"} =
95-
extract_error!(result)
117+
base_image =
118+
[tenant: tenant, id: id]
119+
|> delete_base_image_mutation()
120+
|> extract_result!()
121+
122+
assert base_image["version"] == fixture.version
123+
124+
refute BaseImage
125+
|> Ash.Query.filter(id == ^fixture.id)
126+
|> Ash.Query.set_tenant(tenant)
127+
|> Ash.exists?()
96128
end
97129
end
98130

0 commit comments

Comments
 (0)