Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
2 changes: 2 additions & 0 deletions lib/livebook/apps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ defmodule Livebook.Apps do
Livebook.Hubs.TeamClient.user_app_access?(id, user.groups, slug)
end

def authorized?(%{permanent: false}, _user), do: true
Comment thread
aleDsz marked this conversation as resolved.
Outdated
Comment thread
jonatanklosko marked this conversation as resolved.
Outdated

@doc """
Updates the given app info across the cluster.
"""
Expand Down
34 changes: 21 additions & 13 deletions lib/livebook/hubs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,28 @@ defmodule Livebook.Hubs do
if get_default_hub().id == hub_id, do: unset_default_hub(), else: :ok
end

defp disconnect_hub(hub) do
# We use a task supervisor because the hub connection itself
# calls delete_hub (which calls this function), otherwise we deadlock.
Task.Supervisor.start_child(Livebook.TaskSupervisor, fn ->
# Since other processes may have been communicating
# with the hub, we don't want to terminate abruptly and
# make them crash, so we give it some time to shut down.
#
# The default backoff is 5.5s, so we round it down to 5s.
Process.sleep(30_000)
:ok = Provider.disconnect(hub)
end)
if Mix.env() == :test do
# In test environment, disconnect synchronously to avoid race conditions
# during test cleanup where other processes might still be accessing hubs
defp disconnect_hub(hub) do
Provider.disconnect(hub)
end
Comment thread
aleDsz marked this conversation as resolved.
Outdated
else
defp disconnect_hub(hub) do
# We use a task supervisor because the hub connection itself
# calls delete_hub (which calls this function), otherwise we deadlock.
Task.Supervisor.start_child(Livebook.TaskSupervisor, fn ->
# Since other processes may have been communicating
# with the hub, we don't want to terminate abruptly and
# make them crash, so we give it some time to shut down.
#
# The default backoff is 5.5s, so we round it down to 5s.
Process.sleep(30_000)
:ok = Provider.disconnect(hub)
end)

:ok
:ok
end
end

defp to_struct(%{id: "personal-" <> _} = fields) do
Expand Down
5 changes: 2 additions & 3 deletions lib/livebook/hubs/team.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,13 @@ defmodule Livebook.Hubs.Team do
end

defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
alias Livebook.Hubs.Team
alias Livebook.Hubs.TeamClient
alias Livebook.Hubs.{Team, TeamClient}
alias Livebook.Teams.Requests
alias Livebook.FileSystem
alias Livebook.Secrets.Secret

@teams_key_prefix Livebook.Teams.Org.teams_key_prefix()
@public_key_prefix Livebook.Hubs.Team.public_key_prefix()
@public_key_prefix Team.public_key_prefix()

def load(team, fields) do
{offline?, fields} = Map.pop(fields, :offline?, false)
Expand Down
22 changes: 21 additions & 1 deletion lib/livebook/hubs/team_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec get_secrets(String.t()) :: list(Secrets.Secret.t())
def get_secrets(id) do
GenServer.call(registry_name(id), :get_secrets)
catch
:exit, _ -> []
end

@doc """
Expand All @@ -71,6 +73,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec get_file_systems(String.t()) :: list(FileSystem.t())
def get_file_systems(id) do
GenServer.call(registry_name(id), :get_file_systems)
catch
:exit, _ -> []
end

@doc """
Expand All @@ -89,6 +93,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec get_deployment_groups(String.t()) :: list(Teams.DeploymentGroup.t())
def get_deployment_groups(id) do
GenServer.call(registry_name(id), :get_deployment_groups)
catch
:exit, _ -> []
end

@doc """
Expand All @@ -97,6 +103,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec get_app_deployments(String.t()) :: list(Teams.AppDeployment.t())
def get_app_deployments(id) do
GenServer.call(registry_name(id), :get_app_deployments)
catch
:exit, _ -> []
Comment thread
aleDsz marked this conversation as resolved.
Outdated
end

@doc """
Expand All @@ -106,6 +114,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec get_agent_app_deployments(String.t()) :: list(Teams.AppDeployment.t())
def get_agent_app_deployments(id) do
GenServer.call(registry_name(id), :get_agent_app_deployments)
catch
:exit, _ -> []
end

@doc """
Expand All @@ -124,6 +134,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec get_agents(String.t()) :: list(Teams.Agent.t())
def get_agents(id) do
GenServer.call(registry_name(id), :get_agents)
catch
:exit, _ -> []
end

@doc """
Expand All @@ -132,14 +144,18 @@ defmodule Livebook.Hubs.TeamClient do
@spec identity_enabled?(String.t()) :: boolean()
def identity_enabled?(id) do
GenServer.call(registry_name(id), :identity_enabled?)
catch
:exit, _ -> false
end
Comment thread
aleDsz marked this conversation as resolved.

@doc """
Returns a list of cached environment variables.
"""
@spec get_environment_variables(String.t()) :: list(Teams.Agent.t())
@spec get_environment_variables(String.t()) :: list(Teams.EnvironmentVariable.t())
def get_environment_variables(id) do
GenServer.call(registry_name(id), :get_environment_variables)
catch
:exit, _ -> []
end

@doc """
Expand All @@ -148,6 +164,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec user_full_access?(String.t(), list(map())) :: boolean()
def user_full_access?(id, groups) do
GenServer.call(registry_name(id), {:check_full_access, groups})
catch
:exit, _ -> false
Comment thread
aleDsz marked this conversation as resolved.
Outdated
end

@doc """
Expand All @@ -156,6 +174,8 @@ defmodule Livebook.Hubs.TeamClient do
@spec user_app_access?(String.t(), list(map()), String.t()) :: boolean()
def user_app_access?(id, groups, slug) do
GenServer.call(registry_name(id), {:check_app_access, groups, slug})
catch
:exit, _ -> false
Comment thread
aleDsz marked this conversation as resolved.
Outdated
end

@doc """
Expand Down
16 changes: 4 additions & 12 deletions lib/livebook/teams.ex
Original file line number Diff line number Diff line change
Expand Up @@ -197,25 +197,17 @@ defmodule Livebook.Teams do
end

@doc """
Creates a new app deployment.
Deploys the given app deployment.
"""
@spec deploy_app(Team.t(), Teams.AppDeployment.t()) ::
:ok
| {:error, Ecto.Changeset.t()}
| {:transport_error, String.t()}
def deploy_app(%Team{} = team, %Teams.AppDeployment{} = app_deployment) do
case Requests.deploy_app(team, app_deployment) do
{:ok, %{"id" => _id}} ->
:ok

{:error, %{"errors" => %{"detail" => error}}} ->
{:error, add_external_errors(app_deployment, %{"file" => [error]})}

{:error, %{"errors" => errors}} ->
{:error, add_external_errors(app_deployment, errors)}

any ->
any
{:ok, %{"id" => _id}} -> :ok
{:error, %{"errors" => errors}} -> {:error, add_external_errors(app_deployment, errors)}
any -> any
end
end

Expand Down
31 changes: 20 additions & 11 deletions lib/livebook/teams/app_deployment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,27 @@ defmodule Livebook.Teams.AppDeployment do
@doc """
Creates a new app deployment from notebook.
"""
@spec new(Livebook.Notebook.t(), Livebook.FileSystem.File.t()) ::
@spec new(Livebook.Notebook.t() | String.t(), Livebook.FileSystem.File.t()) ::
{:ok, t()} | {:warning, list(String.t())} | {:error, FileSystem.error()}
def new(notebook, files_dir) do
with {:ok, source} <- fetch_notebook_source(notebook),
{:ok, files} <- build_and_check_file_entries(notebook, source, files_dir),
def new(%Livebook.Notebook{} = notebook, files_dir) do
case Livebook.LiveMarkdown.notebook_to_livemd(notebook) do
{source, []} -> new(notebook, source, files_dir)
{_, warnings} -> {:warning, warnings}
end
end

@stamp_error "notebook does not have a stamp, disabling access to secrets and remote files"

def new(source, files_dir) when is_binary(source) do
case Livebook.LiveMarkdown.notebook_from_livemd(source) do
{notebook, %{warnings: [], stamp_verified?: true}} -> new(notebook, source, files_dir)
{_, %{warnings: [], stamp_verified?: false}} -> {:warning, [@stamp_error]}
{_, %{warnings: warnings}} -> {:warning, warnings}
end
end

def new(%Livebook.Notebook{} = notebook, source, files_dir) do
with {:ok, files} <- build_and_check_file_entries(notebook, source, files_dir),
{:ok, {_, zip_content}} <- :zip.create(~c"app_deployment.zip", files, [:memory]),
:ok <- validate_size(zip_content) do
md5_hash = :crypto.hash(:md5, zip_content)
Expand All @@ -66,13 +82,6 @@ defmodule Livebook.Teams.AppDeployment do
end
end

defp fetch_notebook_source(notebook) do
case Livebook.LiveMarkdown.notebook_to_livemd(notebook) do
{source, []} -> {:ok, source}
{_, warnings} -> {:warning, warnings}
end
end

defp build_and_check_file_entries(notebook, source, files_dir) do
notebook.file_entries
|> Enum.filter(&(&1.type == :attachment))
Expand Down
12 changes: 8 additions & 4 deletions lib/livebook/teams/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ defmodule Livebook.Teams.Connection do
:keep_state_and_data
end

def handle_event(:info, message, @no_state, data) when elem(message, 0) in @expected_messages do
handle_websocket_message(message, data)
end

def handle_event(:info, message, @no_state, %{http_conn: nil})
when elem(message, 0) in @expected_messages do
:keep_state_and_data
end

def handle_event(:info, message, @no_state, data) when elem(message, 0) in @expected_messages do
handle_websocket_message(message, data)
end

def handle_event(:info, _message, @no_state, _data) do
:keep_state_and_data
end
Expand All @@ -116,6 +116,10 @@ defmodule Livebook.Teams.Connection do

# Private

defp handle_websocket_message(_message, %{http_conn: nil} = data) do
{:keep_state, data, {:next_event, :internal, :connect}}
end

defp handle_websocket_message(message, data) do
case WebSocket.receive(data.http_conn, data.ref, data.websocket, message) do
{:ok, conn, websocket, binaries} ->
Expand Down
Loading