Skip to content

Commit 016276e

Browse files
authored
Merge pull request #251 from agrare/network_interface_ip_output_json
Use --json for ip command output
2 parents 1e256b9 + 3b3b128 commit 016276e

File tree

2 files changed

+39
-64
lines changed

2 files changed

+39
-64
lines changed

lib/linux_admin/network_interface.rb

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
require 'ipaddr'
2-
31
module LinuxAdmin
42
class NetworkInterface
3+
require "ipaddr"
4+
require "json"
5+
56
# Cached class instance variable for what distro we are running on
67
@dist_class = nil
78

@@ -60,14 +61,16 @@ def reload
6061
return false
6162
end
6263

63-
parse_ip4(ip_output)
64-
parse_ip6(ip_output, :global)
65-
parse_ip6(ip_output, :link)
64+
addr_info = ip_output["addr_info"]
6665

67-
@network_conf[:mac] = parse_ip_output(ip_output, %r{link/ether}, 1)
66+
parse_ip4(addr_info)
67+
parse_ip6(addr_info, "global")
68+
parse_ip6(addr_info, "link")
69+
70+
@network_conf[:mac] = ip_output["address"]
6871

6972
[4, 6].each do |version|
70-
@network_conf["gateway#{version}".to_sym] = parse_ip_output(ip_route(version), /^default/, 2)
73+
@network_conf["gateway#{version}".to_sym] = ip_route(version, "default")&.dig("gateway")
7174
end
7275
true
7376
end
@@ -168,23 +171,15 @@ def stop
168171

169172
private
170173

171-
# Parses the output of `ip addr show`
172-
#
173-
# @param output [String] The command output
174-
# @param regex [Regexp] Regular expression to match the desired output line
175-
# @param col [Fixnum] The whitespace delimited column to be returned
176-
# @return [String] The parsed data
177-
def parse_ip_output(output, regex, col)
178-
the_line = output.split("\n").detect { |l| l =~ regex }
179-
the_line.nil? ? nil : the_line.strip.split(' ')[col]
180-
end
181-
182174
# Runs the command `ip addr show <interface>`
183175
#
184176
# @return [String] The command output
185177
# @raise [NetworkInterfaceError] if the command fails
186178
def ip_show
187-
Common.run!(Common.cmd("ip"), :params => ["addr", "show", @interface]).output
179+
output = Common.run!(Common.cmd("ip"), :params => ["--json", "addr", "show", @interface]).output
180+
return {} if output.blank?
181+
182+
JSON.parse(output).first
188183
rescue AwesomeSpawn::CommandResultError => e
189184
raise NetworkInterfaceError.new(e.message, e.result)
190185
end
@@ -194,35 +189,36 @@ def ip_show
194189
# @param version [Fixnum] Version of IP protocol (4 or 6)
195190
# @return [String] The command output
196191
# @raise [NetworkInterfaceError] if the command fails
197-
def ip_route(version)
198-
Common.run!(Common.cmd("ip"), :params => ["-#{version}", 'route']).output
192+
def ip_route(version, route = "default")
193+
output = Common.run!(Common.cmd("ip"), :params => ["--json", "-#{version}", "route", "show", route]).output
194+
return {} if output.blank?
195+
196+
JSON.parse(output).first
199197
rescue AwesomeSpawn::CommandResultError => e
200198
raise NetworkInterfaceError.new(e.message, e.result)
201199
end
202200

203201
# Parses the IPv4 information from the output of `ip addr show <device>`
204202
#
205203
# @param ip_output [String] The command output
206-
def parse_ip4(ip_output)
207-
cidr_ip = parse_ip_output(ip_output, /inet /, 1)
208-
return unless cidr_ip
204+
def parse_ip4(addr_info)
205+
inet = addr_info&.detect { |addr| addr["family"] == "inet" }
206+
return if inet.nil?
209207

210-
parts = cidr_ip.split('/')
211-
@network_conf[:address] = parts[0]
212-
@network_conf[:prefix] = parts[1].to_i
208+
@network_conf[:address] = inet["local"]
209+
@network_conf[:prefix] = inet["prefixlen"]
213210
end
214211

215212
# Parses the IPv6 information from the output of `ip addr show <device>`
216213
#
217214
# @param ip_output [String] The command output
218215
# @param scope [Symbol] The IPv6 scope (either `:global` or `:local`)
219-
def parse_ip6(ip_output, scope)
220-
cidr_ip = parse_ip_output(ip_output, /inet6 .* scope #{scope}/, 1)
221-
return unless cidr_ip
216+
def parse_ip6(addr_info, scope)
217+
inet6 = addr_info&.detect { |addr| addr["family"] == "inet6" && addr["scope"] == scope }
218+
return if inet6.nil?
222219

223-
parts = cidr_ip.split('/')
224-
@network_conf["address6_#{scope}".to_sym] = parts[0]
225-
@network_conf["prefix6_#{scope}".to_sym] = parts[1].to_i
220+
@network_conf["address6_#{scope}".to_sym] = inet6["local"]
221+
@network_conf["prefix6_#{scope}".to_sym] = inet6["prefixlen"]
226222
end
227223
end
228224
end

spec/network_interface_spec.rb

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@
5656

5757
context "on all systems" do
5858
let(:ip_link_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[--json link]}] }
59-
let(:ip_show_eth0_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[addr show eth0]}] }
60-
let(:ip_show_lo_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[addr show lo]}] }
61-
let(:ip_route_args) { [LinuxAdmin::Common.cmd("ip"), {:params => ['-4', 'route']}] }
62-
let(:ip6_route_args) { [LinuxAdmin::Common.cmd("ip"), {:params => ['-6', 'route']}] }
59+
let(:ip_show_eth0_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[--json addr show eth0]}] }
60+
let(:ip_show_lo_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[--json addr show lo]}] }
61+
let(:ip_route_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[--json -4 route show default]}] }
62+
let(:ip6_route_args) { [LinuxAdmin::Common.cmd("ip"), {:params => %w[--json -6 route show default]}] }
6363
let(:ifup_args) { [LinuxAdmin::Common.cmd("ifup"), {:params => ["eth0"]}] }
6464
let(:ifdown_args) { [LinuxAdmin::Common.cmd("ifdown"), {:params => ["eth0"]}] }
6565
let(:ip_link_out) do
@@ -69,53 +69,32 @@
6969
end
7070
let(:ip_addr_eth0_out) do
7171
<<~IP_OUT
72-
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
73-
link/ether 00:0c:29:ed:0e:8b brd ff:ff:ff:ff:ff:ff
74-
inet 192.168.1.9/24 brd 192.168.1.255 scope global dynamic eth0
75-
valid_lft 1297sec preferred_lft 1297sec
76-
inet6 fe80::20c:29ff:feed:e8b/64 scope link
77-
valid_lft forever preferred_lft forever
78-
inet6 fd12:3456:789a:1::1/96 scope global
79-
valid_lft forever preferred_lft forever
72+
[{"ifindex":2,"ifname":"eth0","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"fq_codel","operstate":"UP","group":"default","txqlen":1000,"link_type":"ether","address":"00:0c:29:ed:0e:8b","broadcast":"ff:ff:ff:ff:ff:ff","altnames":["enp0s2","ens2"],"addr_info":[{"family":"inet","local":"192.168.1.9","prefixlen":24,"broadcast":"192.168.255","scope":"global","noprefixroute":true,"label":"eth0","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"fe80::20c:29ff:feed:e8b","prefixlen":64,"scope":"link","noprefixroute":true,"valid_life_time":"forever","preferred_life_time":"forever"},{"family":"inet6","local":"fd12:3456:789a:1::1","prefixlen":96,"scope":"global","noprefixroute":true,"valid_life_time":"forever","preferred_life_time":"forever"}]}]
8073
IP_OUT
8174
end
8275
let(:ip_addr_lo_out) do
8376
<<~IP_OUT
84-
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
85-
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
86-
inet 127.0.0.1/8 scope host lo
87-
valid_lft forever preferred_lft forever
88-
inet6 ::1/128 scope host
89-
valid_lft forever preferred_lft forever
77+
[{"ifindex":1,"ifname":"lo","flags":["LOOPBACK","UP","LOWER_UP"],"mtu":65536,"qdisc":"noqueue","operstate":"UNKNOWN","group":"default","txqlen":1000,"link_type":"loopback","address":"00:00:00:00:00:00","broadcast":"00:00:00:00:00:00","addr_info":[{"family":"inet","local":"127.0.0.1","prefixlen":8,"scope":"host","label":"lo","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"::1","prefixlen":128,"scope":"host","valid_life_time":"forever","preferred_life_time":"forever"}]}]
9078
IP_OUT
9179
end
9280
let(:ip6_addr_out) do
9381
<<~IP_OUT
94-
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
95-
link/ether 00:0c:29:ed:0e:8b brd ff:ff:ff:ff:ff:ff
96-
inet6 fe80::20c:29ff:feed:e8b/64 scope link
97-
valid_lft forever preferred_lft forever
98-
inet6 fd12:3456:789a:1::1/96 scope global
99-
valid_lft forever preferred_lft forever
82+
[{"ifindex":2,"ifname":"eth0","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"fq_codel","operstate":"UP","group":"default","txqlen":1000,"link_type":"ether","address":"00:0c:29:ed:0e:8b","broadcast":"ff:ff:ff:ff:ff:ff","altnames":["enp0s2","ens2"],"addr_info":[{"family":"inet6","local":"fe80::20c:29ff:feed:e8b","prefixlen":64,"scope":"link","noprefixroute":true,"valid_life_time":"forever","preferred_life_time":"forever"},{"family":"inet6","local":"fd12:3456:789a:1::1","prefixlen":96,"scope":"global","noprefixroute":true,"valid_life_time":"forever","preferred_life_time":"forever"}]}]
10083
IP_OUT
10184
end
10285
let(:ip_route_out) do
10386
<<~IP_OUT
104-
default via 192.168.1.1 dev eth0 proto static metric 100
105-
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.9 metric 100
87+
[{"dst":"default","gateway":"192.168.1.1","dev":"eth0","protocol":"static","metric":100,"flags":[]}]
10688
IP_OUT
10789
end
10890
let(:ip6_route_out) do
10991
<<~IP_OUT
110-
default via d:e:a:d:b:e:e:f dev eth0 proto static metric 100
111-
fc00:dead:beef:a::/64 dev virbr1 proto kernel metric 256 linkdown pref medium
112-
fe80::/64 dev eth0 proto kernel scope link metric 100
92+
[{"dst":"default","gateway":"d:e:a:d:b:e:e:f","dev":"eth0","protocol":"static","metric":100,"flags":[]}]
11393
IP_OUT
11494
end
11595
let(:ip_none_addr_out) do
11696
<<~IP_OUT
117-
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr1 state DOWN group default qlen 1000
118-
link/ether 52:54:00:ce:b4:f4 brd ff:ff:ff:ff:ff:ff
97+
[{"ifindex":2,"ifname":"eth0","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"fq_codel","operstate":"UP","group":"default","txqlen":1000,"link_type":"ether","address":"00:0c:29:ed:0e:8b","broadcast":"ff:ff:ff:ff:ff:ff","altnames":["enp0s2","ens2"],"addr_info":[]}]
11998
IP_OUT
12099
end
121100

0 commit comments

Comments
 (0)