Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
nshoes committed Nov 26, 2024
1 parent 5ef3530 commit d3db206
Show file tree
Hide file tree
Showing 25 changed files with 209 additions and 107 deletions.
4 changes: 2 additions & 2 deletions lib/nerves_hub/accounts/remove_account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule NervesHub.Accounts.RemoveAccount do
alias NervesHub.{
Accounts,
Firmwares,
Deployments.Deployment,
Deployments.DeploymentGroup,
Products,
Repo,
OrgKey,
Expand All @@ -25,7 +25,7 @@ defmodule NervesHub.Accounts.RemoveAccount do
|> Multi.delete_all(:invites, &query_by_org_id(Invite, &1))
|> Multi.delete_all(:device_certificates, &query_by_org_id(DeviceCertificate, &1))
|> Multi.delete_all(:ca_certificates, &query_by_org_id(CACertificate, &1))
|> Multi.delete_all(:deployments, &query_by_org_id(Deployment, &1))
|> Multi.delete_all(:deployments, &query_by_org_id(DeploymentGroup, &1))
|> Multi.delete_all(:firmware_deltas, &query_firmware_deltas/1)
|> Multi.delete_all(:firmware_transfers, &query_by_org_id(FirmwareTransfer, &1))
|> Multi.merge(&delete_firmwares/1)
Expand Down
6 changes: 3 additions & 3 deletions lib/nerves_hub/audit_logs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule NervesHub.AuditLogs do
import Ecto.Query

alias NervesHub.AuditLogs.AuditLog
alias NervesHub.Deployments.Deployment
alias NervesHub.Deployments.DeploymentGroup
alias NervesHub.Repo
alias NimbleCSV.RFC4180, as: CSV

Expand Down Expand Up @@ -58,8 +58,8 @@ defmodule NervesHub.AuditLogs do
|> Flop.run(flop)
end

defp query_for_feed(%Deployment{id: id}) do
resource_type = to_string(Deployment)
defp query_for_feed(%DeploymentGroup{id: id}) do
resource_type = to_string(DeploymentGroup)

from(al in AuditLog, where: [resource_type: ^resource_type, resource_id: ^id])
|> order_by(desc: :inserted_at)
Expand Down
95 changes: 69 additions & 26 deletions lib/nerves_hub/deployments.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ defmodule NervesHub.Deployments do
require Logger

alias NervesHub.AuditLogs
alias NervesHub.Deployments.Deployment
alias NervesHub.Deployments.DeploymentGroup
alias NervesHub.Deployments.InflightDeploymentCheck
alias NervesHub.Devices.Device
alias NervesHub.Products.Product
alias NervesHub.Repo
alias Ecto.Changeset

def all() do
Repo.all(Deployment)
Repo.all(DeploymentGroup)
end

@spec get_deployments_by_product(integer()) :: [Deployment.t()]
@spec get_deployments_by_product(integer()) :: [DeploymentGroup.t()]
def get_deployments_by_product(product_id) do
from(
d in Deployment,
d in DeploymentGroup,
join: f in assoc(d, :firmware),
where: f.product_id == ^product_id,
preload: [{:firmware, :product}]
Expand All @@ -44,14 +44,14 @@ defmodule NervesHub.Deployments do
|> Repo.one()
end

@spec get_deployments_by_firmware(integer()) :: [Deployment.t()]
@spec get_deployments_by_firmware(integer()) :: [DeploymentGroup.t()]
def get_deployments_by_firmware(firmware_id) do
from(d in Deployment, where: d.firmware_id == ^firmware_id)
from(d in DeploymentGroup, where: d.firmware_id == ^firmware_id)
|> Repo.all()
end

def get(id) when is_integer(id) do
case Repo.get(Deployment, id) do
case Repo.get(DeploymentGroup, id) do
nil ->
{:error, :not_found}

Expand All @@ -60,16 +60,17 @@ defmodule NervesHub.Deployments do
end
end

@spec get_deployment(Product.t(), String.t()) :: {:ok, Deployment.t()} | {:error, :not_found}
@spec get_deployment(Product.t(), String.t()) ::
{:ok, DeploymentGroup.t()} | {:error, :not_found}
def get_deployment(%Product{id: product_id}, deployment_id) do
from(
d in Deployment,
d in DeploymentGroup,
where: d.id == ^deployment_id,
join: f in assoc(d, :firmware),
where: f.product_id == ^product_id,
preload: [{:firmware, :product}]
)
|> Deployment.with_firmware()
|> DeploymentGroup.with_firmware()
|> Repo.one()
|> case do
nil ->
Expand All @@ -80,16 +81,16 @@ defmodule NervesHub.Deployments do
end
end

def get_deployment!(deployment_id), do: Repo.get!(Deployment, deployment_id)
def get_deployment!(deployment_id), do: Repo.get!(DeploymentGroup, deployment_id)

@spec get_by_product_and_name!(Product.t(), String.t()) :: Deployment.t()
@spec get_by_product_and_name!(Product.t(), String.t()) :: DeploymentGroup.t()
def get_by_product_and_name!(product, name) do
get_by_product_and_name_query(product, name)
|> Repo.one!()
end

@spec get_deployment_by_name(Product.t(), String.t()) ::
{:ok, Deployment.t()} | {:error, :not_found}
{:ok, DeploymentGroup.t()} | {:error, :not_found}
def get_deployment_by_name(product, name) do
get_by_product_and_name_query(product, name)
|> Repo.one()
Expand All @@ -103,17 +104,18 @@ defmodule NervesHub.Deployments do
end

defp get_by_product_and_name_query(%Product{id: product_id}, name) do
Deployment
DeploymentGroup
|> where(name: ^name)
|> where(product_id: ^product_id)
|> join(:left, [d], f in assoc(d, :firmware))
|> join(:left, [d], p in assoc(d, :product))
|> preload([d, f, p], firmware: f, product: p)
end

@spec delete_deployment(Deployment.t()) :: {:ok, Deployment.t()} | {:error, :not_found}
def delete_deployment(%Deployment{id: deployment_id}) do
case Repo.delete(Repo.get!(Deployment, deployment_id)) do
@spec delete_deployment(DeploymentGroup.t()) ::
{:ok, DeploymentGroup.t()} | {:error, :not_found}
def delete_deployment(%DeploymentGroup{id: deployment_id}) do
case Repo.delete(Repo.get!(DeploymentGroup, deployment_id)) do
{:error, _changeset} ->
{:error, :not_found}

Expand All @@ -129,7 +131,8 @@ defmodule NervesHub.Deployments do
- Records audit logs depending on changes
"""
@spec update_deployment(Deployment.t(), map) :: {:ok, Deployment.t()} | {:error, Changeset.t()}
@spec update_deployment(DeploymentGroup.t(), map) ::
{:ok, DeploymentGroup.t()} | {:error, Changeset.t()}
def update_deployment(deployment, params) do
result =
Repo.transaction(fn ->
Expand All @@ -141,8 +144,8 @@ defmodule NervesHub.Deployments do

changeset =
deployment
|> Deployment.with_firmware()
|> Deployment.changeset(params)
|> DeploymentGroup.with_firmware()
|> DeploymentGroup.changeset(params)
|> Ecto.Changeset.put_change(:total_updating_devices, device_count)

case Repo.update(changeset) do
Expand Down Expand Up @@ -213,9 +216,49 @@ defmodule NervesHub.Deployments do
end

@doc """
<<<<<<< HEAD
=======
Create any matching inflight deployment checks for devices
This includes devices that are already part of the deployment and devices
that have no current deployment. They all will be rechecked by `NervesHub.Deployments.Calculator`
Also clears any previous inflight checks for this deployment.
"""
def schedule_deployment_calculations(deployment_group) do
query =
Device
|> select([d], %{
worker: "NervesHub.Workers.DeviceCalculateDeployment",
queue: "device_deployment_calculations",
args:
fragment(
"json_build_object('device_id', ?, 'deployment_id', ?::integer)",
d.id,
^deployment_group.id
)
})
|> where([d], d.status == :provisioned)
|> where(
[d],
d.deployment_id == ^deployment_group.id or
(is_nil(d.deployment_id) and d.product_id == ^deployment_group.product_id)
)
|> where([d], d.firmware_metadata["platform"] == ^deployment_group.firmware.platform)
|> where(
[d],
d.firmware_metadata["architecture"] == ^deployment_group.firmware.architecture
)
|> where([d], fragment("? <@ ?", ^deployment_group.conditions["tags"], d.tags))

Repo.insert_all(Oban.Job, query)
end

@doc """
>>>>>>> 0bad5315 (WIP)
Delete any matching inflight deployment checks for devices
"""
@spec delete_inflight_checks(Deployment.t()) :: :ok
@spec delete_inflight_checks(DeploymentGroup.t()) :: :ok
def delete_inflight_checks(deployment) do
_ =
InflightDeploymentCheck
Expand All @@ -225,14 +268,14 @@ defmodule NervesHub.Deployments do
:ok
end

@spec change_deployment(Deployment.t(), map()) :: Changeset.t()
@spec change_deployment(DeploymentGroup.t(), map()) :: Changeset.t()
def change_deployment(deployment, params) do
Deployment.changeset(deployment, params)
DeploymentGroup.changeset(deployment, params)
end

@spec create_deployment(map) :: {:ok, Deployment.t()} | {:error, Changeset.t()}
@spec create_deployment(map) :: {:ok, DeploymentGroup.t()} | {:error, Changeset.t()}
def create_deployment(params) do
changeset = Deployment.creation_changeset(%Deployment{}, params)
changeset = DeploymentGroup.creation_changeset(%DeploymentGroup{}, params)

case Repo.insert(changeset) do
{:ok, deployment} ->
Expand Down Expand Up @@ -265,7 +308,7 @@ defmodule NervesHub.Deployments do
)
end

def broadcast(%Deployment{id: id}, event, payload) do
def broadcast(%DeploymentGroup{id: id}, event, payload) do
message = %Phoenix.Socket.Broadcast{
topic: "deployment:#{id}",
event: event,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule NervesHub.Deployments.Deployment do
defmodule NervesHub.Deployments.DeploymentGroup do
use Ecto.Schema

import Ecto.Changeset
Expand Down Expand Up @@ -48,7 +48,7 @@ defmodule NervesHub.Deployments.Deployment do
belongs_to(:org, Org, where: [deleted_at: nil])
belongs_to(:archive, Archive)

has_many(:inflight_updates, InflightUpdate)
has_many(:inflight_updates, InflightUpdate, foreign_key: :deployment_id)

field(:conditions, :map)
field(:device_failure_threshold, :integer, default: 3)
Expand All @@ -72,7 +72,7 @@ defmodule NervesHub.Deployments.Deployment do
timestamps()
end

def creation_changeset(%Deployment{} = deployment, params) do
def creation_changeset(%DeploymentGroup{} = deployment, params) do
# set product_id by getting it from firmware
with_product_id = handle_product_id(deployment, params)

Expand All @@ -93,27 +93,27 @@ defmodule NervesHub.Deployments.Deployment do
end
end

defp handle_product_id(%Deployment{}, %{firmware: %Firmware{product_id: p_id}} = params) do
defp handle_product_id(%DeploymentGroup{}, %{firmware: %Firmware{product_id: p_id}} = params) do
params |> Map.put(:product_id, p_id)
end

defp handle_product_id(%Deployment{firmware: %Firmware{product_id: p_id}}, params) do
defp handle_product_id(%DeploymentGroup{firmware: %Firmware{product_id: p_id}}, params) do
params |> Map.put(:product_id, p_id)
end

defp handle_product_id(%Deployment{} = d, %{firmware_id: f_id} = params) do
defp handle_product_id(%DeploymentGroup{} = d, %{firmware_id: f_id} = params) do
handle_product_id(d, params |> Map.put(:firmware, Firmware |> Repo.get!(f_id)))
end

defp handle_product_id(%Deployment{firmware_id: nil}, params) do
defp handle_product_id(%DeploymentGroup{firmware_id: nil}, params) do
params
end

defp handle_product_id(%Deployment{} = d, params) do
defp handle_product_id(%DeploymentGroup{} = d, params) do
handle_product_id(d |> with_firmware(), params)
end

def changeset(%Deployment{} = deployment, params) do
def changeset(%DeploymentGroup{} = deployment, params) do
deployment
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
Expand All @@ -128,9 +128,9 @@ defmodule NervesHub.Deployments.Deployment do
|> validate_conditions()
end

def with_firmware(%Deployment{firmware: %Firmware{}} = d), do: d
def with_firmware(%DeploymentGroup{firmware: %Firmware{}} = d), do: d

def with_firmware(%Deployment{} = d) do
def with_firmware(%DeploymentGroup{} = d) do
d
|> Repo.preload(:firmware)
end
Expand All @@ -140,9 +140,9 @@ defmodule NervesHub.Deployments.Deployment do
|> preload(:firmware)
end

def with_product(%Deployment{product: %Product{}} = d), do: d
def with_product(%DeploymentGroup{product: %Product{}} = d), do: d

def with_product(%Deployment{} = d) do
def with_product(%DeploymentGroup{} = d) do
d
|> Repo.preload(:product)
end
Expand Down
43 changes: 43 additions & 0 deletions lib/nerves_hub/deployments/deployment_release.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule NervesHub.Deployments.DeploymentRelease do
use Ecto.Schema

import Ecto.Changeset

alias NervesHub.Archives.Archive
alias NervesHub.Deployments.DeploymentGroup
alias NervesHub.Firmwares.Firmware
alias NervesHub.Accounts.User

alias __MODULE__

@type t :: %__MODULE__{}

@required_fields [
:deployment_group_id,
:firmware_id,
:created_by_id,
:status
]

@optional_fields [:archive_id]

schema "deployment_releases" do
belongs_to(:deployment_group, DeploymentGroup)
belongs_to(:firmware, Firmware)
belongs_to(:archive, Archive)
belongs_to(:user, User, foreign_key: :created_by_id)

field(:status, Ecto.Enum,
values: [:inactive, :active, :error, :paused, :complete],
default: :inactive
)

timestamps()
end

def changeset(%DeploymentRelease{} = deployment_release, params) do
deployment_release
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
4 changes: 2 additions & 2 deletions lib/nerves_hub/deployments/inflight_deployment_check.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ defmodule NervesHub.Deployments.InflightDeploymentCheck do

@timestamps_opts updated_at: false

alias NervesHub.Deployments.Deployment
alias NervesHub.Deployments.DeploymentGroup
alias NervesHub.Devices.Device

schema "inflight_deployment_checks" do
belongs_to(:device, Device)
belongs_to(:deployment, Deployment)
belongs_to(:deployment, DeploymentGroup)

timestamps()
end
Expand Down
Loading

0 comments on commit d3db206

Please sign in to comment.