Class: RightScale::MetadataSources::HttpMetadataSource

Inherits:
RightScale::MetadataSource show all
Defined in:
lib/clouds/metadata_sources/http_metadata_source.rb

Overview

Provides metadata via a single http connection which is kept alive in the case of a tree of metadata.

Instance Attribute Summary collapse

Attributes inherited from RightScale::MetadataSource

#logger

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from RightScale::MetadataSource

#append_branch_name, #append_leaf_name

Constructor Details

#initialize(options) ⇒ HttpMetadataSource

Returns a new instance of HttpMetadataSource.

Raises:

  • (ArgumentError)


36
37
38
39
40
41
# File 'lib/clouds/metadata_sources/http_metadata_source.rb', line 36

def initialize(options)
  super(options)
  raise ArgumentError, "options[:hosts] is required" unless @hosts = options[:hosts]
  @host, @port = self.class.(@hosts)
  @connections = {}
end

Instance Attribute Details

#hostObject

Returns the value of attribute host.



34
35
36
# File 'lib/clouds/metadata_sources/http_metadata_source.rb', line 34

def host
  @host
end

#portObject

Returns the value of attribute port.



34
35
36
# File 'lib/clouds/metadata_sources/http_metadata_source.rb', line 34

def port
  @port
end

Class Method Details

.select_metadata_server(hosts) ⇒ Object

selects a host/port by attempting to dig one or more well-known DNS names or IP addresses.

Parameters

hosts(Array)

array of hosts in the form [=> <dns name or ip address>, :port => <port or nil>+]

Return

result(Array)

pair in form of [<selected host ip address>, <selected port>]



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/clouds/metadata_sources/http_metadata_source.rb', line 105

def self.(hosts)
  # note that .each works for strings (by newline) and arrays.
  last_exception = nil
  hosts.each do |host_data|
    begin
      # resolve metadata server hostname.
      addrs = Socket.gethostbyname(host_data[:host])[3..-1]

      # select only IPv4 addresses
      addrs = addrs.select { |x| x.length == 4 }

      # choose a random IPv4 address
      raw_ip = addrs[rand(addrs.size)]

      # transform binary IP address into string representation
      ip = []
      raw_ip.each_byte { |x| ip << x.to_s }
      return [ip.join('.'), host_data[:port] || 80]
    rescue Exception => e
      last_exception = e
    end
  end
  raise last_exception
end

Instance Method Details

#finishObject

Closes any http connections left open after fetching metadata.



86
87
88
89
90
91
92
93
94
95
# File 'lib/clouds/metadata_sources/http_metadata_source.rb', line 86

def finish
  @connections.each_value do |connection|
    begin
      connection.finish
    rescue Exception => e
      logger.error("Failed to close metadata http connection: #{e.backtrace.join("\n")}")
    end
  end
  @connections = {}
end

#query(path) ⇒ Object

Queries for metadata using the given path.

Parameters

path(String)

metadata path

Return

metadata(String)

query result or empty

Raises

QueryFailed

on any failure to query



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/clouds/metadata_sources/http_metadata_source.rb', line 53

def query(path)
  http_path = "http://#{@host}:#{@port}/#{path}"
  attempts = 1
  while true
    begin
      logger.debug("Querying \"#{http_path}\"...")
      # get.
      result = http_get(http_path)
      if result
        logger.debug("Successfully retrieved from: \"#{http_path}\"  Result: #{path} = #{result}")
        return result
      end

      # retry, if allowed.
      if snooze(attempts)
        logger.info("Retrying \"#{http_path}\"...")
      else
        logger.error("Could not retrieve metadata from \"#{http_path}\"; retry limit exceeded.")
        return ""
      end
    rescue Exception => e
      logger.error("#{Time.now().to_s()}: Exception occurred while attempting to retrieve metadata from \"#{http_path}\"; Exception:#{e.message}")
      finish # Reset the connections.
      unless snooze(attempts)
        logger.error("Trace:#{e.backtrace.join("\n")}")
        return ""
      end
    end
    attempts += 1
  end
end