ohai 6.16.0 → 6.18.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,11 +22,28 @@ require 'socket'
22
22
 
23
23
  module Ohai
24
24
  module Mixin
25
+ ##
26
+ # This code parses the EC2 Instance Metadata API to provide details
27
+ # of the running instance.
28
+ #
29
+ # Earlier version of this code assumed a specific version of the
30
+ # metadata API was available. Unfortunately the API versions
31
+ # supported by a particular instance are determined at instance
32
+ # launch and are not extended over the life of the instance. As such
33
+ # the earlier code would fail depending on the age of the instance.
34
+ #
35
+ # The updated code probes the instance metadata endpoint for
36
+ # available versions, determines the most advanced version known to
37
+ # work and executes the metadata retrieval using that version.
38
+ #
39
+ # If no compatible version is found, an empty hash is returned.
40
+ #
25
41
  module Ec2Metadata
26
42
 
27
43
  EC2_METADATA_ADDR = "169.254.169.254" unless defined?(EC2_METADATA_ADDR)
28
- EC2_METADATA_URL = "/2012-01-12/meta-data" unless defined?(EC2_METADATA_URL)
29
- EC2_USERDATA_URL = "/2012-01-12/user-data" unless defined?(EC2_USERDATA_URL)
44
+ EC2_SUPPORTED_VERSIONS = %w[ 1.0 2007-01-19 2007-03-01 2007-08-29 2007-10-10 2007-12-15
45
+ 2008-02-01 2008-09-01 2009-04-04 2011-01-01 2011-05-01 2012-01-12 ]
46
+
30
47
  EC2_ARRAY_VALUES = %w(security-groups)
31
48
  EC2_ARRAY_DIR = %w(network/interfaces/macs)
32
49
  EC2_JSON_DIR = %w(iam)
@@ -57,67 +74,99 @@ module Ohai
57
74
  connected
58
75
  end
59
76
 
77
+ def best_api_version
78
+ response = http_client.get("/")
79
+ unless response.code == '200'
80
+ raise "Unable to determine EC2 metadata version (returned #{response.code} response)"
81
+ end
82
+ # Note: Sorting the list of versions may have unintended consequences in
83
+ # non-EC2 environments. It appears to be safe in EC2 as of 2013-04-12.
84
+ versions = response.body.split("\n")
85
+ versions = response.body.split("\n").sort
86
+ until (versions.empty? || EC2_SUPPORTED_VERSIONS.include?(versions.last)) do
87
+ pv = versions.pop
88
+ Ohai::Log.debug("EC2 shows unsupported metadata version: #{pv}") unless pv == 'latest'
89
+ end
90
+ Ohai::Log.debug("EC2 metadata version: #{versions.last}")
91
+ if versions.empty?
92
+ raise "Unable to determine EC2 metadata version (no supported entries found)"
93
+ end
94
+ versions.last
95
+ end
96
+
60
97
  def http_client
61
98
  Net::HTTP.start(EC2_METADATA_ADDR).tap {|h| h.read_timeout = 600}
62
99
  end
63
100
 
64
- def fetch_metadata(id='')
101
+ def metadata_get(id, api_version)
102
+ response = http_client.get("/#{api_version}/meta-data/#{id}")
103
+ unless response.code == '200'
104
+ raise "Encountered error retrieving EC2 metadata (returned #{response.code} response)"
105
+ end
106
+ response
107
+ end
108
+
109
+ def fetch_metadata(id='', api_version=nil)
110
+ api_version ||= best_api_version
111
+ return Hash.new if api_version.nil?
65
112
  metadata = Hash.new
66
- http_client.get("#{EC2_METADATA_URL}/#{id}").body.split("\n").each do |o|
113
+ metadata_get(id, api_version).body.split("\n").each do |o|
67
114
  key = expand_path("#{id}#{o}")
68
115
  if key[-1..-1] != '/'
69
116
  metadata[metadata_key(key)] =
70
117
  if EC2_ARRAY_VALUES.include? key
71
- http_client.get("#{EC2_METADATA_URL}/#{key}").body.split("\n")
118
+ metadata_get(key, api_version).body.split("\n")
72
119
  else
73
- http_client.get("#{EC2_METADATA_URL}/#{key}").body
120
+ metadata_get(key, api_version).body
74
121
  end
75
122
  elsif not key.eql?(id) and not key.eql?('/')
76
123
  name = key[0..-2]
77
- sym = metadata_key(name)
124
+ sym = metadata_key(name)
78
125
  if EC2_ARRAY_DIR.include?(name)
79
- metadata[sym] = fetch_dir_metadata(key)
126
+ metadata[sym] = fetch_dir_metadata(key, api_version)
80
127
  elsif EC2_JSON_DIR.include?(name)
81
- metadata[sym] = fetch_json_dir_metadata(key)
128
+ metadata[sym] = fetch_json_dir_metadata(key, api_version)
82
129
  else
83
- fetch_metadata(key).each{|k,v| metadata[k] = v}
130
+ fetch_metadata(key, api_version).each{|k,v| metadata[k] = v}
84
131
  end
85
132
  end
86
133
  end
87
134
  metadata
88
135
  end
89
136
 
90
- def fetch_dir_metadata(id)
137
+ def fetch_dir_metadata(id, api_version)
91
138
  metadata = Hash.new
92
- http_client.get("#{EC2_METADATA_URL}/#{id}").body.split("\n").each do |o|
139
+ metadata_get(id, api_version).body.split("\n").each do |o|
93
140
  key = expand_path(o)
94
141
  if key[-1..-1] != '/'
95
- metadata[metadata_key(key)] = http_client.get("#{EC2_METADATA_URL}/#{id}#{key}").body
142
+ metadata[metadata_key(key)] = metadata_get("#{id}#{key}", api_version).body
96
143
  elsif not key.eql?('/')
97
- metadata[key[0..-2]] = fetch_dir_metadata("#{id}#{key}")
144
+ metadata[key[0..-2]] = fetch_dir_metadata("#{id}#{key}", api_version)
98
145
  end
99
146
  end
100
147
  metadata
101
148
  end
102
149
 
103
- def fetch_json_dir_metadata(id)
150
+ def fetch_json_dir_metadata(id, api_version)
104
151
  metadata = Hash.new
105
- http_client.get("#{EC2_METADATA_URL}/#{id}").body.split("\n").each do |o|
152
+ metadata_get(id, api_version).body.split("\n").each do |o|
106
153
  key = expand_path(o)
107
154
  if key[-1..-1] != '/'
108
- data = http_client.get("#{EC2_METADATA_URL}/#{id}#{key}").body
155
+ data = metadata_get("#{id}#{key}", api_version).body
109
156
  json = StringIO.new(data)
110
157
  parser = Yajl::Parser.new
111
158
  metadata[metadata_key(key)] = parser.parse(json)
112
159
  elsif not key.eql?('/')
113
- metadata[key[0..-2]] = fetch_json_dir_metadata("#{id}#{key}")
160
+ metadata[key[0..-2]] = fetch_json_dir_metadata("#{id}#{key}", api_version)
114
161
  end
115
162
  end
116
163
  metadata
117
164
  end
118
165
 
119
166
  def fetch_userdata()
120
- response = http_client.get("#{EC2_USERDATA_URL}/")
167
+ api_version = best_api_version
168
+ return nil if api_version.nil?
169
+ response = http_client.get("/#{api_version}/user-data/")
121
170
  response.code == "200" ? response.body : nil
122
171
  end
123
172
 
@@ -138,4 +187,3 @@ module Ohai
138
187
  end
139
188
  end
140
189
  end
141
-
@@ -0,0 +1,101 @@
1
+ #
2
+ # Author:: Ranjib Dey (<dey.ranjib@gmail.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'net/http'
18
+ require 'socket'
19
+
20
+ module Ohai
21
+ module Mixin
22
+ module GCEMetadata
23
+
24
+ GCE_METADATA_ADDR = "metadata.google.internal" unless defined?(GCE_METADATA_ADDR)
25
+ GCE_METADATA_URL = "/0.1/meta-data" unless defined?(GCE_METADATA_URL)
26
+
27
+ def can_metadata_connect?(addr, port, timeout=2)
28
+ t = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
29
+ saddr = Socket.pack_sockaddr_in(port, addr)
30
+ connected = false
31
+
32
+ begin
33
+ t.connect_nonblock(saddr)
34
+ rescue Errno::EINPROGRESS
35
+ r,w,e = IO::select(nil,[t],nil,timeout)
36
+ if !w.nil?
37
+ connected = true
38
+ else
39
+ begin
40
+ t.connect_nonblock(saddr)
41
+ rescue Errno::EISCONN
42
+ t.close
43
+ connected = true
44
+ rescue SystemCallError
45
+ end
46
+ end
47
+ rescue SystemCallError
48
+ end
49
+ Ohai::Log.debug("can_metadata_connect? == #{connected}")
50
+ connected
51
+ end
52
+
53
+ def http_client
54
+ Net::HTTP.start(GCE_METADATA_ADDR).tap {|h| h.read_timeout = 600}
55
+ end
56
+
57
+ def fetch_metadata(id='')
58
+ uri = "#{GCE_METADATA_URL}/#{id}"
59
+ response = http_client.get(uri)
60
+ return nil unless response.code == "200"
61
+
62
+ if json?(response.body)
63
+ data = StringIO.new(response.body)
64
+ parser = Yajl::Parser.new
65
+ parser.parse(data)
66
+ elsif has_trailing_slash?(id) or (id == '')
67
+ temp={}
68
+ response.body.split("\n").each do |sub_attr|
69
+ temp[sanitize_key(sub_attr)] = fetch_metadata("#{id}#{sub_attr}")
70
+ end
71
+ temp
72
+ else
73
+ response.body
74
+ end
75
+ end
76
+
77
+ def json?(data)
78
+ data = StringIO.new(data)
79
+ parser = Yajl::Parser.new
80
+ begin
81
+ parser.parse(data)
82
+ true
83
+ rescue Yajl::ParseError
84
+ false
85
+ end
86
+ end
87
+
88
+ def multiline?(data)
89
+ data.lines.to_a.size > 1
90
+ end
91
+
92
+ def has_trailing_slash?(data)
93
+ !! ( data =~ %r{/$} )
94
+ end
95
+
96
+ def sanitize_key(key)
97
+ key.gsub(/\-|\//, '_')
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,13 @@
1
+
2
+ provides "azure"
3
+
4
+
5
+ azure_metadata_from_hints = hint?('azure')
6
+ if azure_metadata_from_hints
7
+ Ohai::Log.debug("azure_metadata_from_hints is present.")
8
+ azure Mash.new
9
+ azure_metadata_from_hints.each {|k, v| azure[k] = v }
10
+ else
11
+ Ohai::Log.debug("No hints present for azure.")
12
+ false
13
+ end
@@ -17,10 +17,12 @@
17
17
  provides "cloud"
18
18
 
19
19
  require_plugin "ec2"
20
+ require_plugin "gce"
20
21
  require_plugin "rackspace"
21
22
  require_plugin "eucalyptus"
22
23
  require_plugin "linode"
23
24
  require_plugin "openstack"
25
+ require_plugin "azure"
24
26
 
25
27
  # Make top-level cloud hashes
26
28
  #
@@ -29,6 +31,41 @@ def create_objects
29
31
  cloud[:public_ips] = Array.new
30
32
  cloud[:private_ips] = Array.new
31
33
  end
34
+ #---------------------------------------
35
+ # Google Compute Engine (gce)
36
+ #--------------------------------------
37
+
38
+ def on_gce?
39
+ gce != nil
40
+ end
41
+ def get_gce_values
42
+ cloud[:public_ipv4] = []
43
+ cloud[:local_ipv4] = []
44
+
45
+ public_ips = gce['network']["networkInterface"].collect do |interface|
46
+ if interface.has_key?('accessConfiguration')
47
+ interface['accessConfiguration'].collect{|ac| ac['externalIp']}
48
+ end
49
+ end.flatten.compact
50
+
51
+ private_ips = gce['network']["networkInterface"].collect do |interface|
52
+ interface['ip']
53
+ end.compact
54
+
55
+ cloud[:public_ips] += public_ips
56
+ cloud[:private_ips] += private_ips
57
+ cloud[:public_ipv4] += public_ips
58
+ cloud[:public_hostname] = nil
59
+ cloud[:local_ipv4] += private_ips
60
+ cloud[:local_hostname] = gce['hostname']
61
+ cloud[:provider] = "gce"
62
+ end
63
+
64
+ # setup gce cloud
65
+ if on_gce?
66
+ create_objects
67
+ get_gce_values
68
+ end
32
69
 
33
70
  # ----------------------------------------
34
71
  # ec2
@@ -179,3 +216,32 @@ if on_openstack?
179
216
  create_objects
180
217
  get_openstack_values
181
218
  end
219
+
220
+ # ----------------------------------------
221
+ # azure
222
+ # ----------------------------------------
223
+
224
+ # Is current cloud azure?
225
+ #
226
+ # === Return
227
+ # true:: If azure Hash is defined
228
+ # false:: Otherwise
229
+ def on_azure?
230
+ azure != nil
231
+ end
232
+
233
+ # Fill cloud hash with azure values
234
+ def get_azure_values
235
+ cloud[:vm_name] = azure["vm_name"]
236
+ cloud[:public_ips] << azure['public_ip']
237
+ cloud[:public_fqdn] = azure['public_fqdn']
238
+ cloud[:public_ssh_port] = azure['public_ssh_port'] if azure['public_ssh_port']
239
+ cloud[:public_winrm_port] = azure['public_winrm_port'] if azure['public_winrm_port']
240
+ cloud[:provider] = "azure"
241
+ end
242
+
243
+ # setup azure cloud data
244
+ if on_azure?
245
+ create_objects
246
+ get_azure_values
247
+ end
@@ -0,0 +1,23 @@
1
+ #
2
+ # Author:: Nathan L Smith (<nlloyds@gmail.com>)
3
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ provides "cpu"
20
+
21
+ cpu Mash.new
22
+ cpu[:real] = from("sysctl -n hw.physicalcpu").to_i
23
+ cpu[:total] = from("sysctl -n hw.logicalcpu").to_i
@@ -0,0 +1,40 @@
1
+ #
2
+ # Author:: Ranjib Dey (<dey.ranjib@google.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ provides "gce"
18
+
19
+ require 'ohai/mixin/gce_metadata'
20
+
21
+ extend Ohai::Mixin::GCEMetadata
22
+ GOOGLE_SYSFS_DMI = '/sys/firmware/dmi/entries/1-0/raw'
23
+
24
+ #https://developers.google.com/compute/docs/instances#dmi
25
+ def has_google_dmi?
26
+ ::File.read(GOOGLE_SYSFS_DMI).include?('Google')
27
+ end
28
+
29
+ def looks_like_gce?
30
+ hint?('gce') || has_google_dmi? && can_metadata_connect?(GCE_METADATA_ADDR,80)
31
+ end
32
+
33
+ if looks_like_gce?
34
+ Ohai::Log.debug("looks_like_gce? == true")
35
+ gce Mash.new
36
+ fetch_metadata.each {|k, v| gce[k] = v }
37
+ else
38
+ Ohai::Log.debug("looks_like_gce? == false")
39
+ false
40
+ end
@@ -38,11 +38,17 @@ elsif File.exists?("/etc/enterprise-release")
38
38
  platform "oracle"
39
39
  platform_version get_redhatish_version(contents)
40
40
  elsif File.exists?("/etc/debian_version")
41
- # Ubuntu and Debian both have /etc/debian_version
42
- # Ubuntu should always have a working lsb, debian does not by default
41
+ # Ubuntu, GCEL and Debian both have /etc/debian_version
42
+ # Ubuntu, GCEL should always have a working lsb, debian does not by default
43
43
  if lsb[:id] =~ /Ubuntu/i
44
44
  platform "ubuntu"
45
45
  platform_version lsb[:release]
46
+ elsif lsb[:id] =~ /gcel/i
47
+ platform "gcel"
48
+ platform_version lsb[:release]
49
+ elsif lsb[:id] =~ /LinuxMint/i
50
+ platform "linuxmint"
51
+ platform_version lsb[:release]
46
52
  else
47
53
  if File.exists?("/usr/bin/raspi-config")
48
54
  platform "raspbian"
@@ -63,9 +69,15 @@ elsif File.exists?('/etc/gentoo-release')
63
69
  platform "gentoo"
64
70
  platform_version File.read('/etc/gentoo-release').scan(/(\d+|\.+)/).join
65
71
  elsif File.exists?('/etc/SuSE-release')
66
- platform "suse"
67
- platform_version File.read("/etc/SuSE-release").scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join(".")
68
- platform_version File.read("/etc/SuSE-release").scan(/VERSION = ([\d\.]{2,})/).flatten.join(".") if platform_version == ""
72
+ suse_release = File.read("/etc/SuSE-release")
73
+ suse_version = suse_release.scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join(".")
74
+ suse_version = suse_release[/VERSION = ([\d\.]{2,})/, 1] if suse_version == ""
75
+ platform_version suse_version
76
+ if suse_release =~ /^openSUSE/
77
+ platform "opensuse"
78
+ else
79
+ platform "suse"
80
+ end
69
81
  elsif File.exists?('/etc/slackware-version')
70
82
  platform "slackware"
71
83
  platform_version File.read("/etc/slackware-version").scan(/(\d+|\.+)/).join
@@ -82,6 +94,9 @@ elsif lsb[:id] =~ /Amazon/i
82
94
  elsif lsb[:id] =~ /ScientificSL/i
83
95
  platform "scientific"
84
96
  platform_version lsb[:release]
97
+ elsif lsb[:id] =~ /XenServer/i
98
+ platform "xenserver"
99
+ platform_version lsb[:release]
85
100
  elsif lsb[:id] # LSB can provide odd data that changes between releases, so we currently fall back on it rather than dealing with its subtleties
86
101
  platform lsb[:id].downcase
87
102
  platform_version lsb[:release]
@@ -89,11 +104,11 @@ end
89
104
 
90
105
 
91
106
  case platform
92
- when /debian/, /ubuntu/, /linuxmint/, /raspbian/
107
+ when /debian/, /ubuntu/, /linuxmint/, /raspbian/, /gcel/
93
108
  platform_family "debian"
94
109
  when /fedora/
95
110
  platform_family "fedora"
96
- when /oracle/, /centos/, /redhat/, /scientific/, /enterpriseenterprise/, /amazon/
111
+ when /oracle/, /centos/, /redhat/, /scientific/, /enterpriseenterprise/, /amazon/, /xenserver/ # Note that 'enterpriseenterprise' is oracle's LSB "distributor ID"
97
112
  platform_family "rhel"
98
113
  when /suse/
99
114
  platform_family "suse"