From d58d8e49fa216451e147c6eb041f6ba98e80a485 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:17:44 +0100 Subject: [PATCH 01/24] feat: Add Env Secrets in Server API Signed-off-by: shiipou --- apps/lenra/lib/lenra/apps.ex | 35 +++++++++++++ apps/lenra/lib/lenra/apps/env_secret.ex | 41 +++++++++++++++ apps/lenra/lib/lenra/apps/environment.ex | 3 +- .../20240119122616_add_env_secret.exs | 15 ++++++ .../controllers/environment_controller.ex | 50 ++++++++++++++++++- apps/lenra_web/lib/lenra_web/router.ex | 6 +++ libs/application_runner/priv/components-api | 2 +- 7 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 apps/lenra/lib/lenra/apps/env_secret.ex create mode 100644 apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs diff --git a/apps/lenra/lib/lenra/apps.ex b/apps/lenra/lib/lenra/apps.ex index 70599a00..fbbc31fd 100644 --- a/apps/lenra/lib/lenra/apps.ex +++ b/apps/lenra/lib/lenra/apps.ex @@ -33,6 +33,7 @@ defmodule Lenra.Apps do Build, Deployment, Environment, + EnvSecret, Image, Logo, MainEnv, @@ -197,6 +198,40 @@ defmodule Lenra.Apps do Repo.fetch_by(Environment, id: main_env.environment_id) end + ############### + # Env Secrets # + ############### + + def all_env_secrets_for_env(env_id) do + Repo.all(from(s in EnvSecret, where: s.environment_id == ^env_id)) + end + + def get_env_secret(secret_id) do + Repo.get(EnvSecret, secret_id) + end + + def fetch_env_secret(secret_id) do + Repo.fetch(EnvSecret, secret_id) + end + + def create_env_secret(env_id, key, params) do + Ecto.Multi.new() + |> Ecto.Multi.insert(:inserted_env_secret, EnvSecret.new(env_id, key, params)) + |> Repo.transaction() + end + + def update_env_secret(env_secret, params) do + Ecto.Multi.new() + |> Ecto.Multi.update(:updated_env_secret, EnvSecret.update(env_secret, params)) + |> Repo.transaction() + end + + def delete_env_secret(env_secret, params) do + Ecto.Multi.new() + |> Ecto.Multi.delete(:deleted_env, %{ id: env_secret.id }) + |> Repo.transaction() + end + ########## # Builds # ########## diff --git a/apps/lenra/lib/lenra/apps/env_secret.ex b/apps/lenra/lib/lenra/apps/env_secret.ex new file mode 100644 index 00000000..7e42fc96 --- /dev/null +++ b/apps/lenra/lib/lenra/apps/env_secret.ex @@ -0,0 +1,41 @@ +defmodule Lenra.Apps.EnvSecret do + @moduledoc """ + The Environment's Secret schema. + """ + + use Lenra.Schema + import Ecto.Changeset + + alias Lenra.Apps.{Environment} + + @type t :: %__MODULE__{} + + @hex_regex ~r/[0-9A-Fa-f]{6}/ + + @derive {Jason.Encoder, only: [:id, :environment_id, :key, :value, :is_obfuscated]} + schema "env_secrets" do + field(:key, :string) + field(:value,:string) + field(:is_obfuscated, :boolean) + belongs_to(:environment, Environment) + timestamps() + end + + def changeset(env_secret, params \\ %{}) do + env_secret + |> cast(params, [:key, :value, :is_obfuscated]) + |> validate_required([:key, :value]) + |> unique_constraint([:key, :environment_id]) + |> validate_length(:key, min: 2, max: 64) + end + + def new(env_id, key, params) do + %__MODULE__{environment_id: env_id, key: key} + |> __MODULE__.changeset(params) + end + + def update(secret, params) do + secret + |> __MODULE__.changeset(params) + end +end diff --git a/apps/lenra/lib/lenra/apps/environment.ex b/apps/lenra/lib/lenra/apps/environment.ex index 3563ebb0..61377c7a 100644 --- a/apps/lenra/lib/lenra/apps/environment.ex +++ b/apps/lenra/lib/lenra/apps/environment.ex @@ -7,7 +7,7 @@ defmodule Lenra.Apps.Environment do import Ecto.Changeset alias Lenra.Accounts.User - alias Lenra.Apps.{App, Deployment} + alias Lenra.Apps.{App, Deployment, EnvSecret} alias Lenra.Apps.UserEnvironmentAccess @type t :: %__MODULE__{} @@ -30,6 +30,7 @@ defmodule Lenra.Apps.Environment do belongs_to(:creator, User) belongs_to(:deployment, Deployment) many_to_many(:shared_with, User, join_through: UserEnvironmentAccess) + has_many(:secrets, EnvSecret) timestamps() end diff --git a/apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs b/apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs new file mode 100644 index 00000000..2bc45b4a --- /dev/null +++ b/apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs @@ -0,0 +1,15 @@ +defmodule Lenra.Repo.Migrations.AddEnvSecret do + use Ecto.Migration + + def change do + create table(:env_secrets) do + add(:environment_id, references(:environments)) + add(:key, :string) + add(:value, :string) + add(:is_obfuscated, :boolean, default: true) + timestamps() + end + + create(unique_index(:env_secrets, [:environment_id, :key], name: :env_secrets_environment_id_key_index)) + end +end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 2bed3b06..36eccdac 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -4,7 +4,8 @@ defmodule LenraWeb.EnvsController do use LenraWeb.Policy, module: LenraWeb.EnvsController.Policy - alias Lenra.Apps + alias Lenra.{Apps, Repo} + alias Lenra.Apps.{Environment} alias Lenra.Errors.BusinessError alias alias Lenra.Subscriptions alias Lenra.Subscriptions.Subscription @@ -34,6 +35,7 @@ defmodule LenraWeb.EnvsController do end end + def create(conn, params) do with {:ok, app} <- get_app_and_allow(conn, params), user <- LenraWeb.Auth.current_resource(conn), @@ -62,6 +64,47 @@ defmodule LenraWeb.EnvsController do |> reply(env) end end + + def list_secrets(conn, %{"env_id" => env_id} = params) do + with {:ok, _app} <- get_app_and_allow(conn, params), + {:ok, environment} <- Apps.fetch_env(env_id), + env_secrets <- Apps.all_env_secrets_for_env(environment.id) do + conn + |> reply(env_secrets) + end + end + + def create_secret(conn, %{"env_id" => env_id, "key" => key} = params) do + with {:ok, _app} <- get_app_and_allow(conn, params), + {:ok, environment} <- Apps.fetch_env(env_id), + {:ok, %{inserted_env_secret: env_secret}} <- Apps.create_env_secret(environment.id, key, params) do + conn + |> reply(env_secret) + end + end + + # def update_secret(conn, %{"env_id" => env_id, "key" => key} = params) do + # with {:ok, _app} <- get_app_and_allow(conn, params), + # {:ok, environment} <- Apps.fetch_env(env_id), + # {:ok, secret} <- Repo.update_all(from(s in EnvSecret, + # where: s.environment_id == environment.id and s.key == key ), + # order_by: is_nil(s.environment_id), + # limit: 1 + # ), + # {:ok, %{updated_env_secret: env_secret}} <- Apps.update_env_secret(secret, params) do + # conn + # |> reply(env_secret) + # end + # end + + def delete_secret(conn, %{"env_id" => env_id, "key" => key} = params) do + with {:ok, _app} <- get_app_and_allow(conn, params), + {:ok, environment} <- Apps.fetch_env(env_id), + {:ok, %{deleted_env_secret: env_secret}} <- Apps.delete_env_secret(environment.id, key) do + conn + |> reply(env_secret) + end + end end defmodule LenraWeb.EnvsController.Policy do @@ -82,6 +125,11 @@ defmodule LenraWeb.EnvsController.Policy do def authorize(:update, %App{id: app_id}, %Subscription{application_id: app_id}), do: true + def authorize(:list_secrets, %User{id: user_id}, %App{creator_id: user_id}), do: true + def authorize(:create_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true + # def authorize(:update_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true + def authorize(:delete_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true + # credo:disable-for-next-line Credo.Check.Readability.StrictModuleLayout use LenraWeb.Policy.Default end diff --git a/apps/lenra_web/lib/lenra_web/router.ex b/apps/lenra_web/lib/lenra_web/router.ex index 5c89346f..d50afef8 100644 --- a/apps/lenra_web/lib/lenra_web/router.ex +++ b/apps/lenra_web/lib/lenra_web/router.ex @@ -113,6 +113,12 @@ defmodule LenraWeb.Router do resources("/:app_id/environments", EnvsController, only: [:index, :create]) patch("/:app_id/environments/:env_id", EnvsController, :update) + # Environment's Secrets + get("/:app_id/environments/:env_id/secrets", EnvsController, :list_secrets) + post("/:app_id/environments/:env_id/secrets", EnvsController, :create_secret) + put("/:app_id/environments/:env_id/secrets/:key", EnvsController, :update_secret) + delete("/:app_id/environments/:env_id/secrets/:key", EnvsController, :delete_secret) + # Invitations to env resources("/:app_id/environments/:env_id/invitations", UserEnvironmentAccessController, only: [:index, :create]) diff --git a/libs/application_runner/priv/components-api b/libs/application_runner/priv/components-api index 87c0e492..c6584e75 160000 --- a/libs/application_runner/priv/components-api +++ b/libs/application_runner/priv/components-api @@ -1 +1 @@ -Subproject commit 87c0e492eda38e38ce900d4dc6cd21c270f6a9d6 +Subproject commit c6584e757ecf0b7cbf4cccc5475768c4e4ab78c3 From 47a822da462249ecd2b83edc5fee54cdad557619 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 02/24] fix: use k8s api to create and read env's secrets Signed-off-by: shiipou --- apps/lenra/lib/lenra/apps.ex | 34 --- apps/lenra/lib/lenra/apps/env_secret.ex | 41 ---- .../lib/lenra/kubernetes/api_services.ex | 201 +++++++++++++++--- .../20240119122616_add_env_secret.exs | 15 -- .../controllers/environment_controller.ex | 56 ++--- config/config.exs | 3 +- config/dev.exs | 1 + config/runtime.exs | 1 + 8 files changed, 203 insertions(+), 149 deletions(-) delete mode 100644 apps/lenra/lib/lenra/apps/env_secret.ex delete mode 100644 apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs diff --git a/apps/lenra/lib/lenra/apps.ex b/apps/lenra/lib/lenra/apps.ex index fbbc31fd..8d234804 100644 --- a/apps/lenra/lib/lenra/apps.ex +++ b/apps/lenra/lib/lenra/apps.ex @@ -198,40 +198,6 @@ defmodule Lenra.Apps do Repo.fetch_by(Environment, id: main_env.environment_id) end - ############### - # Env Secrets # - ############### - - def all_env_secrets_for_env(env_id) do - Repo.all(from(s in EnvSecret, where: s.environment_id == ^env_id)) - end - - def get_env_secret(secret_id) do - Repo.get(EnvSecret, secret_id) - end - - def fetch_env_secret(secret_id) do - Repo.fetch(EnvSecret, secret_id) - end - - def create_env_secret(env_id, key, params) do - Ecto.Multi.new() - |> Ecto.Multi.insert(:inserted_env_secret, EnvSecret.new(env_id, key, params)) - |> Repo.transaction() - end - - def update_env_secret(env_secret, params) do - Ecto.Multi.new() - |> Ecto.Multi.update(:updated_env_secret, EnvSecret.update(env_secret, params)) - |> Repo.transaction() - end - - def delete_env_secret(env_secret, params) do - Ecto.Multi.new() - |> Ecto.Multi.delete(:deleted_env, %{ id: env_secret.id }) - |> Repo.transaction() - end - ########## # Builds # ########## diff --git a/apps/lenra/lib/lenra/apps/env_secret.ex b/apps/lenra/lib/lenra/apps/env_secret.ex deleted file mode 100644 index 7e42fc96..00000000 --- a/apps/lenra/lib/lenra/apps/env_secret.ex +++ /dev/null @@ -1,41 +0,0 @@ -defmodule Lenra.Apps.EnvSecret do - @moduledoc """ - The Environment's Secret schema. - """ - - use Lenra.Schema - import Ecto.Changeset - - alias Lenra.Apps.{Environment} - - @type t :: %__MODULE__{} - - @hex_regex ~r/[0-9A-Fa-f]{6}/ - - @derive {Jason.Encoder, only: [:id, :environment_id, :key, :value, :is_obfuscated]} - schema "env_secrets" do - field(:key, :string) - field(:value,:string) - field(:is_obfuscated, :boolean) - belongs_to(:environment, Environment) - timestamps() - end - - def changeset(env_secret, params \\ %{}) do - env_secret - |> cast(params, [:key, :value, :is_obfuscated]) - |> validate_required([:key, :value]) - |> unique_constraint([:key, :environment_id]) - |> validate_length(:key, min: 2, max: 64) - end - - def new(env_id, key, params) do - %__MODULE__{environment_id: env_id, key: key} - |> __MODULE__.changeset(params) - end - - def update(secret, params) do - secret - |> __MODULE__.changeset(params) - end -end diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index cf223036..019f2d25 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -44,43 +44,18 @@ defmodule Lenra.Kubernetes.ApiServices do build_name = "build-#{service_name}-#{build_number}" - base64_repository = Base.encode64(app_repository) - base64_repository_branch = Base.encode64(app_repository_branch || "") - - base64_callback_url = Base.encode64("#{runner_callback_url}/runner/builds/#{build_id}?secret=#{runner_secret}") - - base64_image_name = Base.encode64(Apps.image_name(service_name, build_number)) - - secret_body = - Jason.encode!(%{ - apiVersion: "v1", - kind: "Secret", - type: "Opaque", - metadata: %{ - name: build_name, - namespace: kubernetes_build_namespace - }, - data: %{ - APP_REPOSITORY: base64_repository, - REPOSITORY_BRANCH: base64_repository_branch, - CALLBACK_URL: base64_callback_url, - IMAGE_NAME: base64_image_name - } - }) - - secret_response = - Finch.build(:post, secrets_url, headers, secret_body) - |> Finch.request(PipelineHttp) - |> response(:secret) + secret_response = create_k8s_secret(build_name, kubernetes_build_namespace, %{ + APP_REPOSITORY: app_repository, + REPOSITORY_BRANCH: app_repository_branch || "", + CALLBACK_URL: "#{runner_callback_url}/runner/builds/#{build_id}?secret=#{runner_secret}", + IMAGE_NAME: Apps.image_name(service_name, build_number) + }) case secret_response do - {:ok, _} -> + {:ok} -> :ok :secret_exist -> - Finch.build(:delete, secrets_url <> "/#{build_name}", headers) - |> Finch.request(PipelineHttp) - |> response(:secret) if retry < 1 do create_pipeline( @@ -229,4 +204,166 @@ defmodule Lenra.Kubernetes.ApiServices do {:error, :kubernetes_error} end + + defp get_k8s_secret(secret_name, namespace) do + kubernetes_api_url = Application.fetch_env!(:lenra, :kubernetes_api_url) + kubernetes_api_token = Application.fetch_env!(:lenra, :kubernetes_api_token) + + secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" + + headers = [ + {"Authorization", "Bearer #{kubernetes_api_token}"}, + {"content-type", "application/json"} + ] + + secret_response = Finch.build(:get, secrets_url, headers) + |> Finch.request(PipelineHttp) + |> response(:secret) + + case secret_response do + {:ok, body} -> + %{"data" => secret_data} = body + Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end, %{})) + _ -> {:secret_not_exist} + end + end + + defp create_k8s_secret(secret_name, namespace, data) do + kubernetes_api_url = Application.fetch_env!(:lenra, :kubernetes_api_url) + kubernetes_api_token = Application.fetch_env!(:lenra, :kubernetes_api_token) + + secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" + + headers = [ + {"Authorization", "Bearer #{kubernetes_api_token}"}, + {"content-type", "application/json"} + ] + + secret_body = + Jason.encode!(%{ + apiVersion: "v1", + kind: "Secret", + type: "Opaque", + metadata: %{ + name: secret_name, + namespace: namespace + }, + data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end, %{})) + }) + + secret_response = + Finch.build(:post, secrets_url, headers, secret_body) + |> Finch.request(PipelineHttp) + |> response(:secret) + + case secret_response do + {:ok, _} -> + :ok + + :secret_exist -> { :secret_exist } + end + end + + defp update_k8s_secret(secret_name, namespace, secrets) do + kubernetes_api_url = Application.fetch_env!(:lenra, :kubernetes_api_url) + kubernetes_api_token = Application.fetch_env!(:lenra, :kubernetes_api_token) + + secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" + + headers = [ + {"Authorization", "Bearer #{kubernetes_api_token}"}, + {"content-type", "application/json"} + ] + + secret_body = + Jason.encode!(%{ + apiVersion: "v1", + kind: "Secret", + metadata: %{ + name: secret_name, + }, + data: Enum.into(Enum.map(secrets, fn ({key, value}) -> {key, Base.encode64(value)} end, %{})) + }) + + secret_response = Finch.build(:put, secrets_url, headers) + |> Finch.request(PipelineHttp) + |> response(:secret) + + case secret_response do + {:ok, _} -> {:ok} + _ -> {:secret_not_exist} + end + + end + + defp delete_k8s_secret(secret_name, namespace) do + kubernetes_api_url = Application.fetch_env!(:lenra, :kubernetes_api_url) + kubernetes_api_token = Application.fetch_env!(:lenra, :kubernetes_api_token) + + secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" + + headers = [ + {"Authorization", "Bearer #{kubernetes_api_token}"}, + {"content-type", "application/json"} + ] + + secret_response = Finch.build(:delete, secrets_url, headers) + |> Finch.request(PipelineHttp) + |> response(:secret) + + case secret_response do + {:ok, _} -> {:ok} + _ -> {:secret_not_exist} + end + end + + def get_environment_secrets(service_name, env_id) do + kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case get_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + {:ok, secrets} -> Enum.map(secrets, fn ({key, value}) -> key end) + {:secret_not_found} -> {:error, :secret_not_found} + _ -> {:error, :unexpected_response} + end + end + def create_environment_secrets(service_name, env_id, secrets) do + kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case create_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace, secrets) do + {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + {:secret_exist} -> {:error, :secret_exist} + _ -> {:error, :unexpected_response} + end + end + def update_environment_secrets(service_name, env_id, secrets) do + kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case get_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + {:ok, current_secrets} -> + case update_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do + {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + {:secret_not_found} -> {:error, :secret_not_found} + _ -> {:error, :unexpected_response} + end + error -> error + end + end + def delete_environment_secrets(service_name, env_id, key) do + kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case get_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + {:ok, current_secrets} -> + case length(Map.keys(current_secrets)) do + len when len <= 1 -> + case delete_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + {:ok, _} -> {:ok, []} + {:secret_not_found} -> {:error, :secret_not_found} + _ -> {:error, :unexpected_response} + end + _ -> + case update_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do + {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + {:secret_not_found} -> {:error, :secret_not_found} + _ -> {:error, :unexpected_response} + end + end + error -> error + end + end end diff --git a/apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs b/apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs deleted file mode 100644 index 2bc45b4a..00000000 --- a/apps/lenra/priv/repo/migrations/20240119122616_add_env_secret.exs +++ /dev/null @@ -1,15 +0,0 @@ -defmodule Lenra.Repo.Migrations.AddEnvSecret do - use Ecto.Migration - - def change do - create table(:env_secrets) do - add(:environment_id, references(:environments)) - add(:key, :string) - add(:value, :string) - add(:is_obfuscated, :boolean, default: true) - timestamps() - end - - create(unique_index(:env_secrets, [:environment_id, :key], name: :env_secrets_environment_id_key_index)) - end -end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 36eccdac..697f36b8 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -4,8 +4,8 @@ defmodule LenraWeb.EnvsController do use LenraWeb.Policy, module: LenraWeb.EnvsController.Policy - alias Lenra.{Apps, Repo} - alias Lenra.Apps.{Environment} + alias Lenra.{Apps} + alias Lenra.Kubernetes.ApiServices alias Lenra.Errors.BusinessError alias alias Lenra.Subscriptions alias Lenra.Subscriptions.Subscription @@ -66,43 +66,47 @@ defmodule LenraWeb.EnvsController do end def list_secrets(conn, %{"env_id" => env_id} = params) do - with {:ok, _app} <- get_app_and_allow(conn, params), + with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id), - env_secrets <- Apps.all_env_secrets_for_env(environment.id) do + env_secrets <- ApiServices.get_environment_secrets(app.service_name, environment.id) do conn |> reply(env_secrets) end end - def create_secret(conn, %{"env_id" => env_id, "key" => key} = params) do - with {:ok, _app} <- get_app_and_allow(conn, params), - {:ok, environment} <- Apps.fetch_env(env_id), - {:ok, %{inserted_env_secret: env_secret}} <- Apps.create_env_secret(environment.id, key, params) do + def create_secret(conn, %{"env_id" => env_id, "key" => key, "value" => value} = params) do + with {:ok, app} <- get_app_and_allow(conn, params), + {:ok, environment} <- Apps.fetch_env(env_id) do + secret_response = case ApiServices.get_environment_secrets(app.service_name, environment.id) do + {:ok, secrets} -> + case Enum.any?(secrets, fn (s) -> s == key end) do + true -> {:secret_exist} + false -> ApiServices.update_environment_secrets(app.service_name, environment.id, Map.merge(secrets, %{key => value})) + end + {:secret_not_found} -> ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) + error -> error + end conn - |> reply(env_secret) + |> reply(secret_response) end end - # def update_secret(conn, %{"env_id" => env_id, "key" => key} = params) do - # with {:ok, _app} <- get_app_and_allow(conn, params), - # {:ok, environment} <- Apps.fetch_env(env_id), - # {:ok, secret} <- Repo.update_all(from(s in EnvSecret, - # where: s.environment_id == environment.id and s.key == key ), - # order_by: is_nil(s.environment_id), - # limit: 1 - # ), - # {:ok, %{updated_env_secret: env_secret}} <- Apps.update_env_secret(secret, params) do - # conn - # |> reply(env_secret) - # end - # end + def update_secret(conn, %{"env_id" => env_id, "key" => key, "value" => value} = params) do + with {:ok, app} <- get_app_and_allow(conn, params), + {:ok, environment} <- Apps.fetch_env(env_id) do + update_secret_response = ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) + conn + |> reply(update_secret_response) + end + end def delete_secret(conn, %{"env_id" => env_id, "key" => key} = params) do - with {:ok, _app} <- get_app_and_allow(conn, params), - {:ok, environment} <- Apps.fetch_env(env_id), - {:ok, %{deleted_env_secret: env_secret}} <- Apps.delete_env_secret(environment.id, key) do + with {:ok, app} <- get_app_and_allow(conn, params), + {:ok, environment} <- Apps.fetch_env(env_id) do + secret_response = ApiServices.delete_environment_secrets(app.service_name, environment.id, key) + conn - |> reply(env_secret) + |> reply(secret_response) end end end diff --git a/config/config.exs b/config/config.exs index 55e4ff69..b80655a6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -122,7 +122,8 @@ config :application_runner, ApplicationRunner.Scheduler, storage: ApplicationRun # additional_env_modules: {LenraWeb.ApplicationRunnerAdapter, :additional_env_modules} config :lenra, - kubernetes_build_namespace: System.get_env("KUBERNETES_BUILD_NAMESPACE", "lenra-build") + kubernetes_build_namespace: System.get_env("KUBERNETES_BUILD_NAMESPACE", "lenra-build"), + kubernetes_apps_namespace: System.get_env("KUBERNETES_APPS_NAMESPACE", "openfaas-fn") config :argon2_elixir, t_cost: 8, diff --git a/config/dev.exs b/config/dev.exs index ba44506b..1b0d98bf 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -97,6 +97,7 @@ config :lenra, kubernetes_api_url: System.get_env("KUBERNETES_API_URL"), kubernetes_api_cert: System.get_env("KUBERNETES_API_CERT"), kubernetes_api_token: System.get_env("KUBERNETES_API_TOKEN", ""), + kubernetes_apps_namespace: System.get_env("KUBERNETES_APPS_NAMESPACE", "openfaas-fn"), kubernetes_build_namespace: System.get_env("KUBERNETES_BUILD_NAMESPACE", "lenra_build"), kubernetes_build_scripts: System.get_env("KUBERNETES_BUILD_SCRIPTS", "lenra_build"), kubernetes_build_secret: System.get_env("KUBERNETES_BUILD_SECRET", "lenra_build"), diff --git a/config/runtime.exs b/config/runtime.exs index 6c8f25ac..c3a92ca6 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -58,6 +58,7 @@ if config_env() == :prod do ) |> File.read!() |> String.trim(), + kubernetes_apps_namespace: System.get_env("KUBERNETES_APPS_NAMESPACE", "openfaas-fn"), kubernetes_build_namespace: System.get_env("KUBERNETES_BUILD_NAMESPACE", "lenra-build"), kubernetes_build_scripts: System.get_env("KUBERNETES_BUILD_SCRIPTS", "lenra-build-scripts"), kubernetes_build_secret: System.get_env("KUBERNETES_BUILD_SECRET", "lenra-build-secret"), From dbeb4eb1aba7a639a9380c4f499d9111841c0656 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 03/24] chore(warning): remove warning bevause env_id is not used Signed-off-by: shiipou --- .../lib/lenra_web/controllers/environment_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 697f36b8..b9ed7c52 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -45,7 +45,7 @@ defmodule LenraWeb.EnvsController do end end - def update(conn, %{"env_id" => env_id, "is_public" => true} = params) do + def update(conn, %{"env_id" => _env_id, "is_public" => true} = params) do with {:ok, app, env} <- get_app_env_and_allow(conn, params), %Subscription{} = _subscription <- Subscriptions.get_subscription_by_app_id(app.id), {:ok, %{updated_env: env}} <- Apps.update_env(env, params) do @@ -57,7 +57,7 @@ defmodule LenraWeb.EnvsController do end end - def update(conn, %{"env_id" => env_id} = params) do + def update(conn, %{"env_id" => _env_id} = params) do with {:ok, _app, env} <- get_app_env_and_allow(conn, params), {:ok, %{updated_env: env}} <- Apps.update_env(env, params) do conn From 8af3c2b1792c29a54ddfd80e37d0adf111a162f5 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 04/24] fix: add or remove secret from openfaas deployment Signed-off-by: shiipou --- apps/lenra/lib/lenra/apps/environment.ex | 3 +- .../lib/lenra/kubernetes/api_services.ex | 49 +++++++++++++------ .../lib/lenra/services/openfaas_services.ex | 20 ++++++++ .../lib/services/application_services.ex | 5 +- 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/apps/lenra/lib/lenra/apps/environment.ex b/apps/lenra/lib/lenra/apps/environment.ex index 61377c7a..3563ebb0 100644 --- a/apps/lenra/lib/lenra/apps/environment.ex +++ b/apps/lenra/lib/lenra/apps/environment.ex @@ -7,7 +7,7 @@ defmodule Lenra.Apps.Environment do import Ecto.Changeset alias Lenra.Accounts.User - alias Lenra.Apps.{App, Deployment, EnvSecret} + alias Lenra.Apps.{App, Deployment} alias Lenra.Apps.UserEnvironmentAccess @type t :: %__MODULE__{} @@ -30,7 +30,6 @@ defmodule Lenra.Apps.Environment do belongs_to(:creator, User) belongs_to(:deployment, Deployment) many_to_many(:shared_with, User, join_through: UserEnvironmentAccess) - has_many(:secrets, EnvSecret) timestamps() end diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 019f2d25..d203683b 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -177,6 +177,10 @@ defmodule Lenra.Kubernetes.ApiServices do when status_code in [200, 201, 202] do {:ok, Jason.decode!(body)} end + defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) + when status_code in [404] do + {:secret_not_exist, Jason.decode!(body)} + end defp response({:ok, %Finch.Response{status: status_code, body: body}}, :build) when status_code in [200, 201, 202] do @@ -223,8 +227,8 @@ defmodule Lenra.Kubernetes.ApiServices do case secret_response do {:ok, body} -> %{"data" => secret_data} = body - Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end, %{})) - _ -> {:secret_not_exist} + Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end), %{}) + _ -> {:secret_not_found} end end @@ -248,7 +252,7 @@ defmodule Lenra.Kubernetes.ApiServices do name: secret_name, namespace: namespace }, - data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end, %{})) + data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) }) secret_response = @@ -282,7 +286,7 @@ defmodule Lenra.Kubernetes.ApiServices do metadata: %{ name: secret_name, }, - data: Enum.into(Enum.map(secrets, fn ({key, value}) -> {key, Base.encode64(value)} end, %{})) + data: Enum.into(Enum.map(secrets, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) }) secret_response = Finch.build(:put, secrets_url, headers) @@ -291,7 +295,7 @@ defmodule Lenra.Kubernetes.ApiServices do case secret_response do {:ok, _} -> {:ok} - _ -> {:secret_not_exist} + _ -> {:secret_not_found} end end @@ -313,31 +317,39 @@ defmodule Lenra.Kubernetes.ApiServices do case secret_response do {:ok, _} -> {:ok} - _ -> {:secret_not_exist} + _ -> {:secret_not_found} end end def get_environment_secrets(service_name, env_id) do + secret_name = '#{service_name}-secret-#{env_id}' kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case get_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, secrets} -> Enum.map(secrets, fn ({key, value}) -> key end) {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end end def create_environment_secrets(service_name, env_id, secrets) do + secret_name = '#{service_name}-secret-#{env_id}' kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case create_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace, secrets) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do + {:ok, secrets} -> + env = Apps.fetch_env(env_id) + |> Ecto.preload(deployment: [:build]) + build_number = env.deployment.build.build_number + Lenra.OpenfaasServices.update_secrets(service_name, build_number, []) + {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} {:secret_exist} -> {:error, :secret_exist} _ -> {:error, :unexpected_response} end end def update_environment_secrets(service_name, env_id, secrets) do + secret_name = '#{service_name}-secret-#{env_id}' kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case get_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> - case update_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do + case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} @@ -345,19 +357,28 @@ defmodule Lenra.Kubernetes.ApiServices do error -> error end end + def delete_environment_secrets(service_name, env_id, key) do + secret_name = '#{service_name}-secret-#{env_id}' kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case get_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> case length(Map.keys(current_secrets)) do len when len <= 1 -> - case delete_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace) do + # TODO: Get App's last build_id to update it's OpenFaas secrets + _openfaas_secret_updated = case Apps.fetch_env(env_id) + |> Ecto.preload(deployment: [:build]) do + %{ deployment: %{ build: build_number }} when not is_nil(build_number) -> + Lenra.OpenfaasServices.update_secrets(service_name, build_number, [secret_name]) + _ -> {:error, :build_not_exist} + end + case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, _} -> {:ok, []} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end _ -> - case update_k8s_secret('#{service_name}_secret_#{env_id}', kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do + case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index 531b4541..f670fc53 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -50,6 +50,26 @@ defmodule Lenra.OpenfaasServices do |> response(:deploy_status) end + def update_secrets(service_name, build_number, secrets \\ []) do + {base_url, headers} = get_http_context() + function_name = get_function_name(service_name, build_number) + url = "#{base_url}/system/function/#{function_name}" + + body = %{ + "service" => function_name, + "secrets" => secrets + } |> Jason.encode!() + + Finch.build( + :put, + url, + headers, + body + ) + |> Finch.request(FaasHttp, receive_timeout: 1000) + |> response(:deploy_status) + end + def delete_app_openfaas(service_name, build_number) do {base_url, headers} = get_http_context() diff --git a/libs/application_runner/lib/services/application_services.ex b/libs/application_runner/lib/services/application_services.ex index 20febb86..762cf534 100644 --- a/libs/application_runner/lib/services/application_services.ex +++ b/libs/application_runner/lib/services/application_services.ex @@ -172,10 +172,13 @@ defmodule ApplicationRunner.ApplicationServices do @spec generate_function_object(String.t(), String.t(), map()) :: map() def generate_function_object(function_name, image_name, labels) do + # secret_name = '#{app.service_name}-secret-#{env.id}' + %{ "image" => image_name, "service" => function_name, - "secrets" => Application.fetch_env!(:application_runner, :faas_secrets), + "secrets" => Application.fetch_env!(:application_runner, :faas_secrets),#, + # "environments" => ApiServices.get_environment_secrets(app.service_name, env.id), "requests" => %{ "cpu" => Application.fetch_env!(:application_runner, :faas_request_cpu), "memory" => Application.fetch_env!(:application_runner, :faas_request_memory) From 52b1734772b69a0c7fbbefcba011d9a66f4a722b Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 05/24] fix: wrong matching :ok must be :error in k8s api fetch Signed-off-by: shiipou --- apps/lenra/lib/lenra/kubernetes/api_services.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index d203683b..e4bec113 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -177,7 +177,8 @@ defmodule Lenra.Kubernetes.ApiServices do when status_code in [200, 201, 202] do {:ok, Jason.decode!(body)} end - defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) + + defp response({:error, %Finch.Response{status: status_code, body: body}}, :secret) when status_code in [404] do {:secret_not_exist, Jason.decode!(body)} end From 30ce951b81e5107adfaf4b35ac830129af706547 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 06/24] fix: add buisness error for the API responses Signed-off-by: shiipou --- apps/lenra/lib/lenra/errors/business_error.ex | 5 ++- .../lib/lenra/kubernetes/api_services.ex | 4 +- .../controllers/environment_controller.ex | 37 +++++++++++++++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/apps/lenra/lib/lenra/errors/business_error.ex b/apps/lenra/lib/lenra/errors/business_error.ex index 7f487378..1d4e6fad 100644 --- a/apps/lenra/lib/lenra/errors/business_error.ex +++ b/apps/lenra/lib/lenra/errors/business_error.ex @@ -33,6 +33,9 @@ defmodule Lenra.Errors.BusinessError do "Currently not capable to handle this type of pipeline. (`pipeline_runner` can be: [GitLab, Kubernetes])"}, {:subscription_required, "You need a subscirption", 402}, {:stripe_error, "Stripe error"}, - {:subscription_already_exist, "You already have a subscription for this app", 403} + {:subscription_already_exist, "You already have a subscription for this app", 403}, + {:env_secret_already_exist, "You already have a secret with this key", 403}, + {:env_secret_not_found, "The secret your tried to update didn't exist", 404}, + {:api_return_unexpected_response, "A dependency API used in this call return an unexpected response", 500} ] end diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index e4bec113..042447d5 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -177,8 +177,8 @@ defmodule Lenra.Kubernetes.ApiServices do when status_code in [200, 201, 202] do {:ok, Jason.decode!(body)} end - - defp response({:error, %Finch.Response{status: status_code, body: body}}, :secret) + + defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) when status_code in [404] do {:secret_not_exist, Jason.decode!(body)} end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index b9ed7c52..76a8e981 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -67,8 +67,13 @@ defmodule LenraWeb.EnvsController do def list_secrets(conn, %{"env_id" => env_id} = params) do with {:ok, app} <- get_app_and_allow(conn, params), - {:ok, environment} <- Apps.fetch_env(env_id), - env_secrets <- ApiServices.get_environment_secrets(app.service_name, environment.id) do + {:ok, environment} <- Apps.fetch_env(env_id) do + env_secrets = case ApiServices.get_environment_secrets(app.service_name, environment.id) do + {:ok, secrets} -> secrets + {:secret_not_found} -> [] + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + conn |> reply(env_secrets) end @@ -80,11 +85,19 @@ defmodule LenraWeb.EnvsController do secret_response = case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> case Enum.any?(secrets, fn (s) -> s == key end) do - true -> {:secret_exist} - false -> ApiServices.update_environment_secrets(app.service_name, environment.id, Map.merge(secrets, %{key => value})) + false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, Map.merge(secrets, %{key => value})) do + {:ok, secrets} -> secrets + {:secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + true -> BusinessError.env_secret_already_exist_tuple() end - {:secret_not_found} -> ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) - error -> error + {:secret_not_found} -> case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, secrets} -> secrets + {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() # This should never happen + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end conn |> reply(secret_response) @@ -94,7 +107,11 @@ defmodule LenraWeb.EnvsController do def update_secret(conn, %{"env_id" => env_id, "key" => key, "value" => value} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do - update_secret_response = ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) + update_secret_response = case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, secrets } -> secrets + { :secret_not_found } -> BusinessError.env_secret_not_found_tuple() + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end conn |> reply(update_secret_response) end @@ -103,7 +120,11 @@ defmodule LenraWeb.EnvsController do def delete_secret(conn, %{"env_id" => env_id, "key" => key} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do - secret_response = ApiServices.delete_environment_secrets(app.service_name, environment.id, key) + secret_response = case ApiServices.delete_environment_secrets(app.service_name, environment.id, key) do + {:ok, secrets} -> secrets + {:secret_not_found} -> BusinessError.env_secret_not_found_tuple() + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end conn |> reply(secret_response) From 795c7dda5721f6c82b1de5aa64f161a45f987832 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 07/24] fix: fix some errors Signed-off-by: shiipou --- .../lenra_server.postman_collection.json | 1161 +++++++++++++++++ .../postman/local.postman_environment.json | 39 + .../postman/staging.postman_environment.json | 39 + apps/lenra/lib/lenra/errors/business_error.ex | 3 +- .../lib/lenra/kubernetes/api_services.ex | 24 +- .../controllers/environment_controller.ex | 44 +- 6 files changed, 1270 insertions(+), 40 deletions(-) create mode 100644 .vscode/postman/lenra_server.postman_collection.json create mode 100644 .vscode/postman/local.postman_environment.json create mode 100644 .vscode/postman/staging.postman_environment.json diff --git a/.vscode/postman/lenra_server.postman_collection.json b/.vscode/postman/lenra_server.postman_collection.json new file mode 100644 index 00000000..b38eff50 --- /dev/null +++ b/.vscode/postman/lenra_server.postman_collection.json @@ -0,0 +1,1161 @@ +{ + "info": { + "_postman_id": "0b9bcb53-2d64-45b9-89af-66f48aff3c1c", + "name": "Lenra Server", + "description": "This document will show you how to authentificate (Oauth2) and interact with the Lenra server API using Postman's VSCode extension.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "6750074" + }, + "item": [ + { + "name": "Authentification", + "item": [ + { + "name": "login_with_authorization_code", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Has access_token\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.access_token, \"Request didn't reply an access token\").to.exist\r", + " pm.collectionVariables.set(\"lenra_access_token\", jsonData.access_token);\r", + "});\r", + "\r", + " \r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "content-type", + "sortOrder": 4, + "infoTitle": "This header was automatically added", + "info": "The Content-Type header is added to help the server identify the media type of the request body that is present in this request.\n\nUse the request body tab to control the value or to remove this header.", + "allowedToToggle": true, + "disableEdit": true, + "previewSettingsLink": "Go to body", + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "system": true, + "type": "text" + }, + { + "name": "content-length", + "sortOrder": 5, + "infoTitle": "This header was automatically added", + "info": "The Content-Length header was added to indicate to the server the size of the request body that is added to this request. Server uses this value to parse the request body accurately.\n\nYou can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "previewSettingsLink": "Go to body", + "key": "Content-Length", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "id": 0 + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "grant_type", + "value": "authorization_code", + "type": "text" + }, + { + "key": "code", + "value": "{{hydra_auth_code}}", + "type": "text" + }, + { + "key": "client_id", + "value": "{{lenra_client_id}}", + "type": "text" + }, + { + "key": "redirect_uri", + "value": "{{hydra_redirect_url}}", + "type": "text" + }, + { + "key": "state", + "value": "p1z8pm12ov", + "type": "text" + } + ] + }, + "url": { + "raw": "{{hydra_endpoint}}/oauth2/token", + "host": [ + "{{hydra_endpoint}}" + ], + "path": [ + "oauth2", + "token" + ] + }, + "description": "# Authentification\n\nThe" + }, + "response": [] + } + ], + "description": "To get your authentification token, you'll need to get you're authentification code from the OAuth process.\n\nTo get it, you'll need to register a new Oauth client for the [oauthdebugger](https://oauthdebugger.com/), go to your terminal in the Lenra Server project directory and run the following command :\n\n``` bash\n# Run the local dependencies to have hydra and postgres running\n~ $ docker compose up -d\n ✔ Network server_default Created 0.1s \n ✔ Container lenra-mongo Started 0.1s \n ✔ Container server-hydra-migrate-1 Started 0.1s \n ✔ Container lenra-postgres Started 0.1s \n ✔ Container server-hydra-1 Started 0.0s \n# Add a new Oauth2 Client for oauthdebugger.com\n~ $ mix create_oauth2_client backoffice --redirect-uri https://oauthdebugger.com/debug\n09:42:09.243 [debug] Create hydra client %{allowed_cors_origins: [\"http://localhost:10000\"], client_name: \"Lenra Backoffice\", redirect_uris: [\"https://oauthdebugger.com/debug\"], scope: \"profile store manage:account manage:apps\", skip_consent: false, token_endpoint_auth_method: \"none\"}\nOauth client backoffice :\n%{\n \"allowed_cors_origins\" => [\"http://localhost:10000\"],\n \"client_id\" => \"5fbecdf6-ad85-4aea-870e-26a45fe90791\",\n \"client_name\" => \"Lenra Backoffice\",\n \"metadata\" => %{},\n \"redirect_uris\" => [\"https://oauthdebugger.com/debug\"],\n \"scope\" => \"profile store manage:account manage:apps\"\n}\n\n ```\n\nJust copy the \\`client_id\\` and go to [oauthdebugger](https://oauthdebugger.com/), fill the form with following informations :\n\n- Authorize URI: [http://localhost:4444/oauth2/auth](http://localhost:4444/oauth2/auth)\n- Redirect URI: [https://oauthdebugger.com/debug](https://oauthdebugger.com/debug)\n- Client ID: 5fbecdf6-ad85-4aea-870e-26a45fe907917\n- Scope: profile store manage:account manage:apps\n- Response type: code\n- Response mode: form_post\n \n\nLet everything else in the default value.\n\nStart the server with the following command :\n\n``` bash\n~ $ mix phx.server\n\n ```\n\nAnd then you can change the LenraClientAuthCode in the Globals Environment from the Postman's extension tabs." + }, + { + "name": "Apps", + "item": [ + { + "name": "current_user_list_app", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Has some apps\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.be.an(\"array\")\r", + " const last_app = jsonData.last()\r", + " pm.expect(last_app).not.to.be.an(\"undefined\");\r", + " pm.collectionVariables.set(\"lenra_latest_created_app\", last_app.id);\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{lenra_access_token}}", + "type": "text", + "id": 0 + } + ], + "url": { + "raw": "{{lenra_endpoint}}/api/me/apps", + "host": [ + "{{lenra_endpoint}}" + ], + "path": [ + "api", + "me", + "apps" + ] + } + }, + "response": [] + }, + { + "name": "list_environments", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Has some envs\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.be.an(\"array\")\r", + " const last_env = jsonData.last()\r", + " pm.expect(last_env).not.to.be.an(\"undefined\");\r", + " pm.collectionVariables.set(\"lenra_latest_created_env\", last_env.id);\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{lenra_access_token}}", + "type": "text", + "id": 0 + } + ], + "url": { + "raw": "{{lenra_endpoint}}/api/apps/:app_id/environments", + "host": [ + "{{lenra_endpoint}}" + ], + "path": [ + "api", + "apps", + ":app_id", + "environments" + ], + "variable": [ + { + "id": 0, + "key": "app_id", + "value": "{{lenra_latest_created_app}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "list_environments_secrets", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Has some secrets\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.be.an(\"array\")\r", + " const last_secret = jsonData.last()\r", + " pm.expect(last_secret).not.to.be.an(\"undefined\");\r", + " pm.collectionVariables.set(\"lenra_latest_created_secret\", last_secret.id);\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{lenra_access_token}}", + "type": "text", + "id": 0 + } + ], + "url": { + "raw": "{{lenra_endpoint}}/api/apps/:app_id/environments/:env_id/secrets", + "host": [ + "{{lenra_endpoint}}" + ], + "path": [ + "api", + "apps", + ":app_id", + "environments", + ":env_id", + "secrets" + ], + "variable": [ + { + "id": 0, + "key": "app_id", + "value": "{{lenra_latest_created_app}}", + "type": "string" + }, + { + "key": "env_id", + "value": "{{lenra_latest_created_env}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "add_environments_secrets", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Secret is created\", function () {\r", + " var jsonData = pm.response.json();\r", + " const {id, key} = jsonData\r", + " pm.expect(id).to.be.a(\"number\")\r", + " pm.collectionVariables.set(\"lenra_latest_created_secret\", id);\r", + " pm.collectionVariables.set(\"lenra_latest_created_secret_key\", key);\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{lenra_access_token}}", + "type": "text", + "id": 0 + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "key", + "value": "test", + "type": "text" + }, + { + "key": "value", + "value": "test", + "type": "text" + } + ] + }, + "url": { + "raw": "{{lenra_endpoint}}/api/apps/:app_id/environments/:env_id/secrets", + "host": [ + "{{lenra_endpoint}}" + ], + "path": [ + "api", + "apps", + ":app_id", + "environments", + ":env_id", + "secrets" + ], + "variable": [ + { + "id": 0, + "key": "app_id", + "value": "{{lenra_latest_created_app}}", + "type": "string" + }, + { + "key": "env_id", + "value": "{{lenra_latest_created_env}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "update_environments_secrets", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Secret is created\", function () {\r", + " var jsonData = pm.response.json();\r", + " const id = jsonData.id\r", + " pm.expect(id).to.be.a(\"number\")\r", + " pm.collectionVariables.set(\"lenra_latest_created_secret\", id);\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{lenra_access_token}}", + "type": "text", + "id": 0 + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "key", + "value": "test", + "type": "text" + }, + { + "key": "value", + "value": "test", + "type": "text" + } + ] + }, + "url": { + "raw": "{{lenra_endpoint}}/api/apps/:app_id/environments/:env_id/secrets/:key", + "host": [ + "{{lenra_endpoint}}" + ], + "path": [ + "api", + "apps", + ":app_id", + "environments", + ":env_id", + "secrets", + ":key" + ], + "variable": [ + { + "id": 0, + "key": "app_id", + "value": "{{lenra_latest_created_app}}", + "type": "string" + }, + { + "key": "env_id", + "value": "{{lenra_latest_created_env}}", + "type": "string" + }, + { + "key": "key", + "value": "{{lenra_latest_created_secret_key}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "current_dev_list_app", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Has some apps\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.be.an(\"array\")\r", + " const last_app = jsonData.last()\r", + " pm.expect(last_app).not.to.be.an(\"undefined\");\r", + " pm.collectionVariables.set(\"lenra_latest_created_app\", last_app.id);\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "name": "cache-control", + "sortOrder": 2, + "infoTitle": "We recommend using this header", + "info": "Postman added \"Cache-Control: no-cache\" as a precautionary measure to prevent the server from returning stale response when one makes repeated requests.\n\nYou can remove this header in the app settings or enter a new one with a different value.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Cache-Control", + "value": "no-cache", + "system": true, + "type": "text" + }, + { + "name": "postman-token", + "sortOrder": 3, + "infoTitle": "We recommend using this header", + "info": "The Postman-Token header appends a random UUID to every outgoing request. Postman adds this header for API developers to better debug requests sent and to ensure separate requests appear distinct to the receiving server.\n\nYou can remove this header in the app settings.", + "allowedToToggle": false, + "disableEdit": true, + "previewSettingsLink": "Go to settings", + "key": "Postman-Token", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "host", + "sortOrder": 6, + "infoTitle": "We recommend using this header", + "info": "The Host header is added to identify the domain name for which a request is being sent to the server. This header is implicitly sent by every HTTP client.\n\nYou can remove the header or enter a new one with a different value. It is most likely that without this header, your request will return an HTTP 400 error.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Host", + "value": "", + "system": true, + "type": "text" + }, + { + "name": "user-agent", + "sortOrder": 7, + "infoTitle": "We recommend using this header", + "info": "The User-Agent header is added to help the server identify Postman as the HTTP requesting application or client.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "User-Agent", + "value": "PostmanRuntime/7.32.1", + "system": true, + "type": "text" + }, + { + "name": "accept", + "sortOrder": 8, + "infoTitle": "We recommend using this header", + "info": "The \"Accept: */*\" header is added to tell the server that Postman can understand and process all forms of response content types.\n\nIt is recommended that this header be sent, but you can remove the header or enter a new one with a different value.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept", + "value": "*/*", + "system": true, + "type": "text" + }, + { + "name": "accept-encoding", + "sortOrder": 9, + "infoTitle": "We recommend using this header", + "info": "The Accept-Encoding header is added to indicate to the server that Postman HTTP client supports a defined list of content-encoding or compression algorithms as response.\n\nYou can remove the header or enter a new one with a different value. Doing that may not accurately render the response within the app.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Accept-Encoding", + "value": "gzip, deflate, br", + "system": true, + "type": "text" + }, + { + "name": "connection", + "sortOrder": 10, + "infoTitle": "We recommend using this header", + "info": "Postman added the Connection header to indicate the server to keep the underlying network connection open once the current response is received. This allows Postman to reuse the same connection for faster response times in subsequent requests to the same server.\n\nYou can remove this header or enter a new one with a different value, such as `Connection: Close` to control this behaviour.", + "allowedToToggle": true, + "disableEdit": true, + "key": "Connection", + "value": "keep-alive", + "system": true, + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{lenra_access_token}}", + "type": "text", + "id": 0 + } + ], + "url": { + "raw": "{{lenra_endpoint}}/api/me/apps", + "host": [ + "{{lenra_endpoint}}" + ], + "path": [ + "api", + "me", + "apps" + ] + } + }, + "response": [] + } + ] + } + ], + "variable": [ + { + "key": "lenra_endpoint", + "value": "http://localhost:4000", + "type": "string" + }, + { + "key": "hydra_endpoint", + "value": "http://localhost:4444", + "type": "string" + }, + { + "key": "hydra_auth_code", + "value": "", + "type": "string" + }, + { + "key": "lenra_client_id", + "value": "", + "type": "string" + }, + { + "key": "hydra_redirect_url", + "value": "https://oauthdebugger.com/debug", + "type": "string" + }, + { + "key": "hydra_client_scope", + "value": "profile store manage:account manage:apps", + "type": "string" + }, + { + "key": "lenra_access_token", + "value": "", + "type": "string" + }, + { + "key": "lenra_latest_created_app", + "value": "", + "type": "default" + }, + { + "key": "lenra_latest_created_env", + "value": "", + "type": "default" + }, + { + "key": "lenra-intra", + "value": "", + "type": "string" + } + ] +} diff --git a/.vscode/postman/local.postman_environment.json b/.vscode/postman/local.postman_environment.json new file mode 100644 index 00000000..663bf03a --- /dev/null +++ b/.vscode/postman/local.postman_environment.json @@ -0,0 +1,39 @@ +{ + "id": "697ac5e7-6171-4875-a90d-276e7bc0d3ee", + "name": "Local", + "values": [ + { + "key": "lenra_endpoint", + "value": "http://localhost:4000", + "type": "default", + "enabled": true + }, + { + "key": "hydra_endpoint", + "value": "http://localhost:4444", + "type": "default", + "enabled": true + }, + { + "key": "hydra_redirect_url", + "value": "https://oauthdebugger.com/debug", + "type": "default", + "enabled": true + }, + { + "key": "hydra_client_scope", + "value": "profile store manage:account manage:apps", + "type": "default", + "enabled": true + }, + { + "key": "lenra_client_id", + "value": "", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-02-06T12:00:49.888Z", + "_postman_exported_using": "Postman/10.22.13-240205-0449" +} \ No newline at end of file diff --git a/.vscode/postman/staging.postman_environment.json b/.vscode/postman/staging.postman_environment.json new file mode 100644 index 00000000..d2909760 --- /dev/null +++ b/.vscode/postman/staging.postman_environment.json @@ -0,0 +1,39 @@ +{ + "id": "1461dd99-7ff3-4a84-a3d3-2b2f57fa466d", + "name": "Staging", + "values": [ + { + "key": "lenra_endpoint", + "value": "https://api.staging.lenra.io", + "type": "default", + "enabled": true + }, + { + "key": "hydra_endpoint", + "value": "https://auth.staging.lenra.io", + "type": "default", + "enabled": true + }, + { + "key": "hydra_redirect_url", + "value": "https://oauthdebugger.com/debug", + "type": "default", + "enabled": true + }, + { + "key": "hydra_client_scope", + "value": "profile store manage:account manage:apps", + "type": "default", + "enabled": true + }, + { + "key": "lenra_client_id", + "value": "4f162a6c-dfdd-4c75-8305-097e30a19e6f", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-02-06T11:58:57.655Z", + "_postman_exported_using": "Postman/10.22.13-240205-0449" +} \ No newline at end of file diff --git a/apps/lenra/lib/lenra/errors/business_error.ex b/apps/lenra/lib/lenra/errors/business_error.ex index 1d4e6fad..43438ea3 100644 --- a/apps/lenra/lib/lenra/errors/business_error.ex +++ b/apps/lenra/lib/lenra/errors/business_error.ex @@ -36,6 +36,7 @@ defmodule Lenra.Errors.BusinessError do {:subscription_already_exist, "You already have a subscription for this app", 403}, {:env_secret_already_exist, "You already have a secret with this key", 403}, {:env_secret_not_found, "The secret your tried to update didn't exist", 404}, - {:api_return_unexpected_response, "A dependency API used in this call return an unexpected response", 500} + {:api_return_unexpected_response, "A dependency API used in this call return an unexpected response", 500}, + {:kubernetes_unexpected_response, "Kubernetes return an unexpected response", 500} ] end diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 042447d5..cb37bdb7 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -177,7 +177,7 @@ defmodule Lenra.Kubernetes.ApiServices do when status_code in [200, 201, 202] do {:ok, Jason.decode!(body)} end - + defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) when status_code in [404] do {:secret_not_exist, Jason.decode!(body)} @@ -193,15 +193,9 @@ defmodule Lenra.Kubernetes.ApiServices do raise "Kubernetes API could not be reached. It should not happen. #{reason}" end - defp response( - {:ok, - %Finch.Response{ - status: status_code - }}, - _atom - ) + defp response({:ok, %Finch.Response{status: status_code}}, _atom) when status_code in [409] do - :secret_exist + {:error, :secret_exist} end defp response({:ok, %Finch.Response{status: status_code, body: body}}, _atom) do @@ -244,6 +238,7 @@ defmodule Lenra.Kubernetes.ApiServices do {"content-type", "application/json"} ] + secret_body = Jason.encode!(%{ apiVersion: "v1", @@ -253,7 +248,7 @@ defmodule Lenra.Kubernetes.ApiServices do name: secret_name, namespace: namespace }, - data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) + data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end) |> IO.inspect(label: "Encoded map"), %{}) |> IO.inspect(label: "Into map") }) secret_response = @@ -262,10 +257,9 @@ defmodule Lenra.Kubernetes.ApiServices do |> response(:secret) case secret_response do - {:ok, _} -> - :ok + {:ok, _} -> :ok - :secret_exist -> { :secret_exist } + {:error, error} -> { :error, error } end end @@ -290,7 +284,7 @@ defmodule Lenra.Kubernetes.ApiServices do data: Enum.into(Enum.map(secrets, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) }) - secret_response = Finch.build(:put, secrets_url, headers) + secret_response = Finch.build(:put, secrets_url, headers, secret_body) |> Finch.request(PipelineHttp) |> response(:secret) @@ -326,7 +320,7 @@ defmodule Lenra.Kubernetes.ApiServices do secret_name = '#{service_name}-secret-#{env_id}' kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case get_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok, secrets} -> Enum.map(secrets, fn ({key, value}) -> key end) + {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 76a8e981..97f278d2 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -68,66 +68,62 @@ defmodule LenraWeb.EnvsController do def list_secrets(conn, %{"env_id" => env_id} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do - env_secrets = case ApiServices.get_environment_secrets(app.service_name, environment.id) do - {:ok, secrets} -> secrets - {:secret_not_found} -> [] + case ApiServices.get_environment_secrets(app.service_name, environment.id) do + {:ok, secrets} -> conn |> reply(secrets) + {:error, :secret_not_found} -> conn |> reply([]) + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end - - conn - |> reply(env_secrets) end end def create_secret(conn, %{"env_id" => env_id, "key" => key, "value" => value} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do - secret_response = case ApiServices.get_environment_secrets(app.service_name, environment.id) do + case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> case Enum.any?(secrets, fn (s) -> s == key end) do false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, Map.merge(secrets, %{key => value})) do - {:ok, secrets} -> secrets - {:secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen + {:ok, secrets} -> conn |> reply(secrets) + {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end true -> BusinessError.env_secret_already_exist_tuple() end - {:secret_not_found} -> case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets} -> secrets + {:error, :secret_not_found} -> case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() # This should never happen + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end - conn - |> reply(secret_response) end end def update_secret(conn, %{"env_id" => env_id, "key" => key, "value" => value} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do - update_secret_response = case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets } -> secrets - { :secret_not_found } -> BusinessError.env_secret_not_found_tuple() + case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, secrets } -> conn |> reply(secrets) + {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end - conn - |> reply(update_secret_response) end end def delete_secret(conn, %{"env_id" => env_id, "key" => key} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do - secret_response = case ApiServices.delete_environment_secrets(app.service_name, environment.id, key) do - {:ok, secrets} -> secrets - {:secret_not_found} -> BusinessError.env_secret_not_found_tuple() + case ApiServices.delete_environment_secrets(app.service_name, environment.id, key) do + {:ok, secrets} -> conn |> reply(secrets) + {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end - - conn - |> reply(secret_response) end end end From a2454bf2e222e561a7c8ded0ca71678cf6e56c65 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 08/24] fix: switch from rlang string (`'`) to elixir string (`"`) Signed-off-by: shiipou --- .../lib/lenra/kubernetes/api_services.ex | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index cb37bdb7..b9fe0103 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -231,7 +231,7 @@ defmodule Lenra.Kubernetes.ApiServices do kubernetes_api_url = Application.fetch_env!(:lenra, :kubernetes_api_url) kubernetes_api_token = Application.fetch_env!(:lenra, :kubernetes_api_token) - secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" + secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets" headers = [ {"Authorization", "Bearer #{kubernetes_api_token}"}, @@ -248,16 +248,16 @@ defmodule Lenra.Kubernetes.ApiServices do name: secret_name, namespace: namespace }, - data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end) |> IO.inspect(label: "Encoded map"), %{}) |> IO.inspect(label: "Into map") - }) + data: Enum.into(Enum.map(data |> IO.inspect(label: "Unencoded secret map"), fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) |> IO.inspect(label: "Encoded map") + }) |> IO.inspect(label: "Full JSON secret resource") secret_response = Finch.build(:post, secrets_url, headers, secret_body) |> Finch.request(PipelineHttp) |> response(:secret) - case secret_response do - {:ok, _} -> :ok + case secret_response |> IO.inspect(label: "Create secret response") do + {:ok, _} -> {:ok, data} {:error, error} -> { :error, error } end @@ -317,7 +317,7 @@ defmodule Lenra.Kubernetes.ApiServices do end def get_environment_secrets(service_name, env_id) do - secret_name = '#{service_name}-secret-#{env_id}' + secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} @@ -326,7 +326,7 @@ defmodule Lenra.Kubernetes.ApiServices do end end def create_environment_secrets(service_name, env_id, secrets) do - secret_name = '#{service_name}-secret-#{env_id}' + secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do {:ok, secrets} -> @@ -340,12 +340,12 @@ defmodule Lenra.Kubernetes.ApiServices do end end def update_environment_secrets(service_name, env_id, secrets) do - secret_name = '#{service_name}-secret-#{env_id}' + secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end @@ -354,14 +354,13 @@ defmodule Lenra.Kubernetes.ApiServices do end def delete_environment_secrets(service_name, env_id, key) do - secret_name = '#{service_name}-secret-#{env_id}' + secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> case length(Map.keys(current_secrets)) do len when len <= 1 -> - # TODO: Get App's last build_id to update it's OpenFaas secrets - _openfaas_secret_updated = case Apps.fetch_env(env_id) + case Apps.fetch_env(env_id) |> Ecto.preload(deployment: [:build]) do %{ deployment: %{ build: build_number }} when not is_nil(build_number) -> Lenra.OpenfaasServices.update_secrets(service_name, build_number, [secret_name]) From 0ba030bb601c8f383c5682f6e9ab57ac95a538a7 Mon Sep 17 00:00:00 2001 From: shiipou Date: Tue, 13 Feb 2024 12:18:03 +0100 Subject: [PATCH 09/24] fix: wrong error matching Signed-off-by: shiipou --- apps/lenra/lib/lenra/kubernetes/api_services.ex | 16 +++++++++------- .../controllers/environment_controller.ex | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index b9fe0103..2a269fc3 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -9,6 +9,7 @@ defmodule Lenra.Kubernetes.ApiServices do alias Lenra.Apps.Deployment alias Lenra.Kubernetes.StatusDynSup alias Lenra.Repo + alias Ecto require Logger @doc """ @@ -180,7 +181,7 @@ defmodule Lenra.Kubernetes.ApiServices do defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) when status_code in [404] do - {:secret_not_exist, Jason.decode!(body)} + {:error, :secret_not_exist, Jason.decode!(body)} end defp response({:ok, %Finch.Response{status: status_code, body: body}}, :build) @@ -222,8 +223,8 @@ defmodule Lenra.Kubernetes.ApiServices do case secret_response do {:ok, body} -> %{"data" => secret_data} = body - Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end), %{}) - _ -> {:secret_not_found} + {:ok, Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end), %{})} + {:error, error} -> { :error, error |> IO.inspect(label: "Fetch error") } end end @@ -321,8 +322,8 @@ defmodule Lenra.Kubernetes.ApiServices do kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} - {:secret_not_found} -> {:error, :secret_not_found} - _ -> {:error, :unexpected_response} + {:error, :secret_not_exist} -> {:error, :secret_not_found} + {:error, error} -> {:error, error} end end def create_environment_secrets(service_name, env_id, secrets) do @@ -331,7 +332,7 @@ defmodule Lenra.Kubernetes.ApiServices do case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do {:ok, secrets} -> env = Apps.fetch_env(env_id) - |> Ecto.preload(deployment: [:build]) + |> Repo.preload(deployment: [:build]) build_number = env.deployment.build.build_number Lenra.OpenfaasServices.update_secrets(service_name, build_number, []) {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} @@ -361,9 +362,10 @@ defmodule Lenra.Kubernetes.ApiServices do case length(Map.keys(current_secrets)) do len when len <= 1 -> case Apps.fetch_env(env_id) - |> Ecto.preload(deployment: [:build]) do + |> Repo.preload(deployment: [:build]) do %{ deployment: %{ build: build_number }} when not is_nil(build_number) -> Lenra.OpenfaasServices.update_secrets(service_name, build_number, [secret_name]) + {:ok, []} # TODO: Return all other secrets _ -> {:error, :build_not_exist} end case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 97f278d2..fca5aabe 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -72,7 +72,7 @@ defmodule LenraWeb.EnvsController do {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_not_found} -> conn |> reply([]) {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + {:error, error} -> BusinessError.api_return_unexpected_response_tuple(error) end end end @@ -83,7 +83,7 @@ defmodule LenraWeb.EnvsController do case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> case Enum.any?(secrets, fn (s) -> s == key end) do - false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, Map.merge(secrets, %{key => value})) do + false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() From ad3b0283798a3e1421f5834041ed9f099ef757c9 Mon Sep 17 00:00:00 2001 From: shiipou Date: Fri, 23 Feb 2024 12:27:25 +0100 Subject: [PATCH 10/24] fix: now we can list/create/delete Still have an issue with the update And the delete show an error but work and delete the key. Signed-off-by: shiipou --- apps/lenra/lib/lenra/apps.ex | 1 - .../lib/lenra/kubernetes/api_services.ex | 26 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/lenra/lib/lenra/apps.ex b/apps/lenra/lib/lenra/apps.ex index 8d234804..70599a00 100644 --- a/apps/lenra/lib/lenra/apps.ex +++ b/apps/lenra/lib/lenra/apps.ex @@ -33,7 +33,6 @@ defmodule Lenra.Apps do Build, Deployment, Environment, - EnvSecret, Image, Logo, MainEnv, diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 2a269fc3..0c6d1f2a 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -181,7 +181,7 @@ defmodule Lenra.Kubernetes.ApiServices do defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) when status_code in [404] do - {:error, :secret_not_exist, Jason.decode!(body)} + {:error, :secret_not_found, Jason.decode!(body)} end defp response({:ok, %Finch.Response{status: status_code, body: body}}, :build) @@ -224,7 +224,7 @@ defmodule Lenra.Kubernetes.ApiServices do {:ok, body} -> %{"data" => secret_data} = body {:ok, Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end), %{})} - {:error, error} -> { :error, error |> IO.inspect(label: "Fetch error") } + {:error, error, _} -> { :error, error |> IO.inspect(label: "Fetch error") } end end @@ -322,7 +322,7 @@ defmodule Lenra.Kubernetes.ApiServices do kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} - {:error, :secret_not_exist} -> {:error, :secret_not_found} + {:error, :secret_not_found} -> {:error, :secret_not_found} {:error, error} -> {:error, error} end end @@ -331,9 +331,9 @@ defmodule Lenra.Kubernetes.ApiServices do kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do {:ok, secrets} -> - env = Apps.fetch_env(env_id) - |> Repo.preload(deployment: [:build]) - build_number = env.deployment.build.build_number + {:ok, partial_env} = Apps.fetch_env(env_id) + env = Repo.preload(partial_env, deployment: [:build]) + build_number = env.deployment.build.build_number Lenra.OpenfaasServices.update_secrets(service_name, build_number, []) {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} {:secret_exist} -> {:error, :secret_exist} @@ -361,13 +361,13 @@ defmodule Lenra.Kubernetes.ApiServices do {:ok, current_secrets} -> case length(Map.keys(current_secrets)) do len when len <= 1 -> - case Apps.fetch_env(env_id) - |> Repo.preload(deployment: [:build]) do - %{ deployment: %{ build: build_number }} when not is_nil(build_number) -> - Lenra.OpenfaasServices.update_secrets(service_name, build_number, [secret_name]) - {:ok, []} # TODO: Return all other secrets - _ -> {:error, :build_not_exist} - end + {:ok, partial_env} = Apps.fetch_env(env_id) + case Repo.preload(partial_env, deployment: [:build]) do + %{ deployment: %{ build: build }} when not is_nil(build) -> + Lenra.OpenfaasServices.update_secrets(service_name, build.build_number, []) + {:ok, []} # TODO: Return all other secrets + _ -> {:error, :build_not_exist} + end case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, _} -> {:ok, []} {:secret_not_found} -> {:error, :secret_not_found} From 0ac31aee64782b802343c0f3f7bd4a70c22123fe Mon Sep 17 00:00:00 2001 From: shiipou Date: Fri, 23 Feb 2024 15:44:27 +0100 Subject: [PATCH 11/24] fix: variable "secrets" does not exist Signed-off-by: shiipou --- apps/lenra/lib/lenra/kubernetes/api_services.ex | 6 +++--- .../lib/lenra_web/controllers/environment_controller.ex | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 0c6d1f2a..383d3905 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -335,7 +335,7 @@ defmodule Lenra.Kubernetes.ApiServices do env = Repo.preload(partial_env, deployment: [:build]) build_number = env.deployment.build.build_number Lenra.OpenfaasServices.update_secrets(service_name, build_number, []) - {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} {:secret_exist} -> {:error, :secret_exist} _ -> {:error, :unexpected_response} end @@ -346,7 +346,7 @@ defmodule Lenra.Kubernetes.ApiServices do case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} + {:ok} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end @@ -375,7 +375,7 @@ defmodule Lenra.Kubernetes.ApiServices do end _ -> case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, value}) -> key end)} + {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index fca5aabe..9a2415d8 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -82,9 +82,9 @@ defmodule LenraWeb.EnvsController do {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> - case Enum.any?(secrets, fn (s) -> s == key end) do + case Enum.any?(secrets |> IO.inspect(label: "Existing Secret keys"), fn (s) -> s == key end) do false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets} -> conn |> reply(secrets) + {:ok, updated_secrets} -> conn |> reply(updated_secrets) {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() From 5c01bc16816f71a60f2f4d825ad1dc6ca667c845 Mon Sep 17 00:00:00 2001 From: shiipou Date: Fri, 23 Feb 2024 18:17:22 +0100 Subject: [PATCH 12/24] fix: openfaas call must now work ? if app get preloaded Signed-off-by: shiipou --- .../lib/lenra/kubernetes/api_services.ex | 22 +++++++++---------- .../lib/lenra/services/openfaas_services.ex | 18 ++++++++++----- .../controllers/environment_controller.ex | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 383d3905..339c3c12 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -223,7 +223,7 @@ defmodule Lenra.Kubernetes.ApiServices do case secret_response do {:ok, body} -> %{"data" => secret_data} = body - {:ok, Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64(value)} end), %{})} + {:ok, Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64!(value)} end), %{})} {:error, error, _} -> { :error, error |> IO.inspect(label: "Fetch error") } end end @@ -249,15 +249,15 @@ defmodule Lenra.Kubernetes.ApiServices do name: secret_name, namespace: namespace }, - data: Enum.into(Enum.map(data |> IO.inspect(label: "Unencoded secret map"), fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) |> IO.inspect(label: "Encoded map") - }) |> IO.inspect(label: "Full JSON secret resource") + data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) + }) secret_response = Finch.build(:post, secrets_url, headers, secret_body) |> Finch.request(PipelineHttp) |> response(:secret) - case secret_response |> IO.inspect(label: "Create secret response") do + case secret_response do {:ok, _} -> {:ok, data} {:error, error} -> { :error, error } @@ -293,7 +293,6 @@ defmodule Lenra.Kubernetes.ApiServices do {:ok, _} -> {:ok} _ -> {:secret_not_found} end - end defp delete_k8s_secret(secret_name, namespace) do @@ -332,11 +331,11 @@ defmodule Lenra.Kubernetes.ApiServices do case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do {:ok, secrets} -> {:ok, partial_env} = Apps.fetch_env(env_id) - env = Repo.preload(partial_env, deployment: [:build]) + env = Repo.preload(partial_env, deployment: [:build]) |> Repo.preload([:application]) build_number = env.deployment.build.build_number - Lenra.OpenfaasServices.update_secrets(service_name, build_number, []) + Lenra.OpenfaasServices.update_secrets(env.application, service_name |> IO.inspect(label: "CreateEnvSecret - ServiceName"), build_number |> IO.inspect(label: "CreateEnvSecret - build_number"), [secret_name]) {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} - {:secret_exist} -> {:error, :secret_exist} + {:error, :secret_exist} -> {:error, :secret_exist} _ -> {:error, :unexpected_response} end end @@ -362,9 +361,10 @@ defmodule Lenra.Kubernetes.ApiServices do case length(Map.keys(current_secrets)) do len when len <= 1 -> {:ok, partial_env} = Apps.fetch_env(env_id) - case Repo.preload(partial_env, deployment: [:build]) do - %{ deployment: %{ build: build }} when not is_nil(build) -> - Lenra.OpenfaasServices.update_secrets(service_name, build.build_number, []) + case Repo.preload(partial_env, deployment: [:build]) + |> Repo.preload([:application]) do + %{ application: app, deployment: %{ build: build }} when not is_nil(build) -> + Lenra.OpenfaasServices.update_secrets(app, service_name, build.build_number, []) {:ok, []} # TODO: Return all other secrets _ -> {:error, :build_not_exist} end diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index f670fc53..49dcdc32 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -5,6 +5,7 @@ defmodule Lenra.OpenfaasServices do alias ApplicationRunner.ApplicationServices alias Lenra.Apps + alias Lenra.Subscriptions alias Lenra.Errors.TechnicalError alias LenraCommon.Errors @@ -50,15 +51,22 @@ defmodule Lenra.OpenfaasServices do |> response(:deploy_status) end - def update_secrets(service_name, build_number, secrets \\ []) do + def update_secrets(app, service_name, build_number, secrets \\ []) do {base_url, headers} = get_http_context() function_name = get_function_name(service_name, build_number) url = "#{base_url}/system/function/#{function_name}" - body = %{ - "service" => function_name, + body = Map.merge(ApplicationServices.generate_function_object( + function_name, + Apps.image_name(service_name, build_number), + %{ + @min_scale_label => @min_scale_default, + @max_scale_label => to_string(Subscriptions.get_max_replicas(app.id)), + @scale_factor_label => @scale_factor_default + } + ), %{ "secrets" => secrets - } |> Jason.encode!() + }) |> Jason.encode!() |> IO.inspect(label: "OpenFaas Update Secret to") Finch.build( :put, @@ -66,7 +74,7 @@ defmodule Lenra.OpenfaasServices do headers, body ) - |> Finch.request(FaasHttp, receive_timeout: 1000) + |> Finch.request(FaasHttp, receive_timeout: 1000) |> IO.inspect(label: "OpenFaas Response") |> response(:deploy_status) end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 9a2415d8..0fb5eacb 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -82,7 +82,7 @@ defmodule LenraWeb.EnvsController do {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> - case Enum.any?(secrets |> IO.inspect(label: "Existing Secret keys"), fn (s) -> s == key end) do + case Enum.any?(secrets, fn (s) -> s == key end) do false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do {:ok, updated_secrets} -> conn |> reply(updated_secrets) {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen From fd8e885a4f2065af4b5d323a410a37f27971f6c0 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 27 Feb 2024 16:31:09 +0100 Subject: [PATCH 13/24] fix format --- .../lib/lenra/kubernetes/api_services.ex | 122 +++++++++++------- .../lib/lenra/services/openfaas_services.ex | 31 +++-- .../controllers/environment_controller.ex | 46 ++++--- .../lib/services/application_services.ex | 3 +- 4 files changed, 125 insertions(+), 77 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 339c3c12..1651dc6a 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -45,19 +45,19 @@ defmodule Lenra.Kubernetes.ApiServices do build_name = "build-#{service_name}-#{build_number}" - secret_response = create_k8s_secret(build_name, kubernetes_build_namespace, %{ - APP_REPOSITORY: app_repository, - REPOSITORY_BRANCH: app_repository_branch || "", - CALLBACK_URL: "#{runner_callback_url}/runner/builds/#{build_id}?secret=#{runner_secret}", - IMAGE_NAME: Apps.image_name(service_name, build_number) - }) + secret_response = + create_k8s_secret(build_name, kubernetes_build_namespace, %{ + APP_REPOSITORY: app_repository, + REPOSITORY_BRANCH: app_repository_branch || "", + CALLBACK_URL: "#{runner_callback_url}/runner/builds/#{build_id}?secret=#{runner_secret}", + IMAGE_NAME: Apps.image_name(service_name, build_number) + }) case secret_response do {:ok} -> :ok :secret_exist -> - if retry < 1 do create_pipeline( service_name, @@ -180,7 +180,7 @@ defmodule Lenra.Kubernetes.ApiServices do end defp response({:ok, %Finch.Response{status: status_code, body: body}}, :secret) - when status_code in [404] do + when status_code in [404] do {:error, :secret_not_found, Jason.decode!(body)} end @@ -216,15 +216,18 @@ defmodule Lenra.Kubernetes.ApiServices do {"content-type", "application/json"} ] - secret_response = Finch.build(:get, secrets_url, headers) - |> Finch.request(PipelineHttp) - |> response(:secret) + secret_response = + Finch.build(:get, secrets_url, headers) + |> Finch.request(PipelineHttp) + |> response(:secret) case secret_response do {:ok, body} -> - %{"data" => secret_data} = body - {:ok, Enum.into(Enum.map(secret_data, fn ({key, value}) -> {key, Base.decode64!(value)} end), %{})} - {:error, error, _} -> { :error, error |> IO.inspect(label: "Fetch error") } + %{"data" => secret_data} = body + {:ok, Enum.into(Enum.map(secret_data, fn {key, value} -> {key, Base.decode64!(value)} end), %{})} + + {:error, error, _} -> + {:error, error |> IO.inspect(label: "Fetch error")} end end @@ -239,7 +242,6 @@ defmodule Lenra.Kubernetes.ApiServices do {"content-type", "application/json"} ] - secret_body = Jason.encode!(%{ apiVersion: "v1", @@ -249,7 +251,7 @@ defmodule Lenra.Kubernetes.ApiServices do name: secret_name, namespace: namespace }, - data: Enum.into(Enum.map(data, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) + data: Enum.into(Enum.map(data, fn {key, value} -> {key, Base.encode64(value)} end), %{}) }) secret_response = @@ -259,8 +261,7 @@ defmodule Lenra.Kubernetes.ApiServices do case secret_response do {:ok, _} -> {:ok, data} - - {:error, error} -> { :error, error } + {:error, error} -> {:error, error} end end @@ -276,18 +277,19 @@ defmodule Lenra.Kubernetes.ApiServices do ] secret_body = - Jason.encode!(%{ - apiVersion: "v1", - kind: "Secret", - metadata: %{ - name: secret_name, - }, - data: Enum.into(Enum.map(secrets, fn ({key, value}) -> {key, Base.encode64(value)} end), %{}) - }) - - secret_response = Finch.build(:put, secrets_url, headers, secret_body) - |> Finch.request(PipelineHttp) - |> response(:secret) + Jason.encode!(%{ + apiVersion: "v1", + kind: "Secret", + metadata: %{ + name: secret_name + }, + data: Enum.into(Enum.map(secrets, fn {key, value} -> {key, Base.encode64(value)} end), %{}) + }) + + secret_response = + Finch.build(:put, secrets_url, headers, secret_body) + |> Finch.request(PipelineHttp) + |> response(:secret) case secret_response do {:ok, _} -> {:ok} @@ -306,9 +308,10 @@ defmodule Lenra.Kubernetes.ApiServices do {"content-type", "application/json"} ] - secret_response = Finch.build(:delete, secrets_url, headers) - |> Finch.request(PipelineHttp) - |> response(:secret) + secret_response = + Finch.build(:delete, secrets_url, headers) + |> Finch.request(PipelineHttp) + |> response(:secret) case secret_response do {:ok, _} -> {:ok} @@ -319,68 +322,95 @@ defmodule Lenra.Kubernetes.ApiServices do def get_environment_secrets(service_name, env_id) do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case get_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} + {:ok, secrets} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} {:error, :secret_not_found} -> {:error, :secret_not_found} {:error, error} -> {:error, error} end end + def create_environment_secrets(service_name, env_id, secrets) do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do {:ok, secrets} -> {:ok, partial_env} = Apps.fetch_env(env_id) env = Repo.preload(partial_env, deployment: [:build]) |> Repo.preload([:application]) build_number = env.deployment.build.build_number - Lenra.OpenfaasServices.update_secrets(env.application, service_name |> IO.inspect(label: "CreateEnvSecret - ServiceName"), build_number |> IO.inspect(label: "CreateEnvSecret - build_number"), [secret_name]) - {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} - {:error, :secret_exist} -> {:error, :secret_exist} - _ -> {:error, :unexpected_response} + + Lenra.OpenfaasServices.update_secrets( + env.application, + service_name |> IO.inspect(label: "CreateEnvSecret - ServiceName"), + build_number |> IO.inspect(label: "CreateEnvSecret - build_number"), + [secret_name] + ) + + {:ok, Enum.map(secrets, fn {key, _value} -> key end)} + + {:error, :secret_exist} -> + {:error, :secret_exist} + + _ -> + {:error, :unexpected_response} end end + def update_environment_secrets(service_name, env_id, secrets) do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do - {:ok} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} + {:ok} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end - error -> error + + error -> + error end end def delete_environment_secrets(service_name, env_id, key) do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) + case get_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, current_secrets} -> case length(Map.keys(current_secrets)) do len when len <= 1 -> {:ok, partial_env} = Apps.fetch_env(env_id) + case Repo.preload(partial_env, deployment: [:build]) - |> Repo.preload([:application]) do - %{ application: app, deployment: %{ build: build }} when not is_nil(build) -> + |> Repo.preload([:application]) do + %{application: app, deployment: %{build: build}} when not is_nil(build) -> Lenra.OpenfaasServices.update_secrets(app, service_name, build.build_number, []) - {:ok, []} # TODO: Return all other secrets - _ -> {:error, :build_not_exist} + # TODO: Return all other secrets + {:ok, []} + + _ -> + {:error, :build_not_exist} end + case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do {:ok, _} -> {:ok, []} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end + _ -> case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} + {:ok, secrets} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} {:secret_not_found} -> {:error, :secret_not_found} _ -> {:error, :unexpected_response} end end - error -> error + + error -> + error end end end diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index 49dcdc32..f027eb16 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -56,17 +56,23 @@ defmodule Lenra.OpenfaasServices do function_name = get_function_name(service_name, build_number) url = "#{base_url}/system/function/#{function_name}" - body = Map.merge(ApplicationServices.generate_function_object( - function_name, - Apps.image_name(service_name, build_number), - %{ - @min_scale_label => @min_scale_default, - @max_scale_label => to_string(Subscriptions.get_max_replicas(app.id)), - @scale_factor_label => @scale_factor_default - } - ), %{ - "secrets" => secrets - }) |> Jason.encode!() |> IO.inspect(label: "OpenFaas Update Secret to") + body = + Map.merge( + ApplicationServices.generate_function_object( + function_name, + Apps.image_name(service_name, build_number), + %{ + @min_scale_label => @min_scale_default, + @max_scale_label => to_string(Subscriptions.get_max_replicas(app.id)), + @scale_factor_label => @scale_factor_default + } + ), + %{ + "secrets" => secrets + } + ) + |> Jason.encode!() + |> IO.inspect(label: "OpenFaas Update Secret to") Finch.build( :put, @@ -74,7 +80,8 @@ defmodule Lenra.OpenfaasServices do headers, body ) - |> Finch.request(FaasHttp, receive_timeout: 1000) |> IO.inspect(label: "OpenFaas Response") + |> Finch.request(FaasHttp, receive_timeout: 1000) + |> IO.inspect(label: "OpenFaas Response") |> response(:deploy_status) end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 0fb5eacb..32bacac6 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -35,7 +35,6 @@ defmodule LenraWeb.EnvsController do end end - def create(conn, params) do with {:ok, app} <- get_app_and_allow(conn, params), user <- LenraWeb.Auth.current_resource(conn), @@ -82,23 +81,34 @@ defmodule LenraWeb.EnvsController do {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> - case Enum.any?(secrets, fn (s) -> s == key end) do - false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, updated_secrets} -> conn |> reply(updated_secrets) - {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() # Should never happen - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() - end - true -> BusinessError.env_secret_already_exist_tuple() + case Enum.any?(secrets, fn s -> s == key end) do + false -> + case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, updated_secrets} -> conn |> reply(updated_secrets) + # Should never happen + {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + + true -> + BusinessError.env_secret_already_exist_tuple() end - {:error, :secret_not_found} -> case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets} -> conn |> reply(secrets) - {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() # This should never happen - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() - end - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + + {:error, :secret_not_found} -> + case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, secrets} -> conn |> reply(secrets) + # This should never happen + {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + + {:error, :kubernetes_error} -> + BusinessError.kubernetes_unexpected_response_tuple() + + {:error, :unexpected_response} -> + BusinessError.api_return_unexpected_response_tuple() end end end @@ -107,7 +117,7 @@ defmodule LenraWeb.EnvsController do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets } -> conn |> reply(secrets) + {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() diff --git a/libs/application_runner/lib/services/application_services.ex b/libs/application_runner/lib/services/application_services.ex index 762cf534..62db68a4 100644 --- a/libs/application_runner/lib/services/application_services.ex +++ b/libs/application_runner/lib/services/application_services.ex @@ -177,7 +177,8 @@ defmodule ApplicationRunner.ApplicationServices do %{ "image" => image_name, "service" => function_name, - "secrets" => Application.fetch_env!(:application_runner, :faas_secrets),#, + # , + "secrets" => Application.fetch_env!(:application_runner, :faas_secrets), # "environments" => ApiServices.get_environment_secrets(app.service_name, env.id), "requests" => %{ "cpu" => Application.fetch_env!(:application_runner, :faas_request_cpu), From 8f813b61c4c7afefedbe66d1caf29201e70d2d74 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Fri, 1 Mar 2024 14:16:47 +0100 Subject: [PATCH 14/24] fix some credo --- .../lib/lenra/kubernetes/api_services.ex | 35 ++++++++++--------- .../lib/lenra/services/openfaas_services.ex | 24 ++++++------- .../controllers/environment_controller.ex | 6 ++-- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 1651dc6a..f2e4647d 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -226,8 +226,8 @@ defmodule Lenra.Kubernetes.ApiServices do %{"data" => secret_data} = body {:ok, Enum.into(Enum.map(secret_data, fn {key, value} -> {key, Base.decode64!(value)} end), %{})} - {:error, error, _} -> - {:error, error |> IO.inspect(label: "Fetch error")} + {:error, error, _reason} -> + {:error, error} end end @@ -292,8 +292,8 @@ defmodule Lenra.Kubernetes.ApiServices do |> response(:secret) case secret_response do - {:ok, _} -> {:ok} - _ -> {:secret_not_found} + {:ok, _secret} -> {:ok} + _other -> {:secret_not_found} end end @@ -314,8 +314,8 @@ defmodule Lenra.Kubernetes.ApiServices do |> response(:secret) case secret_response do - {:ok, _} -> {:ok} - _ -> {:secret_not_found} + {:ok, _secret} -> {:ok} + _error -> {:secret_not_found} end end @@ -337,13 +337,13 @@ defmodule Lenra.Kubernetes.ApiServices do case create_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do {:ok, secrets} -> {:ok, partial_env} = Apps.fetch_env(env_id) - env = Repo.preload(partial_env, deployment: [:build]) |> Repo.preload([:application]) + env = partial_env |> Repo.preload(deployment: [:build]) |> Repo.preload([:application]) build_number = env.deployment.build.build_number Lenra.OpenfaasServices.update_secrets( env.application, - service_name |> IO.inspect(label: "CreateEnvSecret - ServiceName"), - build_number |> IO.inspect(label: "CreateEnvSecret - build_number"), + service_name, + build_number, [secret_name] ) @@ -352,7 +352,7 @@ defmodule Lenra.Kubernetes.ApiServices do {:error, :secret_exist} -> {:error, :secret_exist} - _ -> + _other -> {:error, :unexpected_response} end end @@ -366,7 +366,7 @@ defmodule Lenra.Kubernetes.ApiServices do case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do {:ok} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} {:secret_not_found} -> {:error, :secret_not_found} - _ -> {:error, :unexpected_response} + _other -> {:error, :unexpected_response} end error -> @@ -384,28 +384,29 @@ defmodule Lenra.Kubernetes.ApiServices do len when len <= 1 -> {:ok, partial_env} = Apps.fetch_env(env_id) - case Repo.preload(partial_env, deployment: [:build]) + case partial_env + |> Repo.preload(deployment: [:build]) |> Repo.preload([:application]) do %{application: app, deployment: %{build: build}} when not is_nil(build) -> Lenra.OpenfaasServices.update_secrets(app, service_name, build.build_number, []) # TODO: Return all other secrets {:ok, []} - _ -> + _other -> {:error, :build_not_exist} end case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok, _} -> {:ok, []} + {:ok, _secret} -> {:ok, []} {:secret_not_found} -> {:error, :secret_not_found} - _ -> {:error, :unexpected_response} + _other -> {:error, :unexpected_response} end - _ -> + _other -> case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do {:ok, secrets} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} {:secret_not_found} -> {:error, :secret_not_found} - _ -> {:error, :unexpected_response} + _other -> {:error, :unexpected_response} end end diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index f027eb16..281b7083 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -5,8 +5,8 @@ defmodule Lenra.OpenfaasServices do alias ApplicationRunner.ApplicationServices alias Lenra.Apps - alias Lenra.Subscriptions alias Lenra.Errors.TechnicalError + alias Lenra.Subscriptions alias LenraCommon.Errors require Logger @@ -57,22 +57,19 @@ defmodule Lenra.OpenfaasServices do url = "#{base_url}/system/function/#{function_name}" body = - Map.merge( - ApplicationServices.generate_function_object( - function_name, - Apps.image_name(service_name, build_number), - %{ - @min_scale_label => @min_scale_default, - @max_scale_label => to_string(Subscriptions.get_max_replicas(app.id)), - @scale_factor_label => @scale_factor_default - } - ), + ApplicationServices.generate_function_object( + function_name, + Apps.image_name(service_name, build_number), %{ - "secrets" => secrets + @min_scale_label => @min_scale_default, + @max_scale_label => to_string(Subscriptions.get_max_replicas(app.id)), + @scale_factor_label => @scale_factor_default } ) + |> Map.merge(%{ + "secrets" => secrets + }) |> Jason.encode!() - |> IO.inspect(label: "OpenFaas Update Secret to") Finch.build( :put, @@ -81,7 +78,6 @@ defmodule Lenra.OpenfaasServices do body ) |> Finch.request(FaasHttp, receive_timeout: 1000) - |> IO.inspect(label: "OpenFaas Response") |> response(:deploy_status) end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 32bacac6..ce611388 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -4,10 +4,10 @@ defmodule LenraWeb.EnvsController do use LenraWeb.Policy, module: LenraWeb.EnvsController.Policy - alias Lenra.{Apps} - alias Lenra.Kubernetes.ApiServices + alias Lenra.Apps alias Lenra.Errors.BusinessError - alias alias Lenra.Subscriptions + alias Lenra.Kubernetes.ApiServices + alias Lenra.Subscriptions alias Lenra.Subscriptions.Subscription defp get_app_and_allow(conn, %{"app_id" => app_id_str}) do From 72177a51e825a3f51dfc90e7f25bc153d4aa3e76 Mon Sep 17 00:00:00 2001 From: shiipou Date: Fri, 1 Mar 2024 16:58:32 +0100 Subject: [PATCH 15/24] fix(WIP): openfaas update Signed-off-by: shiipou --- .../lib/lenra/kubernetes/api_services.ex | 10 ++-- .../lib/lenra/services/openfaas_services.ex | 58 ++++++++++++------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index f2e4647d..5bfab2dc 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -397,16 +397,18 @@ defmodule Lenra.Kubernetes.ApiServices do end case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do + {:ok} -> {:ok, []} {:ok, _secret} -> {:ok, []} {:secret_not_found} -> {:error, :secret_not_found} - _other -> {:error, :unexpected_response} + # _other -> {:error, :unexpected_response} end _other -> - case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.drop(current_secrets, [key])) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} + secrets = Map.drop(current_secrets, [key]) + case update_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do + {:ok} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} {:secret_not_found} -> {:error, :secret_not_found} - _other -> {:error, :unexpected_response} + # _other -> {:error, :unexpected_response} end end diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index 281b7083..4ac5459c 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -54,31 +54,39 @@ defmodule Lenra.OpenfaasServices do def update_secrets(app, service_name, build_number, secrets \\ []) do {base_url, headers} = get_http_context() function_name = get_function_name(service_name, build_number) - url = "#{base_url}/system/function/#{function_name}" - - body = - ApplicationServices.generate_function_object( - function_name, - Apps.image_name(service_name, build_number), - %{ - @min_scale_label => @min_scale_default, - @max_scale_label => to_string(Subscriptions.get_max_replicas(app.id)), - @scale_factor_label => @scale_factor_default - } - ) - |> Map.merge(%{ - "secrets" => secrets - }) - |> Jason.encode!() + url = "#{base_url}/system/function/#{function_name}" |> IO.inspect(label: "Url") - Finch.build( - :put, + function = case Finch.build( + :get, url, - headers, - body + headers ) |> Finch.request(FaasHttp, receive_timeout: 1000) - |> response(:deploy_status) + |> response(:get_function) do + {:ok, result} -> result + _other -> nil + end + + if(function != nil) do + url = "#{base_url}/system/functions" |> IO.inspect(label: "Url") + + body = function |> IO.inspect(label: "function") + |> Map.merge(%{ + "secrets" => secrets + }) + |> Jason.encode!() + + Finch.build( + :put, + url, + headers, + body + ) + |> Finch.request(FaasHttp, receive_timeout: 1000) + |> response(:deploy_status) + else + TechnicalError.openfaas_not_reachable_tuple() + end end def delete_app_openfaas(service_name, build_number) do @@ -110,6 +118,14 @@ defmodule Lenra.OpenfaasServices do available_replicas != 0 && available_replicas != nil end + defp response( + {:ok, %Finch.Response{status: status_code, body: body}}, + :get_function + ) + when status_code in [200, 202] do + Jason.decode!(body) + end + defp response({:ok, %Finch.Response{status: status_code}}, :delete_app) when status_code in [200, 202] do {:ok, status_code} From 1efe68b20712aa756868f01b95e876df47bae3e2 Mon Sep 17 00:00:00 2001 From: shiipou Date: Fri, 1 Mar 2024 17:24:19 +0100 Subject: [PATCH 16/24] fix: Openfaas update now work Signed-off-by: shiipou --- apps/lenra/lib/lenra/kubernetes/api_services.ex | 3 +-- apps/lenra/lib/lenra/services/openfaas_services.ex | 2 +- .../lib/lenra_web/controllers/environment_controller.ex | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 5bfab2dc..3cdf1b6c 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -341,7 +341,6 @@ defmodule Lenra.Kubernetes.ApiServices do build_number = env.deployment.build.build_number Lenra.OpenfaasServices.update_secrets( - env.application, service_name, build_number, [secret_name] @@ -388,7 +387,7 @@ defmodule Lenra.Kubernetes.ApiServices do |> Repo.preload(deployment: [:build]) |> Repo.preload([:application]) do %{application: app, deployment: %{build: build}} when not is_nil(build) -> - Lenra.OpenfaasServices.update_secrets(app, service_name, build.build_number, []) + Lenra.OpenfaasServices.update_secrets(service_name, build.build_number, []) # TODO: Return all other secrets {:ok, []} diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index 4ac5459c..48326901 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -51,7 +51,7 @@ defmodule Lenra.OpenfaasServices do |> response(:deploy_status) end - def update_secrets(app, service_name, build_number, secrets \\ []) do + def update_secrets(service_name, build_number, secrets \\ []) do {base_url, headers} = get_http_context() function_name = get_function_name(service_name, build_number) url = "#{base_url}/system/function/#{function_name}" |> IO.inspect(label: "Url") diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index ce611388..eb5b3aa4 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -158,7 +158,7 @@ defmodule LenraWeb.EnvsController.Policy do def authorize(:list_secrets, %User{id: user_id}, %App{creator_id: user_id}), do: true def authorize(:create_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true - # def authorize(:update_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true + def authorize(:update_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true def authorize(:delete_secret, %User{id: user_id}, %App{creator_id: user_id}), do: true # credo:disable-for-next-line Credo.Check.Readability.StrictModuleLayout From 05091e9220974437bca729ef3da939d0dea475d3 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 2 Apr 2024 11:18:16 +0200 Subject: [PATCH 17/24] Return error on kubernetes not configured --- .../lib/lenra/kubernetes/api_services.ex | 66 +++++++++++-------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 3cdf1b6c..044fcebc 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -4,6 +4,7 @@ defmodule Lenra.Kubernetes.ApiServices do Curently only support the request to create a new pipeline. """ + alias ApplicationRunner.Errors.TechnicalError alias Lenra.Apps alias Lenra.Apps.Build alias Lenra.Apps.Deployment @@ -209,25 +210,29 @@ defmodule Lenra.Kubernetes.ApiServices do kubernetes_api_url = Application.fetch_env!(:lenra, :kubernetes_api_url) kubernetes_api_token = Application.fetch_env!(:lenra, :kubernetes_api_token) - secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" - - headers = [ - {"Authorization", "Bearer #{kubernetes_api_token}"}, - {"content-type", "application/json"} - ] - - secret_response = - Finch.build(:get, secrets_url, headers) - |> Finch.request(PipelineHttp) - |> response(:secret) - - case secret_response do - {:ok, body} -> - %{"data" => secret_data} = body - {:ok, Enum.into(Enum.map(secret_data, fn {key, value} -> {key, Base.decode64!(value)} end), %{})} - - {:error, error, _reason} -> - {:error, error} + if kubernetes_api_url == nil || kubernetes_api_token == nil do + TechnicalError.error_500_tuple("Kubernetes configured improperly.") + else + secrets_url = "#{kubernetes_api_url}/api/v1/namespaces/#{namespace}/secrets/#{secret_name}" + + headers = [ + {"Authorization", "Bearer #{kubernetes_api_token}"}, + {"content-type", "application/json"} + ] + + secret_response = + Finch.build(:get, secrets_url, headers) + |> Finch.request(PipelineHttp) + |> response(:secret) + + case secret_response do + {:ok, body} -> + %{"data" => secret_data} = body + {:ok, Enum.into(Enum.map(secret_data, fn {key, value} -> {key, Base.decode64!(value)} end), %{})} + + {:error, error, _reason} -> + {:error, error} + end end end @@ -396,18 +401,27 @@ defmodule Lenra.Kubernetes.ApiServices do end case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok} -> {:ok, []} - {:ok, _secret} -> {:ok, []} - {:secret_not_found} -> {:error, :secret_not_found} - # _other -> {:error, :unexpected_response} + {:ok} -> + {:ok, []} + + {:ok, _secret} -> + {:ok, []} + + {:secret_not_found} -> + {:error, :secret_not_found} + # _other -> {:error, :unexpected_response} end _other -> secrets = Map.drop(current_secrets, [key]) + case update_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do - {:ok} -> {:ok, Enum.map(secrets, fn ({key, _value}) -> key end)} - {:secret_not_found} -> {:error, :secret_not_found} - # _other -> {:error, :unexpected_response} + {:ok} -> + {:ok, Enum.map(secrets, fn {key, _value} -> key end)} + + {:secret_not_found} -> + {:error, :secret_not_found} + # _other -> {:error, :unexpected_response} end end From 8a1f1763e04eba8d5e42ced4bc500ed47ecccd36 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 2 Apr 2024 13:47:57 +0200 Subject: [PATCH 18/24] Fix credo --- apps/lenra/lib/lenra/kubernetes/api_services.ex | 2 +- apps/lenra/lib/lenra/services/openfaas_services.ex | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 044fcebc..2001342f 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -5,12 +5,12 @@ defmodule Lenra.Kubernetes.ApiServices do """ alias ApplicationRunner.Errors.TechnicalError + alias Ecto alias Lenra.Apps alias Lenra.Apps.Build alias Lenra.Apps.Deployment alias Lenra.Kubernetes.StatusDynSup alias Lenra.Repo - alias Ecto require Logger @doc """ diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index 48326901..85fadc6a 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -54,7 +54,7 @@ defmodule Lenra.OpenfaasServices do def update_secrets(service_name, build_number, secrets \\ []) do {base_url, headers} = get_http_context() function_name = get_function_name(service_name, build_number) - url = "#{base_url}/system/function/#{function_name}" |> IO.inspect(label: "Url") + url = "#{base_url}/system/function/#{function_name}" function = case Finch.build( :get, @@ -67,10 +67,10 @@ defmodule Lenra.OpenfaasServices do _other -> nil end - if(function != nil) do - url = "#{base_url}/system/functions" |> IO.inspect(label: "Url") + if function != nil do + url = "#{base_url}/system/functions" - body = function |> IO.inspect(label: "function") + body = function |> Map.merge(%{ "secrets" => secrets }) From 5a549cab84b0e330e19e7aabb03e3325fa199263 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 2 Apr 2024 13:52:22 +0200 Subject: [PATCH 19/24] fix format --- .../lib/lenra/services/openfaas_services.ex | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/lenra/lib/lenra/services/openfaas_services.ex b/apps/lenra/lib/lenra/services/openfaas_services.ex index 85fadc6a..8ac81e7c 100644 --- a/apps/lenra/lib/lenra/services/openfaas_services.ex +++ b/apps/lenra/lib/lenra/services/openfaas_services.ex @@ -56,21 +56,23 @@ defmodule Lenra.OpenfaasServices do function_name = get_function_name(service_name, build_number) url = "#{base_url}/system/function/#{function_name}" - function = case Finch.build( - :get, - url, - headers - ) - |> Finch.request(FaasHttp, receive_timeout: 1000) - |> response(:get_function) do - {:ok, result} -> result - _other -> nil - end + function = + case Finch.build( + :get, + url, + headers + ) + |> Finch.request(FaasHttp, receive_timeout: 1000) + |> response(:get_function) do + {:ok, result} -> result + _other -> nil + end if function != nil do url = "#{base_url}/system/functions" - body = function + body = + function |> Map.merge(%{ "secrets" => secrets }) From 3cf53fb9531d1b3a80ebb028d71633f4f25cb0e2 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 2 Apr 2024 14:29:35 +0200 Subject: [PATCH 20/24] fix credo --- .../lib/lenra/kubernetes/api_services.ex | 6 +-- .../controllers/environment_controller.ex | 48 +++++++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 2001342f..e77aff73 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -382,8 +382,7 @@ defmodule Lenra.Kubernetes.ApiServices do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case get_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok, current_secrets} -> + with {:ok, current_secrets} <- get_k8s_secret(secret_name, kubernetes_apps_namespace) do case length(Map.keys(current_secrets)) do len when len <= 1 -> {:ok, partial_env} = Apps.fetch_env(env_id) @@ -424,9 +423,6 @@ defmodule Lenra.Kubernetes.ApiServices do # _other -> {:error, :unexpected_response} end end - - error -> - error end end end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index eb5b3aa4..d19a6c51 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -81,28 +81,10 @@ defmodule LenraWeb.EnvsController do {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> - case Enum.any?(secrets, fn s -> s == key end) do - false -> - case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, updated_secrets} -> conn |> reply(updated_secrets) - # Should never happen - {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() - end - - true -> - BusinessError.env_secret_already_exist_tuple() - end + handle_secret_found(conn, secrets, app, environment, key, value) {:error, :secret_not_found} -> - case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets} -> conn |> reply(secrets) - # This should never happen - {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() - end + handle_secret_not_found(conn, app, environment, key, value) {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() @@ -113,6 +95,32 @@ defmodule LenraWeb.EnvsController do end end + defp handle_secret_found(conn, secrets, app, environment, key, value) do + case Enum.any?(secrets, fn s -> s == key end) do + false -> + case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, updated_secrets} -> conn |> reply(updated_secrets) + # Should never happen + {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + + true -> + BusinessError.env_secret_already_exist_tuple() + end + end + + defp handle_secret_not_found(conn, app, environment, key, value) do + case ApiServices.create_environment_secrets(app.service_name, environment.id, %{key => value}) do + {:ok, secrets} -> conn |> reply(secrets) + # This should never happen + {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() + {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + end + end + def update_secret(conn, %{"env_id" => env_id, "key" => key, "value" => value} = params) do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do From e5d0ece65a0491ed364a522e75a8f4b2c0b57f0b Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 2 Apr 2024 16:57:32 +0200 Subject: [PATCH 21/24] fix credo --- .../lib/lenra/kubernetes/api_services.ex | 88 ++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index e77aff73..2cebb1c9 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -383,46 +383,54 @@ defmodule Lenra.Kubernetes.ApiServices do kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) with {:ok, current_secrets} <- get_k8s_secret(secret_name, kubernetes_apps_namespace) do - case length(Map.keys(current_secrets)) do - len when len <= 1 -> - {:ok, partial_env} = Apps.fetch_env(env_id) - - case partial_env - |> Repo.preload(deployment: [:build]) - |> Repo.preload([:application]) do - %{application: app, deployment: %{build: build}} when not is_nil(build) -> - Lenra.OpenfaasServices.update_secrets(service_name, build.build_number, []) - # TODO: Return all other secrets - {:ok, []} - - _other -> - {:error, :build_not_exist} - end - - case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok} -> - {:ok, []} - - {:ok, _secret} -> - {:ok, []} - - {:secret_not_found} -> - {:error, :secret_not_found} - # _other -> {:error, :unexpected_response} - end - - _other -> - secrets = Map.drop(current_secrets, [key]) - - case update_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do - {:ok} -> - {:ok, Enum.map(secrets, fn {key, _value} -> key end)} - - {:secret_not_found} -> - {:error, :secret_not_found} - # _other -> {:error, :unexpected_response} - end - end + case length(Map.keys(current_secrets)) do + len when len <= 1 -> + handle_delete_when_one_or_less_secrets(env_id, secret_name, kubernetes_apps_namespace, service_name) + + _other -> + handle_delete_when_multiple_secrets(current_secrets, key, secret_name, kubernetes_apps_namespace) + end + end + end + + defp handle_delete_when_one_or_less_secrets(env_id, secret_name, kubernetes_apps_namespace, service_name) do + {:ok, partial_env} = Apps.fetch_env(env_id) + + case partial_env + |> Repo.preload(deployment: [:build]) + |> Repo.preload([:application]) do + %{application: app, deployment: %{build: build}} when not is_nil(build) -> + Lenra.OpenfaasServices.update_secrets(service_name, build.build_number, []) + # TODO: Return all other secrets + {:ok, []} + + _other -> + {:error, :build_not_exist} + end + + case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do + {:ok} -> + {:ok, []} + + {:ok, _secret} -> + {:ok, []} + + {:secret_not_found} -> + {:error, :secret_not_found} + # _other -> {:error, :unexpected_response} + end + end + + defp handle_delete_when_multiple_secrets(current_secrets, key, secret_name, kubernetes_apps_namespace) do + secrets = Map.drop(current_secrets, [key]) + + case update_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do + {:ok} -> + {:ok, Enum.map(secrets, fn {key, _value} -> key end)} + + {:secret_not_found} -> + {:error, :secret_not_found} + # _other -> {:error, :unexpected_response} end end end From 479052525d89b18be9c83e246ef96592bee20aa7 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Tue, 2 Apr 2024 17:01:23 +0200 Subject: [PATCH 22/24] fix credo --- apps/lenra/lib/lenra/kubernetes/api_services.ex | 5 ++++- apps/lenra_web/lib/lenra_web/app_adapter.ex | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 2cebb1c9..35f15281 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -399,7 +399,10 @@ defmodule Lenra.Kubernetes.ApiServices do case partial_env |> Repo.preload(deployment: [:build]) |> Repo.preload([:application]) do - %{application: app, deployment: %{build: build}} when not is_nil(build) -> + %{application: _app, deployment: %{build: nil}} -> + {:error, :build_not_exist} + + %{application: _app, deployment: %{build: build}} -> Lenra.OpenfaasServices.update_secrets(service_name, build.build_number, []) # TODO: Return all other secrets {:ok, []} diff --git a/apps/lenra_web/lib/lenra_web/app_adapter.ex b/apps/lenra_web/lib/lenra_web/app_adapter.ex index 3a3a9e63..e31917e9 100644 --- a/apps/lenra_web/lib/lenra_web/app_adapter.ex +++ b/apps/lenra_web/lib/lenra_web/app_adapter.ex @@ -126,7 +126,9 @@ defmodule LenraWeb.AppAdapter do }), do: true - def authorize(:join_app, user, app) when not is_nil(user) do + def authorize(:join_app, nil, _app), do: false + + def authorize(:join_app, user, app) do case Apps.fetch_user_env_access( environment_id: app.main_env.environment.id, user_id: user.id From f14877a4b87e9dae520e01c4ff6feef91144579d Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Wed, 29 May 2024 11:33:04 +0200 Subject: [PATCH 23/24] fix dialyzer --- .../lib/lenra/kubernetes/api_services.ex | 54 ++++++------------- .../controllers/environment_controller.ex | 24 ++++----- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/apps/lenra/lib/lenra/kubernetes/api_services.ex b/apps/lenra/lib/lenra/kubernetes/api_services.ex index 35f15281..8651e556 100644 --- a/apps/lenra/lib/lenra/kubernetes/api_services.ex +++ b/apps/lenra/lib/lenra/kubernetes/api_services.ex @@ -55,10 +55,10 @@ defmodule Lenra.Kubernetes.ApiServices do }) case secret_response do - {:ok} -> + {:ok, _data} -> :ok - :secret_exist -> + {:error, :secret_exist} -> if retry < 1 do create_pipeline( service_name, @@ -297,8 +297,8 @@ defmodule Lenra.Kubernetes.ApiServices do |> response(:secret) case secret_response do - {:ok, _secret} -> {:ok} - _other -> {:secret_not_found} + {:ok, secret} -> {:ok, secret} + _other -> {:error, :secret_not_found} end end @@ -319,8 +319,8 @@ defmodule Lenra.Kubernetes.ApiServices do |> response(:secret) case secret_response do - {:ok, _secret} -> {:ok} - _error -> {:secret_not_found} + {:ok, _secret} -> {:ok, _secret} + _error -> {:error, :secret_not_found} end end @@ -328,10 +328,8 @@ defmodule Lenra.Kubernetes.ApiServices do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case get_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok, secrets} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} - {:error, :secret_not_found} -> {:error, :secret_not_found} - {:error, error} -> {:error, error} + with {:ok, secrets} <- get_k8s_secret(secret_name, kubernetes_apps_namespace) do + {:ok, Enum.map(secrets, fn {key, _value} -> key end)} end end @@ -365,16 +363,11 @@ defmodule Lenra.Kubernetes.ApiServices do secret_name = "#{service_name}-secret-#{env_id}" kubernetes_apps_namespace = Application.fetch_env!(:lenra, :kubernetes_apps_namespace) - case get_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok, current_secrets} -> - case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do - {:ok} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} - {:secret_not_found} -> {:error, :secret_not_found} - _other -> {:error, :unexpected_response} - end - - error -> - error + with {:ok, current_secrets} <- get_k8s_secret(secret_name, kubernetes_apps_namespace) do + case update_k8s_secret(secret_name, kubernetes_apps_namespace, Map.merge(current_secrets, secrets)) do + {:ok, _secret} -> {:ok, Enum.map(secrets, fn {key, _value} -> key end)} + {:error, :secret_not_found} -> {:error, :secret_not_found} + end end end @@ -411,29 +404,16 @@ defmodule Lenra.Kubernetes.ApiServices do {:error, :build_not_exist} end - case delete_k8s_secret(secret_name, kubernetes_apps_namespace) do - {:ok} -> - {:ok, []} - - {:ok, _secret} -> - {:ok, []} - - {:secret_not_found} -> - {:error, :secret_not_found} - # _other -> {:error, :unexpected_response} + with {:ok, _secret} <- delete_k8s_secret(secret_name, kubernetes_apps_namespace) do + {:ok, []} end end defp handle_delete_when_multiple_secrets(current_secrets, key, secret_name, kubernetes_apps_namespace) do secrets = Map.drop(current_secrets, [key]) - case update_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do - {:ok} -> - {:ok, Enum.map(secrets, fn {key, _value} -> key end)} - - {:secret_not_found} -> - {:error, :secret_not_found} - # _other -> {:error, :unexpected_response} + with {:ok, _secret} <- update_k8s_secret(secret_name, kubernetes_apps_namespace, secrets) do + {:ok, Enum.map(secrets, fn {key, _value} -> key end)} end end end diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index d19a6c51..270a61cf 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -70,7 +70,7 @@ defmodule LenraWeb.EnvsController do case ApiServices.get_environment_secrets(app.service_name, environment.id) do {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_not_found} -> conn |> reply([]) - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, error} -> BusinessError.api_return_unexpected_response_tuple(error) end end @@ -86,11 +86,11 @@ defmodule LenraWeb.EnvsController do {:error, :secret_not_found} -> handle_secret_not_found(conn, app, environment, key, value) - {:error, :kubernetes_error} -> - BusinessError.kubernetes_unexpected_response_tuple() + # {:error, :kubernetes_error} -> + # BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> - BusinessError.api_return_unexpected_response_tuple() + # {:error, :unexpected_response} -> + # BusinessError.api_return_unexpected_response_tuple() end end end @@ -102,8 +102,8 @@ defmodule LenraWeb.EnvsController do {:ok, updated_secrets} -> conn |> reply(updated_secrets) # Should never happen {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + # {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end true -> @@ -116,7 +116,7 @@ defmodule LenraWeb.EnvsController do {:ok, secrets} -> conn |> reply(secrets) # This should never happen {:error, :secret_exist} -> BusinessError.env_secret_already_exist_tuple() - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end end @@ -127,8 +127,8 @@ defmodule LenraWeb.EnvsController do case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + # {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end end end @@ -139,8 +139,8 @@ defmodule LenraWeb.EnvsController do case ApiServices.delete_environment_secrets(app.service_name, environment.id, key) do {:ok, secrets} -> conn |> reply(secrets) {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() + # {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() end end end From 9ea41a6b3724fbf4fd0b47d0631116cf3bf071f1 Mon Sep 17 00:00:00 2001 From: "jonas.martinez" Date: Wed, 29 May 2024 11:42:03 +0200 Subject: [PATCH 24/24] fix format --- .../controllers/environment_controller.ex | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex index 270a61cf..865983dc 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/environment_controller.ex @@ -85,12 +85,6 @@ defmodule LenraWeb.EnvsController do {:error, :secret_not_found} -> handle_secret_not_found(conn, app, environment, key, value) - - # {:error, :kubernetes_error} -> - # BusinessError.kubernetes_unexpected_response_tuple() - - # {:error, :unexpected_response} -> - # BusinessError.api_return_unexpected_response_tuple() end end end @@ -99,11 +93,12 @@ defmodule LenraWeb.EnvsController do case Enum.any?(secrets, fn s -> s == key end) do false -> case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, updated_secrets} -> conn |> reply(updated_secrets) + {:ok, updated_secrets} -> + conn |> reply(updated_secrets) + # Should never happen - {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - # {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + {:error, :secret_not_found} -> + BusinessError.env_secret_not_found_tuple() end true -> @@ -125,10 +120,11 @@ defmodule LenraWeb.EnvsController do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.update_environment_secrets(app.service_name, environment.id, %{key => value}) do - {:ok, secrets} -> conn |> reply(secrets) - {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - # {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + {:ok, secrets} -> + conn |> reply(secrets) + + {:error, :secret_not_found} -> + BusinessError.env_secret_not_found_tuple() end end end @@ -137,10 +133,11 @@ defmodule LenraWeb.EnvsController do with {:ok, app} <- get_app_and_allow(conn, params), {:ok, environment} <- Apps.fetch_env(env_id) do case ApiServices.delete_environment_secrets(app.service_name, environment.id, key) do - {:ok, secrets} -> conn |> reply(secrets) - {:error, :secret_not_found} -> BusinessError.env_secret_not_found_tuple() - # {:error, :kubernetes_error} -> BusinessError.kubernetes_unexpected_response_tuple() - # {:error, :unexpected_response} -> BusinessError.api_return_unexpected_response_tuple() + {:ok, secrets} -> + conn |> reply(secrets) + + {:error, :secret_not_found} -> + BusinessError.env_secret_not_found_tuple() end end end