Packages

Provides Joyent Manta storage backend for Arc.

Current section

Files

Jump to
arc_manta lib arc storage manta.ex
Raw

lib/arc/storage/manta.ex

defmodule Arc.Storage.Manta do
@signature_algorithm "rsa-sha256"
@authorization_header_strftime_format "%a, %d %b %Y %H:%M:%S GMT"
@directory_content_type_header "application/json; type=directory"
@default_expiry_time 60*5
@default_mimetype "application/octet-stream"
@default_host "us-east.manta.joyent.com"
def put(definition, version, {file, scope}) do
path = definition_to_path(definition, version, {file, scope})
mkdir_p(path)
:ok = store_file(
fully_qualified_url(path),
extract_binary(file),
[{"Content-Type", "#{get_mimetype(file)}; type=file"} | base_headers]
)
{:ok, file.file_name}
end
def delete(definition, version, {file, scope}) do
path = definition_to_url(definition, version, {file, scope})
case delete_file(path) do
:ok -> :ok
{:error, "{\"code\":\"ResourceNotFound\"" <> _} -> :ok
end
end
def url(definition, version, file_and_scope, options \\ []) do
case Keyword.get(options, :signed, false) do
false -> build_url(definition, version, file_and_scope, options)
true -> build_signed_url(definition, version, file_and_scope, options)
end
end
#
# Private
#
defp store_file(fully_qualified_url, data, headers) do
HTTPoison.start
HTTPoison.put!(fully_qualified_url, data, headers)
|> httpoison_response_to_status
end
defp delete_file(fully_qualified_url) do
HTTPoison.start
HTTPoison.delete!(fully_qualified_url, base_headers)
|> httpoison_response_to_status
end
defp mkdir_p(path) do
path
|> Path.split
|> Enum.reduce(fn(segment, partial_path) ->
:ok = partial_path
|> List.wrap
|> mkdir
List.wrap(partial_path) ++ List.wrap(segment)
end)
end
defp mkdir(path) do
fully_qualified_url(path)
|> HTTPoison.put!("", [{"Content-Type", @directory_content_type_header} | base_headers])
|> httpoison_response_to_status
end
defp httpoison_response_to_status(%HTTPoison.Response{status_code: 204}), do: :ok
defp httpoison_response_to_status(%HTTPoison.Response{body: body}), do: {:error, body}
defp definition_to_path(definition, version, {file, scope}) do
destination_dir = definition.storage_dir(version, {file, scope})
Path.join(destination_dir, file.file_name)
end
defp definition_to_url(definition, version, {file, scope}) do
definition_to_path(definition, version, {file, scope})
|> fully_qualified_url
end
defp fully_qualified_url(path) when is_list(path) do
fully_qualified_url(Path.join(path))
end
defp fully_qualified_url(path) when is_binary(path) do
"https://#{manta_host}/#{manta_user}/public/#{path}"
end
def base_headers do
now = :calendar.universal_time()
|> Calendar.Strftime.strftime!(@authorization_header_strftime_format)
[{"Authorization", authorization_header(now)}, {"date", now}]
end
defp authorization_header(now) do
'Signature keyId="#{manta_key_id}",algorithm="#{@signature_algorithm}",signature="#{sign_date("date: #{now}")}"'
end
defp sign_date(now) do
key = manta_ssh_private_key
|> :public_key.pem_decode
|> List.first
|> :public_key.pem_entry_decode
now
|> :public_key.sign(:sha256, key)
|> Base.encode64
end
defp get_file_extension(file) do
file.file_name
|> String.split(".")
|> List.last
end
defp get_mimetype(file) do
:mimerl.extension(get_file_extension(file)) || @default_mimetype
end
defp build_url(definition, version, file_and_scope, _options) do
manta_key(definition, version, file_and_scope)
|> fully_qualified_url
end
# TODO
defp build_signed_url(_definition, _version, _file_and_scope, _options) do
end
defp manta_key(definition, version, file_and_scope) do
Path.join([
definition.storage_dir(version, file_and_scope),
Arc.Definition.Versioning.resolve_file_name(definition, version, file_and_scope)
])
end
defp extract_binary(file) do
Map.get(file, :binary) || File.read!(file.path)
end
defp manta_ssh_fingerprint do
Application.get_env :arc, :manta_ssh_fingerprint
end
defp manta_host do
Application.get_env(:arc, :manta_host) || @default_host
end
defp manta_user do
Application.get_env :arc, :manta_user
end
defp manta_ssh_private_key do
Application.get_env :arc, :manta_ssh_private_key
end
defp manta_key_id do
"/#{manta_user}/keys/#{manta_ssh_fingerprint}"
end
end