lib/phut/netns.rb in phut-0.7.7 vs lib/phut/netns.rb in phut-0.7.8
- old
+ new
@@ -1,48 +1,137 @@
-require 'active_support/core_ext/class/attribute_accessors'
-require 'phut/null_logger'
+# frozen_string_literal: true
+
+require 'phut/finder'
+require 'phut/route'
require 'phut/shell_runner'
+require 'phut/veth'
module Phut
# `ip netns ...` command runner
class Netns
- cattr_accessor(:all, instance_reader: false) { [] }
+ extend ShellRunner
+ extend Finder
- def self.create(options, name, logger = NullLogger.new)
- new(options, name, logger).tap { |netns| all << netns }
+ # rubocop:disable MethodLength
+ # rubocop:disable AbcSize
+ def self.all
+ sh('ip netns list').split("\n").map do |each|
+ name = each.split.first
+ ip_addr_list =
+ sudo("ip netns exec #{name} ip -4 -o addr list").split("\n")
+ mac_addr_list =
+ sudo("ip netns exec #{name} ip -4 -o link list").split("\n")
+ if ip_addr_list.size > 1
+ %r{inet ([^/]+)/(\d+)} =~ ip_addr_list[1]
+ ip_address = Regexp.last_match(1)
+ mask_length = Regexp.last_match(2).to_i
+ netmask = IPAddr.new('255.255.255.255').mask(mask_length).to_s
+ %r{link/ether ((?:[a-f\d]{2}:){5}[a-f\d]{2})}i =~ mac_addr_list[1]
+ new(name: name, ip_address: ip_address, netmask: netmask,
+ mac_address: Regexp.last_match(1))
+ else
+ new(name: name)
+ end
+ end.sort_by(&:name)
end
+ # rubocop:enable MethodLength
+ # rubocop:enable AbcSize
- def self.each(&block)
- all.each(&block)
+ def self.create(*args)
+ new(*args).tap(&:run)
end
+ def self.destroy_all
+ all.each(&:stop)
+ end
+
include ShellRunner
attr_reader :name
- attr_accessor :network_device
+ attr_reader :ip_address
+ attr_reader :mac_address
- def initialize(options, name, logger)
+ # rubocop:disable ParameterLists
+ def initialize(name:,
+ ip_address: nil,
+ mac_address: nil,
+ netmask: '255.255.255.255',
+ route: {},
+ vlan: nil)
@name = name
- @options = options
- @logger = logger
+ @ip_address = ip_address
+ @mac_address = mac_address
+ @netmask = netmask
+ @route = Route.new(net: route[:net], gateway: route[:gateway])
+ @vlan = vlan
end
+ # rubocop:enable MethodLength
+ # rubocop:enable ParameterLists
- # rubocop:disable AbcSize
def run
- sh "sudo ip netns add #{name}"
- sh "sudo ip link set dev #{network_device} netns #{name}"
- sh "sudo ip netns exec #{name} ifconfig lo 127.0.0.1"
- sh "sudo ip netns exec #{name}"\
- " ifconfig #{network_device} #{ip} netmask #{netmask}"
- sh "sudo ip netns exec #{name} route add -net #{net} gw #{gateway}"
+ sudo "ip netns add #{name}"
+ sudo "ip netns exec #{name} ifconfig lo 127.0.0.1"
end
- # rubocop:enable AbcSize
def stop
- sh "sudo ip netns delete #{name}"
+ sudo("ip netns pids #{name}").split("\n").each do |each|
+ exec "kill #{each}"
+ end
+ sudo "ip netns delete #{name}"
end
- def method_missing(message, *_args)
- @options.__send__ :[], message
+ def exec(command)
+ sudo "ip netns exec #{name} #{command}"
+ end
+
+ def device
+ return unless /^\d+: #{Veth::PREFIX}(\d+)_([^:\.]*?)[@:]/ =~
+ sudo("ip netns exec #{name} ip -o link show")
+ Veth.new(name: $LAST_MATCH_INFO[2], link_id: $LAST_MATCH_INFO[1].to_i)
+ end
+
+ # rubocop:disable MethodLength
+ # rubocop:disable AbcSize
+ def device=(veth)
+ sudo "ip link set dev #{veth} netns #{name}"
+
+ vlan_suffix = @vlan ? ".#{@vlan}" : ''
+ if @vlan
+ sudo "ip netns exec #{name} ip link set #{veth} up"
+ sudo "ip netns exec #{name} "\
+ "ip link add link #{veth} name "\
+ "#{veth}#{vlan_suffix} type vlan id #{@vlan}"
+ end
+ if @mac_address
+ sudo "ip netns exec #{name} "\
+ "ip link set #{veth}#{vlan_suffix} address #{@mac_address}"
+ end
+ sudo "ip netns exec #{name} ip link set #{veth}#{vlan_suffix} up"
+ sudo "ip netns exec #{name} "\
+ "ip addr replace #{@ip_address}/#{@netmask} "\
+ "dev #{veth}#{vlan_suffix}"
+ sudo "ip netns exec #{name} ip link set #{veth}#{vlan_suffix} up"
+
+ @route.add name
+ end
+ # rubocop:enable MethodLength
+ # rubocop:enable AbcSize
+
+ def netmask
+ if %r{inet [^/]+/(\d+) } =~
+ sudo("ip netns exec #{name} ip -o -4 address show dev #{device}")
+ IPAddr.new('255.255.255.255').mask(Regexp.last_match(1).to_i).to_s
+ end
+ end
+
+ def route
+ Route.read name
+ end
+
+ def vlan
+ if /^\d+: #{device.device}\.(\d+)@/ =~
+ sudo("ip netns exec #{name} ip -o link show")
+ Regexp.last_match(1)
+ end
end
end
end