mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-09-20 10:05:57 +08:00
Adds ZTA and clustering to deployment groups (#2413)
Co-authored-by: José Valim <jose.valim@gmail.com>
This commit is contained in:
parent
d11165c2a6
commit
4c97bd338e
|
@ -244,9 +244,19 @@ defmodule Livebook.Hubs.TeamClient do
|
|||
}
|
||||
end
|
||||
|
||||
defp build_deployment_group(state, %{id: id, name: name, mode: mode, secrets: secrets}) do
|
||||
secrets = Enum.map(secrets, &build_secret(state, &1))
|
||||
%DeploymentGroup{id: id, name: name, mode: mode, hub_id: state.hub.id, secrets: secrets}
|
||||
defp build_deployment_group(state, deployment_group) do
|
||||
secrets = Enum.map(deployment_group.secrets, &build_secret(state, &1))
|
||||
|
||||
%DeploymentGroup{
|
||||
id: deployment_group.id,
|
||||
name: deployment_group.name,
|
||||
mode: 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
|
||||
}
|
||||
end
|
||||
|
||||
defp handle_event(:secret_created, %Secrets.Secret{} = secret, state) do
|
||||
|
|
|
@ -3,11 +3,17 @@ defmodule Livebook.Teams.DeploymentGroup do
|
|||
import Ecto.Changeset
|
||||
alias Livebook.Secrets.Secret
|
||||
|
||||
# If this list is updated, it must also be mirrored on Livebook Teams Server.
|
||||
@zta_providers ~w(cloudflare google_iap tailscale teleport)a
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
id: String.t() | nil,
|
||||
name: String.t() | nil,
|
||||
mode: :online | :offline,
|
||||
hub_id: String.t() | nil,
|
||||
clustering: :fly_io | nil,
|
||||
zta_provider: :cloudflare | :google_iap | :tailscale | :teleport,
|
||||
zta_key: String.t(),
|
||||
secrets: [Secret.t()]
|
||||
}
|
||||
|
||||
|
@ -16,12 +22,15 @@ defmodule Livebook.Teams.DeploymentGroup do
|
|||
field :name, :string
|
||||
field :mode, Ecto.Enum, values: [:online, :offline]
|
||||
field :hub_id, :string
|
||||
field :clustering, Ecto.Enum, values: [:fly_io]
|
||||
field :zta_provider, Ecto.Enum, values: @zta_providers
|
||||
field :zta_key, :string
|
||||
has_many :secrets, Secret
|
||||
end
|
||||
|
||||
def changeset(deployment_group, attrs \\ %{}) do
|
||||
deployment_group
|
||||
|> cast(attrs, [:id, :name, :mode, :hub_id])
|
||||
|> cast(attrs, [:id, :name, :mode, :hub_id, :clustering, :zta_provider, :zta_key])
|
||||
|> validate_required([:name, :mode])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -169,7 +169,14 @@ defmodule Livebook.Teams.Requests do
|
|||
@spec create_deployment_group(Team.t(), DeploymentGroup.t()) ::
|
||||
{:ok, map()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
||||
def create_deployment_group(team, deployment_group) do
|
||||
params = %{name: deployment_group.name, mode: deployment_group.mode}
|
||||
params = %{
|
||||
name: deployment_group.name,
|
||||
mode: deployment_group.mode,
|
||||
clustering: deployment_group.clustering,
|
||||
zta_provider: deployment_group.zta_provider,
|
||||
zta_key: deployment_group.zta_key
|
||||
}
|
||||
|
||||
post("/api/v1/org/deployment-groups", params, team)
|
||||
end
|
||||
|
||||
|
@ -179,7 +186,15 @@ defmodule Livebook.Teams.Requests do
|
|||
@spec update_deployment_group(Team.t(), DeploymentGroup.t()) ::
|
||||
{:ok, map()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
||||
def update_deployment_group(team, deployment_group) do
|
||||
params = %{id: deployment_group.id, name: deployment_group.name, mode: deployment_group.mode}
|
||||
params = %{
|
||||
id: deployment_group.id,
|
||||
name: deployment_group.name,
|
||||
mode: deployment_group.mode,
|
||||
clustering: deployment_group.clustering,
|
||||
zta_provider: deployment_group.zta_provider,
|
||||
zta_key: deployment_group.zta_key
|
||||
}
|
||||
|
||||
put("/api/v1/org/deployment-groups", params, team)
|
||||
end
|
||||
|
||||
|
|
|
@ -411,6 +411,7 @@ defmodule LivebookWeb.FormComponents do
|
|||
attr :class, :string, default: ""
|
||||
attr :field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form"
|
||||
attr :help, :string, default: nil
|
||||
attr :disabled, :boolean, default: false
|
||||
|
||||
attr :options, :list, default: []
|
||||
attr :prompt, :string, default: nil
|
||||
|
|
|
@ -102,68 +102,85 @@ defmodule LivebookWeb.AppHelpers do
|
|||
]}
|
||||
/>
|
||||
<.radio_field label="Base image" field={@form[:docker_tag]} options={docker_tag_options()} />
|
||||
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||
<.select_field
|
||||
label="Clustering"
|
||||
help={
|
||||
~S'''
|
||||
When running multiple
|
||||
instances of Livebook,
|
||||
they need to be connected
|
||||
into a single cluster.
|
||||
You must either deploy
|
||||
it as a single instance
|
||||
or choose a platform to
|
||||
enable clustering on.
|
||||
'''
|
||||
}
|
||||
field={@form[:clustering]}
|
||||
options={[
|
||||
{"Single instance", ""},
|
||||
{"Fly.io", "fly_io"}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<%= if Hubs.Provider.type(@hub) == "team" do %>
|
||||
<div class="flex flex-col">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<.select_field
|
||||
label="Zero Trust Authentication provider"
|
||||
field={@form[:zta_provider]}
|
||||
help={
|
||||
~S'''
|
||||
Enable this option if you want
|
||||
to deploy your notebooks behind
|
||||
an authentication proxy
|
||||
'''
|
||||
}
|
||||
prompt="None"
|
||||
options={zta_options()}
|
||||
/>
|
||||
<.text_field
|
||||
:if={zta_metadata = zta_metadata(@form[:zta_provider].value)}
|
||||
field={@form[:zta_key]}
|
||||
label={zta_metadata.value}
|
||||
help={zta_help(zta_metadata)}
|
||||
phx-debounce
|
||||
/>
|
||||
</div>
|
||||
<div :if={zta_metadata = zta_metadata(@form[:zta_provider].value)} class="text-sm mt-1">
|
||||
See the
|
||||
<a
|
||||
class="text-blue-800 hover:text-blue-600"
|
||||
href={"https://hexdocs.pm/livebook/#{zta_metadata.type}"}
|
||||
>
|
||||
Authentication with <%= zta_metadata.name %> docs
|
||||
</a>
|
||||
for more information.
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders form fields for Deployment Group.
|
||||
"""
|
||||
attr :form, Phoenix.HTML.Form, required: true
|
||||
attr :hub, :map, required: true
|
||||
|
||||
def deployment_group_form_content(assigns) do
|
||||
~H"""
|
||||
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||
<.select_field
|
||||
label="Clustering"
|
||||
help={
|
||||
~S'''
|
||||
When running multiple
|
||||
instances of Livebook,
|
||||
they need to be connected
|
||||
into a single cluster.
|
||||
You must either deploy
|
||||
it as a single instance
|
||||
or choose a platform to
|
||||
enable clustering on.
|
||||
'''
|
||||
}
|
||||
field={@form[:clustering]}
|
||||
options={[
|
||||
{"Single instance", ""},
|
||||
{"Fly.io", "fly_io"}
|
||||
]}
|
||||
disabled={@form[:ready_only].value}
|
||||
class="disabled:cursor-not-allowed"
|
||||
/>
|
||||
</div>
|
||||
<%= if Hubs.Provider.type(@hub) == "team" do %>
|
||||
<div class="flex flex-col">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<.select_field
|
||||
label="Zero Trust Authentication provider"
|
||||
field={@form[:zta_provider]}
|
||||
help={
|
||||
~S'''
|
||||
Enable this option if you want
|
||||
to deploy your notebooks behind
|
||||
an authentication proxy
|
||||
'''
|
||||
}
|
||||
prompt="None"
|
||||
options={zta_options()}
|
||||
disabled={@form[:ready_only].value}
|
||||
class="disabled:cursor-not-allowed"
|
||||
/>
|
||||
<.text_field
|
||||
:if={zta_metadata = zta_metadata(@form[:zta_provider].value)}
|
||||
field={@form[:zta_key]}
|
||||
label={zta_metadata.value}
|
||||
help={zta_help(zta_metadata)}
|
||||
phx-debounce
|
||||
disabled={@form[:ready_only].value}
|
||||
class="disabled:cursor-not-allowed"
|
||||
/>
|
||||
</div>
|
||||
<div :if={zta_metadata = zta_metadata(@form[:zta_provider].value)} class="text-sm mt-1">
|
||||
See the
|
||||
<a
|
||||
class="text-blue-800 hover:text-blue-600"
|
||||
href={"https://hexdocs.pm/livebook/#{zta_metadata.type}"}
|
||||
>
|
||||
Authentication with <%= zta_metadata.name %> docs
|
||||
</a>
|
||||
for more information.
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
@zta_options for provider <- Livebook.Config.identity_providers(),
|
||||
do: {provider.name, provider.type}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
|||
{"Online", "online"}
|
||||
]}
|
||||
/>
|
||||
<LivebookWeb.AppHelpers.deployment_group_form_content hub={@hub} form={f} />
|
||||
<div class="flex space-x-2">
|
||||
<button class="button-base button-blue" type="submit" disabled={not @changeset.valid?}>
|
||||
<.remix_icon icon={@button.icon} class="align-middle mr-1" />
|
||||
|
|
|
@ -20,7 +20,8 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
hub_secrets: Hubs.get_secrets(assigns.hub),
|
||||
hub_file_systems: Hubs.get_file_systems(assigns.hub, hub_only: true),
|
||||
deployment_groups: deployment_groups,
|
||||
deployment_group_form: %{"id" => assigns.deployment_group_id}
|
||||
deployment_group_form: %{"deployment_group_id" => assigns.deployment_group_id},
|
||||
deployment_group_id: assigns.deployment_group_id
|
||||
)
|
||||
|> assign_new(:changeset, fn -> Hubs.Dockerfile.config_changeset() end)
|
||||
|> assign_new(:save_result, fn -> nil end)
|
||||
|
@ -40,6 +41,7 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
hub={@hub}
|
||||
deployment_groups={@deployment_groups}
|
||||
deployment_group_form={@deployment_group_form}
|
||||
deployment_group_id={@deployment_group_id}
|
||||
changeset={@changeset}
|
||||
session={@session}
|
||||
dockerfile={@dockerfile}
|
||||
|
@ -97,7 +99,6 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
<%= if @deployment_groups do %>
|
||||
<%= if @deployment_groups != [] do %>
|
||||
<.form
|
||||
:let={f}
|
||||
for={@deployment_group_form}
|
||||
phx-change="select_deployment_group"
|
||||
phx-target={@myself}
|
||||
|
@ -109,9 +110,11 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
Share deployment credentials, secrets, and configuration with deployment groups.
|
||||
'''
|
||||
}
|
||||
field={f[:id]}
|
||||
field={@deployment_group_form[:deployment_group_id]}
|
||||
options={deployment_group_options(@deployment_groups)}
|
||||
label="Deployment Group"
|
||||
name="deployment_group_id"
|
||||
value={@deployment_group_id}
|
||||
/>
|
||||
</.form>
|
||||
<% else %>
|
||||
|
@ -127,6 +130,17 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
<%= raw(warning) %>
|
||||
</.message_box>
|
||||
</div>
|
||||
<.form
|
||||
:let={f}
|
||||
for={deployment_group_form_content(assigns)}
|
||||
as={:data}
|
||||
phx-change="validate"
|
||||
phx-target={@myself}
|
||||
>
|
||||
<div class="flex flex-col space-y-4">
|
||||
<AppHelpers.deployment_group_form_content hub={@hub} form={f} />
|
||||
</div>
|
||||
</.form>
|
||||
<.form :let={f} for={@changeset} as={:data} phx-change="validate" phx-target={@myself}>
|
||||
<AppHelpers.docker_config_form_content hub={@hub} form={f} />
|
||||
</.form>
|
||||
|
@ -191,7 +205,7 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
{:noreply, assign(socket, save_result: save_result)}
|
||||
end
|
||||
|
||||
def handle_event("select_deployment_group", %{"id" => id}, socket) do
|
||||
def handle_event("select_deployment_group", %{"deployment_group_id" => id}, socket) do
|
||||
Livebook.Session.set_notebook_deployment_group(socket.assigns.session.pid, id)
|
||||
|
||||
{:noreply, socket}
|
||||
|
@ -255,4 +269,20 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
for deployment_group <- [%{name: "none", id: nil}] ++ deployment_groups,
|
||||
do: {deployment_group.name, deployment_group.id}
|
||||
end
|
||||
|
||||
defp deployment_group_form_content(%{deployment_group_id: id} = assigns) do
|
||||
deployment_group = if id, do: Enum.find(assigns.deployment_groups, &(&1.id == id))
|
||||
|
||||
if deployment_group do
|
||||
%{
|
||||
"deployment_group_id" => deployment_group.id,
|
||||
"clustering" => deployment_group.clustering,
|
||||
"zta_provider" => deployment_group.zta_provider,
|
||||
"zta_key" => deployment_group.zta_key,
|
||||
"ready_only" => true
|
||||
}
|
||||
else
|
||||
assigns.changeset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,4 +5,7 @@ defmodule LivebookProto.DeploymentGroup do
|
|||
field :name, 2, type: :string
|
||||
field :mode, 3, type: :string
|
||||
field :secrets, 4, repeated: true, type: LivebookProto.DeploymentGroupSecret
|
||||
field :clustering, 5, type: :string
|
||||
field :zta_provider, 6, type: :string
|
||||
field :zta_key, 7, type: :string
|
||||
end
|
||||
|
|
|
@ -5,4 +5,7 @@ defmodule LivebookProto.DeploymentGroupCreated do
|
|||
field :name, 2, type: :string
|
||||
field :mode, 3, type: :string
|
||||
field :secrets, 4, repeated: true, type: LivebookProto.DeploymentGroupSecret
|
||||
field :clustering, 5, type: :string
|
||||
field :zta_provider, 6, type: :string
|
||||
field :zta_key, 7, type: :string
|
||||
end
|
||||
|
|
|
@ -5,4 +5,7 @@ defmodule LivebookProto.DeploymentGroupUpdated do
|
|||
field :name, 2, type: :string
|
||||
field :mode, 3, type: :string
|
||||
field :secrets, 4, repeated: true, type: LivebookProto.DeploymentGroupSecret
|
||||
field :clustering, 5, type: :string
|
||||
field :zta_provider, 6, type: :string
|
||||
field :zta_key, 7, type: :string
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue