ohai 8.6.0.alpha.1 → 8.6.0

Sign up to get free protection for your applications and to get access to all the features.
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