Skip to content
146 changes: 117 additions & 29 deletions apps/lenra/lib/lenra/apps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ defmodule Lenra.Apps do
import Ecto.Query

alias ApplicationRunner.ApplicationServices

alias ApplicationRunner.Environment.DynamicSupervisor
alias ApplicationRunner.MongoStorage.MongoUserLink
alias Lenra.Repo
alias Lenra.Subscriptions

alias Lenra.{Accounts, EmailWorker, GitlabApiServices, OpenfaasServices}

alias Lenra.Kubernetes.ApiServices

alias Lenra.Apps.{
App,
Build,
Deployment,
Environment,
EnvironmentScaleOptions,
Image,
Logo,
MainEnv,
Expand All @@ -41,8 +41,6 @@ defmodule Lenra.Apps do
UserEnvironmentRole
}

alias ApplicationRunner.MongoStorage.MongoUserLink

alias Lenra.Errors.{BusinessError, TechnicalError}

require Logger
Expand Down Expand Up @@ -304,14 +302,6 @@ defmodule Lenra.Apps do
end)
end

defp update_build_after_pipeline(multi) do
multi
|> Ecto.Multi.update(:update_build_after_pipeline, fn
%{inserted_build: %Build{} = build, gitlab_pipeline: pipeline} ->
Build.changeset(build, %{"pipeline_id" => pipeline["id"]})
end)
end

def update_build(build, params) do
Ecto.Multi.new()
|> Ecto.Multi.update(:updated_build, Build.update(build, params))
Expand Down Expand Up @@ -342,8 +332,7 @@ defmodule Lenra.Apps do
{:ok, _status} <-
OpenfaasServices.deploy_app(
loaded_build.application.service_name,
build.build_number,
Subscriptions.get_max_replicas(loaded_build.application.id)
build.build_number
) do
update_deployment(deployment, status: :waitingForAppReady)

Expand Down Expand Up @@ -392,21 +381,23 @@ defmodule Lenra.Apps do
when retry <= 120 do
case OpenfaasServices.is_deploy(service_name, build_number) do
true ->
transaction =
Ecto.Multi.new()
|> Ecto.Multi.update(
:updated_deployment,
Ecto.Changeset.change(deployment, status: :success)
)
|> Ecto.Multi.run(:updated_env, fn _repo, %{updated_deployment: updated_deployment} ->
env
|> Ecto.Changeset.change(deployment_id: updated_deployment.id)
|> Repo.update()
end)
|> Repo.transaction()
scale_opts = effective_env_scale_options(env)

service_name
|> OpenfaasServices.get_function_name(build_number)
|> ApplicationServices.set_app_scale_options(scale_opts)

ApplicationServices.stop_app("#{OpenfaasServices.get_function_name(service_name, build_number)}")
transaction
Ecto.Multi.new()
|> Ecto.Multi.update(
:updated_deployment,
Ecto.Changeset.change(deployment, status: :success)
)
|> Ecto.Multi.run(:updated_env, fn _repo, %{updated_deployment: updated_deployment} ->
env
|> Ecto.Changeset.change(deployment_id: updated_deployment.id)
|> Repo.update()
end)
|> Repo.transaction()

# Function not found in openfaas, 2 retry (10s),
# To let openfaas deploy in case of overload, after 2 retry -> failure
Expand Down Expand Up @@ -787,4 +778,101 @@ defmodule Lenra.Apps do
def get_image(image_id) do
Repo.get(Image, image_id)
end

###############
# Environment Scale Options #
###############

def effective_env_scale_options(env) when is_map(env) do
env_scale_options_for_subscription(env, Subscriptions.get_subscription_by_app_id(env.application_id))
end

defp env_scale_options_for_subscription(_env, nil) do
%{
min: Application.fetch_env!(:lenra, :scale_free_min),
max: Application.fetch_env!(:lenra, :scale_free_max)
}
end

defp env_scale_options_for_subscription(env, %Subscriptions.Subscription{}) do
env =
env
|> Repo.preload(:scale_options)

default_scale_min = Application.fetch_env!(:lenra, :scale_paid_min)
default_scale_max = Application.fetch_env!(:lenra, :scale_paid_max)

scale_options = env.scale_options || %{}

scale_min =
(scale_options
|> Map.get(:min) || default_scale_min)
|> max(default_scale_min)
|> min(default_scale_max)

scale_max =
(scale_options
|> Map.get(:max) || default_scale_max)
|> max(1)
|> max(scale_min)
|> min(default_scale_max)

%{
min: scale_min,
max: scale_max
}
end

def get_env_scale_options(env_id) do
Repo.get_by(EnvironmentScaleOptions, environment_id: env_id)
end

def fetch_env_scale_options(env_id) do
Repo.fetch_by(EnvironmentScaleOptions, environment_id: env_id)
end

def create_env_scale_options(env_id, params) do
Ecto.Multi.new()
|> Ecto.Multi.insert(
:inserted_env_scale_options,
EnvironmentScaleOptions.new(env_id, params)
)
|> Repo.transaction()
end

def set_env_scale_options(env_id, params) do
with {:ok, scale_opt} <-
Repo.insert(
EnvironmentScaleOptions.new(env_id, params),
on_conflict: [set: env_scale_opt_to_list(params)]
),
%{
environment:
%Environment{
application: %App{service_name: service_name},
deployment: %Deployment{build: %Build{build_number: build_number}}
} = env
} <- Repo.preload(scale_opt, environment: [:application, deployment: [:build]]),
function_name <- OpenfaasServices.get_function_name(service_name, build_number),
effective_scale_opts <- effective_env_scale_options(env),
:ok <- DynamicSupervisor.update_env_scale_options(env_id, effective_scale_opts),
{:ok, _} <- ApplicationServices.set_app_scale_options(function_name, effective_scale_opts) do
{:ok, scale_opt}
end
end

defp env_scale_opt_to_list(params) do
[]
|> add_present(params, :min)
|> add_present(params, :max)
end

@spec add_present(list :: list, map :: map, key :: atom) :: list
defp add_present(list, map, key) do
if Map.has_key?(map, key) do
[{key, Map.fetch(map, key)} | list]
else
list
end
end
end
1 change: 0 additions & 1 deletion apps/lenra/lib/lenra/apps/app.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ defmodule Lenra.Apps.App do
import Ecto.Changeset

alias Lenra.Accounts.User

alias Lenra.Apps.{Build, Environment, MainEnv}

@type t :: %__MODULE__{}
Expand Down
4 changes: 2 additions & 2 deletions apps/lenra/lib/lenra/apps/environment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ defmodule Lenra.Apps.Environment do
import Ecto.Changeset

alias Lenra.Accounts.User
alias Lenra.Apps.{App, Deployment}
alias Lenra.Apps.UserEnvironmentAccess
alias Lenra.Apps.{App, Deployment, EnvironmentScaleOptions, UserEnvironmentAccess}

@type t :: %__MODULE__{}

Expand All @@ -30,6 +29,7 @@ defmodule Lenra.Apps.Environment do
belongs_to(:creator, User)
belongs_to(:deployment, Deployment)
many_to_many(:shared_with, User, join_through: UserEnvironmentAccess)
has_one(:scale_options, EnvironmentScaleOptions, foreign_key: :environment_id)

timestamps()
end
Expand Down
39 changes: 39 additions & 0 deletions apps/lenra/lib/lenra/apps/environments_scale_options.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
defmodule Lenra.Apps.EnvironmentScaleOptions do
@moduledoc """
The environment scale options.
"""

use Lenra.Schema
import Ecto.Changeset

alias Lenra.Apps.Environment

@type t :: %__MODULE__{}

@derive {Jason.Encoder,
only: [
:environment_id,
:min,
:max
]}
schema "environments_scale_options" do
field(:min, :integer)
field(:max, :integer)
belongs_to(:environment, Environment)

timestamps()
end

def changeset(scale_options, params \\ %{}) do
scale_options
|> cast(params, [:min, :max])
|> validate_required([:environment_id])
|> foreign_key_constraint(:environment_id)
|> unique_constraint([:environment_id], name: :environment_id_unique_index)
end

def new(env_id, params) do
%__MODULE__{environment_id: env_id}
|> __MODULE__.changeset(params)
end
end
8 changes: 2 additions & 6 deletions apps/lenra/lib/lenra/services/openfaas_services.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ defmodule Lenra.OpenfaasServices do

require Logger

@min_scale_label "com.openfaas.scale.min"
@max_scale_label "com.openfaas.scale.max"
@min_scale_default "1"

defp get_http_context do
base_url = Application.fetch_env!(:lenra, :faas_url)
auth = Application.fetch_env!(:lenra, :faas_auth)
Expand All @@ -28,11 +24,11 @@ defmodule Lenra.OpenfaasServices do
String.downcase("#{lenra_env}-#{service_name}-#{build_number}")
end

def deploy_app(service_name, build_number, replicas) do
def deploy_app(service_name, build_number, scale_options \\ %{}) when is_map(scale_options) do
ApplicationServices.deploy_app(
get_function_name(service_name, build_number),
Apps.image_name(service_name, build_number),
replicas
scale_options
)
end

Expand Down
1 change: 1 addition & 0 deletions apps/lenra/lib/lenra/subscriptions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ defmodule Lenra.Subscriptions do
end
end

@deprecated "Use Lenra.Apps.effective_env_scale_options/1"
def get_max_replicas(application_id) do
if get_subscription_by_app_id(application_id) != nil do
5
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Lenra.Repo.Migrations.EnvScaleOption do
use Ecto.Migration

def change do
create table(:environments_scale_options) do
add(:environment_id, references(:environments, on_delete: :delete_all), null: false)
add(:min, :integer)
add(:max, :integer)

timestamps()
end

create(unique_index(:environments_scale_options, [:environment_id]))
end
end
Loading
Loading