diff --git a/.credo.exs b/.credo.exs index 7fc2b75..b9c490e 100644 --- a/.credo.exs +++ b/.credo.exs @@ -82,7 +82,8 @@ # You can customize the priority of any check # Priority values are: `low, normal, high, higher` # - {Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, + {Credo.Check.Design.AliasUsage, + [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, {Credo.Check.Design.TagFIXME, []}, # You can also customize the exit_status of each check. # If you don't want TODO comments to cause `mix credo` to fail, just diff --git a/.formatter.exs b/.formatter.exs index d47daf4..e892486 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,6 @@ # Used by "mix format" [ plugins: [Styler], - inputs: ["{mix,.formatter,.iex,.credo}.exs", "{config,lib,test,bench,scripts}/**/*.{ex,exs,eex}"] + inputs: ["{mix,.formatter,.iex,.credo}.exs", "{config,lib,test,bench,scripts}/**/*.{ex,exs,eex}"], + line_length: 100 ] diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index 280add5..d8e12fb 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -23,8 +23,8 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - otp: ["26.2"] - elixir: ["1.18.1", "1.17.3", "1.16.3"] + otp: ["28.3", "27.3"] + elixir: ["1.19.x", "1.18.x"] steps: - name: Git clone the repository uses: actions/checkout@v4 diff --git a/.tool-versions b/.tool-versions index 6cb11e6..9d3c199 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -elixir ref:v1.18.1 -erlang 27.2 +elixir 1.19.4-otp-28 +erlang 28.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e901af..373fb78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ This changelog follows the same style that I have seen LiveView, Phoenix, and Elixir use in the past. I'll try to make sure that I maintain it - probably should create some sort of automated process for it... who knows. For now - there's only one release so this should be good enough! +## 1.1.0 + +### Enhancements + +- Add `:release_dir` configuration option to customize the deployment directory for Elixir releases. This allows matching the directory path expected by your release bundle. Defaults to `/srv//release` for backward compatibility. + +- Add ARM architecture support for AWS CLI installation in the bootstrap script. The startup script now automatically detects the instance architecture (x86_64 or aarch64/arm64) and downloads the appropriate AWS CLI version, enabling support for Graviton-based EC2 instances. + +- Add `:instance_initiated_shutdown_behavior` configuration option to control EC2 instance shutdown behavior. Valid values are `"stop"` or `"terminate"`. Defaults to `"terminate"` for backward compatibility. When set to `"stop"`, instances are stopped but not terminated on shutdown, allowing access to logs stored in EBS volumes for debugging purposes. + ## 1.0.0 This is the first official release! So everything is empty. Read the docs to get started - have fun! diff --git a/lib/flame_ec2.ex b/lib/flame_ec2.ex index 809fd3c..9cff723 100644 --- a/lib/flame_ec2.ex +++ b/lib/flame_ec2.ex @@ -135,6 +135,12 @@ defmodule FlameEC2 do * `:key_name` - The name of the key pair to use for you to be able to connect to the instance. This is not required, however, an instance that was created without a key pair will be inaccessible without another way to log in. + * `:instance_initiated_shutdown_behavior` - The behavior when an instance-initiated shutdown is triggered. + Valid values are `"stop"` or `"terminate"`. Defaults to `"terminate"`. + When set to `"terminate"`, the instance and its EBS storage (including logs) are terminated on shutdown. + When set to `"stop"`, the instance is stopped but not terminated, allowing you to access the logs stored in the EBS volume. + This is useful for debugging issues in production by examining the logs after a runner shuts down. + * `:instance_metadata_url` - The EC2 instance metadata URL. This is used when auto-configuring the pool with the `auto_configure` configuration set to `true`. Defaults to "http://169.254.169.254/latest/meta-data/" (note the trailing slash), which is the internal EC2 metadata URL. This can be adjusted for local testing, but likely does not need to be adjusted outside of this use case. @@ -222,14 +228,17 @@ defmodule FlameEC2 do EC2Api.run_instances!(state) end) - Utils.log(state.config, "#{inspect(__MODULE__)} #{inspect(node())} EC2 instance created in #{req_connect_time}ms") + Utils.log( + state.config, + "#{inspect(__MODULE__)} #{inspect(node())} EC2 instance created in #{req_connect_time}ms" + ) remaining_connect_window = state.config.boot_timeout - req_connect_time case resp do %{"instanceId" => instance_id, "privateIpAddress" => ip} -> new_state = - %BackendState{ + %{ state | runner_instance_id: instance_id, runner_instance_ip: ip @@ -241,12 +250,14 @@ defmodule FlameEC2 do remote_terminator_pid after remaining_connect_window -> - Logger.error("failed to connect to EC2 instance within #{state.config.boot_timeout}ms") + Logger.error( + "failed to connect to EC2 instance within #{state.config.boot_timeout}ms" + ) exit(:timeout) end - new_state = %BackendState{ + new_state = %{ new_state | remote_terminator_pid: remote_terminator_pid, runner_node_name: node(remote_terminator_pid) @@ -261,7 +272,11 @@ defmodule FlameEC2 do @impl true def handle_info(msg, %BackendState{} = state) do - Utils.log(state.config, "Missed message sent to FlameEC2 Process #{self()}: #{inspect(msg)}") + Utils.log( + state.config, + "Missed message sent to FlameEC2 Process #{inspect(self())}: #{inspect(msg)}" + ) + {:noreply, state} end end diff --git a/lib/flame_ec2/config.ex b/lib/flame_ec2/config.ex index 676ac16..54b0440 100644 --- a/lib/flame_ec2/config.ex +++ b/lib/flame_ec2/config.ex @@ -23,6 +23,8 @@ defmodule FlameEC2.Config do :boot_timeout, :app, :s3_bundle_url, + :release_dir, + :instance_initiated_shutdown_behavior, :instance_metadata_url, :instance_metadata_token_url, :ec2_service_endpoint, @@ -47,6 +49,8 @@ defmodule FlameEC2.Config do :app, :s3_bundle_url, :s3_bundle_compressed?, + :release_dir, + :instance_initiated_shutdown_behavior, :local_ip ]} @@ -66,6 +70,8 @@ defmodule FlameEC2.Config do app: nil, s3_bundle_url: nil, s3_bundle_compressed?: false, + release_dir: nil, + instance_initiated_shutdown_behavior: nil, local_ip: nil, instance_metadata_url: nil, instance_metadata_token_url: nil, @@ -78,6 +84,7 @@ defmodule FlameEC2.Config do launch_template_version: "$Default", boot_timeout: 120_000, app: System.get_env("RELEASE_NAME"), + instance_initiated_shutdown_behavior: "terminate", instance_metadata_url: "http://169.254.169.254/latest/meta-data/", instance_metadata_token_url: "http://169.254.169.254/latest/api/token", ec2_service_endpoint: "https://ec2.amazonaws.com/" @@ -164,7 +171,7 @@ defmodule FlameEC2.Config do end defp validate_s3_bundle_url!(%Config{} = config) do - %Config{config | s3_bundle_compressed?: String.ends_with?(config.s3_bundle_url, ".tar.gz")} + %{config | s3_bundle_compressed?: String.ends_with?(config.s3_bundle_url, ".tar.gz")} end defp validate_local_ip!(%Config{local_ip: nil}) do @@ -180,11 +187,15 @@ defmodule FlameEC2.Config do "You must specify either the image_id or the launch_template_id for the FlameEC2 backend" end - defp validate_instance_creation_details!(%Config{image_id: _image_id, launch_template_id: nil} = config) do + defp validate_instance_creation_details!( + %Config{image_id: _image_id, launch_template_id: nil} = config + ) do config end - defp validate_instance_creation_details!(%Config{image_id: nil, launch_template_id: _launch_template_id} = config) do + defp validate_instance_creation_details!( + %Config{image_id: nil, launch_template_id: _launch_template_id} = config + ) do config end diff --git a/lib/flame_ec2/ec2_api.ex b/lib/flame_ec2/ec2_api.ex index 2a24002..5c15c7e 100644 --- a/lib/flame_ec2/ec2_api.ex +++ b/lib/flame_ec2/ec2_api.ex @@ -31,7 +31,6 @@ defmodule FlameEC2.EC2Api do form: params, aws_sigv4: Map.put_new(credentials, :service, "ec2") ] - |> Req.new() |> Req.request() |> raise_or_response!() |> Map.fetch!(:body) @@ -71,7 +70,9 @@ defmodule FlameEC2.EC2Api do end defp params_from_config(%Config{} = config, env) do - systemd_service = Templates.systemd_service(app: config.app) + systemd_service = + Templates.systemd_service(app: config.app, release_dir: config.release_dir) + env = Templates.env(vars: env) start_script = @@ -81,7 +82,8 @@ defmodule FlameEC2.EC2Api do env: env, aws_region: config.aws_region, s3_bundle_url: config.s3_bundle_url, - s3_bundle_compressed?: config.s3_bundle_compressed? + s3_bundle_compressed?: config.s3_bundle_compressed?, + release_dir: config.release_dir ) base_params = %{ @@ -104,7 +106,7 @@ defmodule FlameEC2.EC2Api do "IamInstanceProfile" => %{ "Arn" => config.iam_instance_profile }, - "InstanceInitiatedShutdownBehavior" => "terminate", + "InstanceInitiatedShutdownBehavior" => config.instance_initiated_shutdown_behavior, "UserData" => Base.encode64(start_script) } @@ -121,7 +123,8 @@ defmodule FlameEC2.EC2Api do } end - defp creation_details_params(%Config{image_id: image_id}) when is_binary(image_id) and image_id != "" do + defp creation_details_params(%Config{image_id: image_id}) + when is_binary(image_id) and image_id != "" do %{ "ImageId" => image_id } diff --git a/lib/flame_ec2/templates.ex b/lib/flame_ec2/templates.ex index 12de08c..9caade6 100644 --- a/lib/flame_ec2/templates.ex +++ b/lib/flame_ec2/templates.ex @@ -6,7 +6,10 @@ defmodule FlameEC2.Templates do @templates_path Path.absname("./templates", __DIR__) @type systemd_assign() :: - {:app, atom() | String.t()} | {:custom_start_command, String.t()} | {:custom_stop_command, String.t()} + {:app, atom() | String.t()} + | {:release_dir, String.t() | nil} + | {:custom_start_command, String.t()} + | {:custom_stop_command, String.t()} @spec systemd_service([systemd_assign()]) :: String.t() def systemd_service(assigns) do systemd_service_template(assigns) @@ -25,12 +28,25 @@ defmodule FlameEC2.Templates do | {:aws_region, String.t()} | {:s3_bundle_url, String.t()} | {:s3_bundle_compressed?, boolean()} + | {:release_dir, String.t() | nil} @spec start_script([start_script_assign()]) :: String.t() def start_script(assigns) do start_script_template(assigns) end - EEx.function_from_file(:defp, :systemd_service_template, Path.join(@templates_path, "systemd.service.eex"), [:assigns]) + EEx.function_from_file( + :defp, + :systemd_service_template, + Path.join(@templates_path, "systemd.service.eex"), + [:assigns] + ) + EEx.function_from_file(:defp, :env_template, Path.join(@templates_path, "env.eex"), [:assigns]) - EEx.function_from_file(:defp, :start_script_template, Path.join(@templates_path, "start.sh.eex"), [:assigns]) + + EEx.function_from_file( + :defp, + :start_script_template, + Path.join(@templates_path, "start.sh.eex"), + [:assigns] + ) end diff --git a/lib/flame_ec2/templates/start.sh.eex b/lib/flame_ec2/templates/start.sh.eex index 1cec13f..926ec62 100644 --- a/lib/flame_ec2/templates/start.sh.eex +++ b/lib/flame_ec2/templates/start.sh.eex @@ -70,8 +70,23 @@ install_aws_cli() { return 0 fi - log "Installing AWS CLI..." - curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + # Detect architecture + ARCH=$(uname -m) + case $ARCH in + x86_64) + AWS_CLI_ARCH="x86_64" + ;; + aarch64|arm64) + AWS_CLI_ARCH="aarch64" + ;; + *) + log "Unsupported architecture: $ARCH" + exit 1 + ;; + esac + + log "Installing AWS CLI for architecture: $AWS_CLI_ARCH..." + curl -s "https://awscli.amazonaws.com/awscli-exe-linux-${AWS_CLI_ARCH}.zip" -o "awscliv2.zip" unzip -q awscliv2.zip ./aws/install --update >/dev/null 2>&1 rm -rf aws awscliv2.zip @@ -94,7 +109,11 @@ aws configure set default.region <%= @aws_region %> S3_URL=<%= @s3_bundle_url %> APP_DIR="/srv/<%= @app %>" SERVICE_NAME=<%= @app %> +<%= if assigns[:release_dir] do %> +RELEASE_DIR="<%= @release_dir %>" +<% else %> RELEASE_DIR="${APP_DIR}/release" +<% end %> mkdir -p "${APP_DIR}" "${RELEASE_DIR}" || { log "Failed to create required directories" diff --git a/lib/flame_ec2/templates/systemd.service.eex b/lib/flame_ec2/templates/systemd.service.eex index de2fce4..6406f8e 100644 --- a/lib/flame_ec2/templates/systemd.service.eex +++ b/lib/flame_ec2/templates/systemd.service.eex @@ -1,21 +1,22 @@ +<% release_dir = if assigns[:release_dir], do: @release_dir, else: "/srv/#{@app}/release" %> [Unit] Description=<%= @app %> service After=local-fs.target network.target [Service] Type=simple -WorkingDirectory=/srv/<%= @app %>/release +WorkingDirectory=<%= release_dir %> <%= if assigns[:custom_start_command] do %> ExecStart=<%= @custom_start_command %> <% else %> -ExecStart=/srv/<%= @app %>/release/bin/<%= @app %> start +ExecStart=<%= release_dir %>/bin/<%= @app %> start <% end %> <%= if assigns[:custom_stop_command] do %> ExecStop=<%= @custom_stop_command %> <% else %> -ExecStop=/srv/<%= @app %>/release/bin/<%= @app %> stop +ExecStop=<%= release_dir %>/bin/<%= @app %> stop <% end %> Environment=LANG=en_US.utf8 diff --git a/mix.exs b/mix.exs index 64dfc97..826c60e 100644 --- a/mix.exs +++ b/mix.exs @@ -1,10 +1,12 @@ defmodule FlameEC2.MixProject do use Mix.Project + @version "1.1.0-rc.1" + def project do [ app: :flame_ec2, - version: "1.0.0", + version: @version, elixir: "~> 1.15", start_permanent: Mix.env() == :prod, elixirc_paths: elixirc_path(Mix.env()), @@ -22,8 +24,13 @@ defmodule FlameEC2.MixProject do aliases: aliases(), docs: docs(), dialyzer: [plt_file: {:no_warn, "priv/plts/dialyzer.plt"}, plt_add_deps: :app_tree], - test_coverage: [tool: ExCoveralls], - preferred_cli_env: [ + test_coverage: [tool: ExCoveralls] + ] + end + + def cli do + [ + preferred_envs: [ ci: :test, coveralls: :test, "coveralls.detail": :test, diff --git a/mix.lock b/mix.lock index afacd72..1d0ae2b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,44 +1,44 @@ %{ - "aws": {:hex, :aws, "1.0.4", "17af14644b93d8249de2d730528ab0f7289817e626eb51460f6451b2cdbb5574", [:mix], [{:aws_signature, "~> 0.3", [hex: :aws_signature, repo: "hexpm", optional: false]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.20", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "925722950c085e246ad2e346c847a3f6c8edcf41ac78dcb82b68813a797dc0e2"}, - "aws_credentials": {:hex, :aws_credentials, "0.3.2", "ba2ccee4ec6dcb5426cf71830b7afd73795b1f19655f401d4401015b468fec6f", [:rebar3], [{:eini, "~> 2.2.4", [hex: :eini_beam, repo: "hexpm", optional: false]}, {:iso8601, "~> 1.3.4", [hex: :iso8601, repo: "hexpm", optional: false]}, {:jsx, "~> 3.1.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "2e748626a935a7a544647fb79d7054f38db8bf378978542c962ccbeab387387b"}, - "aws_signature": {:hex, :aws_signature, "0.3.2", "adf33bc4af00b2089b7708bf20e3246f09c639a905a619b3689f0a0a22c3ef8f", [:rebar3], [], "hexpm", "b0daf61feb4250a8ab0adea60db3e336af732ff71dd3fb22e45ae3dcbd071e44"}, - "benchee": {:hex, :benchee, "1.3.1", "c786e6a76321121a44229dde3988fc772bca73ea75170a73fd5f4ddf1af95ccf", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "76224c58ea1d0391c8309a8ecbfe27d71062878f59bd41a390266bf4ac1cc56d"}, + "aws": {:hex, :aws, "1.0.10", "f2d8a3dd81fa5b00930f7e08cdecf52803f1d58beb5b6011f74d0ab0aed8b0fe", [:mix], [{:aws_signature, "~> 0.3", [hex: :aws_signature, repo: "hexpm", optional: false]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.20", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "499b498b207d62c456c0822d568b34faf52c3751295612b319318fc3ec16f082"}, + "aws_credentials": {:hex, :aws_credentials, "0.3.5", "17c3e1f867cef0d87d06135a5b02194ad2c4c2d429f3d0ca81fa8081a7dc1a97", [:rebar3], [{:eini, "~> 2.2.5", [hex: :eini_beam, repo: "hexpm", optional: false]}, {:iso8601, "~> 1.3.4", [hex: :iso8601, repo: "hexpm", optional: false]}, {:jsx, "~> 3.1.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "6541917ed14c7292b6eae65c2e3baf15a79eded19f009f217c48234202884228"}, + "aws_signature": {:hex, :aws_signature, "0.4.2", "1b35482c89ff5b91f5ead647a2bbc0d9620877479b44800915de92bacf9f1476", [:rebar3], [], "hexpm", "1df4a2d1dff200c7bdfa8f9f935efc71a51273adfc6dd39a9f2cc937e01baa01"}, + "benchee": {:hex, :benchee, "1.5.0", "4d812c31d54b0ec0167e91278e7de3f596324a78a096fd3d0bea68bb0c513b10", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.1", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "5b075393aea81b8ae74eadd1c28b1d87e8a63696c649d8293db7c4df3eb67535"}, "benchee_markdown": {:hex, :benchee_markdown, "0.3.3", "d48a1d9782693fae6c294fdb12f653bb90088172d467996bedb9887ff41cf4ef", [:mix], [{:benchee, ">= 1.1.0 and < 2.0.0", [hex: :benchee, repo: "hexpm", optional: false]}], "hexpm", "106dab9ae0b448747da89b9af7285b71841f5d8131f37c6612b7370a157860a4"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, - "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, - "credo": {:hex, :credo, "1.7.11", "d3e805f7ddf6c9c854fd36f089649d7cf6ba74c42bc3795d587814e3c9847102", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "56826b4306843253a66e47ae45e98e7d284ee1f95d53d1612bb483f88a8cf219"}, + "certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"}, + "credo": {:hex, :credo, "1.7.15", "283da72eeb2fd3ccf7248f4941a0527efb97afa224bcdef30b4b580bc8258e1c", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "291e8645ea3fea7481829f1e1eb0881b8395db212821338e577a90bf225c5607"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.42", "f23d856f41919f17cd06a493923a722d87a2d684f143a1e663c04a2b93100682", [:mix], [], "hexpm", "6915b6ca369b5f7346636a2f41c6a6d78b5af419d61a611079189233358b8b8b"}, - "eini": {:hex, :eini_beam, "2.2.4", "02143b1dce4dda4243248e7d9b3d8274b8d9f5a666445e3d868e2cce79e4ff22", [:rebar3], [], "hexpm", "12de479d144b19e09bb92ba202a7ea716739929afdf9dff01ad802e2b1508471"}, - "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, + "dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, + "eini": {:hex, :eini_beam, "2.2.5", "28fa0a4eb7ff885cc388877b73fbd56fcca3b2eae4d81e47c47f317b900da1da", [:rebar3], [], "hexpm", "511e9207649f3becb5d945f1813615987899cf78fa130f92be07193a6a74ecb8"}, + "erlex": {:hex, :erlex, "0.2.8", "cd8116f20f3c0afe376d1e8d1f0ae2452337729f68be016ea544a72f767d9c12", [:mix], [], "hexpm", "9d66ff9fedf69e49dc3fd12831e12a8a37b76f8651dd21cd45fcf5561a8a7590"}, "ex_doc": {:hex, :ex_doc, "0.36.1", "4197d034f93e0b89ec79fac56e226107824adcce8d2dd0a26f5ed3a95efc36b1", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d7d26a7cf965dacadcd48f9fa7b5953d7d0cfa3b44fa7a65514427da44eafd89"}, - "excoveralls": {:hex, :excoveralls, "0.18.4", "70f70dc37b9bd90cf66868c12778d2f60b792b79e9e12aed000972a8046dc093", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cda8bb587d9deaa0da6158cf0a18929189abbe53bf42b10fe70016d5f4f5d6a9"}, - "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, - "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"}, - "flame": {:hex, :flame, "0.5.2", "d46c4daa19b8921b71e0e57dc69edc01ce1311b1976c160192b05d4253b336e8", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, ">= 0.0.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "82560ebef6ab3c277875493d0c93494740c930db0b1a3ff1a570eee9206cc6c0"}, - "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, - "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, + "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, + "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, + "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, + "flame": {:hex, :flame, "0.5.3", "af9a16c902dac100b4f6b91e64c10ef95f9785ef7b638fcfcebabbec682990e6", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, ">= 0.0.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "8b0b42026c1df2eeffdd8860b77af8437ab7aa72b5e648f8e92d8198f3b7fa1e"}, + "hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"}, + "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "iso8601": {:hex, :iso8601, "1.3.4", "7b1f095f86f6cf65e1e5a77872e8e8bf69bd58d4c3a415b3f77d9cc9423ecbb9", [:rebar3], [], "hexpm", "a334469c07f1c219326bc891a95f5eec8eb12dd8071a3fff56a7843cb20fae34"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "jsx": {:hex, :jsx, "3.1.0", "d12516baa0bb23a59bb35dccaf02a1bd08243fcbb9efe24f2d9d056ccff71268", [:rebar3], [], "hexpm", "0c5cc8fdc11b53cc25cf65ac6705ad39e54ecc56d1c22e4adb8f5a53fb9427f3"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, - "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, - "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, - "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, + "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, + "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "remixed_remix": {:hex, :remixed_remix, "2.0.2", "17305cc2219193c5c443fb5e59e7c67e77a70a80db55fa95068355c0de3bd575", [:mix], [], "hexpm", "2d73083e2e1ad31f742275323c4ad3c184924932346721447e8e5905326a99c4"}, - "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, + "req": {:hex, :req, "0.5.16", "99ba6a36b014458e52a8b9a0543bfa752cb0344b2a9d756651db1281d4ba4450", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "974a7a27982b9b791df84e8f6687d21483795882a7840e8309abdbe08bb06f09"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, - "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "styler": {:hex, :styler, "1.3.3", "5196fc9e9bf1254af4337b051103d38532c2f500b0f01bc6f53f56ee678f65e6", [:mix], [], "hexpm", "c275f73f2ff1b7dfafb03a0f8cf3e928709a235a2b049162b40168f53ba3a07c"}, + "statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"}, + "styler": {:hex, :styler, "1.10.0", "343f1f7bb19a8893c2841a9ae90665b68d2edf6cc37b964a5099e60c78815c2e", [:mix], [], "hexpm", "6a78876611869466139e63722df4cbbb56b18a842d88c19f23ca844d914ad91a"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"}, } diff --git a/scripts/env.exs b/scripts/env.exs deleted file mode 100644 index 2f66aef..0000000 --- a/scripts/env.exs +++ /dev/null @@ -1,3 +0,0 @@ -rendered = FlameEC2.Templates.env(vars: %{"MY_ENV_1" => "1234", "MY_ENV_2" => "5678", "MY_ENV_3" => "90"}) - -File.write!("./example_env", rendered) diff --git a/scripts/start_sh.exs b/scripts/start_sh.exs index 42d3118..4c6fcc6 100644 --- a/scripts/start_sh.exs +++ b/scripts/start_sh.exs @@ -1,5 +1,7 @@ systemd_service = FlameEC2.Templates.systemd_service(app: "flame_ec2") -env = FlameEC2.Templates.env(vars: %{"MY_ENV_1" => "1234", "MY_ENV_2" => "5678", "MY_ENV_3" => "90"}) + +env = + FlameEC2.Templates.env(vars: %{"MY_ENV_1" => "1234", "MY_ENV_2" => "5678", "MY_ENV_3" => "90"}) rendered = FlameEC2.Templates.start_script( diff --git a/scripts/systemd_service.exs b/scripts/systemd_service.exs index 76fa138..d7cfd14 100644 --- a/scripts/systemd_service.exs +++ b/scripts/systemd_service.exs @@ -1,3 +1,8 @@ -rendered = FlameEC2.Templates.systemd_service(app: "flame_ec2", custom_start_command: "ls", custom_stop_command: "ls") +rendered = + FlameEC2.Templates.systemd_service( + app: "flame_ec2", + custom_start_command: "ls", + custom_stop_command: "ls" + ) File.write!("./example_systemd_service.service", rendered) diff --git a/test/flame_ec2/backend_state_test.exs b/test/flame_ec2/backend_state_test.exs index c80ddd9..f11658d 100644 --- a/test/flame_ec2/backend_state_test.exs +++ b/test/flame_ec2/backend_state_test.exs @@ -44,7 +44,7 @@ defmodule FlameEC2.BackendStateTest do parent = FLAME.Parent.get() - assert not is_nil(parent) + assert parent assert is_struct(parent, FLAME.Parent) assert parent.ref == state.parent_ref assert parent.node_base == state.runner_node_base diff --git a/test/flame_ec2/config_test.exs b/test/flame_ec2/config_test.exs index d3dcb98..0b650bc 100644 --- a/test/flame_ec2/config_test.exs +++ b/test/flame_ec2/config_test.exs @@ -23,20 +23,29 @@ defmodule FlameEC2.ConfigTest do assert config.instance_type == "t3.nano" assert config.launch_template_version == "$Default" assert config.boot_timeout == 120_000 + assert config.instance_initiated_shutdown_behavior == "terminate" end test "s3 bundle compressed?" do config = FlameEC2.Config.new( - Keyword.put(FlameEC2.QuickConfigs.simple_valid_config(), :s3_bundle_url, "s3://code-bucket/code"), + Keyword.put( + FlameEC2.QuickConfigs.simple_valid_config(), + :s3_bundle_url, + "s3://code-bucket/code" + ), [] ) - assert not config.s3_bundle_compressed? + refute config.s3_bundle_compressed? config = FlameEC2.Config.new( - Keyword.put(FlameEC2.QuickConfigs.simple_valid_config(), :s3_bundle_url, "s3://code-bucket/code.tar.gz"), + Keyword.put( + FlameEC2.QuickConfigs.simple_valid_config(), + :s3_bundle_url, + "s3://code-bucket/code.tar.gz" + ), [] ) @@ -45,17 +54,54 @@ defmodule FlameEC2.ConfigTest do test "environment variables" do env = %{"MY_ENV_1" => "123", "MY_ENV_2" => "456", "MY_ENV_3" => "789"} - config = FlameEC2.Config.new(Keyword.put(FlameEC2.QuickConfigs.simple_valid_config(), :env, env), []) + + config = + FlameEC2.Config.new(Keyword.put(FlameEC2.QuickConfigs.simple_valid_config(), :env, env), []) assert config.env == env end + test "instance initiated shutdown behavior" do + # Test default value + config = FlameEC2.Config.new(FlameEC2.QuickConfigs.simple_valid_config(), []) + assert config.instance_initiated_shutdown_behavior == "terminate" + + # Test custom value "stop" + config = + FlameEC2.Config.new( + Keyword.put( + FlameEC2.QuickConfigs.simple_valid_config(), + :instance_initiated_shutdown_behavior, + "stop" + ), + [] + ) + + assert config.instance_initiated_shutdown_behavior == "stop" + + # Test custom value "terminate" + config = + FlameEC2.Config.new( + Keyword.put( + FlameEC2.QuickConfigs.simple_valid_config(), + :instance_initiated_shutdown_behavior, + "terminate" + ), + [] + ) + + assert config.instance_initiated_shutdown_behavior == "terminate" + end + describe "instance creation details" do test "must have image id or launch template" do assert_raise ArgumentError, "You must specify either the image_id or the launch_template_id for the FlameEC2 backend", fn -> - FlameEC2.Config.new(Keyword.delete(FlameEC2.QuickConfigs.simple_valid_config(), :image_id), []) + FlameEC2.Config.new( + Keyword.delete(FlameEC2.QuickConfigs.simple_valid_config(), :image_id), + [] + ) end with_launch_template = @@ -84,7 +130,10 @@ defmodule FlameEC2.ConfigTest do for key <- must_specify_keys do test "no #{key} is invalid" do assert_raise ArgumentError, ~r/^You must specify/, fn -> - FlameEC2.Config.new(Keyword.delete(FlameEC2.QuickConfigs.simple_valid_config(), unquote(key)), []) + FlameEC2.Config.new( + Keyword.delete(FlameEC2.QuickConfigs.simple_valid_config(), unquote(key)), + [] + ) end end end diff --git a/test/flame_ec2/ec2_api_test.exs b/test/flame_ec2/ec2_api_test.exs index 81f517d..9c49df8 100644 --- a/test/flame_ec2/ec2_api_test.exs +++ b/test/flame_ec2/ec2_api_test.exs @@ -62,6 +62,30 @@ defmodule FlameEC2.EC2ApiTest do assert decoded == start_script end + test "includes InstanceInitiatedShutdownBehavior with default value" do + config = FlameEC2.QuickConfigs.simple_valid_config() + state = FlameEC2.BackendState.new(config, []) + + parsed = FlameEC2.EC2Api.build_params_from_state(state) + + assert parsed["InstanceInitiatedShutdownBehavior"] == "terminate" + end + + test "includes InstanceInitiatedShutdownBehavior with custom value" do + config = + Keyword.put( + FlameEC2.QuickConfigs.simple_valid_config(), + :instance_initiated_shutdown_behavior, + "stop" + ) + + state = FlameEC2.BackendState.new(config, []) + + parsed = FlameEC2.EC2Api.build_params_from_state(state) + + assert parsed["InstanceInitiatedShutdownBehavior"] == "stop" + end + test "correct query parameters with launch template in state" do config = FlameEC2.QuickConfigs.simple_valid_config() @@ -75,7 +99,7 @@ defmodule FlameEC2.EC2ApiTest do assert parsed["LaunchTemplate.LaunchTemplateId"] == "lt-123" assert parsed["LaunchTemplate.Version"] == "1" - assert not Map.has_key?(parsed, "ImageId") + refute Map.has_key?(parsed, "ImageId") end test "successfully launches an instance", context do @@ -92,8 +116,10 @@ defmodule FlameEC2.EC2ApiTest do [] ) - assert %{"instanceId" => _instance_id, "privateIpAddress" => ip} = FlameEC2.EC2Api.run_instances!(state) + assert %{"instanceId" => _instance_id, "privateIpAddress" => ip} = + FlameEC2.EC2Api.run_instances!(state) - assert List.delete_at(String.split(context[:local_ipv4], "."), 3) == List.delete_at(String.split(ip, "."), 3) + assert List.delete_at(String.split(context[:local_ipv4], "."), 3) == + List.delete_at(String.split(ip, "."), 3) end end diff --git a/test/flame_ec2/templates_test.exs b/test/flame_ec2/templates_test.exs index fb7d988..ecba846 100644 --- a/test/flame_ec2/templates_test.exs +++ b/test/flame_ec2/templates_test.exs @@ -18,11 +18,15 @@ defmodule FlameEC2.TemplatesTest do """ - assert output == FlameEC2.Templates.env(vars: %{"MY_ENV_1" => "123", "MY_ENV_2" => "456", "MY_ENV_3" => "789"}) + assert output == + FlameEC2.Templates.env( + vars: %{"MY_ENV_1" => "123", "MY_ENV_2" => "456", "MY_ENV_3" => "789"} + ) end test "systemd template" do output = """ + [Unit] Description=flame_ec2 service After=local-fs.target network.target @@ -51,11 +55,12 @@ defmodule FlameEC2.TemplatesTest do WantedBy=multi-user.target """ - assert output == FlameEC2.Templates.systemd_service(app: :flame_ec2) + assert output == FlameEC2.Templates.systemd_service(app: :flame_ec2, release_dir: nil) end test "systemd template (custom commands)" do output = """ + [Unit] Description=flame_ec2 service After=local-fs.target network.target @@ -85,11 +90,16 @@ defmodule FlameEC2.TemplatesTest do """ assert output == - FlameEC2.Templates.systemd_service(app: :flame_ec2, custom_start_command: "ls", custom_stop_command: "ls") + FlameEC2.Templates.systemd_service( + app: :flame_ec2, + release_dir: nil, + custom_start_command: "ls", + custom_stop_command: "ls" + ) end test "start script" do - systemd_service = FlameEC2.Templates.systemd_service(app: :flame_ec2) + systemd_service = FlameEC2.Templates.systemd_service(app: :flame_ec2, release_dir: nil) env = FlameEC2.Templates.env(vars: %{"MY_ENV_1" => "123"}) output = @@ -99,10 +109,62 @@ defmodule FlameEC2.TemplatesTest do env: env, aws_region: "us-east-1", s3_bundle_url: "s3://code-bucket/code.tar.gz", - s3_bundle_compressed?: true + s3_bundle_compressed?: true, + release_dir: nil ) assert String.contains?(output, systemd_service) assert String.contains?(output, env) end + + test "systemd template with custom release_dir" do + output = FlameEC2.Templates.systemd_service(app: :my_app, release_dir: "/var/www/my_app") + + # Verify custom release_dir is used in WorkingDirectory + assert String.contains?(output, "WorkingDirectory=/var/www/my_app") + # Verify custom release_dir is used in ExecStart + assert String.contains?(output, "ExecStart=/var/www/my_app/bin/my_app start") + # Verify custom release_dir is used in ExecStop + assert String.contains?(output, "ExecStop=/var/www/my_app/bin/my_app stop") + end + + test "start script with custom release_dir" do + systemd_service = FlameEC2.Templates.systemd_service(app: :my_app, release_dir: "/custom/path") + env = FlameEC2.Templates.env(vars: %{}) + + output = + FlameEC2.Templates.start_script( + app: :my_app, + systemd_service: systemd_service, + env: env, + aws_region: "us-east-1", + s3_bundle_url: "s3://bucket/app.tar.gz", + s3_bundle_compressed?: true, + release_dir: "/custom/path" + ) + + # Verify RELEASE_DIR is set to custom path + assert String.contains?(output, ~s(RELEASE_DIR="/custom/path")) + # Verify it doesn't use the default path + refute String.contains?(output, ~s(RELEASE_DIR="${APP_DIR}/release")) + end + + test "start script with default release_dir" do + systemd_service = FlameEC2.Templates.systemd_service(app: :my_app, release_dir: nil) + env = FlameEC2.Templates.env(vars: %{}) + + output = + FlameEC2.Templates.start_script( + app: :my_app, + systemd_service: systemd_service, + env: env, + aws_region: "us-east-1", + s3_bundle_url: "s3://bucket/app.tar.gz", + s3_bundle_compressed?: true, + release_dir: nil + ) + + # Verify RELEASE_DIR uses default path + assert String.contains?(output, ~s(RELEASE_DIR="${APP_DIR}/release")) + end end diff --git a/test/support/quick_configs.ex b/test/support/quick_configs.ex index 8fa84ff..10a2ab2 100644 --- a/test/support/quick_configs.ex +++ b/test/support/quick_configs.ex @@ -20,7 +20,7 @@ defmodule FlameEC2.QuickConfigs do |> AWS.Client.create("xxxxxxxxxxxx", "xxxxxxxxxxxx", "us-east-1") |> AWS.Client.put_endpoint("localhost") |> then(fn client -> - %AWS.Client{client | port: 4566, proto: "http"} + %{client | port: 4566, proto: "http"} end) {:ok, %{"CreateVpcResponse" => %{"vpc" => %{"vpcId" => vpc_id}}}, _} =