Current section
Files
Jump to
Current section
Files
lib/peerage/ec2.ex
defmodule Peerage.Via.Ec2 do
@moduledoc """
A Peerage provider for easy clustering on AWS EC2 and Elastic Beanstalk
"""
alias ExAws.EC2
import SweetXml, only: [sigil_x: 2, xpath: 2, xpath: 3]
# http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
@metadata_api "http://169.254.169.254/latest/meta-data/"
# http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_InstanceState.html
@running_state_code 16
@doc """
Periodically polls the metadata and EC2 API's for other nodes in the same cluster
"""
def poll() do
%{body: doc} =
EC2.describe_instances(filters: ["tag:#{tag_name(:cluster)}": cluster(), "instance-state-code": @running_state_code])
|> ExAws.request!(aws_opts())
services = doc |> xpath(~x"//instancesSet/item"l, host: ~x"./privateIpAddress/text()",
name: ~x"./tagSet/item[key='#{tag_name(:service)}']/value/text()")
Enum.map(services, fn(service) ->
String.to_atom("#{service.name}@" <> to_string(service.host))
end)
end
defp cluster() do
%{body: doc} =
EC2.describe_instances(instance_id: instance_id())
|> ExAws.request!(aws_opts())
doc
|> xpath(~x"//tagSet/item[key='#{tag_name(:cluster)}']/value/text()")
|> to_string
end
defp instance_id() do
case :hackney.request(:get, @metadata_api <> "instance-id", [], "", hackney_opts()) do
{:ok, 200, _headers, body} -> body
_ -> raise "metadata api down"
end
end
defp aws_opts() do
[access_key_id: Application.fetch_env!(:peerage, :aws_access_key_id),
secret_access_key: Application.fetch_env!(:peerage, :aws_secret_access_key)]
end
defp hackney_opts() do
[{:connect_timeout, 500}, {:recv_timeout, 500}, :with_body]
end
defp tag_name(key) do
Application.fetch_env!(:peerage, :tags)[key]
end
end