Reviewed-on: https://git.nikos.gg/prymn/prymn/pulls/9 Co-authored-by: Nikos Papadakis <nikos@papadakis.xyz> Co-committed-by: Nikos Papadakis <nikos@papadakis.xyz>
199 lines
5.6 KiB
Elixir
199 lines
5.6 KiB
Elixir
defmodule Prymn.Apps.Wordpress do
|
|
use Ecto.Schema
|
|
|
|
import Ecto.Changeset
|
|
alias Prymn.Apps.App
|
|
alias Prymn.Agents
|
|
alias PrymnProto.Prymn.{ExecRequest, ExecResponse}
|
|
|
|
@primary_key false
|
|
embedded_schema do
|
|
field :path, :string
|
|
field :db_host, :string
|
|
field :db_name, :string
|
|
field :db_user, :string
|
|
field :db_pass, :string
|
|
field :admin_username, :string
|
|
field :admin_email, :string
|
|
end
|
|
|
|
def changeset(app, attrs) do
|
|
app
|
|
|> cast(attrs, [
|
|
:path,
|
|
:db_host,
|
|
:db_name,
|
|
:db_user,
|
|
:db_pass,
|
|
:admin_username,
|
|
:admin_email
|
|
])
|
|
|> validate_required([
|
|
:path,
|
|
:db_user,
|
|
:db_host,
|
|
:db_user,
|
|
:db_pass,
|
|
:admin_email,
|
|
:admin_username
|
|
])
|
|
end
|
|
|
|
@max_steps 6
|
|
|
|
# TODO: We need a mechanism to drive some messages to the pubsub, maybe using Health:
|
|
# Health.change_task(%Health.Task{
|
|
# key: "create_db_user",
|
|
# message: "Creating db user...",
|
|
# curr_step: 0,
|
|
# max_steps: 5
|
|
# })
|
|
# |> Health.update_and_broadcast()
|
|
|
|
def deploy(%App{type: "wordpress"} = app, agent, notify_fun) do
|
|
# TODO: Run sanity checks
|
|
# e.g Database does not exist, domain does not exist, etc.
|
|
deploy(app, agent, notify_fun, 1)
|
|
end
|
|
|
|
defp deploy(%App{wordpress: %__MODULE__{} = wp} = app, agent, notify_fun, 1 = step) do
|
|
# TODO: We need a mechanism to wait for the agent to connect before proceeding,
|
|
# this is executed faster than the connection (which happens on deploy_app in Worker)
|
|
|
|
Agents.exec(agent, %ExecRequest{
|
|
user: "root",
|
|
program: "mysql",
|
|
args: [
|
|
"-e",
|
|
# TODO: Sanitize the string to protect from injection
|
|
"create user '#{wp.db_user}'@'#{wp.db_host}' identified by '#{wp.db_pass}';"
|
|
]
|
|
})
|
|
|> then(&get_results/1)
|
|
|> case do
|
|
{_, _, exit_code} = data when exit_code != 0 ->
|
|
notify_fun.(:error, data, 1 / 5 * 100)
|
|
|
|
data ->
|
|
notify_fun.(:progress, data, step / @max_steps * 100)
|
|
deploy(app, agent, notify_fun, step + 1)
|
|
end
|
|
end
|
|
|
|
defp deploy(%App{wordpress: %__MODULE__{} = wp} = app, agent, notify_fun, 2 = step) do
|
|
Agents.exec(agent, %ExecRequest{
|
|
user: "root",
|
|
program: "mysql",
|
|
args: [
|
|
"-e",
|
|
# TODO: Sanitize the string to protect from injection
|
|
"grant all privileges on #{wp.db_name}.* to '#{wp.db_user}'@'#{wp.db_host}';"
|
|
]
|
|
})
|
|
|> then(&get_results/1)
|
|
|> case do
|
|
{_, _, exit_code} = data when exit_code != 0 ->
|
|
notify_fun.(:error, data, step / @max_steps * 100)
|
|
|
|
data ->
|
|
notify_fun.(:progress, data, step / @max_steps * 100)
|
|
deploy(app, agent, notify_fun, step + 1)
|
|
end
|
|
end
|
|
|
|
defp deploy(%App{wordpress: %__MODULE__{} = wp} = app, agent, notify_fun, 3 = step) do
|
|
Agents.exec(agent, %ExecRequest{
|
|
user: "vagrant",
|
|
program: "wp",
|
|
args: ["core", "download", "--path=#{wp.path}"]
|
|
})
|
|
|> then(&get_results/1)
|
|
|> case do
|
|
{_, _, exit_code} = data when exit_code != 0 ->
|
|
notify_fun.(:error, data, step / @max_steps * 100)
|
|
|
|
data ->
|
|
notify_fun.(:progress, data, step / @max_steps * 100)
|
|
deploy(app, agent, notify_fun, step + 1)
|
|
end
|
|
end
|
|
|
|
defp deploy(%App{wordpress: %__MODULE__{} = wp} = app, agent, notify_fun, 4 = step) do
|
|
Agents.exec(agent, %ExecRequest{
|
|
user: "vagrant",
|
|
program: "wp",
|
|
args: [
|
|
"config",
|
|
"create",
|
|
"--path=#{wp.path}",
|
|
"--dbhost=#{wp.db_host}",
|
|
"--dbname=#{wp.db_name}",
|
|
"--dbuser=#{wp.db_user}",
|
|
"--dbpass=#{wp.db_pass}"
|
|
]
|
|
})
|
|
|> then(&get_results/1)
|
|
|> case do
|
|
{_, _, exit_code} = data when exit_code != 0 ->
|
|
notify_fun.(:error, data, step / @max_steps * 100)
|
|
|
|
data ->
|
|
notify_fun.(:progress, data, step / @max_steps * 100)
|
|
deploy(app, agent, notify_fun, step + 1)
|
|
end
|
|
end
|
|
|
|
defp deploy(%App{wordpress: %__MODULE__{} = wp} = app, agent, notify_fun, 5 = step) do
|
|
Agents.exec(agent, %ExecRequest{
|
|
user: "vagrant",
|
|
program: "wp",
|
|
args: ["db", "create", "--path=#{wp.path}"]
|
|
})
|
|
|> then(&get_results/1)
|
|
|> case do
|
|
{_, _, exit_code} = data when exit_code != 0 ->
|
|
notify_fun.(:error, data, step / @max_steps * 100)
|
|
|
|
data ->
|
|
notify_fun.(:progress, data, step / @max_steps * 100)
|
|
deploy(app, agent, notify_fun, step + 1)
|
|
end
|
|
end
|
|
|
|
defp deploy(%App{name: name, wordpress: %__MODULE__{} = wp}, agent, notify_fun, 6 = step) do
|
|
Agents.exec(agent, %ExecRequest{
|
|
user: "vagrant",
|
|
program: "wp",
|
|
args: [
|
|
"core",
|
|
"install",
|
|
"--path=#{wp.path}",
|
|
"--url=http://site.test",
|
|
"--title=#{name}",
|
|
"--admin_user=#{wp.admin_username}",
|
|
"--admin_email=#{wp.admin_email}"
|
|
]
|
|
})
|
|
|> then(&get_results/1)
|
|
|> case do
|
|
{_, _, exit_code} = data when exit_code != 0 ->
|
|
notify_fun.(:error, data, step / @max_steps * 100)
|
|
|
|
data ->
|
|
notify_fun.(:complete, data, step / @max_steps * 100)
|
|
end
|
|
end
|
|
|
|
defp get_results(stream) do
|
|
Enum.reduce_while(stream, {"", "", nil}, fn
|
|
{:ok, %ExecResponse{out: {:exit_code, exit_code}}}, {stdout, stderr, _} ->
|
|
{:halt, {stdout, stderr, exit_code}}
|
|
|
|
{:ok, %ExecResponse{out: {:stdout, stdout}}}, {acc_stdout, stderr, exit_code} ->
|
|
{:cont, {acc_stdout <> stdout, stderr, exit_code}}
|
|
|
|
{:ok, %ExecResponse{out: {:stderr, stderr}}}, {stdout, acc_stderr, exit_code} ->
|
|
{:cont, {stdout, acc_stderr <> stderr, exit_code}}
|
|
end)
|
|
end
|
|
end
|