-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from SmartColumbusOS/composing
Composing
- Loading branch information
Showing
28 changed files
with
562 additions
and
411 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,23 @@ | ||
use Mix.Config | ||
|
||
config :divo, | ||
divo: [ | ||
kafka: %{ | ||
image: "wurstmeister/kafka:latest", | ||
env: [ | ||
val1: "foo", | ||
val2: "bar" | ||
], | ||
ports: [ | ||
{9092, 9092} | ||
] | ||
}, | ||
redis: %{ | ||
image: "redis:5.0.3", | ||
command: "redis start --foreground", | ||
ports: [ | ||
{6379, 6379} | ||
], | ||
volumes: [ | ||
{"/tmp", "/opt/redis"} | ||
] | ||
divo: %{ | ||
version: "3.4", | ||
services: %{ | ||
redis: %{ | ||
image: "redis:5.0.3", | ||
command: ["redis", "start", "--foreground"], | ||
ports: ["2181:2181"], | ||
volumes: ["/tmp:/opt/redis"] | ||
}, | ||
kafka: %{ | ||
image: "wurstmeister/kafka", | ||
depends_on: ["zookeeper"], | ||
ports: ["9094:9094"], | ||
environment: [ | ||
"VAL1=foo", | ||
"VAL2=bar" | ||
] | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,28 @@ | ||
use Mix.Config | ||
|
||
config :divo, | ||
divo: [ | ||
busybox: %{ | ||
image: "busybox:latest", | ||
env: [ | ||
val1: "foo", | ||
val2: "bar" | ||
], | ||
ports: [ | ||
{9092, 9092} | ||
], | ||
command: "ls", | ||
wait_for: %{ | ||
log: "home", | ||
dwell: 400 | ||
divo: %{ | ||
version: "3.4", | ||
services: %{ | ||
busybox: %{ | ||
image: "busybox:latest", | ||
environment: [ | ||
"VAL1=foo", | ||
"VAL2=bar" | ||
], | ||
ports: ["8888:8888"], | ||
command: "sleep 1000", | ||
healthcheck: %{test: ["CMD-SHELL", "ls / | grep home || exit 1"]} | ||
}, | ||
alpine: %{ | ||
image: "alpine:latest", | ||
environment: [ | ||
"VAL1=foo", | ||
"VAL2=bar" | ||
], | ||
ports: ["5432:5432"], | ||
command: ~S{ls /home && echo "Yodel"} | ||
} | ||
}, | ||
alpine: %{ | ||
image: "alpine:latest", | ||
env: [ | ||
val1: "foo", | ||
val2: "bar" | ||
], | ||
ports: [ | ||
{9092, 9092} | ||
], | ||
command: ~S{ls /home && echo "Yodel"} | ||
} | ||
] | ||
}, | ||
divo_wait: [dwell: 700, max_tries: 50] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,43 @@ | ||
defmodule Divo do | ||
@moduledoc false | ||
@moduledoc """ | ||
A library for incorporating docker-compose files or | ||
compose-compliant map structures defined in application | ||
config as dependency orchestration and management for | ||
integration testing Elixir apps with external services | ||
represented by the container services managed by divo. | ||
""" | ||
|
||
defdelegate run(opts), to: Divo.Compose, as: :run | ||
defdelegate stop(), to: Divo.Compose, as: :stop | ||
defdelegate kill(), to: Divo.Compose, as: :kill | ||
|
||
@doc """ | ||
Implements a macro for including directly in integration | ||
test files. Add `use Divo` to an integration test file to | ||
automatically add the Start and Kill commands for your | ||
dependent service definitions to a `setup_all` block of | ||
your tests. | ||
""" | ||
defmacro __using__(opts \\ []) do | ||
auto_start = Keyword.get(opts, :auto_start, true) | ||
|
||
quote do | ||
import Divo.Compose | ||
|
||
setup_all do | ||
Divo.Compose.run(unquote(opts)) | ||
|
||
app = Mix.Project.config() |> Keyword.get(:app) | ||
if unquote(auto_start), do: Application.ensure_all_started(app) | ||
|
||
on_exit(fn -> | ||
if unquote(auto_start), do: Application.stop(app) | ||
|
||
Divo.Compose.kill() | ||
end) | ||
|
||
:ok | ||
end | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
defmodule Divo.Compose do | ||
@moduledoc """ | ||
Implements the basic docker-compose commands for running from | ||
your mix tasks. Run creates and starts the container services. Stop | ||
will only stop the containers but leave them present on the system | ||
for debugging and introspection if needed. Kill will stop any running | ||
containers and remove all containers regardless of their current state. | ||
These operations only apply to services managed by Divo, i.e. defined in | ||
your Mix.env file under the :myapp, :divo key. | ||
""" | ||
require Logger | ||
alias Divo.{File, Helper, Validate} | ||
|
||
def run(opts \\ []) do | ||
services = get_services(opts) | ||
|
||
(["up", "--detach"] ++ services) | ||
|> execute() | ||
|
||
await() | ||
end | ||
|
||
def stop() do | ||
execute("stop") | ||
end | ||
|
||
def kill() do | ||
execute("down") | ||
end | ||
|
||
defp execute(action) do | ||
app = | ||
Helper.fetch_name() | ||
|> to_string() | ||
|
||
file = | ||
Helper.fetch_config() | ||
|> File.ensure_file() | ||
|
||
args = | ||
(["--project-name", app, "--file", file] ++ [action]) | ||
|> List.flatten() | ||
|
||
Validate.validate(file) | ||
|
||
System.cmd("docker-compose", args, stderr_to_stdout: true) | ||
|> log_compose() | ||
end | ||
|
||
defp log_compose({message, 0}), do: Logger.info(message) | ||
defp log_compose({message, code}), do: Logger.error("Docker Compose exited with code: #{code}. #{message}") | ||
|
||
defp get_services(opts) do | ||
case Keyword.get(opts, :services) do | ||
nil -> [] | ||
defined -> Enum.map(defined, &to_string(&1)) | ||
end | ||
end | ||
|
||
defp await() do | ||
fetch_containers() | ||
|> Enum.filter(&health_defined?/1) | ||
|> Enum.map(&await_healthy/1) | ||
end | ||
|
||
defp await_healthy(container) do | ||
wait_config = | ||
Helper.fetch_name() | ||
|> Application.get_env(:divo_wait, dwell: 500, max_tries: 10) | ||
|
||
dwell = Keyword.get(wait_config, :dwell) | ||
tries = Keyword.get(wait_config, :max_tries) | ||
|
||
Patiently.wait_for!( | ||
check_health(container), | ||
dwell: dwell, | ||
max_tries: tries | ||
) | ||
end | ||
|
||
defp check_health(container) do | ||
fn -> | ||
Logger.info("Checking #{container} is healthy...") | ||
|
||
container | ||
|> health_status() | ||
|> case do | ||
"healthy" -> | ||
Logger.info("Service #{container} ready!") | ||
true | ||
|
||
_ -> | ||
false | ||
end | ||
end | ||
end | ||
|
||
defp fetch_containers() do | ||
{containers, _} = System.cmd("docker", ["ps", "--quiet"]) | ||
|
||
String.split(containers, "\n", trim: true) | ||
end | ||
|
||
defp health_defined?(container) do | ||
{health, _} = System.cmd("docker", ["inspect", "--format", "{{json .State.Health}}", container]) | ||
|
||
health | ||
|> Jason.decode!() | ||
|> case do | ||
nil -> false | ||
_ -> true | ||
end | ||
end | ||
|
||
defp health_status(container) do | ||
{status, _} = System.cmd("docker", ["inspect", "--format", "{{json .State.Health.Status}}", container]) | ||
|
||
Jason.decode!(status) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
defmodule Divo.File do | ||
@moduledoc """ | ||
Constructs the ad hoc docker-compose file used by | ||
Divo to run docker dependency services based on | ||
config in the app environment (Mix.env()) file. | ||
""" | ||
require Logger | ||
alias Divo.Helper | ||
|
||
def file_name() do | ||
app = Helper.fetch_name() | ||
|
||
case System.get_env("TMPDIR") do | ||
nil -> "/tmp/#{app}.compose" | ||
defined -> "#{defined}/#{app}.compose" | ||
end | ||
end | ||
|
||
def ensure_file(app_config) when is_binary(app_config) do | ||
Logger.info("Using : #{app_config}") | ||
|
||
app_config | ||
end | ||
|
||
def ensure_file(app_config) when is_map(app_config) do | ||
file = file_name() | ||
|
||
Logger.info("Generating : #{file}") | ||
|
||
app_config | ||
|> Jason.encode!() | ||
|> write(file) | ||
|
||
file | ||
end | ||
|
||
defp write(content, path) do | ||
File.write!(path, content) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
defmodule Divo.Helper do | ||
@moduledoc """ | ||
Extract common key-fetching functionality used by all of the | ||
mix tasks to construct the proper arguments to the docker | ||
commands. | ||
""" | ||
|
||
def fetch_name() do | ||
Mix.Project.config()[:app] | ||
end | ||
|
||
def fetch_config() do | ||
with {:ok, config} <- Application.fetch_env(fetch_name(), :divo) do | ||
config | ||
else | ||
:error -> raise ArgumentError, message: "no services were defined in application config" | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.