Current section
15 Versions
Jump to
Current section
15 Versions
Compare versions
9
files changed
+491
additions
-181
deletions
| @@ -5,6 +5,12 @@ | |
| 5 5 | {<<"elixir">>,<<"~> 1.11">>}. |
| 6 6 | {<<"files">>, |
| 7 7 | [<<"lib">>,<<"lib/secret_config">>,<<"lib/secret_config/cache">>, |
| 8 | + <<"lib/secret_config/cache/util.ex">>, |
| 9 | + <<"lib/secret_config/cache/string_interpolator.ex">>, |
| 10 | + <<"lib/secret_config/cache/config">>, |
| 11 | + <<"lib/secret_config/cache/config/local.ex">>, |
| 12 | + <<"lib/secret_config/cache/config/ssm.ex">>, |
| 13 | + <<"lib/secret_config/cache/config/loader.ex">>, |
| 8 14 | <<"lib/secret_config/cache/server.ex">>, |
| 9 15 | <<"lib/secret_config/application.ex">>,<<"lib/secret_config.ex">>, |
| 10 16 | <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>]}. |
| @@ -47,4 +53,4 @@ | |
| 47 53 | {<<"optional">>,false}, |
| 48 54 | {<<"repository">>,<<"hexpm">>}, |
| 49 55 | {<<"requirement">>,<<"~> 4.0">>}]]}. |
| 50 | - {<<"version">>,<<"0.14.0">>}. |
| 56 | + {<<"version">>,<<"1.0.0">>}. |
| @@ -9,7 +9,7 @@ defmodule SecretConfig do | |
| 9 9 | Sets the env explicitly as this configuration item may not be able to be set |
| 10 10 | inside a releases.exs or runtime.exs if you perform ensure_all_started(:secret_config) |
| 11 11 | """ |
| 12 | - @spec set_env(env :: binary) :: none() |
| 12 | + @spec set_env(env :: binary) :: :ok |
| 13 13 | def set_env(env) do |
| 14 14 | GenServer.cast(SecretConfig.Cache.Server, {:set_env, env}) |
| 15 15 | end |
| @@ -17,7 +17,7 @@ defmodule SecretConfig do | |
| 17 17 | @doc """ |
| 18 18 | Gets parameter from GenServer (returns default value if present) |
| 19 19 | """ |
| 20 | - @spec fetch(key :: binary, default :: binary | nil) :: ExAws.Operation.JSON.t() |
| 20 | + @spec fetch(key :: binary, default :: binary | nil) :: binary | nil |
| 21 21 | def fetch(key, default) do |
| 22 22 | GenServer.call(SecretConfig.Cache.Server, {:fetch, key, default}) |
| 23 23 | end |
| @@ -25,18 +25,21 @@ defmodule SecretConfig do | |
| 25 25 | @doc """ |
| 26 26 | Gets parameter from GenServer (raise error if the value is not present) |
| 27 27 | """ |
| 28 | - @spec fetch!(key :: binary) :: ExAws.Operation.JSON.t() |
| 28 | + @spec fetch!(key :: String.t()) :: String.t() |
| 29 29 | def fetch!(key) do |
| 30 | - case GenServer.call(SecretConfig.Cache.Server, {:fetch, key, :not_exist}) do |
| 31 | - :not_exist -> raise "SecretConfig key does not exist: #{inspect(key)}" |
| 32 | - val -> val |
| 30 | + case GenServer.call(SecretConfig.Cache.Server, {:fetch!, key, :not_exist}) do |
| 31 | + {:not_exist, full_key} -> |
| 32 | + raise "SecretConfig key does not exist: #{inspect(full_key)}" |
| 33 | + |
| 34 | + value -> |
| 35 | + value |
| 33 36 | end |
| 34 37 | end |
| 35 38 | |
| 36 39 | @doc """ |
| 37 40 | Checks for parameter to be present |
| 38 41 | """ |
| 39 | - @spec key?(key :: binary) :: ExAws.Operation.JSON.t() |
| 42 | + @spec key?(key :: binary) :: boolean() |
| 40 43 | def key?(key) do |
| 41 44 | GenServer.call(SecretConfig.Cache.Server, {:key?, key}) |
| 42 45 | end |
| @@ -44,7 +47,7 @@ defmodule SecretConfig do | |
| 44 47 | @doc """ |
| 45 48 | Deletes parameter from the AWS Parameter Store, then it triggers a refresh of the GenServer state |
| 46 49 | """ |
| 47 | - @spec delete(key :: binary) :: ExAws.Operation.JSON.t() |
| 50 | + @spec delete(key :: binary) :: {:deleted, binary} | {:not_exist, binary} |
| 48 51 | def delete(key) do |
| 49 52 | GenServer.call(SecretConfig.Cache.Server, {:delete, key}) |
| 50 53 | end |
| @@ -53,7 +56,7 @@ defmodule SecretConfig do | |
| 53 56 | Adds parameter to the AWS Parameter Store, then it triggers a refresh of the GenServer state |
| 54 57 | """ |
| 55 58 | |
| 56 | - @spec push(key :: binary, value :: binary) :: ExAws.Operation.JSON.t() |
| 59 | + @spec push(key :: binary, value :: binary) :: {:added, binary} | {:error, binary} |
| 57 60 | def push(key, value) do |
| 58 61 | GenServer.call(SecretConfig.Cache.Server, {:push, key, value}) |
| 59 62 | end |
| @@ -61,7 +64,7 @@ defmodule SecretConfig do | |
| 61 64 | @doc """ |
| 62 65 | Triggers a refresh of the GenServer state by pulling the latest from the AWS Parameter Store |
| 63 66 | """ |
| 64 | - @spec refresh() :: none() |
| 67 | + @spec refresh() :: :ok |
| 65 68 | def refresh() do |
| 66 69 | GenServer.cast(SecretConfig.Cache.Server, {:refresh}) |
| 67 70 | end |
| @@ -0,0 +1,56 @@ | |
| 1 | + defmodule Config.Loader do |
| 2 | + @moduledoc """ |
| 3 | + Handles loading of configuration based on the environment setting. |
| 4 | + |
| 5 | + It supports loading configuration from a YAML string, a YAML file, or an SSM parameter store, |
| 6 | + depending on the application's environment settings. |
| 7 | + """ |
| 8 | + |
| 9 | + @doc """ |
| 10 | + Initializes the configuration state based on the provided environment. |
| 11 | + |
| 12 | + ## Parameters |
| 13 | + - env: The environment name as a string or `nil`. |
| 14 | + |
| 15 | + ## Returns |
| 16 | + - The loaded configuration as a map, or `nil` if the environment is not set. |
| 17 | + """ |
| 18 | + @spec init_state(String.t() | nil) :: {:local, String.t(), map()} | nil |
| 19 | + def init_state(env) do |
| 20 | + case env do |
| 21 | + nil -> nil |
| 22 | + _ -> load_config(env) |
| 23 | + end |
| 24 | + end |
| 25 | + |
| 26 | + @doc """ |
| 27 | + Loads configuration based on the environment setting. |
| 28 | + |
| 29 | + Attempts to load configuration from a YAML string, then from a file, and finally |
| 30 | + falls back to loading from the SSM parameter store if the previous methods are not configured. |
| 31 | + |
| 32 | + ## Parameters |
| 33 | + - env: The environment name as a string. |
| 34 | + |
| 35 | + ## Returns |
| 36 | + - The loaded configuration as a map, wrapped in a tuple with `:local` and the environment, |
| 37 | + or directly from the SSM parameter store. |
| 38 | + """ |
| 39 | + @spec load_config(String.t()) :: {:local, String.t(), map()} | any() |
| 40 | + def load_config(env) do |
| 41 | + cond do |
| 42 | + yaml_str = Application.get_env(:secret_config, :yaml_str) -> |
| 43 | + Config.Local.parse_yaml(yaml_str, env) |
| 44 | + |
| 45 | + file = Application.get_env(:secret_config, :file) -> |
| 46 | + yaml_str = File.read!(file) |
| 47 | + local_map = Util.yaml_str_to_map(yaml_str) |
| 48 | + |> Util.apply_local_imports |
| 49 | + |> StringInterpolator.interpolate_env() |
| 50 | + {:local, env, local_map} |
| 51 | + |
| 52 | + true -> |
| 53 | + Config.SSM.load_ssm_config(env) |
| 54 | + end |
| 55 | + end |
| 56 | + end |
| @@ -0,0 +1,47 @@ | |
| 1 | + defmodule Config.Local do |
| 2 | + @moduledoc """ |
| 3 | + Handles parsing of local YAML configurations, providing functionality to load configurations |
| 4 | + from YAML strings or files, applying environment-specific interpolations and imports. |
| 5 | + """ |
| 6 | + |
| 7 | + @doc """ |
| 8 | + Parses a YAML string into a configuration state, applying environment variable interpolation. |
| 9 | + |
| 10 | + ## Parameters |
| 11 | + - yaml_str: The YAML string to be parsed. |
| 12 | + - env: The environment context used for interpolation. |
| 13 | + |
| 14 | + ## Returns |
| 15 | + - A tuple containing `:local`, the environment, and the parsed state as a map. |
| 16 | + """ |
| 17 | + @spec parse_yaml(String.t(), String.t()) :: {:local, String.t(), map()} |
| 18 | + def parse_yaml(yaml_str, env) do |
| 19 | + state = yaml_str |
| 20 | + |> Util.yaml_str_to_map() |
| 21 | + |> StringInterpolator.interpolate_env() |
| 22 | + |
| 23 | + {:local, env, state} |
| 24 | + end |
| 25 | + |
| 26 | + @doc """ |
| 27 | + Reads and parses a YAML file into a configuration state, applying local imports |
| 28 | + and environment variable interpolation. |
| 29 | + |
| 30 | + ## Parameters |
| 31 | + - file: The path to the YAML file to be read and parsed. |
| 32 | + - env: The environment context used for interpolation and imports. |
| 33 | + |
| 34 | + ## Returns |
| 35 | + - A tuple containing `:local`, the environment, and the parsed state as a map. |
| 36 | + """ |
| 37 | + @spec parse_file(String.t(), String.t()) :: {:local, String.t(), map()} |
| 38 | + def parse_file(file, env) do |
| 39 | + state = file |
| 40 | + |> File.read!() |
| 41 | + |> Util.yaml_str_to_map() |
| 42 | + |> Util.apply_local_imports() |
| 43 | + |> StringInterpolator.interpolate_env() |
| 44 | + |
| 45 | + {:local, env, state} |
| 46 | + end |
| 47 | + end |
| \ No newline at end of file |
| @@ -0,0 +1,27 @@ | |
| 1 | + defmodule Config.SSM do |
| 2 | + @moduledoc """ |
| 3 | + Provides functionality to load configuration settings from AWS SSM Parameter Store |
| 4 | + based on the provided environment. |
| 5 | + """ |
| 6 | + |
| 7 | + @doc """ |
| 8 | + Loads configuration from the AWS SSM Parameter Store for the specified environment. |
| 9 | + |
| 10 | + Utilizes utility functions to fetch parameters, apply imports, and interpolate |
| 11 | + environment variables within the parameters. |
| 12 | + |
| 13 | + ## Parameters |
| 14 | + - env: The environment name as a string which scopes the SSM parameter lookup. |
| 15 | + |
| 16 | + ## Returns |
| 17 | + - A tuple with `:ssm`, the environment name, and the configuration map. |
| 18 | + """ |
| 19 | + @spec load_ssm_config(String.t()) :: {:ssm, String.t(), map()} |
| 20 | + def load_ssm_config(env) do |
| 21 | + ssm_map = Util.ssm_parameter_map(%{}, nil, true, env) |
| 22 | + |> Util.apply_imports(env) |
| 23 | + |> StringInterpolator.interpolate_env() |
| 24 | + |
| 25 | + {:ssm, env, ssm_map} |
| 26 | + end |
| 27 | + end |
Loading more files…