Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement File Storage #2212

Merged
merged 35 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
75e3447
New User should use the same id from session data
aleDsz Aug 9, 2023
7fc0e64
Make `create_teams_file_system/2` public
aleDsz Sep 13, 2023
b1d8ca9
Add file system topic docs
aleDsz Sep 13, 2023
1a01870
Add function to list file systems from all hubs
aleDsz Aug 8, 2023
df1a0c2
Use the notebook hub to list file systems
aleDsz Aug 9, 2023
b9f3d93
Handle hub assignment to list hub file systems
aleDsz Sep 13, 2023
70abc79
Add ID to menu item elements from file system
aleDsz Aug 10, 2023
865083d
Add tests for file systems menu
aleDsz Aug 10, 2023
ec724bf
Improve file entry spec from FileSystem protocol
aleDsz Sep 13, 2023
500343e
Keep `:external_id` nil as default
aleDsz Sep 15, 2023
924050b
Add `:id` from changeset
aleDsz Sep 15, 2023
0a776b9
Remove everything related to File System
aleDsz Sep 15, 2023
0674bb5
Add new hub routes to handle file systems
aleDsz Sep 15, 2023
1581e69
Use alias instead
aleDsz Sep 15, 2023
0426f67
Add FileSystemListComponent
aleDsz Sep 15, 2023
66591dd
Add FileSystemFormComponent
aleDsz Sep 15, 2023
a87afba
Handle file system events
aleDsz Sep 15, 2023
3693247
Implement file system components
aleDsz Sep 15, 2023
8d5edcf
Add functions to help handling file system forms
aleDsz Sep 15, 2023
dc8e874
Add tests
aleDsz Sep 15, 2023
9251981
Change flash message from `created` to `added`
aleDsz Sep 18, 2023
db477ba
Improve confirm dialog when deleting a file system
aleDsz Sep 18, 2023
87edef6
Use file systems from notebook's hub
aleDsz Sep 18, 2023
fc916b6
Use configure path based on current hub
aleDsz Sep 18, 2023
32cfbe9
Rename from `Delete` to `Detach`
aleDsz Sep 18, 2023
2ec8508
Fix specs
aleDsz Sep 18, 2023
8a64156
Put region on changeset
aleDsz Sep 18, 2023
0f30bdf
Fix tests
aleDsz Sep 18, 2023
ff2734d
Apply review comments
aleDsz Sep 22, 2023
bb612c7
Apply review comments
aleDsz Sep 22, 2023
683ed6f
Fix test
aleDsz Sep 22, 2023
bcc803a
Improve tests
aleDsz Sep 22, 2023
ed9476e
Apply review comments
aleDsz Sep 22, 2023
85e9e96
Make `personal-hub` as default `:hub_id`
aleDsz Sep 22, 2023
f1ae220
Apply review comments
aleDsz Sep 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions lib/livebook/file_system/s3.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,10 @@ defmodule Livebook.FileSystem.S3 do
bucket_url = String.trim_trailing(bucket_url, "/")
region = opts[:region] || region_from_uri(bucket_url)

hash = :crypto.hash(:sha256, bucket_url) |> Base.url_encode64(padding: false)

id =
if prefix = opts[:prefix],
do: "#{prefix}-s3-#{hash}",
else: "s3-#{hash}"
do: "#{prefix}-#{id(bucket_url)}",
else: id(bucket_url)

%__MODULE__{
id: id,
Expand Down Expand Up @@ -134,14 +132,18 @@ defmodule Livebook.FileSystem.S3 do

defp put_id(changeset) do
if bucket_url = get_field(changeset, :bucket_url) do
hash = :crypto.hash(:sha256, bucket_url)
encrypted_hash = Base.url_encode64(hash, padding: false)

put_change(changeset, :id, "s3-#{encrypted_hash}")
put_change(changeset, :id, id(bucket_url))
aleDsz marked this conversation as resolved.
Show resolved Hide resolved
else
changeset
end
end

defp id(bucket_url) do
hash = :crypto.hash(:sha256, bucket_url)
encrypted_hash = Base.url_encode64(hash, padding: false)

"s3-#{encrypted_hash}"
end
end

defimpl Livebook.FileSystem, for: Livebook.FileSystem.S3 do
Expand Down
16 changes: 9 additions & 7 deletions lib/livebook/hubs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ defmodule Livebook.Hubs do

Topic `hubs:file_systems`:

* `{:file_system_created, t:FileSystem}`
* `{:file_system_updated, t:FileSystem}`
* `{:file_system_deleted, t:FileSystem}`
* `{:file_system_created, FileSystem.t()}`
* `{:file_system_updated, FileSystem.t()}`
* `{:file_system_deleted, FileSystem.t()}`

"""
@spec subscribe(atom() | list(atom())) :: :ok | {:error, term()}
Expand Down Expand Up @@ -316,12 +316,14 @@ defmodule Livebook.Hubs do
@doc """
Gets a list of file systems for given hub.
"""
@spec get_file_systems(Provider.t()) :: list(FileSystem.t())
def get_file_systems(hub) do
@spec get_file_systems(Provider.t(), keyword()) :: list(FileSystem.t())
def get_file_systems(hub, opts \\ []) do
hub_file_systems = Provider.get_file_systems(hub)
local_file_system = Livebook.Config.local_file_system()
sorted_hub_file_systems = Enum.sort_by(hub_file_systems, & &1.id)

[local_file_system | Enum.sort_by(hub_file_systems, & &1.id)]
if opts[:hub_only],
do: sorted_hub_file_systems,
else: [Livebook.Config.local_file_system() | sorted_hub_file_systems]
end

@doc """
Expand Down
21 changes: 13 additions & 8 deletions lib/livebook/session.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2661,15 +2661,20 @@ defmodule Livebook.Session do
{:error, "no file exists at path #{inspect(file.path)}"}
end
else
type = Livebook.FileSystems.type(file.file_system)
dumped_data = FileSystem.dump(file.file_system)
"/" <> key = file.path

spec =
Map.merge(dumped_data, %{
type: String.to_existing_atom(type),
key: key
})
case file.file_system do
%FileSystem.S3{} = file_system ->
"/" <> key = file.path

%{
type: :s3,
bucket_url: file_system.bucket_url,
region: file_system.region,
access_key_id: file_system.access_key_id,
secret_access_key: file_system.secret_access_key,
key: key
}
end

{:ok, spec}
end
Expand Down
10 changes: 5 additions & 5 deletions lib/livebook_web/live/file_select_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ defmodule LivebookWeb.FileSelectComponent do
|> assign(assigns)
|> update_file_infos(force_reload? or running_files_changed?)

configure_path = ~p"/hub/#{Livebook.Hubs.Personal.id()}/file-systems/new"

{file_systems, configure_path} =
{file_systems, configure_hub_id} =
if hub = socket.assigns[:hub],
do: {Livebook.Hubs.get_file_systems(hub), ~p"/hub/#{hub.id}/file-systems/new"},
else: {Livebook.Hubs.get_file_systems(), configure_path}
do: {Livebook.Hubs.get_file_systems(hub), hub.id},
else: {Livebook.Hubs.get_file_systems(), Livebook.Hubs.Personal.id()}

configure_path = ~p"/hub/#{configure_hub_id}/file-systems/new"

{:ok, assign(socket, file_systems: file_systems, configure_path: configure_path)}
end
Expand Down
23 changes: 1 addition & 22 deletions lib/livebook_web/live/hub/edit/personal_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
socket = assign(socket, assigns)
changeset = Personal.change_hub(assigns.hub)
secrets = Hubs.get_secrets(assigns.hub)
[_local | file_systems] = Hubs.get_file_systems(assigns.hub)
file_systems = Hubs.get_file_systems(assigns.hub, hub_only: true)
secret_name = assigns.params["secret_name"]
file_system_id = assigns.params["file_system_id"]

Expand Down Expand Up @@ -101,7 +101,6 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
id="hub-secrets-list"
hub={@hub}
secrets={@secrets}
target={@myself}
/>
</div>

Expand All @@ -119,7 +118,6 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
id="hub-file-systems-list"
hub_id={@hub.id}
file_systems={@file_systems}
target={@myself}
/>
</div>

Expand Down Expand Up @@ -239,25 +237,6 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
{:noreply, validate(params, :stamp_changeset, socket)}
end

def handle_event("delete_hub_secret", attrs, socket) do
%{hub: hub} = socket.assigns

on_confirm = fn socket ->
{:ok, secret} = Livebook.Secrets.update_secret(%Livebook.Secrets.Secret{}, attrs)
_ = Livebook.Hubs.delete_secret(hub, secret)

socket
end

{:noreply,
confirm(socket, on_confirm,
title: "Delete hub secret - #{attrs["name"]}",
description: "Are you sure you want to delete this hub secret?",
confirm_text: "Delete",
confirm_icon: "delete-bin-6-line"
)}
end

defp save(params, changeset_name, socket) do
case Personal.update_hub(socket.assigns.hub, params) do
{:ok, hub} ->
Expand Down
2 changes: 1 addition & 1 deletion lib/livebook_web/live/hub/edit/team_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ defmodule LivebookWeb.Hub.Edit.TeamComponent do
changeset = Team.change_hub(assigns.hub)
show_key? = assigns.params["show-key"] == "true"
secrets = Livebook.Hubs.get_secrets(assigns.hub)
[_local | file_systems] = Hubs.get_file_systems(assigns.hub)
file_systems = Hubs.get_file_systems(assigns.hub, hub_only: true)
secret_name = assigns.params["secret_name"]
file_system_id = assigns.params["file_system_id"]
is_default? = is_default?(assigns.hub)
Expand Down
54 changes: 4 additions & 50 deletions lib/livebook_web/live/hub/edit_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ defmodule LivebookWeb.Hub.EditLive do

@impl true
def mount(_params, _session, socket) do
Hubs.subscribe([:connection])

{:ok, assign(socket, hub: nil, type: nil, page_title: "Hub - Livebook", params: %{})}
end

@impl true
def handle_params(params, _url, socket) do
Hubs.subscribe([:connection, :secrets, :file_systems])
hub = Hubs.fetch_hub!(params["id"])
type = Provider.type(hub)

Expand Down Expand Up @@ -85,55 +86,8 @@ defmodule LivebookWeb.Hub.EditLive do
end

@impl true
def handle_info(
{:secret_created, %{name: name, hub_id: id}},
%{assigns: %{hub: %{id: id}}} = socket
) do
{:noreply,
socket
|> push_navigate(to: ~p"/hub/#{id}")
|> put_flash(:success, "Secret #{name} added successfully")}
end

def handle_info(
{:secret_updated, %{name: name, hub_id: id}},
%{assigns: %{hub: %{id: id}}} = socket
) do
{:noreply,
socket
|> push_navigate(to: ~p"/hub/#{id}")
|> put_flash(:success, "Secret #{name} updated successfully")}
end

def handle_info(
{:secret_deleted, %{name: name, hub_id: id}},
%{assigns: %{hub: %{id: id}}} = socket
) do
{:noreply,
socket
|> push_navigate(to: ~p"/hub/#{id}")
|> put_flash(:success, "Secret #{name} deleted successfully")}
end

def handle_info({:file_system_created, _}, socket) do
{:noreply,
socket
|> push_navigate(to: ~p"/hub/#{socket.assigns.hub.id}")
|> put_flash(:success, "File storage added successfully")}
end

def handle_info({:file_system_updated, _}, socket) do
{:noreply,
socket
|> push_navigate(to: ~p"/hub/#{socket.assigns.hub.id}")
|> put_flash(:success, "File storage updated successfully")}
end

def handle_info({:file_system_deleted, _}, socket) do
{:noreply,
socket
|> push_navigate(to: ~p"/hub/#{socket.assigns.hub.id}")
|> put_flash(:success, "File storage deleted successfully")}
def handle_info({:redirect, id, flash}, %{assigns: %{hub: %{id: id}}} = socket) do
{:noreply, socket |> push_navigate(to: ~p"/hub/#{id}") |> put_flash(:success, flash)}
end

def handle_info({:hub_connected, id}, %{assigns: %{hub: %{id: id}}} = socket) do
Expand Down
32 changes: 24 additions & 8 deletions lib/livebook_web/live/hub/file_system_form_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ defmodule LivebookWeb.Hub.FileSystemFormComponent do
alias Livebook.FileSystems

@impl true
def update(%{file_system: file_system} = assigns, socket) do
def update(assigns, socket) do
{file_system, assigns} = Map.pop!(assigns, :file_system)

mode = mode(file_system)
button = button(file_system)
title = title(file_system)

file_system = file_system || %FileSystem.S3{}
changeset = FileSystems.change_file_system(file_system)
socket = assign(socket, assigns)
Expand All @@ -14,9 +20,9 @@ defmodule LivebookWeb.Hub.FileSystemFormComponent do
assign(socket,
file_system: file_system,
changeset: changeset,
mode: mode(socket),
title: title(socket),
button: button(socket),
mode: mode,
title: title,
button: button,
error_message: nil
)}
end
Expand Down Expand Up @@ -84,9 +90,19 @@ defmodule LivebookWeb.Hub.FileSystemFormComponent do
with {:ok, file_system} <- FileSystems.update_file_system(socket.assigns.file_system, attrs),
:ok <- check_file_system_conectivity(file_system),
:ok <- save_file_system(file_system, socket) do
{:noreply, push_patch(socket, to: socket.assigns.return_to)}
message =
case socket.assigns.mode do
:new -> "File storage added successfully"
:edit -> "File storage updated successfully"
end

{:noreply,
socket
|> put_flash(:success, message)
|> push_redirect(to: socket.assigns.return_to)}
else
{:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, changeset: changeset)}
{:transport_error, message} -> {:noreply, put_flash(socket, :error, message)}
{:error, message} -> {:noreply, assign(socket, error_message: message)}
end
end
Expand All @@ -107,12 +123,12 @@ defmodule LivebookWeb.Hub.FileSystemFormComponent do
end
end

defp mode(%{assigns: %{file_system: nil}}), do: :new
defp mode(nil), do: :new
defp mode(_), do: :edit

defp title(%{assigns: %{file_system: nil}}), do: "Add file storage"
defp title(nil), do: "Add file storage"
defp title(_), do: "Edit file storage"

defp button(%{assigns: %{file_system: nil}}), do: %{icon: "add-line", label: "Add"}
defp button(nil), do: %{icon: "add-line", label: "Add"}
defp button(_), do: %{icon: "save-line", label: "Save"}
end
8 changes: 6 additions & 2 deletions lib/livebook_web/live/hub/file_system_list_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ defmodule LivebookWeb.Hub.FileSystemListComponent do
file_system = Enum.find(file_systems, &(&1.id == id))

case Livebook.Hubs.delete_file_system(hub, file_system) do
:ok -> socket
{:transport_error, reason} -> put_flash(socket, :error, reason)
:ok ->
send(self(), {:redirect, hub.id, "File storage deleted successfully"})
socket
aleDsz marked this conversation as resolved.
Show resolved Hide resolved

{:transport_error, reason} ->
put_flash(socket, :error, reason)
end
end

Expand Down
10 changes: 7 additions & 3 deletions lib/livebook_web/live/hub/secret_list_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ defmodule LivebookWeb.Hub.SecretListComponent do
}
)
}
phx-target={@target}
phx-target={@myself}
role="menuitem"
>
<.remix_icon icon="delete-bin-line" />
Expand Down Expand Up @@ -92,8 +92,12 @@ defmodule LivebookWeb.Hub.SecretListComponent do
hub = Hubs.fetch_hub!(secret.hub_id)

case Hubs.delete_secret(hub, secret) do
:ok -> socket
{:transport_error, reason} -> put_flash(socket, :error, reason)
:ok ->
send(self(), {:redirect, hub.id, "Secret #{secret.name} deleted successfully"})
socket

{:transport_error, reason} ->
put_flash(socket, :error, reason)
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ defmodule LivebookWeb.SessionLive.PersistenceComponent do
socket =
socket
|> assign(assigns)
|> assign_new(:hub, fn -> nil end)
|> assign_new(:attrs, fn -> attrs end)
|> assign_new(:new_attrs, fn -> attrs end)
|> assign_new(:draft_file, fn ->
Expand Down
Loading