class VagrantPlugins::ProviderLibvirt::Action::CreateNetworks
Prepare all networks needed for domain connections.
Public Class Methods
# File lib/vagrant-libvirt/action/create_networks.rb, line 20 def initialize(app, env) mess = 'vagrant_libvirt::action::create_networks' @logger = Log4r::Logger.new(mess) @app = app @available_networks = [] @options = {} @libvirt_client = env[:machine].provider.driver.connection.client end
Public Instance Methods
# File lib/vagrant-libvirt/action/create_networks.rb, line 30 def call(env) if env[:machine].provider_config.qemu_use_session # Get a list of all (active and inactive) Libvirt networks. This # triggers a side effect to ensure networking is fully available # for VMs using sessions. It is likely that this should be done # to determine the correct virtual device for the management # network for sessions instead of assuming the default of virbr0. @available_networks = libvirt_networks( env[:machine].provider.driver.system_connection ) @app.call(env) return end # only one vm at a time should try to set up networks # otherwise they'll have inconsistent views of current state # and conduct redundant operations that cause errors @@lock.synchronize do # Iterate over networks If some network is not # available, create it if possible. Otherwise raise an error. configured_networks(env, @logger).each do |options| # Only need to create private networks next if options[:iface_type] != :private_network || options.fetch(:tunnel_type, nil) @logger.debug "Searching for network with options #{options}" # should fix other methods so this doesn't have to be instance var @options = options # Get a list of all (active and inactive) Libvirt networks. This # list is used throughout this class and should be easier to # process than Libvirt API calls. @available_networks = libvirt_networks( env[:machine].provider.driver.connection.client ) current_network = @available_networks.detect { |network| network[:name] == @options[:network_name] } # Prepare a hash describing network for this specific interface. @interface_network = { name: nil, ip_address: nil, netmask: @options[:netmask], network_address: nil, bridge_name: nil, domain_name: nil, ipv6_address: options[:ipv6_address] || nil, ipv6_prefix: options[:ipv6_prefix] || nil, created: current_network.nil? ? false : true, active: current_network.nil? ? false : current_network[:active], autostart: options[:autostart] || false, guest_ipv6: @options[:guest_ipv6] || 'yes', libvirt_network: current_network.nil? ? nil : current_network[:libvirt_network] } if @options[:ip] handle_ip_option(env) elsif @options[:type].to_s == 'dhcp' handle_dhcp_private_network(env) elsif @options[:network_name] handle_network_name_option(env) else raise Errors::CreateNetworkError, error_message: @options end autostart_network if @interface_network[:autostart] activate_network unless @interface_network[:active] end end @app.call(env) end
Private Instance Methods
# File lib/vagrant-libvirt/action/create_networks.rb, line 392 def activate_network @interface_network[:libvirt_network].create rescue => e raise Errors::ActivateNetworkError, error_message: e.message end
# File lib/vagrant-libvirt/action/create_networks.rb, line 386 def autostart_network @interface_network[:libvirt_network].autostart = true rescue => e raise Errors::AutostartNetworkError, error_message: e.message end
# File lib/vagrant-libvirt/action/create_networks.rb, line 312 def create_private_network(env) @network_name = @interface_network[:name] @network_bridge_name = @interface_network[:bridge_name] @network_address = @interface_network[:ip_address] @network_netmask = @interface_network[:netmask] @network_mtu = Integer(@options[:mtu]) if @options[:mtu] @guest_ipv6 = @interface_network[:guest_ipv6] @network_ipv6_address = @interface_network[:ipv6_address] @network_ipv6_prefix = @interface_network[:ipv6_prefix] @network_bridge_stp = @options[:bridge_stp].nil? || @options[:bridge_stp] ? 'on' : 'off' @network_bridge_delay = @options[:bridge_delay] ? @options[:bridge_delay] : 0 @network_forward_mode = @options[:forward_mode] if @options[:forward_device] @network_forward_device = @options[:forward_device] end if @options[:dhcp_enabled] # Find out DHCP addresses pool range. network_address = "#{@interface_network[:network_address]}/#{(@interface_network[:netmask]).to_s}" net = @interface_network[:network_address] ? IPAddr.new(network_address) : nil # First is address of network, second is gateway (by default). # So start the range two addresses after network address by default. # TODO: Detect if this IP is not set on the interface. start_address = @options[:dhcp_start] || net.to_range.begin.succ # Default to last possible address. (Stop address must not be broadcast address.) stop_address = @options[:dhcp_stop] || (net.to_range.end & IPAddr.new('255.255.255.254')) @network_dhcp_enabled = true @network_dhcp_bootp_file = @options[:dhcp_bootp_file] @network_dhcp_bootp_server = @options[:dhcp_bootp_server] @network_range_start = start_address @network_range_stop = stop_address else @network_dhcp_enabled = false end if @options[:tftp_root] @tftp_root = @options[:tftp_root] end @network_domain_name = @options[:domain_name] begin xml = to_xml('private_network') @logger.debug { "Creating private network with XML:\n#{xml}" } @interface_network[:libvirt_network] = \ @libvirt_client.define_network_xml(xml) @logger.debug 'created network' rescue => e raise Errors::CreateNetworkError, error_message: e.message end end
Return the first available virbr interface name
# File lib/vagrant-libvirt/action/create_networks.rb, line 302 def generate_bridge_name @logger.debug 'generating name for bridge' count = 0 while lookup_bridge_by_name(bridge_name = "virbr#{count}") count += 1 end @logger.debug "found available bridge name #{bridge_name}" bridge_name end
Return provided address or first address of network otherwise
# File lib/vagrant-libvirt/action/create_networks.rb, line 297 def get_host_ip_addr(network) @options[:host_ip] ? IPAddr.new(@options[:host_ip]) : IPAddr.new(network).succ end
# File lib/vagrant-libvirt/action/create_networks.rb, line 267 def handle_dhcp_private_network(env) net_address = @options[:libvirt__network_address] net_address = '172.28.128.0' unless net_address network = lookup_network_by_ip(net_address) @interface_network = network if network # Do we need to create new network? unless @interface_network[:created] @interface_network[:name] = @options[:network_name] ? @options[:network_name] : 'vagrant-private-dhcp' @interface_network[:network_address] = net_address # Set IP address of network (actually bridge). It will be used as # gateway address for machines connected to this network. @interface_network[:ip_address] = get_host_ip_addr(net_address) # Generate a unique name for network bridge. @interface_network[:bridge_name] = generate_bridge_name # Create a private network. create_private_network(env) write_created_network(env) else write_created_network(env) unless @options[:always_destroy] == false end end
Handle only situations, when ip is specified. Variables @options and @available_networks should be filled before calling this function.
# File lib/vagrant-libvirt/action/create_networks.rb, line 139 def handle_ip_option(env) return unless @options[:ip] net_address = nil unless @options[:forward_mode] == 'veryisolated' net_address = network_address(@options[:ip], @options[:netmask]) # Set IP address of network (actually bridge). It will be used as # gateway address for machines connected to this network. @interface_network[:ip_address] = get_host_ip_addr(net_address) end @interface_network[:network_address] = net_address # if network is veryisolated, search by name network = if @options[:libvirt__forward_mode] == 'veryisolated' lookup_network_by_name(@options[:network_name]) elsif net_address # otherwise, search by ip (if set) lookup_network_by_ip(net_address) else # leaving this here to mimic prior behavior. If we get # here, something's probably broken. lookup_network_by_name(@options[:network_name]) end @interface_network = network if network verify_dhcp if @interface_network[:created] if @options[:network_name] @logger.debug 'Checking that network name does not clash with ip' if @interface_network[:created] # Just check for mismatch error here - if name and ip from # config match together. if @options[:network_name] != @interface_network[:name] and @qemu_use_agent == false raise Errors::NetworkNameAndAddressMismatch, ip_address: @options[:ip], network_name: @options[:network_name] end else # Network is not created, but name is set. We need to check, # whether network name from config doesn't already exist. if lookup_network_by_name @options[:network_name] raise Errors::NetworkNameAndAddressMismatch, ip_address: @options[:ip], network_name: @options[:network_name] end # Network with 'name' doesn't exist. Set it as name for new # network. @interface_network[:name] = @options[:network_name] end end # Do we need to create new network? unless @interface_network[:created] # TODO: stop after some loops. Don't create infinite loops. # Is name for new network set? If not, generate a unique one. count = 0 while @interface_network[:name].nil? @logger.debug 'generating name for network' # Generate a network name. network_name = env[:root_path].basename.to_s.dup network_name << count.to_s count += 1 # Check if network name is unique. next if lookup_network_by_name(network_name) @interface_network[:name] = network_name end # Generate a unique name for network bridge. @interface_network[:bridge_name] = generate_bridge_name # Create a private network. create_private_network(env) write_created_network(env) else write_created_network(env) unless @options[:always_destroy] == false end end
Handle network_name option, if ip was not specified. Variables @options and @available_networks should be filled before calling this function.
# File lib/vagrant-libvirt/action/create_networks.rb, line 228 def handle_network_name_option(env) return if @options[:ip] || \ !@options[:network_name] || \ !@options[:libvirt__forward_mode] == 'veryisolated' network = lookup_network_by_name(@options[:network_name]) @interface_network = network if network if @options[:libvirt__forward_mode] == 'veryisolated' # if this interface has a network address, something's wrong. if @interface_network[:network_address] raise Errors::NetworkNotAvailableError, network_name: @options[:network_name] end else if !@interface_network raise Errors::NetworkNotAvailableError, network_name: @options[:network_name] else verify_dhcp end end # Do we need to create new network? unless @interface_network[:created] @interface_network[:name] = @options[:network_name] @interface_network[:ip_address] ||= @options[:host_ip] # Generate a unique name for network bridge. @interface_network[:bridge_name] = generate_bridge_name # Create a private network. create_private_network(env) write_created_network(env) else write_created_network(env) unless @options[:always_destroy] == false end end
Return hash of network for specified bridge, or nil if not found.
# File lib/vagrant-libvirt/action/create_networks.rb, line 118 def lookup_bridge_by_name(bridge_name) @logger.debug "looking up bridge named #{bridge_name}" @available_networks.find { |network| network[:bridge_name] == bridge_name } end
# File lib/vagrant-libvirt/action/create_networks.rb, line 106 def lookup_network_by_ip(ip) @logger.debug "looking up network with ip == #{ip}" @available_networks.find { |network| network[:network_address] == ip } end
Return hash of network for specified name, or nil if not found.
# File lib/vagrant-libvirt/action/create_networks.rb, line 112 def lookup_network_by_name(network_name) @logger.debug "looking up network named #{network_name}" @available_networks.find { |network| network[:name] == network_name } end
Throw an error if dhcp setting for an existing network does not match what was configured in the vagrantfile since we always enable dhcp for the management network this ensures we won't start a vm vagrant can't reach Allow the situation where DHCP is not requested (:libvirt__dhcp_enabled == false) but where it is enabled on the virtual network
# File lib/vagrant-libvirt/action/create_networks.rb, line 129 def verify_dhcp if @interface_network[:dhcp_enabled] == true && @options[:dhcp_enabled] == false raise Errors::DHCPMismatch, network_name: @interface_network[:name], requested: @options[:dhcp_enabled] ? 'enabled' : 'disabled' end end
# File lib/vagrant-libvirt/action/create_networks.rb, line 373 def write_created_network(env) created_networks_file = env[:machine].data_dir + 'created_networks' message = 'Saving information about created network ' \ "#{@interface_network[:name]}, UUID=#{@interface_network[:libvirt_network].uuid} " \ "to file #{created_networks_file}." @logger.info(message) File.open(created_networks_file, 'a') do |file| file.puts @interface_network[:libvirt_network].uuid end end