Implements the management of Deployment Group's agent keys (#2458)

This commit is contained in:
Alexandre de Souza 2024-01-30 14:20:46 -03:00 committed by GitHub
parent 80cd944d3e
commit 1ceab6f540
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 688 additions and 134 deletions

View file

@ -7,7 +7,6 @@ defmodule Livebook.Hubs.TeamClient do
alias Livebook.Hubs
alias Livebook.Secrets
alias Livebook.Teams
alias Livebook.Teams.DeploymentGroup
@registry Livebook.HubsRegistry
@supervisor Livebook.HubsSupervisor
@ -74,7 +73,7 @@ defmodule Livebook.Hubs.TeamClient do
@doc """
Returns a list of cached deployment groups.
"""
@spec get_deployment_groups(String.t()) :: list(DeploymentGroup.t())
@spec get_deployment_groups(String.t()) :: list(Teams.DeploymentGroup.t())
def get_deployment_groups(id) do
GenServer.call(registry_name(id), :get_deployment_groups)
end
@ -152,7 +151,7 @@ defmodule Livebook.Hubs.TeamClient do
end
def handle_call(:get_secrets, _caller, state) do
case find_deployment_group(state) do
case find_deployment_group(state.deployment_group_id, state.deployment_groups) do
nil ->
{:reply, state.secrets, state}
@ -266,18 +265,42 @@ defmodule Livebook.Hubs.TeamClient do
}
end
defp put_agent_key(deployment_group, agent_key) do
deployment_group = remove_agent_key(deployment_group, agent_key)
agent_keys = [agent_key | deployment_group.agent_keys]
%{deployment_group | agent_keys: Enum.sort_by(agent_keys, & &1.id)}
end
defp remove_agent_key(deployment_group, agent_key) do
%{
deployment_group
| agent_keys: Enum.reject(deployment_group.agent_keys, &(&1.id == agent_key.id))
}
end
defp build_agent_key(agent_key) do
%Teams.AgentKey{
id: agent_key.id,
key: agent_key.key,
deployment_group_id: agent_key.deployment_group_id
}
end
defp build_deployment_group(state, deployment_group) do
secrets = Enum.map(deployment_group.secrets, &build_secret(state, &1))
agent_keys = Enum.map(deployment_group.agent_keys, &build_agent_key/1)
%DeploymentGroup{
%Teams.DeploymentGroup{
id: deployment_group.id,
name: deployment_group.name,
mode: deployment_group.mode,
mode: String.to_existing_atom(deployment_group.mode),
hub_id: state.hub.id,
secrets: secrets,
clustering: deployment_group.clustering,
zta_provider: String.to_atom(deployment_group.zta_provider),
zta_key: deployment_group.zta_key
agent_keys: agent_keys,
clustering: nullify(deployment_group.clustering),
zta_provider: atomize(deployment_group.zta_provider),
zta_key: nullify(deployment_group.zta_key)
}
end
@ -344,7 +367,7 @@ defmodule Livebook.Hubs.TeamClient do
end
end
defp handle_event(:deployment_group_created, %DeploymentGroup{} = deployment_group, state) do
defp handle_event(:deployment_group_created, %Teams.DeploymentGroup{} = deployment_group, state) do
Teams.Broadcasts.deployment_group_created(deployment_group)
put_deployment_group(state, deployment_group)
@ -358,7 +381,7 @@ defmodule Livebook.Hubs.TeamClient do
)
end
defp handle_event(:deployment_group_updated, %DeploymentGroup{} = deployment_group, state) do
defp handle_event(:deployment_group_updated, %Teams.DeploymentGroup{} = deployment_group, state) do
Teams.Broadcasts.deployment_group_updated(deployment_group)
put_deployment_group(state, deployment_group)
@ -397,6 +420,32 @@ defmodule Livebook.Hubs.TeamClient do
|> dispatch_deployment_groups(agent_connected)
end
defp handle_event(:agent_key_created, agent_key_created, state) do
agent_key = build_agent_key(agent_key_created)
if deployment_group =
find_deployment_group(agent_key.deployment_group_id, state.deployment_groups) do
handle_event(:deployment_group_updated, put_agent_key(deployment_group, agent_key), state)
else
state
end
end
defp handle_event(:agent_key_deleted, agent_key_deleted, state) do
agent_key = build_agent_key(agent_key_deleted)
if deployment_group =
find_deployment_group(agent_key.deployment_group_id, state.deployment_groups) do
handle_event(
:deployment_group_updated,
remove_agent_key(deployment_group, agent_key),
state
)
else
state
end
end
defp dispatch_secrets(state, %{secrets: secrets}) do
decrypted_secrets = Enum.map(secrets, &build_secret(state, &1))
@ -451,8 +500,9 @@ defmodule Livebook.Hubs.TeamClient do
defp update_hub(state, %{public_key: org_public_key}) do
hub = %{state.hub | org_public_key: org_public_key}
# TODO: Fix this before merging
# ^hub = Hubs.save_hub(hub)
if Livebook.Hubs.hub_exists?(hub.id) do
Hubs.save_hub(hub)
end
%{state | hub: hub}
end
@ -475,9 +525,12 @@ defmodule Livebook.Hubs.TeamClient do
do: (acc -> handle_event(topic, event, acc))
end
defp find_deployment_group(%{deployment_group_id: nil}),
do: nil
defp find_deployment_group(nil, _), do: nil
defp find_deployment_group(id, groups), do: Enum.find(groups, &(&1.id == id))
defp find_deployment_group(%{deployment_group_id: id, deployment_groups: groups}),
do: Enum.find(groups, &(&1.id == id))
defp atomize(value) when value in [nil, ""], do: nil
defp atomize(value), do: String.to_existing_atom(value)
defp nullify(""), do: nil
defp nullify(value), do: value
end

View file

@ -4,7 +4,7 @@ defmodule Livebook.Teams do
alias Livebook.Hubs
alias Livebook.Hubs.Team
alias Livebook.Hubs.TeamClient
alias Livebook.Teams.{Requests, Org, DeploymentGroup}
alias Livebook.Teams.{AgentKey, DeploymentGroup, Org, Requests}
import Ecto.Changeset,
only: [add_error: 3, apply_action: 2, apply_action!: 2, get_field: 2]
@ -177,14 +177,9 @@ defmodule Livebook.Teams do
| {:transport_error, String.t()}
def update_deployment_group(%Team{} = team, deployment_group) do
case Requests.update_deployment_group(team, deployment_group) do
{:ok, %{"id" => id}} ->
{:ok, id}
{:error, %{"errors" => errors}} ->
{:error, Requests.add_errors(deployment_group, errors)}
any ->
any
{:ok, %{"id" => id}} -> {:ok, id}
{:error, %{"errors" => errors}} -> {:error, Requests.add_errors(deployment_group, errors)}
any -> any
end
end
@ -197,14 +192,9 @@ defmodule Livebook.Teams do
| {:transport_error, String.t()}
def create_deployment_group(%Team{} = team, deployment_group) do
case Requests.create_deployment_group(team, deployment_group) do
{:ok, %{"id" => id}} ->
{:ok, id}
{:error, %{"errors" => errors}} ->
{:error, Requests.add_errors(deployment_group, errors)}
any ->
any
{:ok, %{"id" => id}} -> {:ok, id}
{:error, %{"errors" => errors}} -> {:error, Requests.add_errors(deployment_group, errors)}
any -> any
end
end
@ -217,21 +207,61 @@ defmodule Livebook.Teams do
| {:transport_error, String.t()}
def delete_deployment_group(%Team{} = team, deployment_group) do
case Requests.delete_deployment_group(team, deployment_group) do
{:ok, _} ->
:ok
{:ok, _} -> :ok
{:error, %{"errors" => errors}} -> {:error, Requests.add_errors(deployment_group, errors)}
any -> any
end
end
{:error, %{"errors" => errors}} ->
{:error, Requests.add_errors(deployment_group, errors)}
@doc """
Creates an Agent Key.
"""
@spec create_agent_key(Team.t(), DeploymentGroup.t()) ::
{:ok, pos_integer()}
| {:error, Ecto.Changeset.t()}
| {:transport_error, String.t()}
def create_agent_key(%Team{} = team, deployment_group) do
case Requests.create_agent_key(team, deployment_group) do
{:ok, _} -> :ok
{:error, %{"errors" => errors}} -> {:error, Requests.add_errors(deployment_group, errors)}
any -> any
end
end
any ->
any
@doc """
Deletes an Agent Key.
"""
@spec delete_agent_key(Team.t(), AgentKey.t()) ::
:ok
| {:error, Ecto.Changeset.t()}
| {:transport_error, String.t()}
def delete_agent_key(%Team{} = team, agent_key) do
case Requests.delete_agent_key(team, agent_key) do
{:ok, _} -> :ok
{:error, %{"errors" => errors}} -> {:error, Requests.add_errors(agent_key, errors)}
any -> any
end
end
@doc """
Gets a list of deployment groups for a given Hub.
"""
@spec get_deployment_groups(Team.t()) :: list(DeploymentGroup.t())
def get_deployment_groups(team) do
TeamClient.get_deployment_groups(team.id)
end
@doc """
Gets a list of agent keys for a given Hub and deployment group id.
"""
@spec get_agent_keys(Team.t(), String.t()) :: list(AgentKey.t())
def get_agent_keys(team, deployment_group_id) do
deployment_groups = TeamClient.get_deployment_groups(team.id)
if deployment_group = Enum.find(deployment_groups, &(&1.id == deployment_group_id)) do
deployment_group.agent_keys
else
[]
end
end
end

View file

@ -0,0 +1,15 @@
defmodule Livebook.Teams.AgentKey do
use Ecto.Schema
@type t :: %__MODULE__{
id: String.t() | nil,
key: String.t() | nil,
deployment_group_id: String.t() | nil
}
@primary_key {:id, :string, autogenerate: false}
embedded_schema do
field :key, :string
field :deployment_group_id, :string
end
end

View file

@ -1,17 +1,27 @@
defmodule Livebook.Teams.Broadcasts do
alias Livebook.Teams.DeploymentGroup
alias Livebook.Teams.{AgentKey, DeploymentGroup}
@type broadcast :: :ok | {:error, term()}
@deployment_groups_topic "teams:deployment_groups"
@agent_keys_topic "teams:agent_keys"
@doc """
Subscribes to one or more subtopics in `"teams"`.
## Messages
Topic `teams:deployment_groups`:
* `{:deployment_group_created, DeploymentGroup.t()}`
* `{:deployment_group_updated, DeploymentGroup.t()}`
* `{:deployment_group_deleted, DeploymentGroup.t()}`
Topic `teams:agent_keys`:
* `{:agent_key_created, AgentKey.t()}`
* `{:agent_key_deleted, AgentKey.t()}`
"""
@spec subscribe(atom() | list(atom())) :: :ok | {:error, term()}
def subscribe(topics) when is_list(topics) do
@ -62,6 +72,22 @@ defmodule Livebook.Teams.Broadcasts do
broadcast(@deployment_groups_topic, {:deployment_group_deleted, deployment_group})
end
@doc """
Broadcasts under `#{@agent_keys_topic}` topic when hub received a new agent key.
"""
@spec agent_key_created(AgentKey.t()) :: broadcast()
def agent_key_created(%AgentKey{} = agent_key) do
broadcast(@agent_keys_topic, {:agent_key_created, agent_key})
end
@doc """
Broadcasts under `#{@agent_keys_topic}` topic when hub received a deleted agent key.
"""
@spec agent_key_deleted(AgentKey.t()) :: broadcast()
def agent_key_deleted(%AgentKey{} = agent_key) do
broadcast(@agent_keys_topic, {:agent_key_deleted, agent_key})
end
defp broadcast(topic, message) do
Phoenix.PubSub.broadcast(Livebook.PubSub, topic, message)
end

View file

@ -1,7 +1,9 @@
defmodule Livebook.Teams.DeploymentGroup do
use Ecto.Schema
import Ecto.Changeset
alias Livebook.Secrets.Secret
alias Livebook.Teams.AgentKey
# If this list is updated, it must also be mirrored on Livebook Teams Server.
@zta_providers ~w(cloudflare google_iap tailscale teleport)a
@ -14,7 +16,8 @@ defmodule Livebook.Teams.DeploymentGroup do
clustering: :fly_io | nil,
zta_provider: :cloudflare | :google_iap | :tailscale | :teleport,
zta_key: String.t(),
secrets: [Secret.t()]
secrets: [Secret.t()],
agent_keys: [AgentKey.t()]
}
@primary_key {:id, :string, autogenerate: false}
@ -25,7 +28,9 @@ defmodule Livebook.Teams.DeploymentGroup do
field :clustering, Ecto.Enum, values: [:fly_io]
field :zta_provider, Ecto.Enum, values: @zta_providers
field :zta_key, :string
has_many :secrets, Secret
has_many :agent_keys, AgentKey
end
def changeset(deployment_group, attrs \\ %{}) do

View file

@ -4,9 +4,8 @@ defmodule Livebook.Teams.Requests do
alias Livebook.Hubs.Team
alias Livebook.Secrets.Secret
alias Livebook.Teams
alias Livebook.Teams.Org
alias Livebook.Teams.{AgentKey, DeploymentGroup, Org}
alias Livebook.Utils.HTTP
alias Livebook.Teams.DeploymentGroup
@doc """
Send a request to Livebook Team API to create a new org.
@ -207,6 +206,26 @@ defmodule Livebook.Teams.Requests do
delete("/api/v1/org/deployment-groups", %{id: deployment_group.id}, team)
end
@doc """
Send a request to Livebook Team API to create an agent key.
"""
@spec create_agent_key(Team.t(), DeploymentGroup.t()) ::
{:ok, map()} | {:error, map() | String.t()} | {:transport_error, String.t()}
def create_agent_key(team, deployment_group) do
params = %{deployment_group_id: deployment_group.id}
post("/api/v1/org/deployment-groups/agent-keys", params, team)
end
@doc """
Send a request to Livebook Team API to delete an agent key.
"""
@spec delete_agent_key(Team.t(), AgentKey.t()) ::
{:ok, String.t()} | {:error, map() | String.t()} | {:transport_error, String.t()}
def delete_agent_key(team, agent_key) do
params = %{id: agent_key.id, deployment_group_id: agent_key.deployment_group_id}
delete("/api/v1/org/deployment-groups/agent-keys", params, team)
end
@doc """
Add requests errors to a `changeset` for the given `fields`.
"""

View file

@ -0,0 +1,137 @@
defmodule LivebookWeb.Hub.Teams.AgentKeyListComponent do
use LivebookWeb, :live_component
alias Livebook.Teams
@impl true
def render(assigns) do
~H"""
<div id={@id} class="flex flex-col space-y-4">
<div class="flex flex-col space-y-4">
<.no_entries :if={@agent_keys == []}>
No agent keys in this deployment group yet.
</.no_entries>
<div
:for={agent_key <- @agent_keys}
class="flex items-center justify-between border border-gray-200 rounded-lg p-4"
>
<div class="flex items-center space-x-12">
<.labeled_text label="ID">
<div class="flex h-[40px] items-center text-center">
<%= agent_key.id %>
</div>
</.labeled_text>
<.labeled_text label="Key">
<div id="agent-key-toggle" class="relative lg:w-[480px] w-full">
<input
type="password"
id="agent-key"
readonly
value={agent_key.key}
class="input font-mono w-full border-neutral-200 bg-neutral-100 py-2 border-2 pr-8"
/>
<div class="flex items-center absolute inset-y-0 right-1">
<button
class="icon-button"
data-tooltip="Copied to clipboard"
type="button"
aria-label="copy to clipboard"
phx-click={
JS.dispatch("lb:clipcopy", to: "#agent-key")
|> JS.add_class("", transition: {"tooltip top", "", ""}, time: 2000)
}
>
<.remix_icon icon="clipboard-line" class="text-xl" />
</button>
<button
class="icon-button"
data-show
type="button"
aria-label="show password"
phx-click={
JS.remove_attribute("type", to: "#agent-key-toggle input")
|> JS.set_attribute({"type", "text"}, to: "#agent-key-toggle input")
|> toggle_class("hidden", to: "#agent-key-toggle [data-show]")
|> toggle_class("hidden", to: "#agent-key-toggle [data-hide]")
}
>
<.remix_icon icon="eye-line" class="text-xl" />
</button>
<button
class="icon-button hidden"
data-hide
type="button"
aria-label="hide password"
phx-click={
JS.remove_attribute("type", to: "#agent-key-toggle input")
|> JS.set_attribute({"type", "password"}, to: "#agent-key-toggle input")
|> toggle_class("hidden", to: "#agent-key-toggle [data-show]")
|> toggle_class("hidden", to: "#agent-key-toggle [data-hide]")
}
>
<.remix_icon icon="eye-off-line" class="text-xl" />
</button>
</div>
</div>
</.labeled_text>
</div>
<div class="flex items-center space-x-2">
<.menu id={"hub-agent-key-#{agent_key.id}-menu"}>
<:toggle>
<button class="icon-button" aria-label="open deployment group menu" type="button">
<.remix_icon icon="more-2-fill" class="text-xl" />
</button>
</:toggle>
<.menu_item variant={:danger}>
<button
id={"hub-agent-key-#{agent_key.id}-delete"}
type="button"
role="menuitem"
class="text-red-600"
phx-click={JS.push("delete_agent_key", value: %{id: agent_key.id})}
phx-target={@myself}
>
<.remix_icon icon="delete-bin-line" />
<span>Delete</span>
</button>
</.menu_item>
</.menu>
</div>
</div>
</div>
</div>
"""
end
@impl true
def handle_event("delete_agent_key", %{"id" => id}, socket) do
on_confirm = fn socket ->
hub = Livebook.Hubs.fetch_hub!(socket.assigns.hub.id)
agent_keys = Teams.get_agent_keys(hub, socket.assigns.deployment_group_id)
agent_key = Enum.find(agent_keys, &(&1.id == id))
case Teams.delete_agent_key(hub, agent_key) do
:ok ->
socket
|> put_flash(:success, "Agent key deleted successfully")
|> push_patch(
to: ~p"/hub/#{hub.id}/deployment-groups/edit/#{agent_key.deployment_group_id}"
)
{:transport_error, reason} ->
put_flash(socket, :error, reason)
end
end
{:noreply,
confirm(socket, on_confirm,
title: "Delete hub agent key",
description: "Are you sure you want to delete?",
confirm_text: "Delete",
confirm_icon: "delete-bin-6-line"
)}
end
end

View file

@ -66,8 +66,8 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
}
field={f[:mode]}
options={[
{"Offline", "offline"},
{"Online", "online"}
{"Offline", :offline},
{"Online", :online}
]}
/>
<LivebookWeb.AppComponents.deployment_group_form_content hub={@hub} form={f} />

View file

@ -32,6 +32,11 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
do: deployment_group.secrets,
else: []
agent_keys =
if socket.assigns.live_action != :new_deployment_group,
do: deployment_group.agent_keys,
else: []
secret_value =
if socket.assigns.live_action == :edit_secret do
Enum.find_value(secrets, &(&1.name == secret_name and &1.value)) ||
@ -49,7 +54,8 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
secret_name: secret_name,
secret_value: secret_value,
default?: default?,
secrets: secrets
secrets: secrets,
agent_keys: agent_keys
)
|> assign_new(:config_changeset, fn -> Hubs.Dockerfile.config_changeset() end)
|> update_dockerfile()}
@ -114,6 +120,36 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
return_to={~p"/hub/#{@hub.id}/deployment-groups/edit/#{@deployment_group.id}"}
/>
</div>
<div :if={@deployment_group.mode == :online} class="flex flex-col space-y-4">
<h2 class="text-xl text-gray-800 font-medium pb-2 border-b border-gray-200">
Agent Keys
</h2>
<p class="text-gray-700">
Deployment group agent keys for online deployments
</p>
<.live_component
module={LivebookWeb.Hub.Teams.AgentKeyListComponent}
id="agent-keys-list"
hub={@hub}
agent_keys={@agent_keys}
deployment_group={@deployment_group}
/>
<div class="flex">
<button
id="add-agent-key"
type="button"
class="button-base button-blue"
phx-click="add_agent_key"
>
<span>Add agent key</span>
</button>
</div>
</div>
<div class="flex flex-col space-y-4">
<h2 class="text-xl text-gray-800 font-medium pb-2 border-b border-gray-200">
Airgapped deployment
@ -179,6 +215,39 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
|> update_dockerfile()}
end
def handle_event("add_agent_key", _, socket) do
on_confirm = fn socket ->
hub = Livebook.Hubs.fetch_hub!(socket.assigns.hub.id)
deployment_group = socket.assigns.deployment_group
case Teams.create_agent_key(hub, deployment_group) do
:ok ->
socket
|> put_flash(:success, "Agent key created successfully")
|> push_patch(to: ~p"/hub/#{hub.id}/deployment-groups/edit/#{deployment_group.id}")
{:error, _changeset} ->
put_flash(
socket,
:error,
"Something went wrong, try again later or please file a bug if it persists"
)
{:transport_error, reason} ->
put_flash(socket, :error, reason)
end
end
{:noreply,
confirm(socket, on_confirm,
title: "Create agent key",
description: "This will create a new agent key for this deployment group.",
confirm_text: "Create",
confirm_icon: "plus-6-line",
danger: false
)}
end
defp default_hub?(hub) do
Hubs.get_default_hub().id == hub.id
end

View file

@ -113,7 +113,7 @@ defmodule Livebook.MixProject do
{:aws_credentials, "~> 0.2.0", runtime: false},
{:aws_signature, "~> 0.3.0"},
{:mint_web_socket, "~> 1.0.0"},
{:protobuf, "~> 0.8.0"},
{:protobuf, "~> 0.12.0"},
{:dns_cluster, "~> 0.1.2"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:floki, ">= 0.27.0", only: :test},

View file

@ -43,7 +43,7 @@
"plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"protobuf": {:hex, :protobuf, "0.8.0", "61b27d6fd50e7b1b2eb0ee17c1f639906121f4ef965ae0994644eb4c68d4647d", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "3644ed846fd6f5e3b5c2cd617aa8344641e230edf812a45365fee7622bccd25a"},
"protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"req": {:hex, :req, "0.4.4", "a17b6bec956c9af4f08b5d8e8a6fc6e4edf24ccc0ac7bf363a90bba7a0f0138c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "2618c0493444fee927d12073afb42e9154e766b3f4448e1011f0d3d551d1a011"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},

View file

@ -1,6 +1,8 @@
defmodule LivebookProto do
alias LivebookProto.{
AgentConnected,
AgentKeyCreated,
AgentKeyDeleted,
Event,
FileSystemCreated,
FileSystemDeleted,
@ -21,6 +23,8 @@ defmodule LivebookProto do
@type event_proto ::
AgentConnected.t()
| AgentKeyCreated.t()
| AgentKeyDeleted.t()
| FileSystemCreated.t()
| FileSystemDeleted.t()
| FileSystemUpdated.t()
@ -37,7 +41,7 @@ defmodule LivebookProto do
"""
@spec build_event(event_proto()) :: Event.t()
def build_event(%struct{} = data) do
Event.new!(type: {event_type(struct), data})
%Event{type: {event_type(struct), data}}
end
defp event_type(module), do: Map.fetch!(@event_mapping, module)

View file

@ -0,0 +1,7 @@
defmodule LivebookProto.AgentKey do
use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"
field :id, 1, type: :string
field :key, 2, type: :string
field :deployment_group_id, 3, type: :string, json_name: "deploymentGroupId"
end

View file

@ -0,0 +1,7 @@
defmodule LivebookProto.AgentKeyCreated do
use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"
field :id, 1, type: :string
field :key, 2, type: :string
field :deployment_group_id, 3, type: :string, json_name: "deploymentGroupId"
end

View file

@ -0,0 +1,7 @@
defmodule LivebookProto.AgentKeyDeleted do
use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"
field :id, 1, type: :string
field :key, 2, type: :string
field :deployment_group_id, 3, type: :string, json_name: "deploymentGroupId"
end

View file

@ -8,4 +8,5 @@ defmodule LivebookProto.DeploymentGroup do
field :clustering, 5, type: :string
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
field :zta_key, 7, type: :string, json_name: "ztaKey"
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
end

View file

@ -8,4 +8,5 @@ defmodule LivebookProto.DeploymentGroupCreated do
field :clustering, 5, type: :string
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
field :zta_key, 7, type: :string, json_name: "ztaKey"
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
end

View file

@ -8,4 +8,5 @@ defmodule LivebookProto.DeploymentGroupUpdated do
field :clustering, 5, type: :string
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
field :zta_key, 7, type: :string, json_name: "ztaKey"
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
end

View file

@ -57,4 +57,14 @@ defmodule LivebookProto.Event do
type: LivebookProto.AgentConnected,
json_name: "agentConnected",
oneof: 0
field :agent_key_created, 12,
type: LivebookProto.AgentKeyCreated,
json_name: "agentKeyCreated",
oneof: 0
field :agent_key_deleted, 13,
type: LivebookProto.AgentKeyDeleted,
json_name: "agentKeyDeleted",
oneof: 0
end

View file

@ -62,6 +62,7 @@ message DeploymentGroup {
string clustering = 5;
string zta_provider = 6;
string zta_key = 7;
repeated AgentKey agent_keys = 8;
}
message DeploymentGroupCreated {
@ -72,6 +73,7 @@ message DeploymentGroupCreated {
string clustering = 5;
string zta_provider = 6;
string zta_key = 7;
repeated AgentKey agent_keys = 8;
}
message DeploymentGroupUpdated {
@ -82,12 +84,31 @@ message DeploymentGroupUpdated {
string clustering = 5;
string zta_provider = 6;
string zta_key = 7;
repeated AgentKey agent_keys = 8;
}
message DeploymentGroupDeleted {
string id = 1;
}
message AgentKey {
string id = 1;
string key = 2;
string deployment_group_id = 3;
}
message AgentKeyCreated {
string id = 1;
string key = 2;
string deployment_group_id = 3;
}
message AgentKeyDeleted {
string id = 1;
string key = 2;
string deployment_group_id = 3;
}
message UserConnected {
string name = 1;
repeated Secret secrets = 2;
@ -118,5 +139,7 @@ message Event {
DeploymentGroupUpdated deployment_group_updated = 9;
DeploymentGroupDeleted deployment_group_deleted = 10;
AgentConnected agent_connected = 11;
AgentKeyCreated agent_key_created = 12;
AgentKeyDeleted agent_key_deleted = 13;
}
}

View file

@ -17,7 +17,7 @@ defmodule LivebookProto.MixProject do
end
defp deps do
[{:protobuf, "~> 0.8.0"}]
[{:protobuf, "~> 0.12.0"}]
end
defp aliases do

View file

@ -1,3 +1,3 @@
%{
"protobuf": {:hex, :protobuf, "0.8.0", "61b27d6fd50e7b1b2eb0ee17c1f639906121f4ef965ae0994644eb4c68d4647d", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "3644ed846fd6f5e3b5c2cd617aa8344641e230edf812a45365fee7622bccd25a"},
"protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"},
}

View file

@ -49,7 +49,7 @@ defmodule Livebook.Hubs.TeamClientTest do
name = secret.name
value = secret.value
# receives `{:secret_created, secret_created}` event
# receives `{:secret_created, secret}` event
# with the value decrypted
assert_receive {:secret_created, %{name: ^name, value: ^value}}
@ -59,14 +59,14 @@ defmodule Livebook.Hubs.TeamClientTest do
new_value = updated_secret.value
# receives `{:secret_updated, secret_updated}` event
# receives `{:secret_updated, secret}` event
# with the value decrypted
assert_receive {:secret_updated, %{name: ^name, value: ^new_value}}
# deletes the secret
assert Livebook.Hubs.delete_secret(team, updated_secret) == :ok
# receives `{:secret_deleted, secret_deleted}` event
# receives `{:secret_deleted, secret}` event
assert_receive {:secret_deleted, %{name: ^name, value: ^new_value}}
end
@ -79,7 +79,7 @@ defmodule Livebook.Hubs.TeamClientTest do
bucket_url = file_system.bucket_url
region = file_system.region
# receives `{:file_system_created, file_system_created}` event
# receives `{:file_system_created, file_system}` event
assert_receive {:file_system_created,
%{external_id: id, bucket_url: ^bucket_url, region: ^region}}
@ -89,47 +89,70 @@ defmodule Livebook.Hubs.TeamClientTest do
new_region = updated_file_system.region
# receives `{:file_system_updated, file_system_updated}` event
# receives `{:file_system_updated, file_system}` event
assert_receive {:file_system_updated,
%{external_id: ^id, bucket_url: ^bucket_url, region: ^new_region}}
# deletes the file system
assert Livebook.Hubs.delete_file_system(team, updated_file_system) == :ok
# receives `{:file_system_deleted, file_system_deleted}` event
# receives `{:file_system_deleted, file_system}` event
assert_receive {:file_system_deleted, %{external_id: ^id, bucket_url: ^bucket_url}}
end
test "receives the deployment group events", %{team: team} do
deployment_group = build(:deployment_group, name: "DEPLOYMENT_GROUP", mode: "online")
deployment_group =
build(:deployment_group, name: "DEPLOYMENT_GROUP_#{team.id}", mode: :online)
assert {:ok, id} =
Livebook.Teams.create_deployment_group(team, deployment_group)
%{name: name, mode: mode} = deployment_group
# receives `{:event, :deployment_group_created, deployment_group_created}` event
assert_receive {:deployment_group_created, %{name: ^name, mode: ^mode}}
# receives `{:event, :deployment_group_created, deployment_group}` event
assert_receive {:deployment_group_created, %{name: ^name, mode: ^mode} = deployment_group}
# updates the deployment group
update_deployment_group = %{deployment_group | id: id, mode: "online"}
updated_deployment_group = %{deployment_group | mode: :offline}
assert {:ok, ^id} =
Livebook.Teams.update_deployment_group(
team,
update_deployment_group
updated_deployment_group
)
new_mode = update_deployment_group.mode
# receives `{:deployment_group_updated, deployment_group_updated}` event
assert_receive {:deployment_group_updated, %{name: ^name, mode: ^new_mode}}
# receives `{:deployment_group_updated, deployment_group}` event
assert_receive {:deployment_group_updated, ^updated_deployment_group}
# deletes the deployment group
assert Livebook.Teams.delete_deployment_group(team, update_deployment_group) == :ok
assert Livebook.Teams.delete_deployment_group(team, updated_deployment_group) == :ok
# receives `{:deployment_group_deleted, deployment_group_deleted}` event
assert_receive {:deployment_group_deleted, %{name: ^name, mode: ^new_mode}}
# receives `{:deployment_group_deleted, deployment_group}` event
assert_receive {:deployment_group_deleted, ^updated_deployment_group}
end
test "receives the agent key events", %{team: team} do
deployment_group =
build(:deployment_group, name: "DEPLOYMENT_GROUP_AGENT_KEY_#{team.id}", mode: :online)
assert {:ok, id} = Livebook.Teams.create_deployment_group(team, deployment_group)
id = to_string(id)
# receives `{:event, :deployment_group_created, :deployment_group}` event
assert_receive {:deployment_group_created, %{id: ^id} = deployment_group}
# creates the agent key
assert Livebook.Teams.create_agent_key(team, deployment_group) == :ok
# since the `agent_key` belongs to a deployment group,
# we dispatch the `{:event, :deployment_group_updated, :deployment_group}` event
assert_receive {:deployment_group_updated, %{id: ^id, agent_keys: [agent_key]}}
# deletes the agent key
assert Livebook.Teams.delete_agent_key(team, agent_key) == :ok
# since the `agent_key` belongs to a deployment group,
# we dispatch the `{:event, :deployment_group_updated, :deployment_group}` event
assert_receive {:deployment_group_updated, %{id: ^id, agent_keys: []}}
end
end
@ -138,12 +161,12 @@ defmodule Livebook.Hubs.TeamClientTest do
team = build_team_hub(user, node)
user_connected =
LivebookProto.UserConnected.new!(
%LivebookProto.UserConnected{
name: team.hub_name,
secrets: [],
file_systems: [],
deployment_groups: []
)
}
{:ok, team: team, user_connected: user_connected}
end
@ -158,7 +181,7 @@ defmodule Livebook.Hubs.TeamClientTest do
secret_key = Livebook.Teams.derive_key(team.teams_key)
secret_value = Livebook.Teams.encrypt(secret.value, secret_key)
livebook_proto_secret = LivebookProto.Secret.new!(name: secret.name, value: secret_value)
livebook_proto_secret = %LivebookProto.Secret{name: secret.name, value: secret_value}
# creates the secret
user_connected = %{user_connected | secrets: [livebook_proto_secret]}
@ -202,12 +225,12 @@ defmodule Livebook.Hubs.TeamClientTest do
value = Livebook.Teams.encrypt(credentials, secret_key)
livebook_proto_file_system =
LivebookProto.FileSystem.new!(
%LivebookProto.FileSystem{
id: file_system.external_id,
name: name,
type: to_string(type),
value: value
)
}
# creates the file system
user_connected = %{user_connected | file_systems: [livebook_proto_file_system]}
@ -252,18 +275,18 @@ defmodule Livebook.Hubs.TeamClientTest do
build(:deployment_group,
id: "1",
name: "sleepy-cat-#{System.unique_integer([:positive])}",
mode: "offline",
mode: :offline,
hub_id: team.id,
secrets: []
)
livebook_proto_deployment_group =
LivebookProto.DeploymentGroup.new!(
%LivebookProto.DeploymentGroup{
id: to_string(deployment_group.id),
name: deployment_group.name,
mode: to_string(deployment_group.mode),
secrets: []
)
}
# creates the deployment group
user_connected = %{user_connected | deployment_groups: [livebook_proto_deployment_group]}
@ -274,11 +297,11 @@ defmodule Livebook.Hubs.TeamClientTest do
assert deployment_group in TeamClient.get_deployment_groups(team.id)
# updates the deployment group
updated_deployment_group = %{deployment_group | mode: "online"}
updated_deployment_group = %{deployment_group | mode: :online}
updated_livebook_proto_deployment_group = %{
livebook_proto_deployment_group
| mode: updated_deployment_group.mode
| mode: to_string(updated_deployment_group.mode)
}
user_connected = %{
@ -305,7 +328,7 @@ defmodule Livebook.Hubs.TeamClientTest do
org_key_pair = erpc_call(node, :create_org_key_pair, [[org: org]])
agent_connected =
LivebookProto.AgentConnected.new!(
%LivebookProto.AgentConnected{
id: agent_key.id,
name: Livebook.Config.agent_name(),
public_key: org_key_pair.public_key,
@ -313,7 +336,7 @@ defmodule Livebook.Hubs.TeamClientTest do
secrets: [],
file_systems: [],
deployment_groups: []
)
}
{:ok, team: team, deployment_group: deployment_group, agent_connected: agent_connected}
end
@ -328,7 +351,7 @@ defmodule Livebook.Hubs.TeamClientTest do
secret_key = Livebook.Teams.derive_key(team.teams_key)
secret_value = Livebook.Teams.encrypt(secret.value, secret_key)
livebook_proto_secret = LivebookProto.Secret.new!(name: secret.name, value: secret_value)
livebook_proto_secret = %LivebookProto.Secret{name: secret.name, value: secret_value}
# creates the secret
agent_connected = %{agent_connected | secrets: [livebook_proto_secret]}
@ -372,12 +395,12 @@ defmodule Livebook.Hubs.TeamClientTest do
value = Livebook.Teams.encrypt(credentials, secret_key)
livebook_proto_file_system =
LivebookProto.FileSystem.new!(
%LivebookProto.FileSystem{
id: file_system.external_id,
name: name,
type: to_string(type),
value: value
)
}
# creates the file system
agent_connected = %{agent_connected | file_systems: [livebook_proto_file_system]}
@ -423,18 +446,18 @@ defmodule Livebook.Hubs.TeamClientTest do
build(:deployment_group,
id: to_string(teams_deployment_group.id),
name: teams_deployment_group.name,
mode: to_string(teams_deployment_group.mode),
mode: teams_deployment_group.mode,
hub_id: team.id,
secrets: []
)
livebook_proto_deployment_group =
LivebookProto.DeploymentGroup.new!(
%LivebookProto.DeploymentGroup{
id: to_string(deployment_group.id),
name: deployment_group.name,
mode: to_string(deployment_group.mode),
secrets: []
)
}
# creates the deployment group
agent_connected = %{agent_connected | deployment_groups: [livebook_proto_deployment_group]}
@ -444,11 +467,11 @@ defmodule Livebook.Hubs.TeamClientTest do
assert deployment_group in TeamClient.get_deployment_groups(team.id)
# updates the deployment group
updated_deployment_group = %{deployment_group | mode: "offline"}
updated_deployment_group = %{deployment_group | mode: :offline}
updated_livebook_proto_deployment_group = %{
livebook_proto_deployment_group
| mode: updated_deployment_group.mode
| mode: to_string(updated_deployment_group.mode)
}
agent_connected = %{
@ -479,7 +502,7 @@ defmodule Livebook.Hubs.TeamClientTest do
secret_key = Livebook.Teams.derive_key(team.teams_key)
secret_value = Livebook.Teams.encrypt(secret.value, secret_key)
livebook_proto_secret = LivebookProto.Secret.new!(name: secret.name, value: secret_value)
livebook_proto_secret = %LivebookProto.Secret{name: secret.name, value: secret_value}
# creates the secret
agent_connected = %{agent_connected | secrets: [livebook_proto_secret]}
@ -499,28 +522,28 @@ defmodule Livebook.Hubs.TeamClientTest do
secret_value = Livebook.Teams.encrypt(override_secret.value, secret_key)
livebook_proto_deployment_group_secret =
LivebookProto.DeploymentGroupSecret.new!(
%LivebookProto.DeploymentGroupSecret{
name: override_secret.name,
value: secret_value,
deployment_group_id: override_secret.deployment_group_id
)
}
deployment_group =
build(:deployment_group,
id: to_string(teams_deployment_group.id),
name: teams_deployment_group.name,
mode: to_string(teams_deployment_group.mode),
mode: teams_deployment_group.mode,
hub_id: team.id,
secrets: [override_secret]
)
livebook_proto_deployment_group =
LivebookProto.DeploymentGroup.new!(
%LivebookProto.DeploymentGroup{
id: to_string(deployment_group.id),
name: deployment_group.name,
mode: to_string(deployment_group.mode),
secrets: [livebook_proto_deployment_group_secret]
)
}
agent_connected = %{agent_connected | deployment_groups: [livebook_proto_deployment_group]}
send(pid, {:event, :agent_connected, agent_connected})

View file

@ -79,8 +79,8 @@ defmodule Livebook.Teams.ConnectionTest do
assert {:ok, _conn} = Connection.start_link(self(), headers)
assert_receive :connected
# creates a new deployment_group
deployment_group = build(:deployment_group, name: "FOO", mode: "offline")
# creates a new deployment group
deployment_group = build(:deployment_group, name: "FOO", mode: :offline)
assert {:ok, _id} =
Livebook.Teams.create_deployment_group(hub, deployment_group)
@ -88,7 +88,29 @@ defmodule Livebook.Teams.ConnectionTest do
# deployment_group name and mode are not encrypted
assert_receive {:event, :deployment_group_created, deployment_group_created}
assert deployment_group_created.name == deployment_group.name
assert deployment_group_created.mode == deployment_group.mode
assert String.to_existing_atom(deployment_group_created.mode) == deployment_group.mode
end
test "receives the agent_key_created event", %{user: user, node: node} do
{hub, headers} = build_team_headers(user, node)
assert {:ok, _conn} = Connection.start_link(self(), headers)
assert_receive :connected
# creates a new deployment group
deployment_group = build(:deployment_group, name: "FOO", mode: :online)
assert {:ok, deployment_group_id} =
Livebook.Teams.create_deployment_group(hub, deployment_group)
# creates a new agent key
deployment_group = %{deployment_group | id: to_string(deployment_group_id)}
assert Livebook.Teams.create_agent_key(hub, deployment_group) == :ok
# agent_key key is not encrypted
assert_receive {:event, :agent_key_created, agent_key_created}
assert "lb_ak_" <> _ = agent_key_created.key
assert agent_key_created.deployment_group_id == deployment_group.id
end
end
end

View file

@ -199,21 +199,21 @@ defmodule Livebook.TeamsTest do
describe "update_deployment_group/2" do
test "updates a deployment group", %{user: user, node: node} do
team = create_team_hub(user, node)
deployment_group = build(:deployment_group, name: "BAR", mode: "online")
deployment_group = build(:deployment_group, name: "BAR", mode: :online)
assert {:ok, id} = Teams.create_deployment_group(team, deployment_group)
update_deployment_group = %{deployment_group | id: id, name: "BAZ"}
update_deployment_group = %{deployment_group | id: to_string(id), name: "BAZ"}
assert {:ok, ^id} = Teams.update_deployment_group(team, update_deployment_group)
end
test "returns changeset errors when the new name is invalid", %{user: user, node: node} do
team = create_team_hub(user, node)
deployment_group = build(:deployment_group, name: "BAR", mode: "online")
deployment_group = build(:deployment_group, name: "BAR", mode: :online)
assert {:ok, id} = Teams.create_deployment_group(team, deployment_group)
update_deployment_group = %{deployment_group | id: id, name: ""}
update_deployment_group = %{deployment_group | id: to_string(id), name: ""}
assert {:error, changeset} =
Teams.update_deployment_group(team, update_deployment_group)
@ -223,18 +223,18 @@ defmodule Livebook.TeamsTest do
test "returns changeset errors when the new mode is invalid", %{user: user, node: node} do
team = create_team_hub(user, node)
deployment_group = build(:deployment_group, name: "BAR", mode: "online")
deployment_group = build(:deployment_group, name: "BAR", mode: :online)
assert {:ok, id} = Teams.create_deployment_group(team, deployment_group)
update_deployment_group = %{deployment_group | id: id, mode: ""}
update_deployment_group = %{deployment_group | id: to_string(id), mode: nil}
assert {:error, changeset} =
Teams.update_deployment_group(team, update_deployment_group)
assert "can't be blank" in errors_on(changeset).mode
update_deployment_group = %{deployment_group | id: id, mode: "invalid"}
update_deployment_group = %{deployment_group | id: to_string(id), mode: :invalid}
assert {:error, changeset} =
Teams.update_deployment_group(team, update_deployment_group)
@ -246,11 +246,11 @@ defmodule Livebook.TeamsTest do
describe "delete_deployment_group/2" do
test "deletes a deployment group", %{user: user, node: node} do
team = create_team_hub(user, node)
deployment_group = build(:deployment_group, name: "BAR", mode: "online")
deployment_group = build(:deployment_group, name: "BAR", mode: :online)
assert {:ok, id} = Teams.create_deployment_group(team, deployment_group)
delete_deployment_group = %{deployment_group | id: id}
delete_deployment_group = %{deployment_group | id: to_string(id)}
assert Teams.delete_deployment_group(team, delete_deployment_group) == :ok
end
end

View file

@ -21,7 +21,7 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
deployment_group =
build(:deployment_group,
name: "TEAMS_ADD_DEPLOYMENT_GROUP",
mode: "offline",
mode: :offline,
hub_id: hub.id
)
@ -70,7 +70,7 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
test "updates an existing deployment group", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAMS_EDIT_DEPLOYMENT_GROUP",
mode: "online",
mode: :online,
hub_id: hub.id
)
@ -86,7 +86,7 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
}
}
new_mode = "offline"
new_mode = :offline
{:ok, view, html} =
live(conn, ~p"/hub/#{hub.id}/deployment-groups/edit/#{deployment_group.id}")
@ -117,7 +117,7 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
test "creates a secret", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAMS_EDIT_DEPLOYMENT_GROUP",
mode: "online",
mode: :online,
hub_id: hub.id
)
@ -197,7 +197,7 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
test "updates an existing secret", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAMS_EDIT_DEPLOYMENT_GROUP",
mode: "online",
mode: :online,
hub_id: hub.id
)
@ -270,7 +270,7 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
test "deletes an existing secret", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAMS_EDIT_DEPLOYMENT_GROUP",
mode: "online",
mode: :online,
hub_id: hub.id
)
@ -313,4 +313,89 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
refute render(element(view, "#deployment-group-secrets-list")) =~ secret.name
refute secret in deployment_group.secrets
end
test "creates an agent key", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAMS_AGENT_KEY_DEPLOYMENT_GROUP",
mode: :online,
hub_id: hub.id
)
hub_id = hub.id
assert_receive {:deployment_group_created,
%DeploymentGroup{name: "TEAMS_AGENT_KEY_DEPLOYMENT_GROUP", hub_id: ^hub_id} =
deployment_group}
id = deployment_group.id
{:ok, view, _html} =
live(conn, ~p"/hub/#{hub.id}/deployment-groups/edit/#{deployment_group.id}")
view
|> element("#add-agent-key")
|> render_click()
render_confirm(view)
assert_receive {:deployment_group_updated,
%Livebook.Teams.DeploymentGroup{id: ^id, agent_keys: [agent_key]}}
assert render(view) =~ agent_key.key
end
test "deletes an agent key", %{conn: conn, hub: hub} do
insert_agent_key(
name: "TEAMS_AGENT_KEY_DEPLOYMENT_GROUP_DELETE",
mode: :online,
hub_id: hub.id
)
hub_id = hub.id
assert_receive {:deployment_group_updated,
%DeploymentGroup{
id: id,
name: "TEAMS_AGENT_KEY_DEPLOYMENT_GROUP_DELETE",
hub_id: ^hub_id,
agent_keys: [%{deployment_group_id: id} = agent_key]
}}
{:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}/deployment-groups/edit/#{id}")
assert render(view) =~ agent_key.key
view
|> element("#hub-agent-key-#{agent_key.id}-delete")
|> render_click()
render_confirm(view)
assert_receive {:deployment_group_updated,
%Livebook.Teams.DeploymentGroup{id: ^id, agent_keys: []}}
refute render(view) =~ agent_key.key
end
test "doesn't show agent key section for offline deployment groups",
%{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAMS_AGENT_KEY_DEPLOYMENT_GROUP",
mode: :online,
hub_id: hub.id
)
hub_id = hub.id
assert_receive {:deployment_group_created,
%DeploymentGroup{
id: id,
name: "TEAMS_AGENT_KEY_DEPLOYMENT_GROUP",
hub_id: ^hub_id
}}
{:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}/deployment-groups/edit/#{id}")
refute render(view) =~ "#add-agent-key"
end
end

View file

@ -302,7 +302,7 @@ defmodule LivebookWeb.Integration.Hub.EditLiveTest do
deployment_group =
build(:deployment_group,
name: "TEAM_ADD_DEPLOYMENT_GROUP",
mode: "offline",
mode: :offline,
hub_id: hub.id
)
@ -357,7 +357,7 @@ defmodule LivebookWeb.Integration.Hub.EditLiveTest do
test "updates an existing deployment group", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAM_EDIT_DEPLOYMENT_GROUP",
mode: "online",
mode: :online,
hub_id: hub.id
)
@ -375,7 +375,7 @@ defmodule LivebookWeb.Integration.Hub.EditLiveTest do
}
}
new_mode = "offline"
new_mode = :offline
view
|> element("#hub-deployment-group-#{deployment_group.id}-edit")
@ -412,7 +412,7 @@ defmodule LivebookWeb.Integration.Hub.EditLiveTest do
test "deletes existing deployment group", %{conn: conn, hub: hub} do
insert_deployment_group(
name: "TEAM_DELETE_DEPLOYMENT_GROUP",
mode: "online",
mode: :online,
hub_id: hub.id
)

View file

@ -369,7 +369,7 @@ defmodule LivebookWeb.Integration.SessionLiveTest do
insert_deployment_group(
name: "DEPLOYMENT_GROUP_SUSIE",
mode: "online",
mode: :online,
hub_id: team_id
)
@ -399,14 +399,14 @@ defmodule LivebookWeb.Integration.SessionLiveTest do
insert_deployment_group(
name: "DEPLOYMENT_GROUP_SUSIE",
mode: "online",
mode: :online,
hub_id: team_id
)
deployment_group =
insert_deployment_group(
name: "DEPLOYMENT_GROUP_TOBIAS",
mode: "online",
mode: :online,
hub_id: team_id
)

View file

@ -59,10 +59,9 @@ defmodule Livebook.Factory do
def build(:deployment_group) do
%Livebook.Teams.DeploymentGroup{
name: "FOO",
mode: "offline",
clustering: "",
zta_key: "",
zta_provider: :""
mode: :offline,
agent_keys: [],
secrets: []
}
end
@ -115,6 +114,16 @@ defmodule Livebook.Factory do
%{deployment_group | id: to_string(id)}
end
def insert_agent_key(attrs \\ %{}) do
deployment_group = build(:deployment_group, attrs)
hub = Livebook.Hubs.fetch_hub!(deployment_group.hub_id)
{:ok, id} = Livebook.Teams.create_deployment_group(hub, deployment_group)
deployment_group = %{deployment_group | id: to_string(id)}
:ok = Livebook.Teams.create_agent_key(hub, deployment_group)
deployment_group
end
def insert_env_var(factory_name, attrs \\ %{}) do
env_var = build(factory_name, attrs)
attributes = env_var |> Map.from_struct() |> Map.to_list()

View file

@ -161,7 +161,7 @@ defmodule Livebook.HubHelpers do
{:ok, pid} = hub_pid(hub)
secret_key = Livebook.Teams.derive_key(hub.teams_key)
value = Livebook.Teams.encrypt(secret.value, secret_key)
secret_created = LivebookProto.SecretCreated.new(name: secret.name, value: value)
secret_created = %LivebookProto.SecretCreated{name: secret.name, value: value}
send(pid, {:event, :secret_created, secret_created})
end
@ -169,7 +169,7 @@ defmodule Livebook.HubHelpers do
def remove_offline_hub_secret(secret) do
hub = offline_hub()
{:ok, pid} = hub_pid(hub)
secret_deleted = LivebookProto.SecretDeleted.new(name: secret.name)
secret_deleted = %LivebookProto.SecretDeleted{name: secret.name}
send(pid, {:event, :secret_deleted, secret_deleted})
end
@ -179,11 +179,11 @@ defmodule Livebook.HubHelpers do
{:ok, pid} = hub_pid(hub)
deployment_group_created =
LivebookProto.DeploymentGroupCreated.new(
%LivebookProto.DeploymentGroupCreated{
id: deployment_group.id,
name: deployment_group.name,
mode: deployment_group.mode
)
}
send(pid, {:event, :deployment_group_created, deployment_group_created})
end
@ -193,7 +193,7 @@ defmodule Livebook.HubHelpers do
{:ok, pid} = hub_pid(hub)
deployment_group_deleted =
LivebookProto.DeploymentGroupDeleted.new(id: deployment_group.id)
%LivebookProto.DeploymentGroupDeleted{id: deployment_group.id}
send(pid, {:event, :deployment_group_deleted, deployment_group_deleted})
end
@ -208,12 +208,12 @@ defmodule Livebook.HubHelpers do
value = Livebook.Teams.encrypt(json, secret_key)
file_system_created =
LivebookProto.FileSystemCreated.new(
%LivebookProto.FileSystemCreated{
id: file_system.external_id,
name: name,
type: Livebook.FileSystems.type(file_system),
value: value
)
}
send(pid, {:event, :file_system_created, file_system_created})
end
@ -221,7 +221,7 @@ defmodule Livebook.HubHelpers do
def remove_offline_hub_file_system(file_system) do
hub = offline_hub()
{:ok, pid} = hub_pid(hub)
file_system_deleted = LivebookProto.FileSystemDeleted.new(id: file_system.external_id)
file_system_deleted = %LivebookProto.FileSystemDeleted{id: file_system.external_id}
send(pid, {:event, :file_system_deleted, file_system_deleted})
end

View file

@ -13,7 +13,7 @@ defmodule Livebook.TeamsServer do
def setup do
if available?() do
mix(%{"MIX_ENV" => "livebook"}, ["compile"])
mix(%__MODULE__{}, ["compile"])
end
end