From d62e079489c07201cb343f2ca109fecd62d6e567 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Tue, 8 Mar 2011 21:24:54 +1100 Subject: Fixed #2346 - A much cleverer EC2 fact The fact now checks for an EC2 ARP or in the EU Zone for an EC2 MAC This should mean the fact's return is much more robust The fact also now supports returning userdata (which is a bit ugly given Facter returns strings but a good bookmark for refactor in 2.0) --- lib/facter/ec2.rb | 82 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/facter/ec2.rb b/lib/facter/ec2.rb index ea29d14..29b2a1c 100644 --- a/lib/facter/ec2.rb +++ b/lib/facter/ec2.rb @@ -1,27 +1,46 @@ -# Changelog: -# Original facts - Tim Dysinger -# Updated and added can_connect? function - KurtBe +# Original fact Tim Dysinger +# Additional work from KurtBe +# Additional work for Paul Nasrat +# Additional work modelled on Ohai EC2 fact require 'open-uri' -require 'timeout' - -def can_connect?(ip,port,wait_sec=2) - url = "http://#{ip}:#{port}/" - Timeout::timeout(wait_sec) {open(url)} - return true -rescue Timeout::Error - return false -rescue - return false -end +require 'socket' + +EC2_ADDR = "169.254.169.254" +EC2_METADATA_URL = "http://#{EC2_ADDR}/2008-02-01/meta-data" +EC2_USERDATA_URL = "http://#{EC2_ADDR}/2008-02-01/user-data" +def can_metadata_connect?(addr, port, timeout=2) + t = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0) + saddr = Socket.pack_sockaddr_in(port, addr) + connected = false + + begin + t.connect_nonblock(saddr) + rescue Errno::EINPROGRESS + r,w,e = IO::select(nil,[t],nil,timeout) + if !w.nil? + connected = true + else + begin + t.connect_nonblock(saddr) + rescue Errno::EISCONN + t.close + connected = true + rescue SystemCallError + end + end + rescue SystemCallError + end + connected +end def metadata(id = "") - open("http://169.254.169.254/2008-02-01/meta-data/#{id||=''}").read. + open("#{EC2_METADATA_URL}/#{id||=''}").read. split("\n").each do |o| key = "#{id}#{o.gsub(/\=.*$/, '/')}" if key[-1..-1] != '/' - value = open("http://169.254.169.254/2008-02-01/meta-data/#{key}").read. + value = open("#{EC2_METADATA_URL}/#{key}").read. split("\n") value = value.size>1 ? value : value.first symbol = "ec2_#{key.gsub(/\-|\//, '_')}".to_sym @@ -32,7 +51,34 @@ def metadata(id = "") end end -if can_connect?("169.254.169.254","80") - metadata +def userdata() + # assumes the only expected error is the 404 if there's no user-data + begin + value = OpenURI.open_uri("#{EC2_USERDATA_URL}/").read.split + Facter.add(:ec2_userdata) { setcode { value } } + rescue OpenURI::HTTPError + end end +def has_euca_mac? + if Facter.value(:macaddress) =~ /^[dD]0:0[dD]:/ + return true + else + return false + end +end + +def has_ec2_arp? + if Facter.value(:arp) == 'fe:ff:ff:ff:ff:ff' + return true + else + return false + end +end + +if (has_euca_mac? || has_ec2_arp?) && can_metadata_connect?(EC2_ADDR,80) + metadata + userdata +else + Facter.debug "Not an EC2 host" +end -- cgit