diff options
author | Tiago Freire <tcfonnet@gmail.com> | 2016-08-16 01:18:30 -0300 |
---|---|---|
committer | Tiago Freire <code.tiago.frire@locaweb.com.br> | 2016-08-18 15:08:05 -0300 |
commit | 1db1adbf2d061848f78711c38678edd02250f923 (patch) | |
tree | 2932151e492855506a40c9e7af5b6e7583aa1903 /lib/powerdnsex | |
parent | [WIP] Init. (diff) |
WIP
Diffstat (limited to 'lib/powerdnsex')
-rw-r--r-- | lib/powerdnsex/config.ex | 36 | ||||
-rw-r--r-- | lib/powerdnsex/managers/records_manager.ex | 34 | ||||
-rw-r--r-- | lib/powerdnsex/managers/zones_manager.ex | 46 | ||||
-rw-r--r-- | lib/powerdnsex/models/error.ex | 3 | ||||
-rw-r--r-- | lib/powerdnsex/models/record.ex | 27 | ||||
-rw-r--r-- | lib/powerdnsex/models/resource_record_set.ex | 40 | ||||
-rw-r--r-- | lib/powerdnsex/models/zone.ex | 28 |
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 |