summaryrefslogtreecommitdiff
path: root/lib/powerdnsex
diff options
context:
space:
mode:
authorTiago Freire <tcfonnet@gmail.com>2016-08-16 01:18:30 -0300
committerTiago Freire <code.tiago.frire@locaweb.com.br>2016-08-18 15:08:05 -0300
commit1db1adbf2d061848f78711c38678edd02250f923 (patch)
tree2932151e492855506a40c9e7af5b6e7583aa1903 /lib/powerdnsex
parent[WIP] Init. (diff)
WIP
Diffstat (limited to 'lib/powerdnsex')
-rw-r--r--lib/powerdnsex/config.ex36
-rw-r--r--lib/powerdnsex/managers/records_manager.ex34
-rw-r--r--lib/powerdnsex/managers/zones_manager.ex46
-rw-r--r--lib/powerdnsex/models/error.ex3
-rw-r--r--lib/powerdnsex/models/record.ex27
-rw-r--r--lib/powerdnsex/models/resource_record_set.ex40
-rw-r--r--lib/powerdnsex/models/zone.ex28
7 files changed, 214 insertions, 0 deletions
diff --git a/lib/powerdnsex/config.ex b/lib/powerdnsex/config.ex
new file mode 100644
index 0000000..50589d4
--- /dev/null
+++ b/lib/powerdnsex/config.ex
@@ -0,0 +1,36 @@
+defmodule PowerDNSex.Config do
+ defstruct url: "",
+ token: ""
+
+ alias PowerDNSex.Config
+
+ def data do
+ set_attr_value = &(Map.put(&2, &1, get_key(&1)))
+
+ %Config{}
+ |> Map.from_struct
+ |> Map.keys
+ |> Enum.reduce(%Config{}, set_attr_value)
+ end
+
+ def powerdns_url do
+ data.url
+ end
+
+ def powerdns_token do
+ data.token
+ end
+
+ ###
+ # Private
+ ###
+
+ defp get_key(key) do
+ case Application.fetch_env(:powerdns, key) do
+ {:ok, {:system, env_var_name}} -> System.get_env(env_var_name)
+ {:ok, value} -> value
+ _ ->
+ raise "[PowerDNSex] PowerDNS #{Atom.to_string(key)} not configured."
+ end
+ end
+end
diff --git a/lib/powerdnsex/managers/records_manager.ex b/lib/powerdnsex/managers/records_manager.ex
new file mode 100644
index 0000000..f9e71e1
--- /dev/null
+++ b/lib/powerdnsex/managers/records_manager.ex
@@ -0,0 +1,34 @@
+defmodule PowerDNSex.RecordsManager do
+
+ alias PowerDNSex.HttpClient
+ alias PowerDNSex.Models.{Zone, Record, Error}
+ alias PowerDNSex.Models.ResourceRecordSet, as: RRset
+ alias HTTPoison.Response
+
+ def create(%Zone{url: nil}, _) do
+ raise "[Records Manager] Zone URL attribute is empty!"
+ end
+
+ def create(%Zone{} = zone, %{} = rrset_attrs) do
+ rrset_attrs = Map.merge(rrset_attrs, %{changetype: "REPLACE"})
+
+ zone.url
+ |> HttpClient.patch!(RRset.as_body(RRset.build(rrset_attrs)))
+ |> process_request_response
+ end
+
+ def update(%Zone{} = zone, %{} = rrset_attrs) do
+ create(zone, rrset_attrs)
+ end
+
+ ###
+ # Private
+ ##
+
+ defp process_request_response(%Response{body: body, status_code: status}) do
+ case status do
+ s when s < 300 -> :ok
+ s when s >= 300 -> body |> Poison.decode!(as: %Error{})
+ end
+ end
+end
diff --git a/lib/powerdnsex/managers/zones_manager.ex b/lib/powerdnsex/managers/zones_manager.ex
new file mode 100644
index 0000000..e511ac1
--- /dev/null
+++ b/lib/powerdnsex/managers/zones_manager.ex
@@ -0,0 +1,46 @@
+defmodule PowerDNSex.ZonesManager do
+
+ @default_server "localhost"
+
+ alias PowerDNSex.HttpClient
+ alias PowerDNSex.Models.{Zone, Error, ResourceRecordSet, Record}
+ alias HTTPoison.Response
+
+ def create(%Zone{} = zone, server_name \\ @default_server) do
+ zone_path(server_name)
+ |> HttpClient.post!(Zone.as_body(zone))
+ |> process_request_response
+ end
+
+ def show(zone_name, server_name \\ @default_server)
+ when is_bitstring(zone_name) do
+
+ zone_path(server_name, zone_name)
+ |> HttpClient.get!
+ |> process_request_response
+ end
+
+ ###
+ # Private
+ ###
+
+ defp zone_path(server_name) when is_bitstring(server_name) do
+ "api/v1/servers/#{server_name}/zones"
+ end
+
+ defp zone_path(server_name, zone_name) when is_bitstring(server_name) do
+ zone_path(server_name) <> "/#{zone_name}"
+ end
+
+ defp process_request_response(%Response{body: body, status_code: status}) do
+ case status do
+ s when s < 300 ->
+ body |> Poison.decode!(as: %Zone{rrsets: [
+ %ResourceRecordSet{
+ records: [%Record{}]
+ }]})
+ s when s >= 300 ->
+ body |> Poison.decode!(as: %Error{})
+ end
+ end
+end
diff --git a/lib/powerdnsex/models/error.ex b/lib/powerdnsex/models/error.ex
new file mode 100644
index 0000000..1cf9f62
--- /dev/null
+++ b/lib/powerdnsex/models/error.ex
@@ -0,0 +1,3 @@
+defmodule PowerDNSex.Models.Error do
+ defstruct [:error]
+end
diff --git a/lib/powerdnsex/models/record.ex b/lib/powerdnsex/models/record.ex
new file mode 100644
index 0000000..57378fc
--- /dev/null
+++ b/lib/powerdnsex/models/record.ex
@@ -0,0 +1,27 @@
+defmodule PowerDNSex.Models.Record do
+ defstruct [:content, :disabled]
+
+ def build(attrs) when is_list(attrs) do
+ Enum.reduce(attrs, [], &(&2 ++ [build(&1)]))
+ end
+
+ def build(attrs) when is_tuple(attrs) do
+ %__MODULE__{content: elem(attrs, 0), disabled: elem(attrs, 1)}
+ end
+
+ def build(attrs) when is_map(attrs) do
+ %__MODULE__{content: attrs.content, disabled: attrs.disabled}
+ end
+
+ def as_body(content) when is_list(content) do
+ Enum.reduce(content, [], &(&2 ++ [as_body(&1)]))
+ end
+
+ def as_body(%__MODULE__{} = record_attrs) do
+ Map.from_struct(record_attrs)
+ end
+
+ def as_body(record_attrs) when is_tuple(record_attrs) do
+ %{content: elem(record_attrs, 0), disabled: elem(record_attrs, 1)}
+ end
+end
diff --git a/lib/powerdnsex/models/resource_record_set.ex b/lib/powerdnsex/models/resource_record_set.ex
new file mode 100644
index 0000000..f4338a2
--- /dev/null
+++ b/lib/powerdnsex/models/resource_record_set.ex
@@ -0,0 +1,40 @@
+defmodule PowerDNSex.Models.ResourceRecordSet do
+
+ alias PowerDNSex.Models.Record
+
+ defstruct [:name, :type, :ttl, :records, :changetype]
+
+ def build(rrset_attrs) when is_map(rrset_attrs) do
+ rrset = %__MODULE__{}
+
+ rrset
+ |> Map.keys
+ |> Enum.reduce(rrset, &(set_attrs(&2, &1, rrset_attrs)))
+ end
+
+ def as_body(%__MODULE__{} = rrset) do
+ %{ rrsets: [
+ %{
+ name: rrset.name,
+ type: rrset.type,
+ ttl: rrset.ttl,
+ changetype: rrset.changetype,
+ records: Record.as_body(rrset.records)
+ }
+ ]}
+ |> Poison.encode!
+ end
+
+ defp set_attrs(rrset, attr_name, attrs) do
+ if Map.has_key?(attrs, attr_name) do
+ attr_value = case attr_name do
+ :records -> Record.build(Map.fetch!(attrs, attr_name))
+ _ -> Map.fetch!(attrs, attr_name)
+ end
+
+ %{ rrset | attr_name => attr_value }
+ else
+ rrset
+ end
+ end
+end
diff --git a/lib/powerdnsex/models/zone.ex b/lib/powerdnsex/models/zone.ex
new file mode 100644
index 0000000..62a5a2a
--- /dev/null
+++ b/lib/powerdnsex/models/zone.ex
@@ -0,0 +1,28 @@
+defmodule PowerDNSex.Models.Zone do
+ @moduledoc """
+ Model for PowerDns zones, create and validate format
+ """
+
+ @body_attrs ~w(account dns kind masters name nameservers records serial
+ soa_edit soa_edit_api)a
+
+ defstruct name: nil, kind: "Native", masters: [], nameservers: [], rrsets: [],
+ account: nil, comments: [], dnssec: false, id: nil, last_check: 0,
+ notified_serial: 0, serial: nil, soa_edit: "", soa_edit_api: "",
+ url: nil
+
+ def as_body(%__MODULE__{} = zone) do
+ get_valid_attrs = fn({attr, value}, body) ->
+ if Enum.member?(@body_attrs, attr) do
+ Map.merge(body, %{attr => value})
+ else
+ body
+ end
+ end
+
+ zone
+ |> Map.from_struct
+ |> Enum.reduce(%{}, get_valid_attrs)
+ |> Poison.encode!
+ end
+end