Skip to content

Commit

Permalink
feat!: Widget system (#27)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* Add some logs + some fix

* fix tests and fix dialyzer

* change entrypoint to rootWidget

* change application_runner to beta-17

* Config Lenra-CI branch

* woops

* Remove some old commented code

Co-authored-by: Louis G <louis@lenra.me>
  • Loading branch information
Nesqwik and Louis G authored Jan 31, 2022
1 parent 39203b8 commit 96ce160
Show file tree
Hide file tree
Showing 18 changed files with 312 additions and 269 deletions.
11 changes: 4 additions & 7 deletions apps/lenra/lib/lenra/services/datastore_services.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ defmodule Lenra.DatastoreServices do
@doc """
Gets the datastore data
Returns `%{:ok, action}` with :old_data nil if the datastore does not exist.
Returns a `%{:ok, action}` with data assign to :old_data if the datastore exists.
Returns the data.
data is nil if the data does not exists for this user/app
"""
def assign_old_data(action, application_id) do
case get_by(user_id: action.user_id, application_id: application_id) do
nil -> {:ok, action}
datastore -> {:ok, %{action | old_data: datastore.data}}
end
def get_old_data(user_id, application_id) do
get_by(user_id: user_id, application_id: application_id)
end

@doc """
Expand Down
4 changes: 2 additions & 2 deletions apps/lenra/lib/lenra/services/deployment_services.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Lenra.DeploymentServices do
"""
require Logger

alias Lenra.{Repo, Deployment, Build, BuildServices, EnvironmentServices, Openfaas}
alias Lenra.{Repo, Deployment, Build, BuildServices, EnvironmentServices, OpenfaasServices}

def get(deployment_id) do
Repo.get(Deployment, deployment_id)
Expand Down Expand Up @@ -38,7 +38,7 @@ defmodule Lenra.DeploymentServices do
)
|> Ecto.Multi.run(:openfaas_deploy, fn _repo, _ ->
# a faire: check if this build is already deployed on another env
Openfaas.deploy_app(build.application.service_name, build.build_number)
OpenfaasServices.deploy_app(build.application.service_name, build.build_number)
end)
|> Repo.transaction()
end
Expand Down
3 changes: 2 additions & 1 deletion apps/lenra/lib/lenra/services/gitlab_api_services.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ defmodule Lenra.GitlabApiServices do
gitlab_api_token = Application.fetch_env!(:lenra, :gitlab_api_token)
gitlab_project_id = Application.fetch_env!(:lenra, :gitlab_project_id)
runner_secret = Application.fetch_env!(:lenra, :runner_secret)
gitlab_ref = Application.fetch_env!(:lenra, :gitlab_ci_ref)

url = "#{gitlab_api_url}/projects/#{gitlab_project_id}/pipeline"

Expand All @@ -31,7 +32,7 @@ defmodule Lenra.GitlabApiServices do

body =
Jason.encode!(%{
"ref" => "master",
"ref" => gitlab_ref,
"variables" => [
%{"key" => "IMAGE_NAME", "value" => DeploymentServices.image_name(service_name, build_number)},
%{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
defmodule Lenra.Openfaas do
defmodule Lenra.OpenfaasServices do
@moduledoc """
The service that manage calls to an Openfaas action with `run_action/3`
"""
require Logger

alias Lenra.{Telemetry, DeploymentServices}
alias ApplicationRunner.Action
alias Lenra.{DeploymentServices, Environment, LenraApplication}

defp get_http_context do
base_url = Application.fetch_env!(:lenra, :faas_url)
Expand All @@ -17,7 +16,9 @@ defmodule Lenra.Openfaas do

defp get_function_name(service_name, build_number) do
lenra_env = Application.fetch_env!(:lenra, :lenra_env)

"#{lenra_env}-#{service_name}-#{build_number}"
|> String.downcase()
end

@doc """
Expand All @@ -26,50 +27,70 @@ defmodule Lenra.Openfaas do
Returns `{:ok, decoded_body}` if the HTTP Post succeed
Returns `{:error, reason}` if the HTTP Post fail
"""
@spec run_action(Action.t()) :: {:ok, map}
def run_action(action)
when is_binary(action.app_name) and is_binary(action.action_name) and
is_map(%{data: action.old_data, props: action.props, event: action.event}) do
@spec run_listener(%LenraApplication{}, %Environment{}, String.t(), map(), map(), map()) ::
{:ok, map()} | {:error, any()}
def run_listener(%LenraApplication{} = application, %Environment{} = environment, action, data, props, event) do
{base_url, headers} = get_http_context()
function_name = get_function_name(action.app_name, action.build_number)
function_name = get_function_name(application.service_name, environment.deployed_build.build_number)

url = "#{base_url}/function/#{function_name}"

Logger.debug("Call to Openfaas : #{function_name}")

headers = [{"Content-Type", "application/json"} | headers]
params = Map.put(%{data: action.old_data, props: action.props, event: action.event}, :action, action.action_name)
body = Jason.encode!(params)
body = Jason.encode!(%{action: action, data: data, props: props, event: event})

Logger.info("Run app #{action.app_name}[#{action.build_number}] with action #{action.action_name}")
Logger.debug("Call to Openfaas : #{function_name}")

start_time = Telemetry.start(:openfaas_runaction)
Logger.debug(
"Run app #{application.service_name}[#{environment.deployed_build.build_number}] with action #{action}"
)

response =
Finch.build(:post, url, headers, body)
|> Finch.request(FaasHttp)
|> response(:get_apps)
Finch.build(:post, url, headers, body)
|> Finch.request(FaasHttp)
|> response(:decode)
|> case do
{:ok, %{"data" => data}} -> {:ok, data}
err -> err
end
end

docker_telemetry(response, action.action_logs_uuid)
@spec fetch_widget(%LenraApplication{}, %Environment{}, String.t(), map(), map()) :: {:ok, map()} | {:error, any()}
def fetch_widget(%LenraApplication{} = application, %Environment{} = environment, widget_name, data, props) do
{base_url, headers} = get_http_context()
function_name = get_function_name(application.service_name, environment.deployed_build.build_number)

Telemetry.stop(:openfaas_runaction, start_time, %{
user_id: action.user_id,
uuid: action.action_logs_uuid
})
url = "#{base_url}/function/#{function_name}"
headers = [{"Content-Type", "application/json"} | headers]
body = Jason.encode!(%{widget: widget_name, data: data, props: props})

response
Finch.build(:post, url, headers, body)
|> Finch.request(FaasHttp)
|> response(:decode)
|> case do
{:ok, %{"widget" => widget}} -> {:ok, widget}
err -> err
end
end

defp docker_telemetry({:ok, %{"stats" => %{"listeners" => listeners, "ui" => ui}}}, uuid) do
Telemetry.event(:docker_run, %{uuid: uuid}, %{
uiDuration: ui,
listenersTime: listeners
})
end
@spec fetch_manifest(%LenraApplication{}, %Environment{}) :: {:ok, map()} | {:error, any()}
def fetch_manifest(%LenraApplication{} = application, %Environment{} = environment) do
{base_url, headers} = get_http_context()
function_name = get_function_name(application.service_name, environment.deployed_build.build_number)

defp docker_telemetry(_response, _uuid) do
# credo:disable-for-next-line
# TODO: manage error case
url = "#{base_url}/function/#{function_name}"
headers = [{"Content-Type", "application/json"} | headers]

Finch.build(:post, url, headers)
|> Finch.request(FaasHttp)
|> response(:decode)
|> case do
{:ok, %{"manifest" => manifest}} ->
Logger.debug("Got manifest : #{inspect(manifest)}")
{:ok, manifest}

err ->
Logger.error("Error while getting manifest : #{inspect(err)}")
err
end
end

@doc """
Expand All @@ -96,19 +117,22 @@ defmodule Lenra.Openfaas do
def deploy_app(service_name, build_number) do
{base_url, headers} = get_http_context()

Logger.debug("Deploy Openfaas application")

url = "#{base_url}/system/functions"

Finch.build(
:post,
url,
headers,
body =
Jason.encode!(%{
"image" => DeploymentServices.image_name(service_name, build_number),
"service" => get_function_name(service_name, build_number),
"secrets" => Application.fetch_env!(:lenra, :faas_secrets)
})

Logger.debug("Deploy Openfaas application \n#{url} : \n#{body}")

Finch.build(
:post,
url,
headers,
body
)
|> Finch.request(FaasHttp)
|> response(:deploy_app)
Expand All @@ -133,7 +157,7 @@ defmodule Lenra.Openfaas do
|> response(:delete_app)
end

defp response({:ok, %Finch.Response{status: 200, body: body}}, :get_apps) do
defp response({:ok, %Finch.Response{status: 200, body: body}}, :decode) do
{:ok, Jason.decode!(body)}
end

Expand Down
4 changes: 2 additions & 2 deletions apps/lenra/lib/lenra/services/resources_services.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Lenra.ResourcesServices do
"""
require Logger

alias Lenra.{Openfaas, LenraApplicationServices, Repo}
alias Lenra.{OpenfaasServices, LenraApplicationServices, Repo}

@doc """
Gets the `resource` from an app.
Expand All @@ -15,7 +15,7 @@ defmodule Lenra.ResourcesServices do
with {:ok, app} <- LenraApplicationServices.fetch_by(service_name: service_name, creator_id: user_id),
loaded_app <- Repo.preload(app, main_env: [environment: [:deployed_build]]) do
build_number = loaded_app.main_env.environment.deployed_build.build_number
Openfaas.get_app_resource(app.service_name, build_number, resource)
OpenfaasServices.get_app_resource(app.service_name, build_number, resource)
end
end
end
35 changes: 9 additions & 26 deletions apps/lenra/test/lenra/services/datastore_services_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,48 +26,31 @@ defmodule LenraServers.DatastoreServicesTest do

describe "get" do
test "data from datastore but datastore does not exist", %{app: app} do
assert {:ok, %{}} =
DatastoreServices.assign_old_data(
%ApplicationRunner.Action{
app_name: "test",
build_number: 42,
action_logs_uuid: "92846b3e-e85a-431d-9138-8b7ddaf05f66",
user_id: app.creator_id
},
assert nil ==
DatastoreServices.get_old_data(
app.creator_id,
app.id
)
end

test "data from existing datastore", %{app: app} do
DatastoreServices.upsert_data(app.creator_id, app.id, %{"data" => "test data"})
DatastoreServices.upsert_data(app.creator_id, app.id, %{"foo" => "bar"})

assert {:ok,
%ApplicationRunner.Action{
app_name: "test",
build_number: 42,
action_logs_uuid: "92846b3e-e85a-431d-9138-8b7ddaf05f66",
old_data: %{"data" => "test data"},
user_id: app.creator_id
}} ==
DatastoreServices.assign_old_data(
%ApplicationRunner.Action{
app_name: "test",
build_number: 42,
action_logs_uuid: "92846b3e-e85a-431d-9138-8b7ddaf05f66",
user_id: app.creator_id
},
assert %Datastore{data: %{"foo" => "bar"}} =
DatastoreServices.get_old_data(
app.creator_id,
app.id
)
end

test "datastore", %{app: app} do
DatastoreServices.upsert_data(app.creator_id, app.id, %{"data" => "test data"})
DatastoreServices.upsert_data(app.creator_id, app.id, %{"foo" => "bar"})

assert (%Datastore{} = datastore) = DatastoreServices.get_by(user_id: app.creator_id, application_id: app.id)

assert datastore.user_id == app.creator_id
assert datastore.application_id == app.id
assert datastore.data == %{"data" => "test data"}
assert datastore.data == %{"foo" => "bar"}
end

test "datastore but does not exist", %{app: app} do
Expand Down
Loading

0 comments on commit 96ce160

Please sign in to comment.