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