# DockerAvailability
`DockerAvailability` is a small Elixir library for checking whether Docker is installed and usable from the current host process.
It checks more than the presence of the `docker` command. A host may have the Docker CLI installed while the Docker daemon is stopped, unreachable, or inaccessible to the current user. `DockerAvailability` probes both the Docker client and the Docker server so callers can fail early with clear diagnostics.
## Installation
When the package is published to Hex, add `docker_availability` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:docker_availability, "~> 1.0.0"}
]
end
```
During development, you can also depend on this repository directly:
```elixir
def deps do
[
{:docker_availability,
github: "zacky1972/docker_availablility",
branch: "main"}
]
end
```
Then fetch dependencies:
```sh
mix deps.get
```
## Usage
Use `available?/0` when you only need a boolean answer:
```elixir
if DockerAvailability.available?() do
IO.puts("Docker is available")
else
IO.puts("Docker is not available")
end
```
Use `check/0` when you need diagnostic details:
```elixir
case DockerAvailability.check() do
{:ok, info} ->
IO.puts("Docker executable: #{info.executable}")
IO.puts("Docker client: #{info.client_version}")
IO.puts("Docker server: #{info.server_version}")
{:error, :docker_not_found} ->
IO.puts("The docker executable was not found in PATH")
{:error, {:docker_command_failed, status, output}} ->
IO.puts("Docker client command failed with status #{status}")
IO.puts(output)
{:error, {:docker_unavailable, status, output}} ->
IO.puts("Docker daemon is not available with status #{status}")
IO.puts(output)
end
```
Use `executable/0` when you only need to know whether the `docker` executable exists in `PATH`:
```elixir
DockerAvailability.executable()
#=> {:ok, "/usr/bin/docker"}
DockerAvailability.executable()
#=> {:error, :docker_not_found}
```
## API
### `DockerAvailability.executable/0`
Returns the path to the `docker` executable.
It only checks the current process `PATH` by using `System.find_executable/1`. It does not check whether the Docker daemon is running.
Returns:
- `{:ok, path}` when the executable is found
- `{:error, :docker_not_found}` when the executable is not available in `PATH`
### `DockerAvailability.available?/0`
Returns `true` when Docker is installed and usable by the current process.
This is a convenience wrapper around `check/0`. It returns `false` for all error cases, including a missing executable, a failed Docker client command, or an unreachable Docker daemon.
### `DockerAvailability.check/0`
Performs the full availability check.
It verifies that:
1. the `docker` executable exists in `PATH`
2. the Docker client version can be queried
3. the Docker server version can be queried
Returns `{:ok, info}` when Docker is usable. The `info` map contains:
- `:executable` - the resolved path to the Docker executable
- `:client_version` - the Docker client version reported by the executable
- `:server_version` - the Docker server version reported by the daemon
Returns one of the following errors:
- `{:error, :docker_not_found}` when `docker` is not found in `PATH`
- `{:error, {:docker_command_failed, status, output}}` when a Docker client command fails before daemon availability is established
- `{:error, {:docker_unavailable, status, output}}` when the Docker server version cannot be queried
`status` is the command exit status. `output` is the trimmed combined standard output and standard error from the Docker command.
## What this library does not do
`DockerAvailability` is a probe only. It does not:
- install Docker
- start or stop the Docker daemon
- pull, build, run, or remove Docker images or containers
- modify Docker state
- require a specific Docker image
## Examples
A common use case is to skip Docker-dependent work when Docker is not available:
```elixir
case DockerAvailability.check() do
{:ok, _info} ->
run_docker_dependent_work()
{:error, reason} ->
{:skip, {:docker_unavailable, reason}}
end
```
For test suites, `available?/0` can be used to guard integration tests:
```elixir
setup_all do
unless DockerAvailability.available?() do
ExUnit.configure(exclude: [:docker])
end
:ok
end
```
## Testing
Run the test suite with:
```sh
mix test
```
The unit tests use a fake `docker` executable placed in a temporary `PATH`, so they do not require a real Docker daemon or any Docker image.
## Development
Fetch dependencies:
```sh
mix deps.get
```
Run tests:
```sh
mix test
```
Run the project checks:
```sh
mix check
```
Run the maintainer pre-commit checks:
```sh
mix precommit
```
## Documentation
Generate documentation locally with:
```sh
mix docs
```
After the package is published, documentation should be available on HexDocs.
## Requirements
- Elixir `~> 1.19`
- Docker CLI and daemon, when checking real Docker availability at runtime
## License
Apache-2.0. See [LICENSE.md](LICENSE.md).