Support setting node and distribution using environment vars (#1672)

This commit is contained in:
Zach Allaun 2023-02-01 12:22:49 -08:00 committed by GitHub
parent 25b4043dc7
commit 8f92661918
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 9 deletions

View file

@ -164,6 +164,9 @@ The following environment variables configure Livebook:
* LIVEBOOK_APP_SERVICE_URL - sets the application url to manage this * LIVEBOOK_APP_SERVICE_URL - sets the application url to manage this
Livebook instance within the cloud provider platform. Livebook instance within the cloud provider platform.
* LIVEBOOK_BASE_URL_PATH - sets the base url path the web application is served on.
Useful when deploying behind a reverse proxy.
* LIVEBOOK_COOKIE - sets the cookie for running Livebook in a cluster. * LIVEBOOK_COOKIE - sets the cookie for running Livebook in a cluster.
Defaults to a random string that is generated on boot. Defaults to a random string that is generated on boot.
@ -175,6 +178,10 @@ The following environment variables configure Livebook:
"standalone" (Elixir standalone), "attached:NODE:COOKIE" (Attached node) "standalone" (Elixir standalone), "attached:NODE:COOKIE" (Attached node)
or "embedded" (Embedded). Defaults to "standalone". or "embedded" (Embedded). Defaults to "standalone".
* LIVEBOOK_DISTRIBUTION - sets the node distribution for running Livebook in a
cluster. Must be "name" (long names) or "sname" (short names). Note that this
sets RELEASE_DISTRIBUTION if present when creating a release. Defaults to "sname".
* LIVEBOOK_FORCE_SSL_HOST - sets a host to redirect to if the request is not over HTTP. * LIVEBOOK_FORCE_SSL_HOST - sets a host to redirect to if the request is not over HTTP.
Note it does not apply when accessing Livebook via localhost. Defaults to nil. Note it does not apply when accessing Livebook via localhost. Defaults to nil.
@ -192,8 +199,8 @@ The following environment variables configure Livebook:
* LIVEBOOK_IP - sets the ip address to start the web application on. * LIVEBOOK_IP - sets the ip address to start the web application on.
Must be a valid IPv4 or IPv6 address. Must be a valid IPv4 or IPv6 address.
* LIVEBOOK_BASE_URL_PATH - sets the base url path the web application is served on. * LIVEBOOK_NODE - sets the node name for running Livebook in a cluster. Note that
Useful when deploying behind a reverse proxy. this sets RELEASE_NODE if present when creating a release.
* LIVEBOOK_PASSWORD - sets a password that must be used to access Livebook. * LIVEBOOK_PASSWORD - sets a password that must be used to access Livebook.
Must be at least 12 characters. Defaults to token authentication. Must be at least 12 characters. Defaults to token authentication.
@ -224,11 +231,6 @@ The following environment variables configure Livebook:
<!-- Environment variables --> <!-- Environment variables -->
If running Livebook as a Docker image or an Elixir release, [the environment
variables used by Elixir releases are also available](
https://hexdocs.pm/mix/Mix.Tasks.Release.html#module-environment-variables).
The notables ones are `RELEASE_NODE` and `RELEASE_DISTRIBUTION`.
If running Livebook via the command line, run `livebook server --help` to see If running Livebook via the command line, run `livebook server --help` to see
all CLI-specific options. all CLI-specific options.

View file

@ -160,6 +160,10 @@ defmodule Livebook do
Livebook.Config.cookie!("RELEASE_COOKIE") || Livebook.Config.cookie!("RELEASE_COOKIE") ||
Livebook.Utils.random_cookie() Livebook.Utils.random_cookie()
if node = Livebook.Config.node!("LIVEBOOK_NODE", "LIVEBOOK_DISTRIBUTION") do
config :livebook, :node, node
end
if app_service_name = Livebook.Config.app_service_name!("LIVEBOOK_APP_SERVICE_NAME") do if app_service_name = Livebook.Config.app_service_name!("LIVEBOOK_APP_SERVICE_NAME") do
config :livebook, :app_service_name, app_service_name config :livebook, :app_service_name, app_service_name

View file

@ -291,6 +291,25 @@ defmodule Livebook.Config do
end end
end end
@doc """
Parses node and distribution type from env.
"""
def node!(node_env, distribution_env) do
case {System.get_env(node_env), System.get_env(distribution_env, "sname")} do
{nil, _} ->
nil
{name, "name"} ->
{:longnames, String.to_atom(name)}
{sname, "sname"} ->
{:shortnames, String.to_atom(sname)}
{_, other} ->
abort!(~s(#{distribution_env} must be one of "name" or "sname", got "#{other}"))
end
end
@doc """ @doc """
Parses and validates the password from env. Parses and validates the password from env.
""" """

View file

@ -131,7 +131,7 @@ defmodule Livebook.MixProject do
defp releases do defp releases do
[ [
livebook: [ livebook: [
include_executables_for: [:unix], include_executables_for: [:unix, :windows],
include_erts: false, include_erts: false,
rel_templates_path: "rel/server", rel_templates_path: "rel/server",
steps: [:assemble, &remove_cookie/1] steps: [:assemble, &remove_cookie/1]

View file

@ -1,4 +1,6 @@
if defined LIVEBOOK_NODE set RELEASE_NODE="!LIVEBOOK_NODE!"
if not defined RELEASE_NODE set RELEASE_NODE=livebook_server if not defined RELEASE_NODE set RELEASE_NODE=livebook_server
if defined LIVEBOOK_DISTRIBUTION set RELEASE_DISTRIBUTION="!LIVEBOOK_DISTRIBUTION!"
set RELEASE_MODE=interactive set RELEASE_MODE=interactive
set cookie_path="!RELEASE_ROOT!\releases\COOKIE" set cookie_path="!RELEASE_ROOT!\releases\COOKIE"

View file

@ -1,4 +1,5 @@
export RELEASE_NODE="${RELEASE_NODE:-livebook_server}" export RELEASE_NODE=${LIVEBOOK_NODE:-${RELEASE_NODE:-livebook_server}}
export RELEASE_DISTRIBUTION=${LIVEBOOK_DISTRIBUTION:-${RELEASE_DISTRIBUTION:-sname}}
export RELEASE_MODE=interactive export RELEASE_MODE=interactive
cookie_path="${RELEASE_ROOT}/releases/COOKIE" cookie_path="${RELEASE_ROOT}/releases/COOKIE"

View file

@ -0,0 +1,48 @@
defmodule Livebook.ConfigTest do
use ExUnit.Case, async: true
alias Livebook.Config
describe "node!/1" do
test "parses longnames" do
with_env([TEST_LIVEBOOK_NODE: "test@::1", TEST_LIVEBOOK_DISTRIBUTION: "name"], fn ->
assert Config.node!("TEST_LIVEBOOK_NODE", "TEST_LIVEBOOK_DISTRIBUTION") ==
{:longnames, :"test@::1"}
end)
end
test "parses shortnames" do
with_env([TEST_LIVEBOOK_NODE: "test", TEST_LIVEBOOK_DISTRIBUTION: "sname"], fn ->
assert Config.node!("TEST_LIVEBOOK_NODE", "TEST_LIVEBOOK_DISTRIBUTION") ==
{:shortnames, :test}
end)
end
test "parses shortnames by default" do
with_env([TEST_LIVEBOOK_NODE: "test", TEST_LIVEBOOK_DISTRIBUTION: nil], fn ->
assert Config.node!("TEST_LIVEBOOK_NODE", "TEST_LIVEBOOK_DISTRIBUTION") ==
{:shortnames, :test}
end)
end
test "returns nil if node is not set" do
with_env([TEST_LIVEBOOK_NODE: nil, TEST_LIVEBOOK_DISTRIBUTION: "name"], fn ->
assert Config.node!("TEST_LIVEBOOK_NODE", "TEST_LIVEBOOK_DISTRIBUTION") == nil
end)
end
end
defp with_env(env_vars, fun) do
existing =
Enum.map(env_vars, fn {env, _value} ->
{env, env |> to_string() |> System.get_env()}
end)
try do
System.put_env(env_vars)
fun.()
after
System.put_env(existing)
end
end
end