diff --git a/README.md b/README.md index c4ce799..205f1cd 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,17 @@ end libvirt](https://libvirt.org/formatdomain.html#elementsNICSModel). * `memory` - Amount of memory in MBytes. Defaults to 512 if not set. * `cpus` - Number of virtual cpus. Defaults to 1 if not set. +* `cputopology` - Number of CPU sockets, cores and threads running per core. All fields of `:sockets`, `:cores` and `:threads` are mandatory, `cpus` domain option must be present and must be equal to total count of **sockets * cores * threads**. For more details see [documentation](https://libvirt.org/formatdomain.html#elementsCPU). + + ```ruby + Vagrant.configure("2") do |config| + config.vm.provider :libvirt do |libvirt| + libvirt.cpus = 4 + libvirt.cputopology :sockets => '2', :cores => '2', :threads => '1' + end + end + ``` + * `nested` - [Enable nested virtualization](https://github.com/torvalds/linux/blob/master/Documentation/virtual/kvm/nested-vmx.txt). Default is false. @@ -691,6 +702,7 @@ used by this network are configurable at the provider level. specified the default is 'false'. * `:management_network_pci_bus` - The bus of the PCI device. * `:management_network_pci_slot` - The slot of the PCI device. +* `management_network_mac` - MAC address of management network interface. You may wonder how vagrant-libvirt knows the IP address a VM received. Libvirt doesn't provide a standard way to find out the IP address of a running domain. diff --git a/lib/vagrant-libvirt/action/create_domain.rb b/lib/vagrant-libvirt/action/create_domain.rb index 8bc28f3..b9f8c83 100644 --- a/lib/vagrant-libvirt/action/create_domain.rb +++ b/lib/vagrant-libvirt/action/create_domain.rb @@ -34,6 +34,7 @@ module VagrantPlugins @uuid = config.uuid @cpus = config.cpus.to_i @cpu_features = config.cpu_features + @cpu_topology = config.cpu_topology @features = config.features @cpu_mode = config.cpu_mode @cpu_model = config.cpu_model @@ -176,6 +177,10 @@ module VagrantPlugins env[:ui].info(" -- Forced UUID: #{@uuid}") if @uuid != '' env[:ui].info(" -- Domain type: #{@domain_type}") env[:ui].info(" -- Cpus: #{@cpus}") + if not @cpu_topology.empty? + env[:ui].info(" -- CPU topology: sockets=#{@cpu_topology[:sockets]}, cores=#{@cpu_topology[:cores]}, threads=#{@cpu_topology[:threads]}") + end + env[:ui].info("") @cpu_features.each do |cpu_feature| env[:ui].info(" -- CPU Feature: name=#{cpu_feature[:name]}, policy=#{cpu_feature[:policy]}") end diff --git a/lib/vagrant-libvirt/action/forward_ports.rb b/lib/vagrant-libvirt/action/forward_ports.rb index 3e8b8c6..0064ee6 100644 --- a/lib/vagrant-libvirt/action/forward_ports.rb +++ b/lib/vagrant-libvirt/action/forward_ports.rb @@ -47,6 +47,11 @@ module VagrantPlugins message_attributes )) + if fp[:protocol] == 'udp' + env[:ui].warn I18n.t('vagrant_libvirt.warnings.forwarding_udp') + next + end + ssh_pid = redirect_port( @env[:machine], fp[:host_ip] || 'localhost', @@ -95,6 +100,7 @@ module VagrantPlugins StrictHostKeyChecking=no PasswordAuthentication=no ForwardX11=#{ssh_info[:forward_x11] ? 'yes' : 'no'} + IdentitiesOnly=#{ssh_info[:keys_only] ? 'yes' : 'no'} ) + ssh_info[:private_key_path].map do |pk| "IdentityFile='\"#{pk}\"'" end).map { |s| s.prepend('-o ') }.join(' ') diff --git a/lib/vagrant-libvirt/config.rb b/lib/vagrant-libvirt/config.rb index cfd3cda..12218a0 100644 --- a/lib/vagrant-libvirt/config.rb +++ b/lib/vagrant-libvirt/config.rb @@ -67,6 +67,7 @@ module VagrantPlugins attr_accessor :cpu_model attr_accessor :cpu_fallback attr_accessor :cpu_features + attr_accessor :cpu_topology attr_accessor :features attr_accessor :numa_nodes attr_accessor :loader @@ -175,6 +176,7 @@ module VagrantPlugins @cpu_model = UNSET_VALUE @cpu_fallback = UNSET_VALUE @cpu_features = UNSET_VALUE + @cpu_topology = UNSET_VALUE @features = UNSET_VALUE @numa_nodes = UNSET_VALUE @loader = UNSET_VALUE @@ -319,6 +321,20 @@ module VagrantPlugins policy: options[:policy]) end + def cputopology(options = {}) + if options[:sockets].nil? || options[:cores].nil? || options[:threads].nil? + raise 'CPU topology must have all of sockets, cores and threads specified' + end + + if @cpu_topology == UNSET_VALUE + @cpu_topology = {} + end + + @cpu_topology[:sockets] = options[:sockets] + @cpu_topology[:cores] = options[:cores] + @cpu_topology[:threads] = options[:threads] + end + def memorybacking(option, config = {}) case option when :source @@ -600,6 +616,7 @@ module VagrantPlugins elsif @cpu_mode != 'custom' '' end + @cpu_topology = {} if @cpu_topology == UNSET_VALUE @cpu_fallback = 'allow' if @cpu_fallback == UNSET_VALUE @cpu_features = [] if @cpu_features == UNSET_VALUE @features = ['acpi','apic','pae'] if @features == UNSET_VALUE diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb index 4e689b2..ee159ad 100644 --- a/lib/vagrant-libvirt/templates/domain.xml.erb +++ b/lib/vagrant-libvirt/templates/domain.xml.erb @@ -15,6 +15,10 @@ <% @cpu_features.each do |cpu_feature| %> <% end %> + <% unless @cpu_topology.empty? %> + <%# CPU topology -%> + + <% end %> <% end %> <% if @numa_nodes %> diff --git a/locales/en.yml b/locales/en.yml index 316f0c5..cd88b56 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -54,6 +54,8 @@ en: ignoring_virtual_size_too_small: |- Ignoring requested virtual disk size of '%{requested}' as it is below the minimum box image size of '%{minimum}'. + forwarding_udp: |- + Forwarding UDP ports is not supported. Ignoring. errors: package_not_supported: No support for package with libvirt. Create box manually. diff --git a/spec/unit/templates/domain_all_settings.xml b/spec/unit/templates/domain_all_settings.xml index cdd8ac7..a84398f 100644 --- a/spec/unit/templates/domain_all_settings.xml +++ b/spec/unit/templates/domain_all_settings.xml @@ -8,6 +8,7 @@ qemu64 + diff --git a/spec/unit/templates/domain_spec.rb b/spec/unit/templates/domain_spec.rb index 851fe59..9b83249 100644 --- a/spec/unit/templates/domain_spec.rb +++ b/spec/unit/templates/domain_spec.rb @@ -31,6 +31,7 @@ describe 'templates/domain' do domain.instance_variable_set('@domain_type', 'kvm') domain.cpu_mode = 'custom' domain.cpu_feature(name: 'AAA', policy: 'required') + domain.cputopology(sockets: '1', cores: '3', threads: '2') domain.machine_type = 'pc-compatible' domain.machine_arch = 'x86_64' domain.loader = '/efi/loader'