Merge pull request #94 from chef/interface

Merged change ff4b5b58-4dbe-4acd-8a36-8f11e1a7db0d

From review branch interface into master

Signed-off-by: drichter <drichter@chef.io>
This commit is contained in:
chef-delivery 2015-10-08 04:09:19 -07:00
commit 6799af8ce5
6 changed files with 222 additions and 3 deletions

122
lib/resources/interface.rb Normal file
View file

@ -0,0 +1,122 @@
# encoding: utf-8
# author: Christoph Hartmann
# author: Dominik Richter
# Usage:
# describe interface('eth0') do
# it { should exist }
# it { should be_up }
# its(:speed) { should eq 1000 }
# end
require 'utils/convert'
class NetworkInterface < Vulcano.resource(1)
name 'interface'
def initialize(iface)
@iface = iface
@interface_provider = nil
if vulcano.os.linux?
@interface_provider = LinuxInterface.new(vulcano)
elsif vulcano.os.windows?
@interface_provider = WindowsInterface.new(vulcano)
else
return skip_resource 'The `interface` resource is not supported on your OS yet.'
end
end
def exists?
!interface_info.nil? && !interface_info[:name].nil?
end
def up?
interface_info.nil? ? false : interface_info[:up]
end
# returns link speed in Mbits/sec
def speed
interface_info.nil? ? nil : interface_info[:speed]
end
private
def interface_info
return @cache if defined?(@cache)
@cache = @interface_provider.interface_info(@iface) if !@interface_provider.nil?
end
end
class InterfaceInfo
include Converter
def initialize(vulcano)
@vulcano = vulcano
end
end
class LinuxInterface < InterfaceInfo
def interface_info(iface)
# will return "[mtu]\n1500\n[type]\n1"
cmd = @vulcano.command("find /sys/class/net/#{iface}/ -type f -maxdepth 1 -exec sh -c 'echo \"[$(basename {})]\"; cat {} || echo -n' \\;")
return nil if cmd.exit_status.to_i != 0
# parse values, we only recieve values, therefore we threat them as keys
params = SimpleConfig.new(cmd.stdout.chomp).params
# abort if we got an empty result-set
return nil if params.empty?
# parse state
state = false
if params.key?('operstate')
operstate, _value = params['operstate'].first
state = operstate == 'up'
end
# parse speed
speed = nil
if params.key?('speed')
speed, _value = params['speed'].first
speed = convert_to_i(speed)
end
{
name: iface,
up: state,
speed: speed,
}
end
end
class WindowsInterface < InterfaceInfo
def interface_info(iface)
# gather all network interfaces
cmd = @vulcano.command('Get-NetAdapter | Select-Object -Property Name, InterfaceDescription, Status, State, MacAddress, LinkSpeed, ReceiveLinkSpeed, TransmitLinkSpeed, Virtual | ConvertTo-Json')
# filter network interface
begin
net_adapter = JSON.parse(cmd.stdout)
rescue JSON::ParserError => _e
return nil
end
# ensure we have an array of groups
net_adapter = [net_adapter] if !net_adapter.is_a?(Array)
# select the requested interface
adapters = net_adapter.each_with_object([]) do |adapter, adapter_collection|
# map object
info = {
name: adapter['Name'],
up: adapter['State'] == 2,
speed: adapter['ReceiveLinkSpeed'] / 1000,
}
adapter_collection.push(info) if info[:name].casecmp(iface) == 0
end
return nil if adapters.size == 0
warn "[Possible Error] detected multiple network interfaces with the name #{iface}" if adapters.size > 1
adapters[0]
end
end

View file

@ -34,6 +34,7 @@ require 'resources/gem'
require 'resources/group'
require 'resources/group_policy'
require 'resources/inetd_conf'
require 'resources/interface'
require 'resources/json'
require 'resources/kernel_module'
require 'resources/kernel_parameter'

View file

@ -79,6 +79,11 @@ class MockLoader
stdout = ::File.read(::File.join(scriptpath, '/unit/mock/cmd/'+x))
mock.mock_command(stdout, '', 0)
}
empty = lambda {
mock.mock_command('', '', 0)
}
mock.commands = {
'ps aux' => cmd.call('ps-aux'),
'type win_secpol.cfg' => cmd.call('secedit-export'),
@ -124,12 +129,12 @@ class MockLoader
'service sendmail onestatus' => cmd.call('service-sendmail-onestatus'),
# services for system 5 e.g. centos6, debian 6
'service sshd status' => cmd.call('service-sshd-status'),
'find /etc/rc*.d -name S*' => cmd.call('find-etc-rc-d-name-S'),
'find /etc/rc*.d -name S*' => cmd.call('find-etc-rc-d-name-S'),
'ls -1 /etc/init.d/' => cmd.call('ls-1-etc-init.d'),
# user information for linux
'id root' => cmd.call('id-root'),
'getent passwd root' => cmd.call('getent-passwd-root'),
'chage -l root' => cmd.call('chage-l-root'),
'chage -l root' => cmd.call('chage-l-root'),
# user info for mac
'id chartmann' => cmd.call('id-chartmann'),
'dscl -q . -read /Users/chartmann NFSHomeDirectory PrimaryGroupID RecordName UniqueID UserShell' => cmd.call('dscl'),
@ -138,7 +143,11 @@ class MockLoader
# user info for windows
'650b6b72a66316418b25421a54afe21a230704558082914c54711904bb10e370' => cmd.call('GetUserAccount'),
# group info for windows
'Get-WmiObject Win32_Group | Select-Object -Property Caption, Domain, Name, SID, LocalAccount | ConvertTo-Json' => cmd.call('GetWin32Group'),
'Get-WmiObject Win32_Group | Select-Object -Property Caption, Domain, Name, SID, LocalAccount | ConvertTo-Json' => cmd.call('GetWin32Group'),
# network interface
'9e80f048a1af5a0f6ab8a465e46ea5ed5ba6587e9b5e54a7a0c0a1a02bb6f663' => cmd.call('find-net-interface'),
'c33821dece09c8b334e03a5bb9daefdf622007f73af4932605e758506584ec3f' => empty.call,
'Get-NetAdapter | Select-Object -Property Name, InterfaceDescription, Status, State, MacAddress, LinkSpeed, ReceiveLinkSpeed, TransmitLinkSpeed, Virtual | ConvertTo-Json' => cmd.call('Get-NetAdapter'),
}
# set os emulation

View file

@ -0,0 +1,24 @@
[
{
"Name": "vEthernet (Intel(R) PRO 1000 MT Network Connection - Virtual Switch)",
"InterfaceDescription": "Hyper-V Virtual Ethernet Adapter #2",
"Status": "Up",
"State": 2,
"MacAddress": "00-0C-29-E3-48-9B",
"LinkSpeed": "10 Gbps",
"ReceiveLinkSpeed": 10000000000,
"TransmitLinkSpeed": 10000000000,
"Virtual": true
},
{
"Name": "Ethernet0",
"InterfaceDescription": "Intel(R) PRO/1000 MT Network Connection",
"Status": "Not Present",
"State": 3,
"MacAddress": "00-0C-29-E3-48-9B",
"LinkSpeed": "0 bps",
"ReceiveLinkSpeed": 0,
"TransmitLinkSpeed": 0,
"Virtual": false
}
]

View file

@ -0,0 +1,9 @@
[speed]
10000
[phys_switch_id]
[duplex]
full
[address]
02:42:ac:11:00:11
[operstate]
up

View file

@ -0,0 +1,54 @@
# encoding: utf-8
# author: Christoph Hartmann
# author: Dominik Richter
require 'helper'
require 'vulcano/resource'
describe 'Vulcano::Resources::Group' do
# ubuntu 14.04
it 'verify interface on ubuntu' do
resource = MockLoader.new(:ubuntu1404).load_resource('interface', 'eth0')
_(resource.exists?).must_equal true
_(resource.up?).must_equal true
_(resource.speed).must_equal 10000
end
it 'verify invalid interface on ubuntu' do
resource = MockLoader.new(:ubuntu1404).load_resource('interface', 'eth1')
_(resource.exists?).must_equal false
_(resource.up?).must_equal false
_(resource.speed).must_equal nil
end
it 'verify interface on windows' do
resource = MockLoader.new(:windows).load_resource('interface', 'ethernet0')
_(resource.exists?).must_equal true
_(resource.up?).must_equal false
_(resource.speed).must_equal 0
end
it 'verify interface on windows' do
resource = MockLoader.new(:windows).load_resource('interface', 'vEthernet (Intel(R) PRO 1000 MT Network Connection - Virtual Switch)')
_(resource.exists?).must_equal true
_(resource.up?).must_equal true
_(resource.speed).must_equal 10000000
end
it 'verify invalid interface on windows' do
resource = MockLoader.new(:windows).load_resource('interface', 'eth1')
_(resource.exists?).must_equal false
_(resource.up?).must_equal false
_(resource.speed).must_equal nil
end
# undefined
it 'verify interface on unsupported os' do
resource = MockLoader.new(:undefined).load_resource('interface', 'eth0')
_(resource.exists?).must_equal false
_(resource.up?).must_equal false
_(resource.speed).must_equal nil
end
end