Skip to content

Commit

Permalink
Add LinuxAdmin::NetworkInterface.list
Browse files Browse the repository at this point in the history
Previously there wasn't a method for listing interfaces on the system,
which was okay because we assumed an eth0 was available but as we move
away from that and use the standard predictable network interface names
it would be helpful to get a list.
  • Loading branch information
agrare committed Aug 1, 2024
1 parent 12c3933 commit dc04eb2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
15 changes: 15 additions & 0 deletions lib/linux_admin/network_interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ def self.dist_class(clear_cache = false)
end
end

def self.list
ip_link.pluck("ifname").map { |iface| new(iface) }
rescue AwesomeSpawn::CommandResultError => e
raise NetworkInterfaceError.new(e.message, e.result)
end

private_class_method def self.ip_link
require "json"

ip_link = Common.run!(Common.cmd("ip"), :params => ["--json", "link"])
JSON.parse(ip_link.output)
rescue AwesomeSpawn::CommandResultError, JSON::ParserError => e
raise NetworkInterfaceError.new(e.message, e.result)
end

# Creates an instance of the correct NetworkInterface subclass for the local distro
def self.new(*args)
self == LinuxAdmin::NetworkInterface ? dist_class.new(*args) : super
Expand Down
45 changes: 44 additions & 1 deletion spec/network_interface_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,21 @@
end

context "on all systems" do
IP_SHOW_ARGS = [
IP_LINK_ARGS = [
LinuxAdmin::Common.cmd("ip"),
:params => %w(--json link)
]

IP_SHOW_ARGS = IP_SHOW_ETH0_ARGS = [
LinuxAdmin::Common.cmd("ip"),
:params => %w(addr show eth0)
]

IP_SHOW_LO_ARGS = [
LinuxAdmin::Common.cmd("ip"),
:params => %w(addr show lo)
]

IP_ROUTE_ARGS = [
LinuxAdmin::Common.cmd("ip"),
:params => ['-4', 'route']
Expand All @@ -80,6 +90,19 @@
:params => ["eth0"]
]

IP_LINK_OUT = <<~IP_OUT
[{"ifindex":1,"ifname":"lo","flags":["LOOPBACK","UP","LOWER_UP"],"mtu":65536,"qdisc":"noqueue","operstate":"UNKNOWN","linkmode":"DEFAULT","group":"default","txqlen":1000,"link_type":"loopback","address":"00:00:00:00:00:00","broadcast":"00:00:00:00:00:00"},{"ifindex":2,"ifname":"eth0","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"fq_codel","operstate":"UP","linkmode":"DEFAULT","group":"default","txqlen":1000,"link_type":"ether","address":"52:54:00:e8:67:81","broadcast":"ff:ff:ff:ff:ff:ff","altnames":["enp0s2","ens2"]}]
IP_OUT

IP_ADDR_LO_OUT = <<~IP_OUT
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
IP_OUT

IP_ADDR_OUT = <<-IP_OUT
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:ed:0e:8b brd ff:ff:ff:ff:ff:ff
Expand Down Expand Up @@ -115,6 +138,18 @@
link/ether 52:54:00:ce:b4:f4 brd ff:ff:ff:ff:ff:ff
IP_OUT

subject(:subj_list) do
allow(LinuxAdmin::Distros).to receive(:local).and_return(LinuxAdmin::Distros.generic)
described_class.dist_class(true)

allow(AwesomeSpawn).to receive(:run!).with(*IP_LINK_ARGS).and_return(result(IP_LINK_OUT, 0))
allow(AwesomeSpawn).to receive(:run!).with(*IP_SHOW_LO_ARGS).and_return(result(IP_ADDR_LO_OUT, 0))
allow(AwesomeSpawn).to receive(:run!).with(*IP_SHOW_ETH0_ARGS).and_return(result(IP_ADDR_OUT, 0))
allow(AwesomeSpawn).to receive(:run!).with(*IP_ROUTE_ARGS).and_return(result(IP_ROUTE_OUT, 0))
allow(AwesomeSpawn).to receive(:run!).with(*IP6_ROUTE_ARGS).and_return(result(IP6_ROUTE_OUT, 0))
described_class.list
end

subject(:subj) do
allow(LinuxAdmin::Distros).to receive(:local).and_return(LinuxAdmin::Distros.generic)
described_class.dist_class(true)
Expand Down Expand Up @@ -149,6 +184,14 @@ def result(output, exit_status)
AwesomeSpawn::CommandResult.new("", output, "", nil, exit_status)
end

describe ".list" do
it "returns a list of NetworkInterface objects" do
interfaces = subj_list
expect(interfaces.count).to eq(2)
expect(interfaces.map(&:interface)).to match_array(["eth0", "lo"])
end
end

describe "#reload" do
it "returns false when ip addr show fails" do
subj
Expand Down

0 comments on commit dc04eb2

Please sign in to comment.