From 217482d28f9125cc7a0034896da7a75b9e64ca41 Mon Sep 17 00:00:00 2001 From: Tiago Freire Date: Tue, 16 Aug 2016 01:18:30 -0300 Subject: WIP --- lib/http_client.ex | 4 +-- lib/powerdnsex/config.ex | 36 ++++++++++++++++++++++ lib/powerdnsex/managers/records_manager.ex | 30 ++++++++++++++++++ lib/powerdnsex/managers/zones_manager.ex | 46 ++++++++++++++++++++++++++++ lib/powerdnsex/models/error.ex | 3 ++ lib/powerdnsex/models/record.ex | 9 ++++++ lib/powerdnsex/models/resource_record_set.ex | 20 ++++++++++++ lib/powerdnsex/models/zone.ex | 28 +++++++++++++++++ lib/powerdnsx.ex | 2 +- lib/powerdnsx/config.ex | 36 ---------------------- lib/powerdnsx/managers/zones_manager.ex | 40 ------------------------ lib/powerdnsx/models/zone.ex | 25 --------------- lib/powerdnsx/validations/zone_validation.ex | 38 ----------------------- 13 files changed, 175 insertions(+), 142 deletions(-) create mode 100644 lib/powerdnsex/config.ex create mode 100644 lib/powerdnsex/managers/records_manager.ex create mode 100644 lib/powerdnsex/managers/zones_manager.ex create mode 100644 lib/powerdnsex/models/error.ex create mode 100644 lib/powerdnsex/models/record.ex create mode 100644 lib/powerdnsex/models/resource_record_set.ex create mode 100644 lib/powerdnsex/models/zone.ex delete mode 100644 lib/powerdnsx/config.ex delete mode 100644 lib/powerdnsx/managers/zones_manager.ex delete mode 100644 lib/powerdnsx/models/zone.ex delete mode 100644 lib/powerdnsx/validations/zone_validation.ex (limited to 'lib') diff --git a/lib/http_client.ex b/lib/http_client.ex index d819087..6d18cbe 100644 --- a/lib/http_client.ex +++ b/lib/http_client.ex @@ -1,11 +1,11 @@ -defmodule PowerDNSx.HttpClient do +defmodule PowerDNSex.HttpClient do @moduledoc""" Client to do http requests for PowerDns API """ use HTTPoison.Base - alias PowerDNSx.Config + alias PowerDNSex.Config def process_url(url) do Config.powerdns_url <> url 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..7d580b2 --- /dev/null +++ b/lib/powerdnsex/managers/records_manager.ex @@ -0,0 +1,30 @@ +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) do + rrset = %{rrset | changetype: "REPLACE"} + + zone.url + |> HttpClient.patch!(rrset.as_body(rrset)) + |> process_request_response + 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..82dca74 --- /dev/null +++ b/lib/powerdnsex/models/record.ex @@ -0,0 +1,9 @@ +defmodule PowerDNSex.Models.Record do + defstruct [:content, :disabled] + + def as_body(content) when is_list(content) do + Enum.reduce(content, [], fn({value, status}, records) -> + records ++ [%__MODULE__{ content: value, disabled: status }] + end) + 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..a3bca8d --- /dev/null +++ b/lib/powerdnsex/models/resource_record_set.ex @@ -0,0 +1,20 @@ +defmodule PowerDNSex.Models.ResourceRecordSet do + + alias PowerDNSex.Models.Record + + defstruct [:name, :type, :ttl, :records, :changetype] + + def as_body(%__MODULE__{} = record) do + %{ rrsets: [ + %{ + name: record.name, + type: record.type, + ttl: record.ttl, + changetype: record.changetype, + records: Record.as_body(record.content) + } + ]} + |> Poison.encode! + 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 diff --git a/lib/powerdnsx.ex b/lib/powerdnsx.ex index 711fde6..c82aa59 100644 --- a/lib/powerdnsx.ex +++ b/lib/powerdnsx.ex @@ -1,2 +1,2 @@ -defmodule PowerDNSx do +defmodule PowerDNSex do end diff --git a/lib/powerdnsx/config.ex b/lib/powerdnsx/config.ex deleted file mode 100644 index d172fa9..0000000 --- a/lib/powerdnsx/config.ex +++ /dev/null @@ -1,36 +0,0 @@ -defmodule PowerDNSx.Config do - defstruct url: "", - token: "" - - alias PowerDNSx.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 "[PowerDNSx] PowerDNS #{Atom.to_string(key)} not configured." - end - end -end diff --git a/lib/powerdnsx/managers/zones_manager.ex b/lib/powerdnsx/managers/zones_manager.ex deleted file mode 100644 index 6e313d6..0000000 --- a/lib/powerdnsx/managers/zones_manager.ex +++ /dev/null @@ -1,40 +0,0 @@ -defmodule PowerDNSx.ZonesManager do - - @default_server "localhost" - - alias PowerDNSx.HttpClient - alias HTTPoison.Response, as: PoisonResp - alias PowerDNSx.Models.Zone - - def create(%Zone{} = zone, server_name \\ @default_server) do - case Zone.is_valid?(zone) do - true -> - zone_path(server_name) - |> HttpClient.post!(zone) - |> process_request_response - {false, errors} -> {:error, errors} - end - 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 - "/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(%PoisonResp{body: body, status_code: status} ) do - body |> Poison.decode!(as: %Zone{}) - end -end diff --git a/lib/powerdnsx/models/zone.ex b/lib/powerdnsx/models/zone.ex deleted file mode 100644 index b2a9249..0000000 --- a/lib/powerdnsx/models/zone.ex +++ /dev/null @@ -1,25 +0,0 @@ -defmodule PowerDNSx.Models.Zone do - @moduledoc """ - Model for PowerDns zones, create and validate format - """ - - @valid_hostname_regex ~r/^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/ - - defstruct name: nil, - kind: "Native", - masters: [], - nameservers: [], - records: [], - account: nil, - comments: [], - dnssec: false, - id: nil, - last_check: 0, - notified_serial: 0, - serial: nil, - soa_edit: "", - soa_edit_api: "", - url: nil - - -end diff --git a/lib/powerdnsx/validations/zone_validation.ex b/lib/powerdnsx/validations/zone_validation.ex deleted file mode 100644 index a2abc6e..0000000 --- a/lib/powerdnsx/validations/zone_validation.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule PowerDNSx.ZoneValidator do - alias PowerDNSx.Models.Zone - - @valid_zone_name_reg ~r/^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/ - - def check(%Zone{} = zone) do - verify_attr = fn({attr, value}, errors)-> - validate_attr_value(attr, value) - end - - errors = Enum.reduce(zone, nil, verify_attr) - if errors, do: {:error, errors}, else: :ok - end - - ### - # Private - ### - - defp validate_attr_value(:name, zone_name) do - case validate_zone_name(zone_name) do - {true, true} -> nil - {false, _} -> {:error, %{name: "#{zone_name} is invalid."}} - {_, false} -> {:error, %{name: "#{zone_name} is invalid. Max lenght is 64."}} - {:format_error} -> {:error, %{name: "Name MUST be a string."}} - end - end - - defp validate_zone_name(zone_name) when is_bitstring(zone_name) do - {String.match?(zone_name, @valid_zone_name_reg), correct_length?(zone_name)} - end - - defp validate_zone_name(_), do: {:format_error} - - defp correct_length?(zone_name) do - name = zone_name |> String.split(".") |> hd - name |> String.length <= 63 - end -end -- cgit v1.2.3