diff --git a/lib/linux_admin/distro.rb b/lib/linux_admin/distro.rb index f125911..b2f2997 100644 --- a/lib/linux_admin/distro.rb +++ b/lib/linux_admin/distro.rb @@ -18,8 +18,12 @@ def self.ubuntu @ubuntu ||= Distro.new(:ubuntu, nil, ['ubuntu'], LinuxAdmin::Deb) end + def self.mac + @mac ||= Distro.new(:mac, "/etc/mach_init.d") + end + def self.all - @distros ||= [rhel, fedora, ubuntu, generic] + @distros ||= [rhel, fedora, ubuntu, mac, generic] end def self.local diff --git a/lib/linux_admin/network_interface.rb b/lib/linux_admin/network_interface.rb index 5b8d40a..9968288 100644 --- a/lib/linux_admin/network_interface.rb +++ b/lib/linux_admin/network_interface.rb @@ -16,6 +16,8 @@ def self.dist_class(clear_cache = false) @dist_class ||= begin if [Distros.rhel, Distros.fedora].include?(Distros.local) NetworkInterfaceRH + elsif Distros.mac == Distros.local + NetworkInterfaceMac else NetworkInterfaceGeneric end @@ -45,7 +47,7 @@ def initialize(interface) # @raise [NetworkInterfaceError] if network information cannot be retrieved def reload @network_conf = {} - return false unless (ip_output = ip_show) + return unless (ip_output = ip_show) parse_ip4(ip_output) parse_ip6(ip_output, :global) @@ -53,11 +55,8 @@ def reload @network_conf[:mac] = parse_ip_output(ip_output, %r{link/ether}, 1) - ip_route_res = run!(cmd("ip"), :params => ["route"]) - @network_conf[:gateway] = parse_ip_output(ip_route_res.output, /^default/, 2) if ip_route_res.success? - true - rescue AwesomeSpawn::CommandResultError => e - raise NetworkInterfaceError.new(e.message, e.result) + @network_conf[:gateway] = parse_ip_output(ip_route, /^default/, 2) + self end # Retrieve the IPv4 address assigned to the interface @@ -154,6 +153,16 @@ def ip_show raise NetworkInterfaceError.new(e.message, e.result) end + # Runs the command `ip route` + # + # @return [String] The command output + # @raise [NetworkInterfaceError] if the command fails + def ip_route + run!(cmd("ip"), :params => ["route"]).output + rescue AwesomeSpawn::CommandResultError => e + raise NetworkInterfaceError.new(e.message, e.result) + end + # Parses the IPv4 information from the output of `ip addr show ` # # @param ip_output [String] The command output diff --git a/lib/linux_admin/network_interface/network_interface_mac.rb b/lib/linux_admin/network_interface/network_interface_mac.rb new file mode 100644 index 0000000..6ef4e97 --- /dev/null +++ b/lib/linux_admin/network_interface/network_interface_mac.rb @@ -0,0 +1,35 @@ +require 'socket' + +module LinuxAdmin + class NetworkInterfaceMac < NetworkInterface + # Determine the ip address of a ipv4 (non loopback) interface + # NOTE: currently ignores the interface name + # + # @return [String] The command output + # @raise [NetworkInterfaceError] if the command fails + def ip_show + socket = Socket.ip_address_list.detect { |intf| intf.ipv4? && !intf.ipv4_loopback? } + if socket + socket.ip_address + else + raise NetworkInterfaceError.new("could not find ipv4 interface", 4) + end + end + + # Determine the Runs the command `ip route` + # + # @return [String] The command output + # @raise [NetworkInterfaceError] if the command fails + def ip_route + gateway = run!(cmd("route"), :params => %w(-n get default)).output + .split("\n").detect { |l| l =~ /gateway/ }.split(":").last.strip + "default via #{gateway} dev #{@interface}" + rescue AwesomeSpawn::CommandResultError => e + raise NetworkInterfaceError.new(e.message, e.result) + end + + def parse_conf + # currently a noop + end + end +end diff --git a/lib/linux_admin/time_date.rb b/lib/linux_admin/time_date.rb index 487d46b..af0aca6 100644 --- a/lib/linux_admin/time_date.rb +++ b/lib/linux_admin/time_date.rb @@ -6,10 +6,12 @@ class TimeDate TimeCommandError = Class.new(StandardError) def self.system_timezone_detailed - result = run(cmd(COMMAND), :params => ["status"]) + result = run!(cmd(COMMAND), :params => ["status"]) result.output.split("\n").each do |l| return l.split(':')[1].strip if l =~ /Time.*zone/ end + rescue AwesomeSpawn::CommandResultError, AwesomeSpawn::NoSuchFileError + Time.now.zone end def self.system_timezone diff --git a/spec/distro_spec.rb b/spec/distro_spec.rb index 3f22d6a..e418bfd 100644 --- a/spec/distro_spec.rb +++ b/spec/distro_spec.rb @@ -30,23 +30,29 @@ context "/etc/redhat-release exists" do it "returns Distros.rhel" do - exists("/etc/fedora-release" => false, "/etc/redhat-release" => true) + exists("/etc/fedora-release" => false, "/etc/redhat-release" => true, "/etc/mach_init.d" => false) expect(subject).to eq(LinuxAdmin::Distros.rhel) end end context "/etc/fedora-release exists" do it "returns Distros.fedora" do - exists("/etc/fedora-release" => true, "/etc/redhat-release" => false) + exists("/etc/fedora-release" => true, "/etc/redhat-release" => false, "/etc/mach_init.d" => false) expect(subject).to eq(LinuxAdmin::Distros.fedora) end end - end - it "returns Distros.generic" do - etc_issue_contains('') - exists("/etc/fedora-release" => false, "/etc/redhat-release" => false) - expect(subject).to eq(LinuxAdmin::Distros.generic) + context "/etc/mach_init.d exists" do + it "returns Distros.mac" do + exists("/etc/fedora-release" => false, "/etc/redhat-release" => false, "/etc/mach_init.d" => true) + expect(subject).to eq(LinuxAdmin::Distros.mac) + end + end + + it "returns Distros.generic" do + exists("/etc/fedora-release" => false, "/etc/redhat-release" => false, "/etc/mach_init.d" => false) + expect(subject).to eq(LinuxAdmin::Distros.generic) + end end end @@ -63,7 +69,7 @@ LinuxAdmin::Distros.local.info 'ruby' end - it "dispatches to ubuntu lookup mechanism" do + it "dispatches to generic lookup mechanism" do stub_distro(LinuxAdmin::Distros.generic) expect { LinuxAdmin::Distros.local.info 'ruby' }.not_to raise_error end diff --git a/spec/network_interface/network_interface_mac_spec.rb b/spec/network_interface/network_interface_mac_spec.rb new file mode 100644 index 0000000..e28ada1 --- /dev/null +++ b/spec/network_interface/network_interface_mac_spec.rb @@ -0,0 +1,17 @@ +describe LinuxAdmin::NetworkInterfaceMac do + it "raises exception if none found" do + expect(Socket).to receive(:ip_address_list).and_return([]) + expect { described_class.new("eth0") }.to raise_error(LinuxAdmin::NetworkInterfaceError) + end + + it "returns the ip of the first ipv4 non loopback device" do + expect(Socket).to receive(:ip_address_list).at_least(:once).and_return([ + double(:ipv4? => false, :ipv4_loopback? => false, :ip_address => "::1"), + double(:ipv4? => true, :ipv4_loopback? => true, :ip_address => "127.0.0.1"), + double(:ipv4? => true, :ipv4_loopback? => false, :ip_address => "192.168.10.10"), + ]) + expect_any_instance_of(described_class).to receive(:ip_route).and_return("1921.68.1.1") + ip = described_class.new("eth0") + expect(ip.ip_show).to eq("192.168.10.10") + end +end diff --git a/spec/network_interface_spec.rb b/spec/network_interface_spec.rb index 10ff209..3da7337 100644 --- a/spec/network_interface_spec.rb +++ b/spec/network_interface_spec.rb @@ -35,6 +35,28 @@ end end + context "on mac" do + subject do + allow_any_instance_of(LinuxAdmin::NetworkInterfaceMac).to receive(:ip_show).and_return(nil) + allow(LinuxAdmin::Distros).to receive(:local).and_return(LinuxAdmin::Distros.mac) + described_class.dist_class(true) + described_class.new("eth0") + end + + describe ".dist_class" do + it "returns NetworkInterfaceMac" do + allow(LinuxAdmin::Distros).to receive(:local).and_return(LinuxAdmin::Distros.mac) + expect(described_class.dist_class(true)).to eq(LinuxAdmin::NetworkInterfaceMac) + end + end + + describe ".new" do + it "creates a NetworkInterfaceMac instance" do + expect(subject).to be_an_instance_of(LinuxAdmin::NetworkInterfaceMac) + end + end + end + context "on other linux systems" do subject do allow_any_instance_of(described_class).to receive(:ip_show).and_return(nil)