Skip to content

Commit

Permalink
Merge pull request #731 from noaccOS/feat/run-ready-action
Browse files Browse the repository at this point in the history
feat(containers): run ready actions when the deployment is ready
  • Loading branch information
lusergit authored Nov 25, 2024
2 parents 59babfd + 6c12827 commit 50c3ce5
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 4 deletions.
13 changes: 11 additions & 2 deletions backend/lib/edgehog/containers/containers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ defmodule Edgehog.Containers do

alias Edgehog.Containers.Application
alias Edgehog.Containers.Deployment
alias Edgehog.Containers.DeploymentReadyAction
alias Edgehog.Containers.DeploymentReadyAction.Upgrade
alias Edgehog.Containers.ImageCredentials
alias Edgehog.Containers.Release

Expand Down Expand Up @@ -103,6 +105,7 @@ defmodule Edgehog.Containers do
define :delete_deployment, action: :destroy
define :deployment_update_status, action: :update_status
define :deployments_with_release, action: :filter_by_release, args: [:release_id]
define :run_ready_actions, action: :run_ready_actions
end

resource Edgehog.Containers.Image do
Expand All @@ -124,13 +127,19 @@ defmodule Edgehog.Containers do
resource Edgehog.Containers.Network
resource Edgehog.Containers.Volume

resource Edgehog.Containers.DeploymentReadyAction
resource Edgehog.Containers.DeploymentReadyAction.Upgrade
resource DeploymentReadyAction
resource Upgrade

resource Edgehog.Containers.ContainerNetwork do
define :containers_with_network,
action: :containers_by_network,
args: [:network_id]
end

resource DeploymentReadyAction do
define :run_ready_action, action: :run
end

resource Upgrade
end
end
12 changes: 12 additions & 0 deletions backend/lib/edgehog/containers/deployment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ defmodule Edgehog.Containers.Deployment do
manual {ManualActions.SendDeploymentCommand, command: :delete}
end

update :run_ready_actions do
description """
Executes deployment callbacks
"""

manual ManualActions.RunReadyActions
end

action :send_deploy_request do
argument :deployment, :struct do
constraints instance_of: __MODULE__
Expand Down Expand Up @@ -144,6 +152,10 @@ defmodule Edgehog.Containers.Deployment do
attribute_type :uuid
public? true
end

has_many :ready_actions, Edgehog.Containers.DeploymentReadyAction do
public? true
end
end

identities do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ defmodule Edgehog.Containers.Deployment.Changes.CheckDeployments do
@moduledoc false
use Ash.Resource.Change

alias Edgehog.Containers
alias Edgehog.Devices

@impl Ash.Resource.Change
Expand All @@ -37,7 +38,13 @@ defmodule Edgehog.Containers.Deployment.Changes.CheckDeployments do
Enum.map(available_deployments, & &1.id)

if deployment.id in available_deployments do
Ash.Changeset.change_attribute(changeset, :status, :ready)
changeset
|> Ash.Changeset.change_attribute(:status, :ready)
|> Ash.Changeset.after_transaction(fn _changeset, transaction_result ->
with {:ok, deployment} <- transaction_result do
Containers.run_ready_actions(deployment)
end
end)
else
changeset
end
Expand Down
4 changes: 4 additions & 0 deletions backend/lib/edgehog/containers/deployment_ready_action.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ defmodule Edgehog.Containers.DeploymentReadyAction do
change manage_relationship(:deployment, on_no_match: {:create, :deploy}, on_match: :ignore)
change ManualActions.DeploymentReadyActionAddRelationship
end

update :run do
manual ManualActions.RunReadyAction
end
end

attributes do
Expand Down
59 changes: 59 additions & 0 deletions backend/lib/edgehog/containers/manual_actions/run_ready_action.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#
# 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.Containers.ManualActions.RunReadyAction do
@moduledoc false

use Ash.Resource.ManualUpdate

alias Edgehog.Devices

require Ash.Query

@impl Ash.Resource.ManualUpdate
def update(changeset, _opts, _context) do
ready_action = changeset.data
action_type = ready_action.action_type

extra_loads =
case action_type do
:upgrade_deployment -> [upgrade_deployment: [:upgrade_target]]
end

# We always load the device
loads = extra_loads ++ [deployment: [:device]]

with {:ok, ready_action} <- Ash.load(ready_action, loads),
:ok <- run_ready_action(ready_action, action_type) do
{:ok, ready_action}
end
end

defp run_ready_action(action, :upgrade_deployment) do
with {:ok, _device} <-
Devices.update_application(
action.deployment.device,
action.upgrade_deployment.upgrade_target,
action.deployment
) do
:ok
end
end
end
45 changes: 45 additions & 0 deletions backend/lib/edgehog/containers/manual_actions/run_ready_actions.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# 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.Containers.ManualActions.RunReadyActions do
@moduledoc false

use Ash.Resource.ManualUpdate

alias Edgehog.Containers

require Ash.Query
require Logger

@impl Ash.Resource.ManualUpdate
def update(changeset, _opts, _context) do
deployment = changeset.data

with {:ok, deployment} <- Ash.load(deployment, :ready_actions) do
ready_actions_results = Enum.map(deployment.ready_actions, &Containers.run_ready_action/1)

for {status, result} <- ready_actions_results, status == :error do
Logger.error("Error running ready action for deployment #{deployment.id}: #{inspect(result)}")
end

{:ok, deployment}
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,18 @@ defmodule EdgehogWeb.Schema.Mutation.SendDeploymentUpgradeTest do

import Edgehog.ContainersFixtures

alias Edgehog.Astarte.Device.AvailableContainers.ContainerStatus
alias Edgehog.Astarte.Device.AvailableContainersMock
alias Edgehog.Astarte.Device.AvailableDeployments.DeploymentStatus
alias Edgehog.Astarte.Device.AvailableDeploymentsMock
alias Edgehog.Astarte.Device.AvailableImages.ImageStatus
alias Edgehog.Astarte.Device.AvailableImagesMock
alias Edgehog.Astarte.Device.AvailableNetworks.NetworkStatus
alias Edgehog.Astarte.Device.AvailableNetworksMock
alias Edgehog.Astarte.Device.CreateDeploymentRequestMock
alias Edgehog.Astarte.Device.DeploymentUpdateMock
alias Edgehog.Containers
alias Edgehog.Containers.Deployment

describe "sendDeploymentUpgrade" do
setup %{tenant: tenant} do
Expand All @@ -48,7 +59,7 @@ defmodule EdgehogWeb.Schema.Mutation.SendDeploymentUpgradeTest do
}
end

test "correctly sends the deployment upgrade with valid data", args do
test "correctly sends the deployment request with valid data", args do
%{deployment_0_0_1: deployment_0_0_1, release_0_0_2: release_0_0_2, tenant: tenant} =
args

Expand All @@ -66,6 +77,26 @@ defmodule EdgehogWeb.Schema.Mutation.SendDeploymentUpgradeTest do
|> Map.fetch!(:deployment_id) == deployment_id
end

test "sends the deployment upgrade once the new deployment reaches :ready state", args do
%{deployment_0_0_1: deployment_0_0_1, release_0_0_2: release_0_0_2, tenant: tenant} =
args

expect(CreateDeploymentRequestMock, :send_create_deployment_request, fn _, _, _ -> :ok end)
expect(DeploymentUpdateMock, :update, fn _, _, _ -> :ok end)

result =
[tenant: tenant, deployment: deployment_0_0_1, target: release_0_0_2]
|> send_deployment_upgrade_mutation()
|> extract_result!()

{:ok, %{id: deployment_id}} = AshGraphql.Resource.decode_relay_id(result["id"])

deployment = Ash.get!(Deployment, deployment_id, tenant: tenant)
set_resource_expectations([deployment_0_0_1, deployment])

Containers.deployment_update_status!(deployment)
end

test "fails if the deployments do not belong to the same application", args do
%{deployment_0_0_1: deployment_0_0_1, release_0_0_2: release_0_0_2, tenant: tenant} =
args
Expand Down Expand Up @@ -142,4 +173,37 @@ defmodule EdgehogWeb.Schema.Mutation.SendDeploymentUpgradeTest do

error
end

defp set_resource_expectations(deployments) do
deployments =
Enum.map(deployments, &Ash.load!(&1, release: [containers: [:image, :networks]]))

containers =
deployments
|> Enum.map(& &1.release)
|> Enum.flat_map(& &1.containers)
|> Enum.uniq_by(& &1.id)

available_containers = Enum.map(containers, &%ContainerStatus{id: &1.id, status: "Created"})

available_images =
containers
|> Enum.flat_map(& &1.image)
|> Enum.map(&%ImageStatus{id: &1.id, pulled: false})
|> Enum.uniq()

available_networks =
containers
|> Enum.flat_map(& &1.network)
|> Enum.map(&%NetworkStatus{id: &1.id, created: false})
|> Enum.uniq()

available_deployments =
Enum.map(deployments, &%DeploymentStatus{id: &1.id, status: :stopped})

expect(AvailableImagesMock, :get, fn _, _ -> {:ok, available_images} end)
expect(AvailableNetworksMock, :get, fn _, _ -> {:ok, available_networks} end)
expect(AvailableContainersMock, :get, fn _, _ -> {:ok, available_containers} end)
expect(AvailableDeploymentsMock, :get, fn _, _ -> {:ok, available_deployments} end)
end
end

0 comments on commit 50c3ce5

Please sign in to comment.