defmodule ExAws.Config.Defaults do
@moduledoc """
Defaults for each service
"""
@common %{
access_key_id: [{:system, "AWS_ACCESS_KEY_ID"}, :instance_role],
secret_access_key: [{:system, "AWS_SECRET_ACCESS_KEY"}, :instance_role],
http_client: ExAws.Request.Hackney,
json_codec: Jason,
retries: [
max_attempts: 10,
base_backoff_in_ms: 10,
max_backoff_in_ms: 10_000
],
require_imds_v2: false,
normalize_path: true
}
@doc """
Retrieve the default configuration for a service.
"""
@spec defaults(service :: atom) :: map
def defaults(:dynamodb_streams) do
%{service_override: :dynamodb}
|> Map.merge(defaults(:dynamodb))
end
def defaults(:lex_runtime) do
%{service_override: :lex}
|> Map.merge(defaults(:lex))
end
def defaults(:lex_models) do
%{service_override: :lex}
|> Map.merge(defaults(:lex))
end
def defaults(:"personalize-runtime") do
%{service_override: :personalize}
|> Map.merge(defaults(:personalize))
end
def defaults(:"personalize-events") do
%{service_override: :personalize}
|> Map.merge(defaults(:personalize))
end
def defaults(:sagemaker_runtime) do
%{service_override: :sagemaker}
|> Map.merge(defaults(:sagemaker))
end
def defaults(:sagemaker_runtime_a2i) do
%{service_override: :sagemaker}
|> Map.merge(defaults(:sagemaker))
end
def defaults(:iot_data) do
%{service_override: :iotdata}
|> Map.merge(defaults(:iot))
end
def defaults(:"session.qldb") do
%{service_override: :qldb}
|> Map.merge(defaults(:qldb))
end
def defaults(:ingest_timestream) do
%{service_override: :timestream}
|> Map.merge(defaults(:timestream))
end
def defaults(:query_timestream) do
%{service_override: :timestream}
|> Map.merge(defaults(:timestream))
end
def defaults(service) when service in [:places, :maps, :geofencing, :tracking, :routes] do
%{service_override: :geo}
|> Map.merge(defaults(:geo))
end
def defaults(chime_service)
when chime_service in [
:"chime-sdk-media-pipelines",
:"chime-sdk-identity",
:"chime-sdk-meetings",
:"chime-sdk-voice"
] do
%{service_override: :chime}
|> Map.merge(defaults(:chime))
end
def defaults(_) do
Map.merge(
%{
scheme: "https://",
region: "us-east-1",
port: 443
},
@common
)
end
def get(service, region) do
service
|> defaults
|> Map.put(:host, host(service, region))
end
@partitions [
{~r/^(us|eu|af|ap|sa|ca|me)\-\w+-\d?-?\w+$/, "aws"},
{~r/^cn\-\w+\-\d+$/, "aws-cn"},
{~r/^us\-gov\-\w+\-\d+$/, "aws-us-gov"}
]
def host(service, region) do
partition =
Enum.find(@partitions, fn {regex, _} ->
Regex.run(regex, region)
end)
with {_, partition} <- partition do
do_host(partition, service, region)
end
end
defp service_map(:ses), do: "email"
defp service_map(:sagemaker_runtime), do: "runtime.sagemaker"
defp service_map(:sagemaker_runtime_a2i), do: "a2i-runtime.sagemaker"
defp service_map(:lex_runtime), do: "runtime.lex"
defp service_map(:lex_models), do: "models.lex"
defp service_map(:dynamodb_streams), do: "streams.dynamodb"
defp service_map(:iot_data), do: "data.iot"
defp service_map(:ingest_timestream), do: "ingest.timestream"
defp service_map(:query_timestream), do: "query.timestream"
defp service_map(:places), do: "places.geo"
defp service_map(:maps), do: "maps.geo"
defp service_map(:geofencing), do: "geofencing.geo"
defp service_map(:tracking), do: "tracking.geo"
defp service_map(:routes), do: "routes.geo"
defp service_map(service) do
service
|> to_string
|> String.replace("_", "-")
end
@external_resource "priv/endpoints.exs"
@partition_data Code.eval_file("priv/endpoints.exs", File.cwd!())
|> elem(0)
|> Map.get("partitions")
|> Map.new(fn partition ->
{partition["partition"], partition}
end)
defp do_host(partition, service_slug, region) do
partition = @partition_data |> Map.fetch!(partition)
partition_name = partition["partition"]
service = service_map(service_slug)
partition
|> Map.fetch!("services")
|> fetch_or(service, "#{service_slug} not found in partition #{partition_name}")
|> case do
%{"isRegionalized" => false} = data ->
data
|> Map.fetch!("endpoints")
|> Map.values()
|> List.first()
data ->
data
|> Map.fetch!("endpoints")
|> fetch_or(
region,
"#{service_slug} not supported in region #{region} for partition #{partition_name}"
)
end
|> case do
%{"hostname" => hostname} ->
hostname
_ ->
dns_suffix = Map.fetch!(partition, "dnsSuffix")
hostname = Map.fetch!(partition, "defaults") |> Map.fetch!("hostname")
apply_defaults(hostname, service, region, dns_suffix)
end
end
defp fetch_or(map, key, msg) do
Map.get(map, key) || raise msg
end
def apply_defaults(hostname, service, region, dns_suffix) do
hostname
|> String.replace("{service}", service)
|> String.replace("{region}", region)
|> String.replace("{dnsSuffix}", dns_suffix)
end
end