Skip to content

Commit

Permalink
Merge pull request #79 from upmaru/feature/remove-instellar-orchestra…
Browse files Browse the repository at this point in the history
…tion-dependency

Feature/remove instellar orchestration dependency
  • Loading branch information
zacksiri authored Nov 24, 2023
2 parents 1a65af7 + bfca380 commit c53e4c2
Show file tree
Hide file tree
Showing 21 changed files with 712 additions and 340 deletions.
2 changes: 1 addition & 1 deletion lib/uplink/clients/caddy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule Uplink.Clients.Caddy do
end

params
|> Config.Reload.new(schedule_in: 5)
|> Config.Reload.new(schedule_in: 1)
|> Oban.insert()
end

Expand Down
40 changes: 28 additions & 12 deletions lib/uplink/clients/caddy/config/builder.ex
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
defmodule Uplink.Clients.Caddy.Config.Builder do
alias Uplink.{
Clients,
Packages,
Repo
}
alias Uplink.Repo
alias Uplink.Cache

alias Clients.Caddy
alias Caddy.Admin
alias Caddy.Apps
alias Caddy.Storage
alias Uplink.Packages

alias Uplink.Clients.Caddy.Admin
alias Uplink.Clients.Caddy.Apps
alias Uplink.Clients.Caddy.Storage

def new do
install_states =
Expand Down Expand Up @@ -94,7 +92,10 @@ defmodule Uplink.Clients.Caddy.Config.Builder do
end

defp build_route(
%{install: %{deployment: %{app: _app}}, metadata: metadata} = _state
%{
install: %{id: install_id, deployment: %{app: _app}},
metadata: metadata
} = _state
) do
main_routing = Map.get(metadata.main_port, :routing)

Expand All @@ -112,6 +113,8 @@ defmodule Uplink.Clients.Caddy.Config.Builder do
"installation_#{metadata.id}"
end

valid_instances = find_valid_instances(metadata.instances, install_id)

main_route = %{
group: main_group,
match: [
Expand All @@ -138,7 +141,7 @@ defmodule Uplink.Clients.Caddy.Config.Builder do
}
},
upstreams:
Enum.map(metadata.instances, fn instance ->
Enum.map(valid_instances, fn instance ->
%{
dial: "#{instance.slug}:#{metadata.main_port.target}",
max_requests: 80
Expand Down Expand Up @@ -196,7 +199,7 @@ defmodule Uplink.Clients.Caddy.Config.Builder do
}
},
upstreams:
Enum.map(metadata.instances, fn instance ->
Enum.map(valid_instances, fn instance ->
%{
dial: "#{instance.slug}:#{port.target}",
max_requests: 80
Expand All @@ -209,4 +212,17 @@ defmodule Uplink.Clients.Caddy.Config.Builder do

[main_route | sub_routes]
end

defp find_valid_instances(instances, install_id) do
completed_instances = Cache.get({:install, install_id, "completed"})

if is_list(completed_instances) and Enum.count(completed_instances) > 0 do
instances
|> Enum.filter(fn instance ->
instance.slug in completed_instances
end)
else
instances
end
end
end
20 changes: 0 additions & 20 deletions lib/uplink/clients/caddy/config/reload.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,6 @@ defmodule Uplink.Clients.Caddy.Config.Reload do
end)
end)

maybe_mark_install_complete(install, params)

:ok
end

defp maybe_mark_install_complete(
%Install{current_state: "refreshing"} = install,
params
) do
actor_id = Map.get(params, "actor_id")

actor =
if actor_id do
Repo.get(Members.Actor, actor_id)
else
Members.get_bot!()
end

Packages.transition_install_with(install, actor, "complete")
end

defp maybe_mark_install_complete(_install, _params), do: :ok
end
3 changes: 2 additions & 1 deletion lib/uplink/clients/instellar/instance.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ defmodule Uplink.Clients.Instellar.Instance do
json: %{
"event" => %{
"name" => event_name,
"comment" => Keyword.get(options, :comment)
"comment" => Keyword.get(options, :comment),
"parameters" => Keyword.get(options, :parameters, %{})
}
},
headers: Instellar.headers(install.deployment.hash)
Expand Down
4 changes: 4 additions & 0 deletions lib/uplink/clients/lxd.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ defmodule Uplink.Clients.LXD do
to: __MODULE__.Instance.Manager,
as: :list

defdelegate list_instances(),
to: __MODULE__.Instance.Manager,
as: :list

defdelegate managed_network(),
to: __MODULE__.Network.Manager,
as: :managed
Expand Down
18 changes: 18 additions & 0 deletions lib/uplink/clients/lxd/instance/manager.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ defmodule Uplink.Clients.LXD.Instance.Manager do
alias Clients.LXD
alias LXD.Instance

def list do
LXD.client()
|> Lexdee.list_instances(query: [{:recursion, 1}, {"all-projects", true}])
|> case do
{:ok, %{body: instances}} ->
instances =
instances
|> Enum.map(fn instance ->
Instance.parse(instance)
end)

instances

error ->
error
end
end

def list(project) do
LXD.client()
|> Lexdee.list_instances(query: [recursion: 1, project: project])
Expand Down
4 changes: 4 additions & 0 deletions lib/uplink/packages.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ defmodule Uplink.Packages do
to: Install.Manager,
as: :transition_with

defdelegate maybe_mark_install_complete(install, actor),
to: Install.Manager,
as: :maybe_mark_complete

alias __MODULE__.Deployment

defdelegate get_deployment(id),
Expand Down
107 changes: 84 additions & 23 deletions lib/uplink/packages/install/execute.ex
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
defmodule Uplink.Packages.Install.Execute do
use Oban.Worker, queue: :install, max_attempts: 1

alias Uplink.{
Clients,
Members,
Packages,
Repo
}
alias Uplink.Repo
alias Uplink.Cache

alias Members.Actor
alias Uplink.Clients.LXD
alias Uplink.Clients.Instellar

alias Packages.{
Install,
Metadata
}
alias Uplink.Members.Actor

alias Clients.{
LXD,
Instellar
}
alias Uplink.Packages
alias Uplink.Packages.Install
alias Uplink.Packages.Metadata
alias Uplink.Packages.Instance

alias Uplink.Packages.Instance.Bootstrap
alias Uplink.Packages.Instance.Upgrade

import Ecto.Query,
only: [where: 3, preload: 2]

@state ~s(executing)

@task_supervisor Application.compile_env(:uplink, :task_supervisor) ||
Task.Supervisor

@transition_parameters %{
"from" => "uplink",
"trigger" => false
}

def perform(%Oban.Job{
args: %{"install_id" => install_id, "actor_id" => actor_id}
}) do
Expand Down Expand Up @@ -54,16 +59,21 @@ defmodule Uplink.Packages.Install.Execute do

project = Packages.get_project_name(client, metadata)

existing_instances_name =
existing_instances =
LXD.list_instances(project)
|> Enum.filter(&only_uplink_instance/1)
|> Enum.map(fn instance ->
instance.name
end)

Cache.put({:install, state.install.id, "completed"}, [],
ttl: :timer.hours(24)
)

Cache.put({:install, state.install.id, "executing"}, [],
ttl: :timer.hours(24)
)

jobs =
instances
|> Enum.map(&choose_execution_path(&1, existing_instances_name, state))
|> Enum.map(&choose_execution_path(&1, existing_instances, state))

{:ok, jobs}
end
Expand All @@ -75,11 +85,62 @@ defmodule Uplink.Packages.Install.Execute do
end

defp choose_execution_path(instance, existing_instances, state) do
existing_instances_name = Enum.map(existing_instances, & &1.name)

event_name =
if instance.slug in existing_instances, do: "upgrade", else: "boot"
if instance.slug in existing_instances_name, do: "upgrade", else: "boot"

Instellar.transition_instance(instance.slug, state.install, event_name,
comment: "[Uplink.Packages.Install.Execute]"
@task_supervisor.async_nolink(Uplink.TaskSupervisor, fn ->
Instellar.transition_instance(instance.slug, state.install, event_name,
comment: "[Uplink.Packages.Install.Execute]",
parameters: @transition_parameters
)
end)

Cache.transaction(
[keys: [{:install, state.install.id, "executing"}]],
fn ->
Cache.get_and_update(
{:install, state.install.id, "executing"},
fn current_value ->
executing_instances =
if current_value,
do: current_value ++ [instance.slug],
else: [instance.slug]

{current_value, Enum.uniq(executing_instances)}
end
)
end
)

case event_name do
"upgrade" ->
existing_instance =
Enum.find(existing_instances, &(&1.name == instance.slug))

%{
"instance" => %{
"slug" => instance.slug,
"node" => %{
"slug" => existing_instance.location
}
},
"install_id" => state.install.id,
"actor_id" => state.actor.id
}
|> Upgrade.new()
|> Oban.insert()

"boot" ->
Bootstrap.new(%{
"instance" => %{
"slug" => instance.slug
},
"install_id" => state.install.id,
"actor_id" => state.actor.id
})
|> Oban.insert()
end
end
end
11 changes: 11 additions & 0 deletions lib/uplink/packages/install/manager.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ defmodule Uplink.Packages.Install.Manager do
|> Repo.one()
end

def maybe_mark_complete(%Install{} = install, actor) do
completed_instances = Cache.get({:install, install.id, "completed"})
executing_instances = Cache.get({:install, install.id, "executing"})

if Enum.count(completed_instances) == Enum.count(executing_instances) do
Packages.transition_install_with(install, actor, "complete")
else
{:ok, :executing}
end
end

@spec build_state(%Install{}, %Actor{} | nil) :: %{
install: %Install{},
metadata: %Metadata{},
Expand Down
Loading

0 comments on commit c53e4c2

Please sign in to comment.