Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: workflow for building soft upgrade tarball #316

Merged
merged 7 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
46 changes: 39 additions & 7 deletions .github/workflows/stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Publish upgrade artifacts to staging
on:
push:
branches:
- main
- release_stage
env:
INCLUDE_ERTS: true
MIX_ENV: prod
Expand All @@ -16,7 +16,14 @@ jobs:
packages: write
id-token: write
steps:
- uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4
- name: Set upgrade variables
run: |
elixir ./deploy/upgrade/handler.exs all_keys ./deploy/upgrade/staging.config
echo "RELEASE_FROM=$(elixir ./deploy/upgrade/handler.exs upgrade_from ./deploy/upgrade/staging.config)" >> $GITHUB_ENV
echo "RELEASE_TO=$(elixir ./deploy/upgrade/handler.exs upgrade_to ./deploy/upgrade/staging.config)" >> $GITHUB_ENV
echo "NAME=$(elixir ./deploy/upgrade/handler.exs name ./deploy/upgrade/staging.config)" >> $GITHUB_ENV
- name: Setup Elixir
run: |
. ~/.asdf/asdf.sh
Expand All @@ -26,7 +33,27 @@ jobs:
- name: Set up Rust
uses: ATiltedTree/setup-rust@v1
with:
rust-version: stable
rust-version: stable
- name: Get git tags
run: git fetch --tags origin
- name: Checkout RELEASE_FROM
run: git checkout v${{ env.RELEASE_FROM }}
- name: Cache Mix
uses: actions/cache@v3
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
restore-keys: |
${{ runner.os }}-mix-
- name: Install dependencies
run: |
mix local.hex --force
mix local.rebar --force
mix deps.get
- name: Make old release
run: mix release supavisor
- name: Checkout RELEASE_TO
run: git checkout v${{ env.RELEASE_TO }}
- name: Cache Mix
uses: actions/cache@v3
with:
Expand All @@ -39,15 +66,20 @@ jobs:
mix local.hex --force
mix local.rebar --force
mix deps.get
- name: Make release
run: mix release supavisor
- name: Clean up old release
run: |
rm -rf ./_build/${{ env.MIX_ENV }}/lib/supavisor
rm ./_build/${{ env.MIX_ENV }}/rel/supavisor/releases/COOKIE
rm ./_build/${{ env.MIX_ENV }}/supavisor-${{ env.RELEASE_FROM }}.tar.gz
- name: Make upgrade release
run: RELEASE_COOKIE=${{ secrets.RELEASE_COOKIE_STAGE }} UPGRADE_FROM=${{ env.RELEASE_FROM }} mix release supavisor
- name: Create tarball
run: cd _build/prod/rel/ && tar -czvf ${{ secrets.TARBALL_REGIONS_STAGE }}_supavisor_v$(cat ../../../VERSION)_$(date "+%s").tar.gz supavisor
run: cd _build/${{ env.MIX_ENV }} && mv supavisor-${{ env.RELEASE_TO }}.tar.gz "${{ env.NAME }}_$(date "+%s").tar.gz"
- name: configure aws credentials - staging
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.DEV_AWS_ROLE }}
aws-region: "us-east-1"
- name: Deploy to S3
shell: bash
run: aws s3 sync ./_build/prod/rel/ ${{ secrets.TARBALLS_PATH_STAGE }} --exclude '*' --include '*tar.gz'
run: aws s3 sync ./_build/${{ env.MIX_ENV }} ${{ secrets.TARBALLS_PATH_STAGE }} --exclude '*' --include '*tar.gz'
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.40
1.1.41
3 changes: 2 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import Config

config :supavisor,
ecto_repos: [Supavisor.Repo],
version: Mix.Project.config()[:version]
version: Mix.Project.config()[:version],
env: Mix.env()

# Configures the endpoint
config :supavisor, SupavisorWeb.Endpoint,
Expand Down
23 changes: 23 additions & 0 deletions deploy/upgrade/handler.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Handler do
def main([key, config]) do
{:ok, [config]} = :file.consult(config)

case key do
"all_keys" ->
IO.write(inspect(config, pretty: true))
"name" ->
regions = Enum.join(config[:regions], "&")

IO.write(
"supavisor_#{config[:type]}_#{regions}_#{config[:upgrade_from]}_#{config[:upgrade_to]}"
)

key ->
IO.write(config[String.to_atom(key)])
end

end
end


Handler.main(System.argv())
9 changes: 9 additions & 0 deletions deploy/upgrade/prod.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{upgrade_from, "x.x.x"},
{upgrade_to, "x.x.x"},
% list() | [:all]
{regions, ["ap-southeast-1"]},
% :soft | :hard
{type, soft}
].
% supavisor_soft_all-1_1.1.13_1.1.39
9 changes: 9 additions & 0 deletions deploy/upgrade/staging.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{upgrade_from, "x.x.x"},
{upgrade_to, "x.x.x"},
% list() | [:all]
{regions, ["ap-southeast-1"]},
% :soft | :hard
{type, soft}
].
% supavisor_soft_all-1_1.1.13_1.1.39
7 changes: 6 additions & 1 deletion lib/supavisor/client_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,12 @@ defmodule Supavisor.ClientHandler do
@impl true
def handle_event(:info, {_proto, _, <<"GET", _::binary>>}, :exchange, data) do
Logger.debug("ClientHandler: Client is trying to request HTTP")
HH.sock_send(data.sock, "HTTP/1.1 204 OK\r\n\r\n")

HH.sock_send(
data.sock,
"HTTP/1.1 204 OK\r\nx-app-version: #{Application.spec(:supavisor, :vsn)}\r\n\r\n"
)

{:stop, {:shutdown, :http_request}}
end

Expand Down
59 changes: 59 additions & 0 deletions lib/supavisor/hot_upgrade.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
defmodule Supavisor.HotUpgrade do
@moduledoc false

@type app :: atom
@type version_str :: String.t()
@type path_str :: String.t()
@type change :: :soft | {:advanced, [term]}
@type dep_mods :: [module]
@type appup_ver :: charlist | binary
@type instruction ::
{:add_module, module}
| {:delete_module, module}
| {:update, module, :supervisor | change}
| {:update, module, change, dep_mods}
| {:load_module, module}
| {:load_module, module, dep_mods}
| {:apply, {module, atom, [term]}}
| {:add_application, atom}
| {:remove_application, atom}
| {:restart_application, atom}
| :restart_new_emulator
| :restart_emulator
@type upgrade_instructions :: [{appup_ver, instruction}]
@type downgrade_instructions :: [{appup_ver, instruction}]
@type appup :: {appup_ver, upgrade_instructions, downgrade_instructions}

@spec up(app(), version_str(), version_str(), [appup()], any()) :: [appup()]
def up(_app, _from_vsn, to_vsn, appup, _transform),
do: [{:apply, {Supavisor.HotUpgrade, :apply_runtime_config, [to_vsn]}} | appup]

@spec down(app(), version_str(), version_str(), [appup()], any()) :: [appup()]
def down(_app, from_vsn, _to_vsn, appup, _transform),
do: [{:apply, {Supavisor.HotUpgrade, :apply_runtime_config, [from_vsn]}} | appup]

@spec apply_runtime_config(version_str()) :: any()
def apply_runtime_config(vsn) do
path =
if System.get_env("DEBUG_LOAD_RUNTIME_CONFIG"),
do: "config/runtime.exs",
else: "releases/#{vsn}/runtime.exs"

if File.exists?(path) do
IO.write("Loading runtime.exs from releases/#{vsn}")

for {app, config} <-
Config.Reader.read!(path, env: Application.get_env(:supavisor, :env)) do
updated_config =
Config.Reader.merge(
[{app, Application.get_all_env(app)}],
[{app, config}]
)

Application.put_all_env(updated_config)
end
else
IO.write("No runtime.exs found in releases/#{vsn}")
end
end
end
13 changes: 9 additions & 4 deletions lib/supavisor/monitoring/prom_ex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defmodule Supavisor.Monitoring.PromEx do
|> :ets.select_delete([{{{:_, meta}, :_}, [], [true]}])
end

@spec set_metrics_tags() :: :ok
@spec set_metrics_tags() :: map()
def set_metrics_tags() do
[_, host] = node() |> Atom.to_string() |> String.split("@")

Expand All @@ -53,6 +53,7 @@ defmodule Supavisor.Monitoring.PromEx do
end

Application.put_env(:supavisor, :metrics_tags, metrics_tags)
metrics_tags
end

@spec short_node_id() :: String.t() | nil
Expand All @@ -68,9 +69,13 @@ defmodule Supavisor.Monitoring.PromEx do

@spec get_metrics() :: String.t()
def get_metrics() do
def_tags =
Application.fetch_env!(:supavisor, :metrics_tags)
|> Enum.map_join(",", fn {k, v} -> "#{k}=\"#{v}\"" end)
metrics_tags =
case Application.fetch_env(:supavisor, :metrics_tags) do
:error -> set_metrics_tags()
{:ok, tags} -> tags
end

def_tags = Enum.map_join(metrics_tags, ",", fn {k, v} -> "#{k}=\"#{v}\"" end)

metrics =
PromEx.get_metrics(__MODULE__)
Expand Down
4 changes: 3 additions & 1 deletion lib/tasks/gen.appup.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ defmodule Mix.Tasks.Supavisor.Gen.Appup do
path_to = Path.join(lib_path, "supavisor-#{to_vsn}")
appup_path = Path.join([path_to, "ebin", "supavisor.appup"])

case Appup.make(:supavisor, from_vsn, to_vsn, path_from, path_to) do
transforms = [Supavisor.HotUpgrade]

case Appup.make(:supavisor, from_vsn, to_vsn, path_from, path_to, transforms) do
{:ok, appup} ->
IO.puts("Writing appup to #{appup_path}")

Expand Down
5 changes: 3 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ defmodule Supavisor.MixProject do
[
supavisor: [
steps: [:assemble, &upgrade/1, :tar],
include_erts: System.get_env("INCLUDE_ERTS", "true") == "true"
include_erts: System.get_env("INCLUDE_ERTS", "true") == "true",
cookie: System.get_env("RELEASE_COOKIE", Base.url_encode64(:crypto.strong_rand_bytes(30)))
],
supavisor_bin: [
steps: [:assemble, &Burrito.wrap/1],
Expand Down Expand Up @@ -118,7 +119,7 @@ defmodule Supavisor.MixProject do
defp upgrade(release) do
from = System.get_env("UPGRADE_FROM")

if from do
if from && from != "" do
vsn = release.version
path = Path.join([release.path, "releases", "supavisor-#{vsn}.rel"])
rel_content = File.read!(Path.join(release.version_path, "supavisor.rel"))
Expand Down
4 changes: 3 additions & 1 deletion test/integration/proxy_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,9 @@ defmodule Supavisor.Integration.ProxyTest do
assert :httpc.request(
"http://localhost:#{Application.get_env(:supavisor, :proxy_port_transaction)}"
) ==
{:ok, {{'HTTP/1.1', 204, 'OK'}, [], []}}
{:ok,
{{'HTTP/1.1', 204, 'OK'}, [{'x-app-version', Application.spec(:supavisor, :vsn)}],
[]}}
end

test "checks that client_handler is idle and db_pid is nil for transaction mode" do
Expand Down
Loading