Fix Dockerfile generation with deployment group (#2475)

This commit is contained in:
Jonatan Kłosko 2024-02-07 20:36:21 +01:00 committed by GitHub
parent 6d2a70bf6e
commit a2d6b1caae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 86 additions and 62 deletions

View file

@ -70,7 +70,7 @@
/* Form fields */ /* Form fields */
.input { .input {
@apply w-full px-3 py-2 bg-gray-50 text-sm border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600 phx-form-error:border-red-300; @apply w-full px-3 py-2 bg-gray-50 text-sm border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600 phx-form-error:border-red-300 disabled:opacity-70 disabled:cursor-not-allowed;
} }
.input[type="color"] { .input[type="color"] {

View file

@ -14,20 +14,26 @@ defmodule Livebook.Hubs.Dockerfile do
} }
@doc """ @doc """
Builds a changeset for app Dockerfile configuration. Builds the default Dockerfile configuration.
""" """
@spec config_changeset(map()) :: Ecto.Changeset.t() @spec config_new() :: config()
def config_changeset(attrs \\ %{}) do def config_new() do
default_image = Livebook.Config.docker_images() |> hd() default_image = Livebook.Config.docker_images() |> hd()
data = %{ %{
deploy_all: false, deploy_all: false,
docker_tag: default_image.tag, docker_tag: default_image.tag,
clustering: nil, clustering: nil,
zta_provider: nil, zta_provider: nil,
zta_key: nil zta_key: nil
} }
end
@doc """
Builds a changeset for app Dockerfile configuration.
"""
@spec config_changeset(config(), map()) :: Ecto.Changeset.t()
def config_changeset(config, attrs \\ %{}) do
zta_types = zta_types =
for provider <- Livebook.Config.identity_providers(), for provider <- Livebook.Config.identity_providers(),
do: provider.type do: provider.type
@ -40,7 +46,7 @@ defmodule Livebook.Hubs.Dockerfile do
zta_key: :string zta_key: :string
} }
cast({data, types}, attrs, [:deploy_all, :docker_tag, :clustering, :zta_provider, :zta_key]) cast({config, types}, attrs, [:deploy_all, :docker_tag, :clustering, :zta_provider, :zta_key])
|> validate_required([:deploy_all, :docker_tag]) |> validate_required([:deploy_all, :docker_tag])
end end

View file

@ -111,6 +111,7 @@ defmodule LivebookWeb.AppComponents do
""" """
attr :form, Phoenix.HTML.Form, required: true attr :form, Phoenix.HTML.Form, required: true
attr :hub, :map, required: true attr :hub, :map, required: true
attr :disabled, :boolean, default: false
def deployment_group_form_content(assigns) do def deployment_group_form_content(assigns) do
~H""" ~H"""
@ -134,8 +135,7 @@ defmodule LivebookWeb.AppComponents do
{"Single instance", ""}, {"Single instance", ""},
{"Fly.io", "fly_io"} {"Fly.io", "fly_io"}
]} ]}
disabled={@form[:ready_only].value} disabled={@disabled}
class="disabled:cursor-not-allowed"
/> />
</div> </div>
<%= if Hubs.Provider.type(@hub) == "team" do %> <%= if Hubs.Provider.type(@hub) == "team" do %>
@ -153,8 +153,7 @@ defmodule LivebookWeb.AppComponents do
} }
prompt="None" prompt="None"
options={zta_options()} options={zta_options()}
disabled={@form[:ready_only].value} disabled={@disabled}
class="disabled:cursor-not-allowed"
/> />
<.text_field <.text_field
:if={zta_metadata = zta_metadata(@form[:zta_provider].value)} :if={zta_metadata = zta_metadata(@form[:zta_provider].value)}
@ -162,8 +161,7 @@ defmodule LivebookWeb.AppComponents do
label={zta_metadata.value} label={zta_metadata.value}
placeholder={zta_placeholder(zta_metadata)} placeholder={zta_placeholder(zta_metadata)}
phx-debounce phx-debounce
disabled={@form[:ready_only].value} disabled={@disabled}
class="disabled:cursor-not-allowed"
/> />
</div> </div>
<div :if={zta_metadata = zta_metadata(@form[:zta_provider].value)} class="text-sm mt-1"> <div :if={zta_metadata = zta_metadata(@form[:zta_provider].value)} class="text-sm mt-1">

View file

@ -421,12 +421,11 @@ defmodule LivebookWeb.FormComponents do
attr :class, :string, default: "" attr :class, :string, default: ""
attr :field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form" attr :field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form"
attr :help, :string, default: nil attr :help, :string, default: nil
attr :disabled, :boolean, default: false
attr :options, :list, default: [] attr :options, :list, default: []
attr :prompt, :string, default: nil attr :prompt, :string, default: nil
attr :rest, :global attr :rest, :global, include: ~w(disabled)
def select_field(assigns) do def select_field(assigns) do
assigns = assigns_from_field(assigns) assigns = assigns_from_field(assigns)
@ -438,7 +437,7 @@ defmodule LivebookWeb.FormComponents do
id={@id} id={@id}
name={@name} name={@name}
class={[ class={[
"w-full px-3 py-2 pr-7 appearance-none bg-gray-50 text-sm border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600 phx-form-error:border-red-300", "w-full px-3 py-2 pr-7 appearance-none bg-gray-50 text-sm border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600 phx-form-error:border-red-300 disabled:opacity-70 disabled:cursor-not-allowed",
@class @class
]} ]}
{@rest} {@rest}

View file

@ -57,7 +57,9 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
secrets: secrets, secrets: secrets,
agent_keys: agent_keys agent_keys: agent_keys
) )
|> assign_new(:config_changeset, fn -> Hubs.Dockerfile.config_changeset() end) |> assign_new(:config_changeset, fn ->
Hubs.Dockerfile.config_changeset(Hubs.Dockerfile.config_new())
end)
|> update_dockerfile()} |> update_dockerfile()}
end end
@ -206,7 +208,7 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
def handle_event("validate_dockerfile", %{"data" => data}, socket) do def handle_event("validate_dockerfile", %{"data" => data}, socket) do
changeset = changeset =
data data
|> Hubs.Dockerfile.config_changeset() |> Hubs.Dockerfile.config_changeset(Hubs.Dockerfile.config_new())
|> Map.replace!(:action, :validate) |> Map.replace!(:action, :validate)
{:noreply, {:noreply,
@ -252,12 +254,23 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupLive do
Hubs.get_default_hub().id == hub.id Hubs.get_default_hub().id == hub.id
end end
defp update_dockerfile(socket) when socket.assigns.deployment_group == nil, do: socket
defp update_dockerfile(socket) do defp update_dockerfile(socket) do
config = config =
socket.assigns.config_changeset socket.assigns.config_changeset
|> Ecto.Changeset.apply_changes() |> Ecto.Changeset.apply_changes()
|> Map.replace!(:deploy_all, true) |> Map.replace!(:deploy_all, true)
deployment_group = socket.assigns.deployment_group
config = %{
config
| clustering: deployment_group.clustering,
zta_provider: deployment_group.zta_provider,
zta_key: deployment_group.zta_key
}
%{hub: hub, secrets: deployment_group_secrets} = socket.assigns %{hub: hub, secrets: deployment_group_secrets} = socket.assigns
hub_secrets = Hubs.get_secrets(hub) hub_secrets = Hubs.get_secrets(hub)

View file

@ -10,22 +10,48 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
@impl true @impl true
def update(assigns, socket) do def update(assigns, socket) do
deployment_group_changed? =
not Map.has_key?(socket.assigns, :deployment_group_id) or
socket.assigns.deployment_group_id != assigns.deployment_group_id
socket = assign(socket, assigns) socket = assign(socket, assigns)
deployment_groups = Provider.deployment_groups(assigns.hub) deployment_groups = Provider.deployment_groups(assigns.hub)
{:ok, socket =
socket socket
|> assign(settings_valid?: Livebook.Notebook.AppSettings.valid?(socket.assigns.settings)) |> assign(settings_valid?: Livebook.Notebook.AppSettings.valid?(socket.assigns.settings))
|> assign( |> assign(
hub_secrets: Hubs.get_secrets(assigns.hub), hub_secrets: Hubs.get_secrets(assigns.hub),
hub_file_systems: Hubs.get_file_systems(assigns.hub, hub_only: true), hub_file_systems: Hubs.get_file_systems(assigns.hub, hub_only: true),
deployment_groups: deployment_groups, deployment_groups: deployment_groups,
deployment_group_form: %{"deployment_group_id" => assigns.deployment_group_id}, deployment_group_form: %{"deployment_group_id" => assigns.deployment_group_id},
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)
|> assign_new(:save_result, fn -> nil end)
|> update_dockerfile()} socket =
if deployment_group_changed? do
assign(socket, :changeset, Hubs.Dockerfile.config_changeset(base_config(socket)))
else
socket
end
{:ok, update_dockerfile(socket)}
end
defp base_config(socket) do
if id = socket.assigns.deployment_group_id do
deployment_group = Enum.find(socket.assigns.deployment_groups, &(&1.id == id))
%{
Hubs.Dockerfile.config_new()
| clustering: deployment_group.clustering,
zta_provider: deployment_group.zta_provider,
zta_key: deployment_group.zta_key
}
else
Hubs.Dockerfile.config_new()
end
end end
@impl true @impl true
@ -128,19 +154,15 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
<%= raw(warning) %> <%= raw(warning) %>
</.message_box> </.message_box>
</div> </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">
<AppComponents.deployment_group_form_content hub={@hub} form={f} />
</div>
</.form>
<.form :let={f} for={@changeset} as={:data} phx-change="validate" phx-target={@myself}> <.form :let={f} for={@changeset} as={:data} phx-change="validate" phx-target={@myself}>
<AppComponents.docker_config_form_content hub={@hub} form={f} /> <div class="flex flex-col space-y-4">
<AppComponents.deployment_group_form_content
hub={@hub}
form={f}
disabled={@deployment_group_id != nil}
/>
<AppComponents.docker_config_form_content hub={@hub} form={f} />
</div>
</.form> </.form>
<.save_result :if={@save_result} save_result={@save_result} /> <.save_result :if={@save_result} save_result={@save_result} />
<AppComponents.docker_instructions <AppComponents.docker_instructions
@ -184,8 +206,9 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
@impl true @impl true
def handle_event("validate", %{"data" => data}, socket) do def handle_event("validate", %{"data" => data}, socket) do
changeset = changeset =
data socket
|> Hubs.Dockerfile.config_changeset() |> base_config()
|> Hubs.Dockerfile.config_changeset(data)
|> Map.replace!(:action, :validate) |> Map.replace!(:action, :validate)
{:noreply, assign(socket, changeset: changeset) |> update_dockerfile()} {:noreply, assign(socket, changeset: changeset) |> update_dockerfile()}
@ -204,6 +227,7 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
end end
def handle_event("select_deployment_group", %{"deployment_group_id" => id}, socket) do def handle_event("select_deployment_group", %{"deployment_group_id" => id}, socket) do
id = if(id != "", do: id)
Livebook.Session.set_notebook_deployment_group(socket.assigns.session.pid, id) Livebook.Session.set_notebook_deployment_group(socket.assigns.session.pid, id)
{:noreply, socket} {:noreply, socket}
@ -268,22 +292,6 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
do: {deployment_group.name, deployment_group.id} do: {deployment_group.name, deployment_group.id}
end 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
defp deployment_group_help() do defp deployment_group_help() do
"Share deployment credentials, secrets, and configuration with deployment groups." "Share deployment credentials, secrets, and configuration with deployment groups."
end end

View file

@ -292,8 +292,8 @@ defmodule Livebook.Hubs.DockerfileTest do
end end
defp dockerfile_config(attrs \\ %{}) do defp dockerfile_config(attrs \\ %{}) do
attrs Dockerfile.config_new()
|> Dockerfile.config_changeset() |> Dockerfile.config_changeset(attrs)
|> Ecto.Changeset.apply_changes() |> Ecto.Changeset.apply_changes()
end end