Code as infrastructure
"Infrastructure as code" is a misnomer.
We should call it "infrastructure as configuration" or "infrastructure as data" because YAML (Ansible/CloudFormation) and glorified JSON (Terraform) are not code.
Just as functional languages enable us to treat code as data, I believe they give us the capability to treat code as infrastructure. Crucible is going to explore this idea.
- Declarative and idempotent
- Granular control of create/delete/rollback behavior
- Rollbacks as a first class citizen
- Testing as a first class citizen
- Does not track state outside of execution
defmodule My.VPC do
@moduledoc """
Some thoughts on what the end goal could look like.
"""
use Crucible
alias Crucible.AWS.VPC
alias Crucible.AWS.Subnet
@vpc %VPC{
cidr: "10.0.0.0/16"
tags: [foo: "bar", abc: "xyz"]
}
def init(infra) do
infra
|> declare(:my_vpc, @vpc)
|> declare(:my_subnet_1, subnet("1"))
|> declare(:my_subnet_2, subnet("2"))
|> declare(:my_subnet_3, subnet("3"))
end
@doc """
This is a pseudo-code example of pattern matching an edge case.
Only create `:my_subnet_3` if `APPENV` environment variable is
equal to "prod."
"""
def handle_create(%{state: %{my_vpc: vpc}} = _infra, %Subnet{cid: :my_subnet_3} = sn) do
with "prod" <- System.get_env("APPENV"),
sn3 <- %{sn | vpc: vpc},
{:ok, _} = resp <- Subnet.create(sn3) do
resp
else
{:error, _} = err ->
err
_ ->
{:ok, %{}}
end
end
defp subnet(i) do
%Subnet{
vpc: :my_vpc,
cidr: "10.0.#{i}.0/24",
tags: [foo: "baz"]
}
end
end
defmodule My.Vpc do
@moduledoc """
Provide a more declarative DSL, too.
"""
use Crucible.DSL
vpc(:my_vpc) do
subnet :my_subnet_1, cidr: "10.0.3.0/24" do
vm :jenkins do
end
vm :foobar do
end
end
subnet :my_subnet_2, cidr: "10.0.4.0/24" do
on_create fn x -> do_something(x) end
end
end
end
If available in Hex, the package can be installed
by adding crucible
to your list of dependencies in mix.exs
:
def deps do
[
{:crucible, "~> 0.0.1"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/crucible.