Packages

An Elixir framework to build your own in-house PaaS (Platform as a Service).

Current section

Files

Jump to
antikythera lib util env.ex
Raw

lib/util/env.ex

# Copyright(c) 2015-2019 ACCESS CO., LTD. All rights reserved.
use Croma
defmodule Antikythera.Env do
@moduledoc """
Module to provide helpers to access environment variables defined by antikythera.
## Environments and deployments
Antikythera instances and gears may run in the following two modes:
- As a mix project, when invoked by running `iex` or `mix` command-line tool.
- As an OTP release, which is generated by e.g. `antikythera_core.generate_release` task.
In general there are multiple deployments per antikythera instance.
To distingish the target deployment from code, antikythera defines the following environment variables:
- At compile time (for metaprogramming):
`ANTIKYTHERA_COMPILE_ENV` must be appropriately set; the value can be retrieved by `compile_env/0`.
- At runtime:
`ANTIKYTHERA_RUNTIME_ENV` must be appropriately set; the value can be retrieved by `runtime_env/0`.
It is the responsibility of antikythera instance administrators to correctly set these environment variables
when compiling/running antikythera and gears.
Possible values returned by `compile_env/0` and `runtime_env/0` are:
- names of deployments given by `:deployments` application config
- `:local` (running an OTP release at local machine for testing purpose)
- `:undefined`
As an example, if you set `:dev` and `:prod` in `:deployments`, then you get:
| | Mix.env() at compile-time | Mix.env() at runtime | compile_env(), runtime_env() |
|---------------------------+----------------------------------------+-------------------------+------------------------------|
| $ iex -S mix | :dev (toplevel), :prod (dependencies) | :dev | :undefined |
| $ mix test | :test (toplevel), :prod (dependencies) | :test | :undefined |
| $ mix antikythera_local.* | :prod | (:mix is not available) | :local |
| :dev deployment | :prod | (:mix is not available) | :dev |
| :prod deployment | :prod | (:mix is not available) | :prod |
You can use these values to distinguish the current context from your code.
"""
deployment_envs = Application.fetch_env!(:antikythera, :deployments) |> Keyword.keys()
use Croma.SubtypeOfAtom, values: (deployment_envs ++ [:local, :undefined])
alias Antikythera.{GearName, GearNameStr, Url}
alias AntikytheraCore.Handler.CowboyRouting, as: Routing
defmodule Mapping do
Enum.each(deployment_envs, fn env ->
env_str = Atom.to_string(env)
def env_var_to_atom(unquote(env_str)), do: unquote(env)
end)
def env_var_to_atom("local"), do: :local
def env_var_to_atom(_ ), do: :undefined
Enum.each(deployment_envs, fn env ->
def cloud?(unquote(env)), do: true
end)
def cloud?(_), do: false
end
defun no_listen?() :: boolean do
case System.get_env() do
%{"NO_LISTEN" => "true"} -> true
%{"TEST_MODE" => "blackbox_" <> _} -> true
_otherwise -> false
end
end
defun runtime_env() :: t , do: System.get_env("ANTIKYTHERA_RUNTIME_ENV") |> Mapping.env_var_to_atom()
defun running_with_release?() :: boolean, do: runtime_env() != :undefined
defun running_in_cloud?() :: boolean, do: Mapping.cloud?(runtime_env())
@compile_env System.get_env("ANTIKYTHERA_COMPILE_ENV") |> Mapping.env_var_to_atom()
@compiling_for_release? @compile_env != :undefined
@compiling_for_cloud? Mapping.cloud?(@compile_env)
defun compile_env() :: t , do: @compile_env
defun compiling_for_release?() :: boolean, do: @compiling_for_release?
defun compiling_for_cloud?() :: boolean, do: @compiling_for_cloud?
@antikythera_instance_name Application.fetch_env!(:antikythera, :antikythera_instance_name)
defun antikythera_instance_name() :: atom, do: @antikythera_instance_name
@gear_action_timeout_default 10_000
@gear_action_timeout String.to_integer(System.get_env("GEAR_ACTION_TIMEOUT") || "#{@gear_action_timeout_default}")
@doc """
Timeout (in milli-seconds) for gear actions.
This can be configurable by specifying `"GEAR_ACTION_TIMEOUT"` environment variable when compiling antikythera.
Defaults to `#{@gear_action_timeout_default}`.
"""
defun gear_action_timeout() :: pos_integer, do: @gear_action_timeout
@default_port 8080
@default_port_during_test 8081
# To see which port number to use, we have to get the current mix environment at runtime,
# since `Mix.env()` always returns `:prod` during compilation of antikythera within a gear project.
# However, when running with an OTP release, `Mix.env/0` is not available at runtime
# (as `:mix` is not included in antikythera's runtime dependencies).
# Therefore we need both compile-time- and runtime-branching.
if @compiling_for_release? do
defp default_port_at_runtime(), do: @default_port
else
defp default_port_at_runtime(), do: (if Mix.env() == :test, do: @default_port_during_test, else: @default_port)
end
@doc """
TCP port to listen to for incoming web requests.
The port can be specified by `"PORT"` runtime environment variable.
Defaults to `#{@default_port_during_test}` during `mix test`, and `#{@default_port}` otherwise
(thus one can run both `iex -S mix` and `mix test` at the same time).
"""
defun port_to_listen() :: non_neg_integer do
case System.get_env("PORT") do
nil -> default_port_at_runtime()
port_str -> String.to_integer(port_str)
end
end
defun default_base_url(gear_name :: v[GearName.t | GearNameStr.t], env :: v[t] \\ @compile_env) :: Url.t do
if Mapping.cloud?(env) do
"https://" <> Routing.default_domain(gear_name, env)
else
"http://" <> Routing.default_domain(gear_name, env) <> ":#{port_to_listen()}"
end
end
defun asset_base_url(gear_name :: v[GearName.t | GearNameStr.t]) :: Url.t do
case Application.fetch_env!(:antikythera, :asset_cdn_endpoint) do
nil -> default_base_url(gear_name)
base_url -> base_url
end
end
end