defmodule Nola.Subnet do use Agent def start_link(_) do Agent.start_link(&setup/0, name: __MODULE__) end def assignations() do :dets.select(dets(), [{{:"$1", :"$2"}, [is_binary: :"$2"], [{{:"$1", :"$2"}}]}]) end def find_subnet_for(binary) when is_binary(binary) do case :dets.select(dets(), [{{:"$1", :"$2"}, [{:==, :"$2", binary}], [{{:"$1", :"$2"}}]}]) do [{subnet, _}] -> subnet _ -> nil end end def assign(binary) when is_binary(binary) do result = if subnet = find_subnet_for(binary) do {:ok, subnet} else Agent.get_and_update(__MODULE__, fn(dets) -> {subnet, _} = available_select(dets) :dets.insert(dets, {subnet, binary}) :dets.sync(dets) {{:new, subnet}, dets} end) end case result do {:new, subnet} -> ip = Pfx.host(subnet, 1) set_reverse(binary, ip) subnet {:ok, subnet} -> subnet end end def set_reverse(name, ip, value \\ nil) def set_reverse(name, ip, nil) do set_reverse(name, ip, "#{name}.users.goulag.org") end def set_reverse(_, ip, value) do ptr_zone = "3.0.0.2.d.f.0.a.2.ip6.arpa" ip_fqdn = Pfx.dns_ptr(ip) ip_local = String.replace(ip_fqdn, ".#{ptr_zone}", "") rev? = String.ends_with?(value, ".users.goulag.org") if rev? do {:ok, rev_zone} = PowerDNSex.show_zone("users.goulag.org") rev_update? = Enum.any?(rev_zone.rrsets, fn(rr) -> rr.name == "#{ip_fqdn}." end) record = %{name: "#{value}.", type: "AAAA", ttl: 8600, records: [%{content: ip, disabled: false}]} if(rev_update?, do: PowerDNSex.update_record(rev_zone, record), else: PowerDNSex.create_record(rev_zone, record)) end {:ok, zone} = PowerDNSex.show_zone(ptr_zone) update? = Enum.any?(zone.rrsets, fn(rr) -> rr.name == "#{ip_fqdn}." end) record = %{name: "#{ip_fqdn}.", type: "PTR", ttl: 3600, records: [%{content: "#{value}.", disabled: false}]} pdns = if(update?, do: PowerDNSex.update_record(zone, record), else: PowerDNSex.create_record(zone, record)) :ok end @doc false def dets() do (Nola.data_path() <> "/subnets.dets") |> String.to_charlist() end @doc false def setup() do {:ok, dets} = :dets.open_file(dets(), []) dets end defp available_select(dets) do spec = [{{:"$1", :"$2"}, [is_integer: :"$2"], [{{:"$1", :"$2"}}]}] {subnets, _} = :dets.select(dets, spec, 20) subnet = subnets |> Enum.sort_by(fn({_, last}) -> last end) |> List.first() end end