Created
August 4, 2013 02:34
-
-
Save dbaba/6148843 to your computer and use it in GitHub Desktop.
A lightweight client for Amazon Route53 with Amazon OpsWorks + Chef11, where the latest Fog + Nokogiri don't work because of forcedly installed Ruby 1.8.7 (Enterprise).
Put this file in `libraries` folder and you can create/delete resource recordsets.
Some of source codes are imported from Fog (https://github.com/fog/fog).
Change and use this as…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'time' | |
require 'base64' | |
require 'net/http' | |
require 'net/https' | |
require 'openssl' | |
require 'uri' | |
module Route53 | |
class Client | |
def initialize(aws_access_key_id, aws_secret_access_key) | |
@endpoint = "https://route53.amazonaws.com/" | |
@aws_access_key_id = aws_access_key_id | |
@aws_secret_access_key = aws_secret_access_key | |
@version = "2012-12-12" | |
@hmac = Route53::HMAC.new('sha1', @aws_secret_access_key) | |
end | |
# Creates a recordset | |
def create_record(name, value, type, zone_id) | |
do_post("CREATE", name, value, type, zone_id) | |
end | |
# Deletes a recordset | |
def delete_record(name, value, type, zone_id) | |
do_post("DELETE", name, value, type, zone_id) | |
end | |
def create_or_update_record(name, value, type, zone_id) | |
begin | |
create_record(name, value, type, zone_id) | |
rescue | |
delete_record(name, value, type, zone_id) | |
create_record(name, value, type, zone_id) | |
end | |
end | |
private | |
def do_post(operation, name, value, type, zone_id) | |
request({ | |
:method => "POST", | |
:path => "hostedzone/#{zone_id}/rrset", | |
:body => | |
"<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/#{@version}/\"> | |
<ChangeBatch> | |
<Comment></Comment> | |
<Changes> | |
<Change> | |
<Action>#{operation}</Action> | |
<ResourceRecordSet> | |
<Name>#{name}</Name> | |
<Type>#{type}</Type> | |
<TTL>3600</TTL> | |
<ResourceRecords> | |
#{to_resource_value(value)} | |
</ResourceRecords> | |
</ResourceRecordSet> | |
</Change> | |
</Changes> | |
</ChangeBatch> | |
</ChangeResourceRecordSetsRequest>" | |
}) do |response| | |
raise response.body unless response.kind_of? Net::HTTPSuccess | |
end | |
end | |
def to_resource_value(value) | |
return "<ResourceRecord><Value>#{value}</Value></ResourceRecord>" unless value.kind_of?(Array) | |
value.map { |e| "<ResourceRecord><Value>#{e}</Value></ResourceRecord>" }.join | |
end | |
def request(params, &block) | |
params[:headers] ||= {} | |
params[:headers]['Content-Type'] = "application/xml" | |
params[:headers]['Date'] = Time.new.httpdate | |
params[:headers]['X-Amzn-Authorization'] = "AWS3-HTTPS AWSAccessKeyId=#{@aws_access_key_id},Algorithm=HmacSHA1,Signature=#{signature(params)}" | |
params[:path] = "#{@version}/#{params[:path]}" | |
uri = URI.parse("#{@endpoint}#{params[:path]}") | |
https = Net::HTTP.new(uri.host, uri.port) | |
https.use_ssl = true | |
https.start do |http| | |
case params[:method] | |
when "GET" | |
response = https.get(uri.path, params[:headers]) | |
else | |
response = https.post(uri.path, params[:body], params[:headers]) | |
end | |
yield response | |
end | |
end | |
def signature(params) | |
string_to_sign = params[:headers]['Date'] | |
signed_string = @hmac.sign(string_to_sign) | |
Base64.encode64(signed_string).chomp! | |
end | |
end | |
# imported from fog | |
class HMAC | |
def initialize(type, key) | |
@key = key | |
case type | |
when 'sha1' | |
setup_sha1 | |
when 'sha256' | |
setup_sha256 | |
end | |
end | |
def sign(data) | |
@signer.call(data) | |
end | |
private | |
def setup_sha1 | |
@digest = OpenSSL::Digest::Digest.new('sha1') | |
@signer = lambda do |data| | |
OpenSSL::HMAC.digest(@digest, @key, data) | |
end | |
end | |
def setup_sha256 | |
begin | |
@digest = OpenSSL::Digest::Digest.new('sha256') | |
@signer = lambda do |data| | |
OpenSSL::HMAC.digest(@digest, @key, data) | |
end | |
rescue RuntimeError => error | |
unless error.message == 'Unsupported digest algorithm (sha256).' | |
raise error | |
else | |
require 'hmac-sha2' | |
@hmac = ::HMAC::SHA256.new(@key) | |
@signer = lambda do |data| | |
@hmac.update(data) | |
@hmac.digest | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I've not had much experience interacting directly with the AWS Restful API. Do you know if a resource has a role assigned to it, will this work with an empty signature?