Skip to content

Commit

Permalink
replace global simplex config with separate config processes
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkittelson committed Sep 17, 2014
1 parent 2787dae commit 17296d6
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 218 deletions.
128 changes: 112 additions & 16 deletions lib/simplex.ex
Original file line number Diff line number Diff line change
@@ -1,33 +1,129 @@
defmodule Simplex do
use Application
alias Simplex.Config
use GenServer
use Timex

def start(_type, _args) do
Simplex.Supervisor.start_link
def new(access_key \\ nil, secret_access_key \\ nil) do
config = %{
:aws_access_key => access_key || System.get_env("AWS_ACCESS_KEY"),
:aws_secret_access_key => secret_access_key || System.get_env("AWS_SECRET_ACCESS_KEY"),
:simpledb_url => System.get_env("SIMPLEDB_URL") || "https://sdb.amazonaws.com"
}

GenServer.start_link(__MODULE__, config, [])
end

def aws_access_key(simplex) do
GenServer.call(simplex, :get_aws_access_key)
end

def aws_access_key(simplex, access_key) do
GenServer.call(simplex, {:set_aws_access_key, access_key})
end

def aws_secret_access_key(simplex) do
GenServer.call(simplex, :get_aws_secret_access_key)
end

def aws_secret_access_key(simplex, secret_access_key) do
GenServer.call(simplex, {:set_aws_secret_access_key, secret_access_key})
end

def simpledb_url(simplex) do
GenServer.call(simplex, :get_simpledb_url)
end

def simpledb_url(simplex, url) do
GenServer.call(simplex, {:set_simpledb_url, url})
end

defp needs_refresh?(:aws_access_key, config) do
expiring?(config) or !config[:aws_access_key]
end

defp needs_refresh?(:aws_secret_access_key, config) do
expiring?(config) or !config[:aws_secret_access_key]
end

# keys expired or expiring within the next 60 seconds
defp expiring?(%{:expires_at => nil}), do: false
defp expiring?(%{:expires_at => expires_at}) do
expires_at = DateFormat.parse!(expires_at, "{ISOz}")
Date.shift(Date.now, secs: 60) > expires_at
end
defp expiring?(_config), do: false

defp load_credentials_from_metadata do
try do
%HTTPoison.Response{:body => role_name} = HTTPoison.get("http://169.254.169.254/latest/meta-data/iam/security-credentials/", [], [timeout: 500])
%HTTPoison.Response{:body => body} = HTTPoison.get("http://169.254.169.254/latest/meta-data/iam/security-credentials/#{role_name}", [], [timeout: 500])
Poison.decode!(body)
rescue
_ ->
%{}
end
end

defp refresh(config) do
credentials_from_metadata = load_credentials_from_metadata
update = %{
:aws_access_key => credentials_from_metadata["AccessKeyId"],
:aws_secret_access_key => credentials_from_metadata["SecretAccessKey"],
:expires_at => credentials_from_metadata["Expiration"]
}
Map.merge(config, update)
end


###################
# Server Callbacks

def init(config) do
{:ok, config}
end

def handle_call(:get_aws_access_key, _from, config) do
if needs_refresh?(:aws_access_key, config) do
config = refresh(config)
{:reply, config[:aws_access_key], config}
else
{:reply, config[:aws_access_key], config}
end
end

def aws_access_key do
Config.aws_access_key || System.get_env("SIMPLEX_AWS_ACCESS_KEY")
def handle_call(:get_aws_secret_access_key, _from, config) do
if needs_refresh?(:aws_secret_access_key, config) do
config = refresh(config)
{:reply, config[:aws_secret_access_key], config}
else
{:reply, config[:aws_secret_access_key], config}
end
end

def aws_access_key(key) do
Config.aws_access_key(key)
def handle_call(:get_simpledb_url, _from, config) do
{:reply, config[:simpledb_url], config}
end

def aws_secret_access_key do
Config.aws_secret_access_key || System.get_env("SIMPLEX_AWS_SECRET_ACCESS_KEY")
def handle_call({:set_aws_access_key, access_key}, _from, config) do
config = config
|> Map.put(:aws_access_key, access_key)
|> Map.delete(:expires_at)
{:reply, config[:aws_access_key], config}
end

def aws_secret_access_key(key) do
Config.aws_secret_access_key(key)
def handle_call({:set_aws_secret_access_key, secret_access_key}, _from, config) do
config = config
|> Map.put(:aws_secret_access_key, secret_access_key)
|> Map.delete(:expires_at)
{:reply, config[:aws_secret_access_key], config}
end

def simpledb_url do
Config.simpledb_url || System.get_env("SIMPLEX_SIMPLEDB_URL") || "https://sdb.amazonaws.com"
def handle_call({:set_simpledb_url, url}, _from, config) do
config = Map.put(config, :simpledb_url, url)
{:reply, config[:simpledb_url], config}
end

def simpledb_url(url) do
Config.simpledb_url(url)
def handle_info(_msg, config) do
{:noreply, config}
end

end
12 changes: 6 additions & 6 deletions lib/simplex/attributes.ex
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
defmodule Simplex.Attributes do
alias Simplex.Request

def get(domain_name, item_name, params \\ %{}) do
def get(simplex, domain_name, item_name, params \\ %{}) do
params
|> Map.merge(%{"Action" => "GetAttributes",
"DomainName" => domain_name,
"ItemName" => item_name})
|> Request.get
|> Request.get(simplex)
end

def put(domain_name, item_name, attributes, expected \\ %{}) do
def put(simplex, domain_name, item_name, attributes, expected \\ %{}) do
params = expected
|> format_expected
|> Map.merge(parse_attributes(attributes))
|> Map.merge(%{"Action" => "PutAttributes",
"DomainName" => domain_name,
"ItemName" => item_name})
Request.get(params)
Request.get(params, simplex)
end

def delete(domain_name, item_name, attributes \\ %{}, expected \\ %{}) do
def delete(simplex, domain_name, item_name, attributes \\ %{}, expected \\ %{}) do
params = expected
|> format_expected
|> Map.merge(parse_attributes(attributes))
|> Map.merge(%{"Action" => "DeleteAttributes",
"DomainName" => domain_name,
"ItemName" => item_name})
Request.get(params)
Request.get(params, simplex)
end

def parse_attributes(attributes) do
Expand Down
116 changes: 0 additions & 116 deletions lib/simplex/config.ex

This file was deleted.

12 changes: 6 additions & 6 deletions lib/simplex/domains.ex
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
defmodule Simplex.Domains do
alias Simplex.Request

def create(name) do
Request.get(%{"Action" => "CreateDomain", "DomainName" => name})
def create(simplex, name) do
Request.get(%{"Action" => "CreateDomain", "DomainName" => name}, simplex)
end

def list(params \\ %{}) do
def list(simplex, params \\ %{}) do
params
|> Map.merge(%{"Action" => "ListDomains"})
|> Request.get
|> Request.get(simplex)
end

def delete(name) do
Request.get(%{"Action" => "DeleteDomain", "DomainName" => name})
def delete(simplex, name) do
Request.get(%{"Action" => "DeleteDomain", "DomainName" => name}, simplex)
end

end
20 changes: 10 additions & 10 deletions lib/simplex/request.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ defmodule Simplex.Request do
alias Simplex.Response
use Timex

def get(params) do
response = Simplex.simpledb_url
|> signed(params)
def get(params, config) do
response = Simplex.simpledb_url(config)
|> signed(params, config)
|> HTTPoison.get
Response.handle(params["Action"], response)
end

def signed(url, params) do
def signed(url, params, config) do
uri = URI.parse(url)

query = query_string(params)
query = query_string(params, config)

request = Enum.join(["GET", uri.host, uri.path || "/", query], "\n")

signature = :crypto.hmac(:sha256, String.to_char_list(Simplex.aws_secret_access_key), String.to_char_list(request))
signature = :crypto.hmac(:sha256, String.to_char_list(Simplex.aws_secret_access_key(config)), String.to_char_list(request))
|> :base64.encode
|> URI.encode
|> String.replace("/", "%2F")
Expand All @@ -27,17 +27,17 @@ defmodule Simplex.Request do
"#{uri.scheme}://#{uri.authority}#{uri.path || "/"}?#{query}&Signature=#{signature}"
end

defp auth_params do
defp auth_params(config) do
[
AWSAccessKeyId: Simplex.aws_access_key,
AWSAccessKeyId: Simplex.aws_access_key(config),
SignatureVersion: 2,
SignatureMethod: "HmacSHA256",
Timestamp: DateFormat.format!(Date.now, "{ISOz}")
]
end

defp query_string(params) do
Parameters.from_map(params) ++ [{:Version, "2009-04-15"}] ++ auth_params
defp query_string(params, config) do
Parameters.from_map(params) ++ [{:Version, "2009-04-15"}] ++ auth_params(config)
|> Enum.sort
|> URI.encode_query
|> String.replace("+", "%20")
Expand Down
4 changes: 2 additions & 2 deletions lib/simplex/select.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
defmodule Simplex.Select do
alias Simplex.Request

def select(select_expression, params \\ %{}) do
def select(simplex, select_expression, params \\ %{}) do
params
|> Map.merge(%{"Action" => "Select", "SelectExpression" => select_expression})
|> Request.get
|> Request.get(simplex)
end

end

0 comments on commit 17296d6

Please sign in to comment.