Packages
A declarative container orchestrator for Linux, built on the public Linx API: declare pods of namespaced workloads as data, and a reconcile loop converges the machine onto them — host-reconciled macvlan networking, cgroup limits, and a Khepri-backed desired-state store.
Current section
Files
Jump to
Current section
Files
lib/tank/nic.ex
defmodule Tank.Nic do
@moduledoc """
One network interface inside a pod's network namespace.
* `mode` — `:macvlan` (v1); `:bridge` / `:ipvlan` are modelled for later.
* `parent` — the host uplink to attach to, or `:auto` to resolve it via
`Tank.Host`.
* `ip` — `{address, prefix}` for a static address (v1), or `:dhcp` (later).
* `gateway` — optional default-route next hop for this NIC.
Loopback is always raised by the runtime and is not listed here.
"""
alias Tank.Validate
@modes [:macvlan, :bridge, :ipvlan]
@type ip :: {String.t(), 0..32} | :dhcp
@type t :: %__MODULE__{
name: String.t(),
mode: :macvlan | :bridge | :ipvlan,
parent: String.t() | :auto,
ip: ip(),
gateway: String.t() | nil
}
@enforce_keys [:name, :ip]
defstruct name: nil, mode: :macvlan, parent: :auto, ip: nil, gateway: nil
@keys [:name, :mode, :parent, :ip, :gateway]
@doc "Build a validated NIC from a map or keyword list."
@spec new(map() | keyword()) :: {:ok, t()} | {:error, term()}
def new(attrs) do
attrs = attrs |> Map.new() |> Map.delete(:__struct__)
with :ok <- Validate.keys(attrs, @keys),
{:ok, name} <- Validate.name(attrs[:name]),
{:ok, mode} <- Validate.one_of(Map.get(attrs, :mode, :macvlan), @modes),
{:ok, parent} <- parent(Map.get(attrs, :parent, :auto)),
{:ok, ip} <- ip(attrs[:ip]),
{:ok, gateway} <- gateway(Map.get(attrs, :gateway)) do
{:ok, %__MODULE__{name: name, mode: mode, parent: parent, ip: ip, gateway: gateway}}
end
end
@doc "Like `new/1` but raises `ArgumentError` on invalid input."
@spec new!(map() | keyword()) :: t()
def new!(attrs), do: Validate.bang(__MODULE__, attrs)
defp parent(:auto), do: {:ok, :auto}
defp parent(p) when is_binary(p) and p != "", do: {:ok, p}
defp parent(other), do: {:error, {:invalid_parent, other}}
defp ip(:dhcp), do: {:ok, :dhcp}
defp ip({address, prefix}) when is_integer(prefix) and prefix in 0..32 do
with {:ok, _} <- Validate.ipv4(address), do: {:ok, {address, prefix}}
end
defp ip(other), do: {:error, {:invalid_ip, other}}
defp gateway(nil), do: {:ok, nil}
defp gateway(gw), do: Validate.ipv4(gw)
end