ohai 8.6.0.alpha.1 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -12
  3. data/lib/ohai/config.rb +3 -0
  4. data/lib/ohai/dsl/plugin/versionvii.rb +41 -0
  5. data/lib/ohai/exception.rb +1 -0
  6. data/lib/ohai/mixin/softlayer_metadata.rb +64 -0
  7. data/lib/ohai/plugin_config.rb +46 -0
  8. data/lib/ohai/plugins/aix/cpu.rb +23 -18
  9. data/lib/ohai/plugins/aix/memory.rb +9 -2
  10. data/lib/ohai/plugins/aix/network.rb +1 -1
  11. data/lib/ohai/plugins/cloud.rb +34 -3
  12. data/lib/ohai/plugins/ec2.rb +6 -0
  13. data/lib/ohai/plugins/linux/network.rb +245 -190
  14. data/lib/ohai/plugins/linux/platform.rb +50 -15
  15. data/lib/ohai/plugins/linux/virtualization.rb +3 -1
  16. data/lib/ohai/plugins/softlayer.rb +47 -0
  17. data/lib/ohai/plugins/solaris2/cpu.rb +46 -17
  18. data/lib/ohai/plugins/solaris2/memory.rb +9 -1
  19. data/lib/ohai/plugins/vmware.rb +73 -0
  20. data/lib/ohai/plugins/windows/memory.rb +38 -0
  21. data/lib/ohai/version.rb +1 -1
  22. data/spec/unit/config_spec.rb +28 -0
  23. data/spec/unit/dsl/plugin_spec.rb +73 -0
  24. data/spec/unit/mixin/softlayer_metadata_spec.rb +71 -0
  25. data/spec/unit/plugin_config_spec.rb +118 -0
  26. data/spec/unit/plugins/aix/cpu_spec.rb +31 -12
  27. data/spec/unit/plugins/aix/memory_spec.rb +47 -0
  28. data/spec/unit/plugins/aix/network_spec.rb +1 -1
  29. data/spec/unit/plugins/ec2_spec.rb +35 -13
  30. data/spec/unit/plugins/linux/memory_spec.rb +204 -0
  31. data/spec/unit/plugins/linux/network_spec.rb +40 -0
  32. data/spec/unit/plugins/linux/platform_spec.rb +62 -6
  33. data/spec/unit/plugins/linux/virtualization_spec.rb +21 -0
  34. data/spec/unit/plugins/softlayer_spec.rb +60 -0
  35. data/spec/unit/plugins/solaris2/cpu_spec.rb +2887 -42
  36. data/spec/unit/plugins/solaris2/memory_spec.rb +15 -2
  37. data/spec/unit/plugins/vmware_spec.rb +62 -0
  38. data/spec/unit/plugins/windows/memory_spec.rb +52 -0
  39. metadata +18 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 12feba79315d30d742f71e9c26690a64ad71d11e
4
- data.tar.gz: fcf8ae37a2db845807a95a41deccf634a3373ff8
3
+ metadata.gz: e00fe8c9c7789a01f275184d7cfe7a6bbc4a8631
4
+ data.tar.gz: 2368b6c70151bf9b89ee2dc2d3518a8d10add807
5
5
  SHA512:
6
- metadata.gz: a901bb634ac4cc771412dd23140c7c6af7d52e0123e9ba010d7debe478ccc678e7acfcf8302c7c9be972b4fcccc25c8a73d58872c985640ba66998be96785541
7
- data.tar.gz: 4f792e178bf51309803110aad9c9ddb107aa7724417437013b845918d89244f09320389179bb12278ea3e57a86551d1ef2768592345f42a77d34eba40f8b4cff
6
+ metadata.gz: 9aa2d69b2544e9b270429795f02e3db9e8d2b978c16afba7fecfd377cfac3553c8da4a350a1e8d4edc55577c0a64d8d1d2266dc8135f1d354455494fb7b741c5
7
+ data.tar.gz: 523a0112f688c7536c5f4bff387ec0218f4ba8f0c97e995917dba271c2f41137c4793e572c826f3050ca577b4a0483c776c98376bd71a93913b61f388db8a79c
data/Rakefile CHANGED
@@ -1,18 +1,7 @@
1
- require 'rubygems'
2
- require 'rubygems/package_task'
3
- require 'rubygems/specification'
1
+ require "bundler/gem_tasks"
4
2
  require 'date'
5
3
  require 'ohai/version'
6
4
 
7
- gemspec = eval(IO.read("ohai.gemspec"))
8
-
9
- Gem::PackageTask.new(gemspec).define
10
-
11
- desc "install the gem locally"
12
- task :install => [:package] do
13
- sh %{gem install pkg/ohai-#{Ohai::VERSION}.gem}
14
- end
15
-
16
5
  begin
17
6
  require 'rspec/core/rake_task'
18
7
 
@@ -18,7 +18,9 @@
18
18
  #
19
19
 
20
20
  require 'chef-config/config'
21
+ require 'ohai/exception'
21
22
  require 'ohai/log'
23
+ require 'ohai/plugin_config'
22
24
 
23
25
  module Ohai
24
26
  Config = ChefConfig::Config
@@ -93,6 +95,7 @@ module Ohai
93
95
  default :hints_path, Ohai::Config.default_hints_path
94
96
  default :log_level, :auto
95
97
  default :log_location, STDERR
98
+ default :plugin, Ohai::PluginConfig.new { |h, k| h[k] = Ohai::PluginConfig.new }
96
99
  default :plugin_path, Ohai::Config.default_plugin_path
97
100
  end
98
101
 
@@ -100,6 +100,47 @@ module Ohai
100
100
  def require_plugin(*args)
101
101
  Ohai::Log.warn("[UNSUPPORTED OPERATION] \'require_plugin\' is no longer supported. Please use \'depends\' instead.\nIgnoring plugin(s) #{args.join(", ")}")
102
102
  end
103
+
104
+ def configuration(option, *options)
105
+ return nil if plugin_config.nil? || !plugin_config.key?(option)
106
+ value = plugin_config[option]
107
+ options.each do |opt|
108
+ return nil unless value.key?(opt)
109
+ value = value[opt]
110
+ end
111
+ value
112
+ end
113
+
114
+ private
115
+ def plugin_config
116
+ @plugin_config ||= fetch_plugin_config
117
+ end
118
+
119
+ def fetch_plugin_config
120
+ # DMI => ["DMI"]
121
+ # Memory => ["", "Memory"]
122
+ # NetworkListeners => ["", "Network", "", "Listeners"]
123
+ # SSHHostKey => ["SSH", "Host", "", "Key"]
124
+ parts = self.name.to_s.split(/([A-Z][a-z]+)/)
125
+ # ["DMI"] => ["DMI"]
126
+ # ["", "Memory"] => ["Memory"]
127
+ # ["", "Network", "", "Listeners"] => ["Network", "Listeners"]
128
+ # ["SSH", "Host", "", "Key"] => ["SSH", "Host", "Key"]
129
+ parts.delete_if { |part| part.empty? }
130
+ # ["DMI"] => :dmi
131
+ # ["Memory"] => :memory
132
+ # ["Network", "Listeners"] => :network_listeners
133
+ # ["SSH", "Host", "Key"] => :ssh_host_key
134
+ snake_case_name = parts.map { |part| part.downcase }.join("_").to_sym
135
+
136
+ # Plugin names in config hashes are auto-vivified, so we check with
137
+ # key? to avoid falsely instantiating a configuration hash.
138
+ if Ohai.config[:plugin].key?(snake_case_name)
139
+ Ohai.config[:plugin][snake_case_name]
140
+ else
141
+ nil
142
+ end
143
+ end
103
144
  end
104
145
  end
105
146
  end
@@ -28,5 +28,6 @@ module Ohai
28
28
  class DependencyCycle < Error; end
29
29
  class DependencyNotFound < Error; end
30
30
  class AttributeSyntaxError < Error; end
31
+ class PluginConfigError < Error; end
31
32
  end
32
33
  end
@@ -0,0 +1,64 @@
1
+ #
2
+ # Author:: Alexey Karpik <alexey.karpik@rightscale.com>
3
+ # Author:: Peter Schroeter <peter.schroeter@rightscale.com>
4
+ # Author:: Stas Turlo <stanislav.turlo@rightscale.com>
5
+ # Copyright:: Copyright (c) 2010-2014 RightScale Inc
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+
20
+ require 'net/https'
21
+ require 'uri'
22
+
23
+ # http://sldn.softlayer.com/reference/services/SoftLayer_Resource_Metadata
24
+ module ::Ohai::Mixin::SoftlayerMetadata
25
+ SOFTLAYER_API_QUERY_URL = 'https://api.service.softlayer.com/rest/v3.1/SoftLayer_Resource_Metadata' unless defined?(SOFTLAYER_API_QUERY_URL)
26
+
27
+ def fetch_metadata
28
+ metadata = {
29
+ 'public_fqdn' => fetch_metadata_item("getFullyQualifiedDomainName.txt"),
30
+ 'local_ipv4' => fetch_metadata_item("getPrimaryBackendIpAddress.txt"),
31
+ 'public_ipv4' => fetch_metadata_item("getPrimaryIpAddress.txt"),
32
+ 'region' => fetch_metadata_item("getDatacenter.txt"),
33
+ 'instance_id' => fetch_metadata_item("getId.txt")
34
+ }
35
+ end
36
+
37
+ # Softlayer's metadata api is only available over HTTPS.
38
+ # Ruby by default does not link to the system's CA bundle
39
+ # however Chef-omnibus should set SSL_CERT_FILE to point to a valid file.
40
+ # Manually supply and specify a suitable CA bundle here or
41
+ # set the SSL_CERT_FILE file environment variable to a valid value otherwise.
42
+ def ca_file_location
43
+ ::Ohai::Config[:ca_file]
44
+ end
45
+
46
+ def fetch_metadata_item(item)
47
+ full_url = "#{SOFTLAYER_API_QUERY_URL}/#{item}"
48
+ u = URI(full_url)
49
+ net = ::Net::HTTP.new(u.hostname, u.port)
50
+ net.ssl_version = "TLSv1"
51
+ net.use_ssl = true
52
+ net.ca_file = ca_file_location
53
+ res = net.get(u.request_uri)
54
+ if res.code.to_i.between?(200,299)
55
+ res.body
56
+ else
57
+ ::Ohai::Log.error("Unable to fetch item #{full_url}: status (#{res.code}) body (#{res.body})")
58
+ nil
59
+ end
60
+ rescue => e
61
+ ::Ohai::Log.error("Unable to fetch softlayer metadata from #{u}: #{e.class}: #{e.message}")
62
+ raise e
63
+ end
64
+ end
@@ -0,0 +1,46 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
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
+
18
+ require 'ohai/exception'
19
+
20
+ module Ohai
21
+ class PluginConfig < Hash
22
+
23
+ def []=(key, value_or_hash)
24
+ enforce_symbol(key)
25
+ enforce_symbol_keys(value_or_hash) if value_or_hash.is_a?(Hash)
26
+ super(key, value_or_hash)
27
+ end
28
+
29
+ private
30
+
31
+ def enforce_symbol(key)
32
+ unless key.is_a?(Symbol)
33
+ msg = "Expected Symbol, got #{key.inspect}"
34
+ raise Ohai::Exceptions::PluginConfigError, msg
35
+ end
36
+ end
37
+
38
+ def enforce_symbol_keys(hash)
39
+ hash.each do |key, value|
40
+ enforce_symbol(key)
41
+ enforce_symbol_keys(value) if value.is_a?(Hash)
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -22,32 +22,37 @@ Ohai.plugin(:CPU) do
22
22
 
23
23
  collect_data(:aix) do
24
24
  cpu Mash.new
25
-
26
- # IBM is the only maker of CPUs for AIX systems.
27
- cpu[:vendor_id] = "IBM"
25
+
26
+ cpu[:total] = shell_out("pmcycles -m").stdout.lines.length
28
27
  # At least one CPU will be available, but we'll wait to increment this later.
29
28
  cpu[:available] = 0
30
- cpu[:total] = 0
31
29
 
32
30
  cpudevs = shell_out("lsdev -Cc processor").stdout.lines
33
- cpudevs.each do |c|
34
- cpu[:total] += 1
31
+ #from http://www-01.ibm.com/software/passportadvantage/pvu_terminology_for_customers.html
32
+ #on AIX number of cores and processors are considered same
33
+ cpu[:real] = cpu[:cores] = cpudevs.length
34
+ cpudevs.each.with_index do |c,i|
35
35
  name, status, location = c.split
36
- cpu[name] = Mash.new
37
- cpu[name][:status] = status
38
- cpu[name][:location] = location
36
+ index = i.to_s
37
+ cpu[index] = Mash.new
38
+ cpu[index][:status] = status
39
+ cpu[index][:location] = location
39
40
  if status =~ /Available/
40
- cpu[:available] += 1
41
- lsattr = shell_out("lsattr -El #{name}").stdout.lines
42
- lsattr.each do |attribute|
41
+ cpu[:available] += 1
42
+ lsattr = shell_out("lsattr -El #{name}").stdout.lines
43
+ lsattr.each do |attribute|
43
44
  attrib, value = attribute.split
44
- cpu[name][attrib] = value
45
- end
45
+ if attrib == "type"
46
+ cpu[index][:model_name] = value
47
+ elsif attrib == "frequency"
48
+ cpu[index][:mhz] = value.to_i / (1000 * 1000) #convert from hz to MHz
49
+ else
50
+ cpu[index][attrib] = value
51
+ end
52
+ end
53
+ # IBM is the only maker of CPUs for AIX systems.
54
+ cpu[index][:vendor_id] = "IBM"
46
55
  end
47
56
  end
48
-
49
- # Every AIX system has proc0.
50
- cpu[:model] = cpu[:proc0][:type]
51
- cpu[:mhz] = cpu[:proc0][:frequency].to_i / 1024
52
57
  end
53
58
  end
@@ -20,9 +20,16 @@ Ohai.plugin(:Memory) do
20
20
  provides "memory"
21
21
 
22
22
  collect_data(:aix) do
23
- memory = Mash.new
23
+ memory Mash.new
24
+ memory[:swap] = Mash.new
24
25
 
25
26
  meminfo = shell_out("svmon -G -O unit=MB,summary=longreal | grep '[0-9]'").stdout
26
- memory[:total], u, memory[:free] = meminfo.split
27
+ total_in_mb, u, free_in_mb = meminfo.split
28
+ memory[:total] = "#{total_in_mb.to_i * 1024}kB"
29
+ memory[:free] = "#{free_in_mb.to_i * 1024}kB"
30
+
31
+ swapinfo = shell_out("swap -s").stdout.split #returns swap info in 4K blocks
32
+ memory[:swap]['total'] = "#{(swapinfo[2].to_i) * 4}kB"
33
+ memory[:swap]['free'] = "#{(swapinfo[10].to_i) * 4}kB"
27
34
  end
28
35
  end
@@ -56,7 +56,7 @@ Ohai.plugin(:Network) do
56
56
  end
57
57
 
58
58
  # List the interfaces in system.
59
- so = shell_out("lsdev -Cc if")
59
+ so = shell_out("lsdev -Cc if | grep Available")
60
60
  so.stdout.lines.each do |line|
61
61
  if line =~ /(\S+) (\S+)\s+(.+)/
62
62
  interface = $1
@@ -25,6 +25,7 @@ Ohai.plugin(:Cloud) do
25
25
  depends "openstack"
26
26
  depends "azure"
27
27
  depends "digital_ocean"
28
+ depends "softlayer"
28
29
 
29
30
  # Make top-level cloud hashes
30
31
  #
@@ -60,7 +61,7 @@ Ohai.plugin(:Cloud) do
60
61
  private_ips = gce['instance']["networkInterfaces"].collect do |interface|
61
62
  interface['ip']
62
63
  end.compact
63
-
64
+
64
65
  cloud[:public_ips] += public_ips
65
66
  cloud[:private_ips] += private_ips
66
67
  cloud[:public_ipv4] += public_ips
@@ -108,7 +109,7 @@ Ohai.plugin(:Cloud) do
108
109
  end
109
110
 
110
111
  # Fill cloud hash with rackspace values
111
- def get_rackspace_values
112
+ def get_rackspace_values
112
113
  cloud[:public_ips] << rackspace['public_ipv4'] if rackspace['public_ipv4']
113
114
  cloud[:private_ips] << rackspace['local_ipv4'] if rackspace['local_ipv4']
114
115
  cloud[:public_ipv4] = rackspace['public_ipv4']
@@ -245,7 +246,31 @@ Ohai.plugin(:Cloud) do
245
246
  cloud[:provider] = "digital_ocean"
246
247
  end
247
248
 
248
- collect_data do
249
+ # ----------------------------------------
250
+ # softlayer
251
+ # ----------------------------------------
252
+
253
+ # Is current cloud softlayer?
254
+ #
255
+ # === Return
256
+ # true:: If softlayer Hash is defined
257
+ # false:: Otherwise
258
+ def on_softlayer?
259
+ softlayer != nil
260
+ end
261
+
262
+ # Fill cloud hash with softlayer values
263
+ def get_softlayer_values
264
+ cloud[:public_ipv4] = softlayer['public_ipv4']
265
+ cloud[:local_ipv4] = softlayer['local_ipv4']
266
+ cloud[:public_ips] << softlayer['public_ipv4'] if softlayer['public_ipv4']
267
+ cloud[:private_ips] << softlayer['local_ipv4'] if softlayer['local_ipv4']
268
+ cloud[:public_hostname] = softlayer['public_fqdn']
269
+ cloud[:provider] = 'softlayer'
270
+ end
271
+
272
+
273
+ collect_data do
249
274
  # setup gce cloud
250
275
  if on_gce?
251
276
  create_objects
@@ -292,5 +317,11 @@ Ohai.plugin(:Cloud) do
292
317
  create_objects
293
318
  get_digital_ocean_values
294
319
  end
320
+
321
+ # setup softlayer cloud
322
+ if on_softlayer?
323
+ create_objects
324
+ get_softlayer_values
325
+ end
295
326
  end
296
327
  end
@@ -18,6 +18,7 @@
18
18
  # limitations under the License.
19
19
 
20
20
  require 'ohai/mixin/ec2_metadata'
21
+ require 'base64'
21
22
 
22
23
  Ohai.plugin(:EC2) do
23
24
  include Ohai::Mixin::Ec2Metadata
@@ -58,6 +59,11 @@ Ohai.plugin(:EC2) do
58
59
  ec2[k] = v
59
60
  end
60
61
  ec2[:userdata] = self.fetch_userdata
62
+ #ASCII-8BIT is equivalent to BINARY in this case
63
+ if ec2[:userdata].encoding.to_s == "ASCII-8BIT"
64
+ Ohai::Log.debug("Binary UserData Found. Storing in base64")
65
+ ec2[:userdata] = Base64.encode64(ec2[:userdata])
66
+ end
61
67
  else
62
68
  Ohai::Log.debug("looks_like_ec2? == false")
63
69
  false
@@ -41,6 +41,246 @@ Ohai.plugin(:Network) do
41
41
  ["/sbin/ip", "/usr/bin/ip", "/bin/ip"].any? { |path| File.exist?(path) }
42
42
  end
43
43
 
44
+ def is_openvz?
45
+ ::File.directory?('/proc/vz')
46
+ end
47
+
48
+ def is_openvz_host?
49
+ is_openvz? && ::File.directory?('/proc/bc')
50
+ end
51
+
52
+ def extract_neighbors(family, iface, neigh_attr)
53
+ so = shell_out("ip -f #{family[:name]} neigh show")
54
+ so.stdout.lines do |line|
55
+ if line =~ /^([a-f0-9\:\.]+)\s+dev\s+([^\s]+)\s+lladdr\s+([a-fA-F0-9\:]+)/
56
+ interface = iface[$2]
57
+ unless interface
58
+ Ohai::Log.warn("neighbor list has entries for unknown interface #{interface}")
59
+ next
60
+ end
61
+ interface[neigh_attr] = Mash.new unless interface[neigh_attr]
62
+ interface[neigh_attr][$1] = $3.downcase
63
+ end
64
+ end
65
+ iface
66
+ end
67
+
68
+ # checking the routing tables
69
+ # why ?
70
+ # 1) to set the default gateway and default interfaces attributes
71
+ # 2) on some occasions, the best way to select node[:ipaddress] is to look at
72
+ # the routing table source field.
73
+ # 3) and since we're at it, let's populate some :routes attributes
74
+ # (going to do that for both inet and inet6 addresses)
75
+ def check_routing_table(family, iface)
76
+ so = shell_out("ip -o -f #{family[:name]} route show")
77
+ so.stdout.lines do |line|
78
+ line.strip!
79
+ Ohai::Log.debug("Parsing #{line}")
80
+ if line =~ /\\/
81
+ parts = line.split('\\')
82
+ route_dest = parts.shift.strip
83
+ route_endings = parts
84
+ elsif line =~ /^([^\s]+)\s(.*)$/
85
+ route_dest = $1
86
+ route_endings = [$2]
87
+ else
88
+ next
89
+ end
90
+ route_endings.each do |route_ending|
91
+ if route_ending =~ /\bdev\s+([^\s]+)\b/
92
+ route_int = $1
93
+ else
94
+ Ohai::Log.debug("Skipping route entry without a device: '#{line}'")
95
+ next
96
+ end
97
+ route_int = 'venet0:0' if is_openvz? && !is_openvz_host? && route_int == 'venet0' && iface['venet0:0']
98
+
99
+ unless iface[route_int]
100
+ Ohai::Log.debug("Skipping previously unseen interface from 'ip route show': #{route_int}")
101
+ next
102
+ end
103
+
104
+ route_entry = Mash.new(:destination => route_dest,
105
+ :family => family[:name])
106
+ %w[via scope metric proto src].each do |k|
107
+ route_entry[k] = $1 if route_ending =~ /\b#{k}\s+([^\s]+)\b/
108
+ end
109
+
110
+ # a sanity check, especially for Linux-VServer, OpenVZ and LXC:
111
+ # don't report the route entry if the src address isn't set on the node
112
+ next if route_entry[:src] and not iface[route_int][:addresses].has_key? route_entry[:src]
113
+
114
+ iface[route_int][:routes] = Array.new unless iface[route_int][:routes]
115
+ iface[route_int][:routes] << route_entry
116
+ end
117
+ end
118
+ iface
119
+ end
120
+
121
+ # now looking at the routes to set the default attributes
122
+ # for information, default routes can be of this form :
123
+ # - default via 10.0.2.4 dev br0
124
+ # - default dev br0 scope link
125
+ # - default via 10.0.3.1 dev eth1 src 10.0.3.2 metric 10
126
+ # - default via 10.0.4.1 dev eth2 src 10.0.4.2 metric 20
127
+
128
+ # using a temporary var to hold routes and their interface name
129
+ def parse_routes(family, iface)
130
+ iface.collect do |i, iv|
131
+ iv[:routes].collect do |r|
132
+ r.merge(:dev => i) if r[:family] == family[:name]
133
+ end.compact if iv[:routes]
134
+ end.compact.flatten
135
+ end
136
+
137
+
138
+ def link_statistics(iface, net_counters)
139
+ so = shell_out("ip -d -s link")
140
+ tmp_int = nil
141
+ on_rx = true
142
+ so.stdout.lines do |line|
143
+ if line =~ IPROUTE_INT_REGEX
144
+ tmp_int = $2
145
+ iface[tmp_int] = Mash.new unless iface[tmp_int]
146
+ net_counters[tmp_int] = Mash.new unless net_counters[tmp_int]
147
+ end
148
+
149
+ if line =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/
150
+ int = on_rx ? :rx : :tx
151
+ net_counters[tmp_int][int] = Mash.new unless net_counters[tmp_int][int]
152
+ net_counters[tmp_int][int][:bytes] = $1
153
+ net_counters[tmp_int][int][:packets] = $2
154
+ net_counters[tmp_int][int][:errors] = $3
155
+ net_counters[tmp_int][int][:drop] = $4
156
+ if (int == :rx)
157
+ net_counters[tmp_int][int][:overrun] = $5
158
+ else
159
+ net_counters[tmp_int][int][:carrier] = $5
160
+ net_counters[tmp_int][int][:collisions] = $6
161
+ end
162
+
163
+ on_rx = !on_rx
164
+ end
165
+
166
+ if line =~ /qlen (\d+)/
167
+ net_counters[tmp_int][:tx] = Mash.new unless net_counters[tmp_int][:tx]
168
+ net_counters[tmp_int][:tx][:queuelen] = $1
169
+ end
170
+
171
+ if line =~ /vlan id (\d+)/ or line =~ /vlan protocol ([\w\.]+) id (\d+)/
172
+ if $2
173
+ tmp_prot = $1
174
+ tmp_id = $2
175
+ else
176
+ tmp_id = $1
177
+ end
178
+ iface[tmp_int][:vlan] = Mash.new unless iface[tmp_int][:vlan]
179
+ iface[tmp_int][:vlan][:id] = tmp_id
180
+ iface[tmp_int][:vlan][:protocol] = tmp_prot if tmp_prot
181
+
182
+ vlan_flags = line.scan(/(REORDER_HDR|GVRP|LOOSE_BINDING)/)
183
+ if vlan_flags.length > 0
184
+ iface[tmp_int][:vlan][:flags] = vlan_flags.flatten.uniq
185
+ end
186
+ end
187
+
188
+ if line =~ /state (\w+)/
189
+ iface[tmp_int]['state'] = $1.downcase
190
+ end
191
+ end
192
+ iface
193
+ end
194
+
195
+ def match_iproute(iface, line, cint)
196
+ if line =~ IPROUTE_INT_REGEX
197
+ cint = $2
198
+ iface[cint] = Mash.new
199
+ if cint =~ /^(\w+)(\d+.*)/
200
+ iface[cint][:type] = $1
201
+ iface[cint][:number] = $2
202
+ end
203
+
204
+ if line =~ /mtu (\d+)/
205
+ iface[cint][:mtu] = $1
206
+ end
207
+
208
+ flags = line.scan(/(UP|BROADCAST|DEBUG|LOOPBACK|POINTTOPOINT|NOTRAILERS|LOWER_UP|NOARP|PROMISC|ALLMULTI|SLAVE|MASTER|MULTICAST|DYNAMIC)/)
209
+ if flags.length > 1
210
+ iface[cint][:flags] = flags.flatten.uniq
211
+ end
212
+ end
213
+ cint
214
+ end
215
+
216
+ def parse_ip_addr(iface)
217
+ so = shell_out("ip addr")
218
+ cint = nil
219
+ so.stdout.lines do |line|
220
+ cint = match_iproute(iface, line, cint)
221
+
222
+ parse_ip_addr_link_line(cint, iface, line)
223
+ cint = parse_ip_addr_inet_line(cint, iface, line)
224
+ parse_ip_addr_inet6_line(cint, iface, line)
225
+ end
226
+ end
227
+
228
+
229
+ def parse_ip_addr_link_line(cint, iface, line)
230
+ if line =~ /link\/(\w+) ([\da-f\:]+) /
231
+ iface[cint][:encapsulation] = linux_encaps_lookup($1)
232
+ unless $2 == "00:00:00:00:00:00"
233
+ iface[cint][:addresses] = Mash.new unless iface[cint][:addresses]
234
+ iface[cint][:addresses][$2.upcase] = {"family" => "lladdr"}
235
+ end
236
+ end
237
+ end
238
+
239
+ def parse_ip_addr_inet_line(cint, iface, line)
240
+ if line =~ /inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(\/(\d{1,2}))?/
241
+ tmp_addr, tmp_prefix = $1, $3
242
+ tmp_prefix ||= "32"
243
+ original_int = nil
244
+
245
+ # Are we a formerly aliased interface?
246
+ if line =~ /#{cint}:(\d+)$/
247
+ sub_int = $1
248
+ alias_int = "#{cint}:#{sub_int}"
249
+ original_int = cint
250
+ cint = alias_int
251
+ end
252
+
253
+ iface[cint] = Mash.new unless iface[cint] # Create the fake alias interface if needed
254
+ iface[cint][:addresses] = Mash.new unless iface[cint][:addresses]
255
+ iface[cint][:addresses][tmp_addr] = {"family" => "inet", "prefixlen" => tmp_prefix}
256
+ iface[cint][:addresses][tmp_addr][:netmask] = IPAddr.new("255.255.255.255").mask(tmp_prefix.to_i).to_s
257
+
258
+ if line =~ /peer (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
259
+ iface[cint][:addresses][tmp_addr][:peer] = $1
260
+ end
261
+
262
+ if line =~ /brd (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
263
+ iface[cint][:addresses][tmp_addr][:broadcast] = $1
264
+ end
265
+
266
+ if line =~ /scope (\w+)/
267
+ iface[cint][:addresses][tmp_addr][:scope] = ($1.eql?("host") ? "Node" : $1.capitalize)
268
+ end
269
+
270
+ # If we found we were an an alias interface, restore cint to its original value
271
+ cint = original_int unless original_int.nil?
272
+ end
273
+ cint
274
+ end
275
+
276
+ def parse_ip_addr_inet6_line(cint, iface, line)
277
+ if line =~ /inet6 ([a-f0-9\:]+)\/(\d+) scope (\w+)/
278
+ iface[cint][:addresses] = Mash.new unless iface[cint][:addresses]
279
+ tmp_addr = $1
280
+ iface[cint][:addresses][tmp_addr] = {"family" => "inet6", "prefixlen" => $2, "scope" => ($3.eql?("host") ? "Node" : $3.capitalize)}
281
+ end
282
+ end
283
+
44
284
  collect_data(:linux) do
45
285
  require 'ipaddr'
46
286
 
@@ -73,204 +313,19 @@ Ohai.plugin(:Network) do
73
313
  :neighbour_attribute => :neighbour_inet6
74
314
  } if ipv6_enabled?
75
315
 
76
- so = shell_out("ip addr")
77
- cint = nil
78
- so.stdout.lines do |line|
79
- if line =~ IPROUTE_INT_REGEX
80
- cint = $2
81
- iface[cint] = Mash.new
82
- if cint =~ /^(\w+)(\d+.*)/
83
- iface[cint][:type] = $1
84
- iface[cint][:number] = $2
85
- end
86
-
87
- if line =~ /mtu (\d+)/
88
- iface[cint][:mtu] = $1
89
- end
90
-
91
- flags = line.scan(/(UP|BROADCAST|DEBUG|LOOPBACK|POINTTOPOINT|NOTRAILERS|LOWER_UP|NOARP|PROMISC|ALLMULTI|SLAVE|MASTER|MULTICAST|DYNAMIC)/)
92
- if flags.length > 1
93
- iface[cint][:flags] = flags.flatten.uniq
94
- end
95
- end
96
- if line =~ /link\/(\w+) ([\da-f\:]+) /
97
- iface[cint][:encapsulation] = linux_encaps_lookup($1)
98
- unless $2 == "00:00:00:00:00:00"
99
- iface[cint][:addresses] = Mash.new unless iface[cint][:addresses]
100
- iface[cint][:addresses][$2.upcase] = { "family" => "lladdr" }
101
- end
102
- end
103
- if line =~ /inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(\/(\d{1,2}))?/
104
- tmp_addr, tmp_prefix = $1, $3
105
- tmp_prefix ||= "32"
106
- original_int = nil
107
-
108
- # Are we a formerly aliased interface?
109
- if line =~ /#{cint}:(\d+)$/
110
- sub_int = $1
111
- alias_int = "#{cint}:#{sub_int}"
112
- original_int = cint
113
- cint = alias_int
114
- end
316
+ parse_ip_addr(iface)
115
317
 
116
- iface[cint] = Mash.new unless iface[cint] # Create the fake alias interface if needed
117
- iface[cint][:addresses] = Mash.new unless iface[cint][:addresses]
118
- iface[cint][:addresses][tmp_addr] = { "family" => "inet", "prefixlen" => tmp_prefix }
119
- iface[cint][:addresses][tmp_addr][:netmask] = IPAddr.new("255.255.255.255").mask(tmp_prefix.to_i).to_s
120
-
121
- if line =~ /peer (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
122
- iface[cint][:addresses][tmp_addr][:peer] = $1
123
- end
124
-
125
- if line =~ /brd (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
126
- iface[cint][:addresses][tmp_addr][:broadcast] = $1
127
- end
128
-
129
- if line =~ /scope (\w+)/
130
- iface[cint][:addresses][tmp_addr][:scope] = ($1.eql?("host") ? "Node" : $1.capitalize)
131
- end
132
-
133
- # If we found we were an an alias interface, restore cint to its original value
134
- cint = original_int unless original_int.nil?
135
- end
136
- if line =~ /inet6 ([a-f0-9\:]+)\/(\d+) scope (\w+)/
137
- iface[cint][:addresses] = Mash.new unless iface[cint][:addresses]
138
- tmp_addr = $1
139
- iface[cint][:addresses][tmp_addr] = { "family" => "inet6", "prefixlen" => $2, "scope" => ($3.eql?("host") ? "Node" : $3.capitalize) }
140
- end
141
- end
142
-
143
- so = shell_out("ip -d -s link")
144
- tmp_int = nil
145
- on_rx = true
146
- so.stdout.lines do |line|
147
- if line =~ IPROUTE_INT_REGEX
148
- tmp_int = $2
149
- iface[tmp_int] = Mash.new unless iface[tmp_int]
150
- net_counters[tmp_int] = Mash.new unless net_counters[tmp_int]
151
- end
152
-
153
- if line =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/
154
- int = on_rx ? :rx : :tx
155
- net_counters[tmp_int][int] = Mash.new unless net_counters[tmp_int][int]
156
- net_counters[tmp_int][int][:bytes] = $1
157
- net_counters[tmp_int][int][:packets] = $2
158
- net_counters[tmp_int][int][:errors] = $3
159
- net_counters[tmp_int][int][:drop] = $4
160
- if(int == :rx)
161
- net_counters[tmp_int][int][:overrun] = $5
162
- else
163
- net_counters[tmp_int][int][:carrier] = $5
164
- net_counters[tmp_int][int][:collisions] = $6
165
- end
166
-
167
- on_rx = !on_rx
168
- end
169
-
170
- if line =~ /qlen (\d+)/
171
- net_counters[tmp_int][:tx] = Mash.new unless net_counters[tmp_int][:tx]
172
- net_counters[tmp_int][:tx][:queuelen] = $1
173
- end
174
-
175
- if line =~ /vlan id (\d+)/ or line =~ /vlan protocol ([\w\.]+) id (\d+)/
176
- if $2
177
- tmp_prot = $1
178
- tmp_id = $2
179
- else
180
- tmp_id = $1
181
- end
182
- iface[tmp_int][:vlan] = Mash.new unless iface[tmp_int][:vlan]
183
- iface[tmp_int][:vlan][:id] = tmp_id
184
- iface[tmp_int][:vlan][:protocol] = tmp_prot if tmp_prot
185
-
186
- vlan_flags = line.scan(/(REORDER_HDR|GVRP|LOOSE_BINDING)/)
187
- if vlan_flags.length > 0
188
- iface[tmp_int][:vlan][:flags] = vlan_flags.flatten.uniq
189
- end
190
- end
191
-
192
- if line =~ /state (\w+)/
193
- iface[tmp_int]['state'] = $1.downcase
194
- end
195
- end
318
+ iface = link_statistics(iface, net_counters)
196
319
 
197
320
  families.each do |family|
198
321
  neigh_attr = family[:neighbour_attribute]
199
322
  default_prefix = family[:default_prefix]
200
323
 
201
- so = shell_out("ip -f #{family[:name]} neigh show")
202
- so.stdout.lines do |line|
203
- if line =~ /^([a-f0-9\:\.]+)\s+dev\s+([^\s]+)\s+lladdr\s+([a-fA-F0-9\:]+)/
204
- unless iface[$2]
205
- Ohai::Log.warn("neighbour list has entries for unknown interface #{iface[$2]}")
206
- next
207
- end
208
- iface[$2][neigh_attr] = Mash.new unless iface[$2][neigh_attr]
209
- iface[$2][neigh_attr][$1] = $3.downcase
210
- end
211
- end
212
-
213
- # checking the routing tables
214
- # why ?
215
- # 1) to set the default gateway and default interfaces attributes
216
- # 2) on some occasions, the best way to select node[:ipaddress] is to look at
217
- # the routing table source field.
218
- # 3) and since we're at it, let's populate some :routes attributes
219
- # (going to do that for both inet and inet6 addresses)
220
- so = shell_out("ip -o -f #{family[:name]} route show")
221
- so.stdout.lines do |line|
222
- line.strip!
223
- Ohai::Log.debug("Parsing #{line}")
224
- if line =~ /\\/
225
- parts = line.split('\\')
226
- route_dest = parts.shift.strip
227
- route_endings = parts
228
- elsif line =~ /^([^\s]+)\s(.*)$/
229
- route_dest = $1
230
- route_endings = [$2]
231
- else
232
- next
233
- end
234
- route_endings.each do |route_ending|
235
- if route_ending =~ /\bdev\s+([^\s]+)\b/
236
- route_int = $1
237
- else
238
- Ohai::Log.debug("Skipping route entry without a device: '#{line}'")
239
- next
240
- end
241
-
242
- unless iface[route_int]
243
- Ohai::Log.debug("Skipping previously unseen interface from 'ip route show': #{route_int}")
244
- next
245
- end
246
-
247
- route_entry = Mash.new( :destination => route_dest,
248
- :family => family[:name] )
249
- %w[via scope metric proto src].each do |k|
250
- route_entry[k] = $1 if route_ending =~ /\b#{k}\s+([^\s]+)\b/
251
- end
324
+ iface = extract_neighbors(family, iface, neigh_attr)
252
325
 
253
- # a sanity check, especially for Linux-VServer, OpenVZ and LXC:
254
- # don't report the route entry if the src address isn't set on the node
255
- next if route_entry[:src] and not iface[route_int][:addresses].has_key? route_entry[:src]
326
+ iface = check_routing_table(family, iface)
256
327
 
257
- iface[route_int][:routes] = Array.new unless iface[route_int][:routes]
258
- iface[route_int][:routes] << route_entry
259
- end
260
- end
261
- # now looking at the routes to set the default attributes
262
- # for information, default routes can be of this form :
263
- # - default via 10.0.2.4 dev br0
264
- # - default dev br0 scope link
265
- # - default via 10.0.3.1 dev eth1 src 10.0.3.2 metric 10
266
- # - default via 10.0.4.1 dev eth2 src 10.0.4.2 metric 20
267
-
268
- # using a temporary var to hold routes and their interface name
269
- routes = iface.collect do |i,iv|
270
- iv[:routes].collect do |r|
271
- r.merge(:dev=>i) if r[:family] == family[:name]
272
- end.compact if iv[:routes]
273
- end.compact.flatten
328
+ routes = parse_routes(family, iface)
274
329
 
275
330
  # using a temporary var to hold the default route
276
331
  # in case there are more than 1 default route, sort it by its metric