Merge pull request #2 from pradels/master

Update base
This commit is contained in:
Maxym Kutsevol 2015-09-30 18:11:34 +03:00
commit 994b096854
9 changed files with 278 additions and 40 deletions

View File

@ -7,34 +7,35 @@ control and provision machines via Libvirt toolkit.
**Note:** Actual version is still a development one. Feedback is
welcome and can help a lot :-)
- [Features](#)
- [Future work](#)
- [Installation](#)
- [Possible problems with plugin installation on Linux](#)
- [Vagrant Project Preparation](#)
- [Add Box](#)
- [Create Vagrantfile](#)
- [Start VM](#)
- [How Project Is Created](#)
- [Libvirt Configuration](#)
- [Provider Options](#)
- [Domain Specific Options](#)
- [Networks](#)
- [Private Network Options](#)
- [Public Network Options](#)
- [Management Network](#)
- [Additional Disks](#)
- [CDROMs](#)
- [Input](#)
- [No box and PXE boot](#)
- [SSH Access To VM](#)
- [Forwarded Ports](#)
- [Synced Folders](#)
- [Customized Graphics](#)
- [Box Format](#)
- [Create Box](#)
- [Development](#)
- [Contributing](#)
- [Features](#features)
- [Future work](#future-work)
- [Installation](#installation)
- [Possible problems with plugin installation on Linux](#possible-problems-with-plugin-installation-on-linux)
- [Vagrant Project Preparation](#vagrant-project-preparation)
- [Add Box](#add-box)
- [Create Vagrantfile](#create-vagrantfile)
- [Start VM](#start-vm)
- [How Project Is Created](#how-project-is-created)
- [Libvirt Configuration](#libvirt-configuration)
- [Provider Options](#provider-options)
- [Domain Specific Options](#domain-specific-options)
- [Reload behavior](#reload-behavior)
- [Networks](#networks)
- [Private Network Options](#private-network-options)
- [Public Network Options](#public-network-options)
- [Management Network](#management-network)
- [Additional Disks](#additional-disks)
- [CDROMs](#cdroms)
- [Input](#input)
- [No box and PXE boot](#no-box-and-pxe-boot)
- [SSH Access To VM](#ssh-access-to-vm)
- [Forwarded Ports](#forwarded-ports)
- [Synced Folders](#synced-folders)
- [Customized Graphics](#customized-graphics)
- [Box Format](#box-format)
- [Create Box](#create-box)
- [Development](#development)
- [Contributing](#contributing)
## Features
@ -157,7 +158,7 @@ Although it should work without any configuration for most people, this provider
* `driver` - A hypervisor name to access. For now only kvm and qemu are supported.
* `host` - The name of the server, where libvirtd is running.
* `connect_via_ssh` - If use ssh tunnel to connect to Libvirt.
* `connect_via_ssh` - If use ssh tunnel to connect to Libvirt. Absolutely needed to access libvirt on remote host. It will not be able to get the IP address of a started VM otherwise.
* `username` - Username and password to access Libvirt.
* `password` - Password to access Libvirt.
* `id_ssh_key_file` - If not nil, uses this ssh private key to access Libvirt. Default is $HOME/.ssh/id_rsa. Prepends $HOME/.ssh/ if no directory.
@ -181,11 +182,11 @@ end
### Domain Specific Options
* `disk_bus` - The type of disk device to emulate. Defaults to virtio if not set. Possible values are documented in libvirt's [description for _target_](http://libvirt.org/formatdomain.html#elementsDisks).
* `nic_model_type` - parameter specifies the model of the network adapter when you create a domain value by default virtio KVM believe possible values, see the documentation for libvirt
* `nic_model_type` - parameter specifies the model of the network adapter when you create a domain value by default virtio KVM believe possible values, see the [documentation for 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.
* `nested` - [Enable nested virtualization](https://github.com/torvalds/linux/blob/master/Documentation/virtual/kvm/nested-vmx.txt). Default is false.
* `cpu_mode` - [What cpu type to emulate](https://libvirt.org/formatdomain.html#elementsCPU). Defaults to 'host-model' if not set. Allowed values: host-model, host-passthrough.
* `cpu_mode` - [CPU emulation mode](https://libvirt.org/formatdomain.html#elementsCPU). Defaults to 'host-model' if not set. Allowed values: host-model, host-passthrough.
* `loader` - Sets path to custom UEFI loader.
* `volume_cache` - Controls the cache mechanism. Possible values are "default", "none", "writethrough", "writeback", "directsync" and "unsafe". [See driver->cache in libvirt documentation](http://libvirt.org/formatdomain.html#elementsDisks).
* `kernel` - To launch the guest with a kernel residing on host filesystems. Equivalent to qemu `-kernel`.
@ -196,14 +197,18 @@ end
* `graphics_port` - Sets the port for the display protocol to bind to. Defaults to 5900.
* `graphics_ip` - Sets the IP for the display protocol to bind to. Defaults to "127.0.0.0.1".
* `graphics_passwd` - Sets the password for the display protocol. Working for vnc and spice. by default working without passsword.
* `video_type` - Sets the graphics card type exposed to the guest. Defaults to "cirrus". [Possible values](http://libvirt.org/formatdomain.html#elementsVideo) are "vga", "cirrus", "vmvga", "xen", "vbox", or "qxl".
* `graphics_autoport` - Sets autoport for graphics, libvirt in this case ignores graphics_port value, Defaults to 'yes'. Possible value are "yes" and "no"
* `keymap` - Set keymap for vm. default: en-us
* `video_type` - Sets the graphics card type exposed to the guest. Defaults to "cirrus". [Possible values](http://libvirt.org/formatdomain.html#elementsVideo) are "vga", "cirrus", "vmvga", "xen", "vbox", or "qxl".
* `video_vram` - Used by some graphics card types to vary the amount of RAM dedicated to video. Defaults to 9216.
* `machine` - Sets machine type. Equivalent to qemu `-machine`. Use `qemu-system-x86_64 -machine help` to get a list of supported machines.
* `machine_arch` - Sets machine architecture. This helps libvirt to determine the correct emulator type. Possible values depend on your version of qemu. For possible values, see which emulator executable `qemu-system-*` your system provides. Common examples are `aarch64`, `alpha`, `arm`, `cris`, `i386`, `lm32`, `m68k`, `microblaze`, `microblazeel`, `mips`, `mips64`, `mips64el`, `mipsel`, `moxie`, `or32`, `ppc`, `ppc64`, `ppcemb`, `s390x`, `sh4`, `sh4eb`, `sparc`, `sparc64`, `tricore`, `unicore32`, `x86_64`, `xtensa`, `xtensaeb`.
* `machine_virtual_size` - Sets the disk size in GB for the machine overriding the default specified in the box. Allows boxes to defined with a minimal size disk by default and to be grown to a larger size at creation time. Will ignore sizes smaller than the size specified by the box metadata. Note that currently there is no support for automatically resizing the filesystem to take advantage of the larger disk.
* `boot` - Change the boot order and enables the boot menu. Possible options are "hd", "network", "cdrom". Defaults to "hd" with boot menu disabled. When "network" is set without "hd", only all NICs will be tried; see below for more detail.
* `nic_adapter_count` - Defaults to '8'. Only use case for increasing this count is for VMs that virtualize switches such as Cumulus Linux. Max value for Cumulus Linux VMs is 33.
* `uuid` - Force a domain UUID. Defaults to autogenerated value by libvirt if not set.
* `suspend_mode` - What is done on vagrant suspend. Possible values: 'pause', 'managedsave'. Pause mode executes a la `virsh suspend`, which just pauses execution of a VM, not freeing resources. Managed save mode does a la `virsh managedsave` which frees resources suspending a domain.
Specific domain settings can be set for each domain separately in multi-VM
@ -243,6 +248,25 @@ Vagrant.configure("2") do |config|
# ...
```
#### Reload behavior
On vagrant reload the following domain specific attributes are updated in defined domain:
* `disk_bus` - Is updated only on disks. It skips cdroms.
* `nic_model_type` - Updated.
* `memory` - Updated.
* `cpus` - Updated.
* `nested` - Updated.
* `cpu_mode` - Updated. Pay attention that custom mode is not supported.
* `graphics_type` - Updated.
* `graphics_port` - Updated.
* `graphics_ip` - Updated.
* `graphics_passwd` - Updated.
* `graphics_autoport` - Updated.
* `keymap` - Updated.
* `video_type` - Updated.
* `video_vram` - Updated.
## Networks
Networking features in the form of `config.vm.network` support private networks

View File

@ -31,6 +31,7 @@ module VagrantPlugins
# Gather some info about domain
@name = env[:domain_name]
@uuid = config.uuid
@cpus = config.cpus.to_i
@cpu_mode = config.cpu_mode
@loader = config.loader
@ -133,6 +134,9 @@ module VagrantPlugins
# Output the settings we're going to use to the user
env[:ui].info(I18n.t('vagrant_libvirt.creating_domain'))
env[:ui].info(" -- Name: #{@name}")
if @uuid != ''
env[:ui].info(" -- Forced UUID: #{@uuid}")
end
env[:ui].info(" -- Domain type: #{@domain_type}")
env[:ui].info(" -- Cpus: #{@cpus}")
env[:ui].info(" -- Memory: #{@memory_size / 1024}M")
@ -177,7 +181,7 @@ module VagrantPlugins
env[:ui].info(" -- CDROM(#{cdrom[:dev]}): #{cdrom[:path]}")
end
@inputs.each do |input|
env[:ui].info(" -- INPUT : type=#{input[:type]}, bus=#{input[:bus]}")
env[:ui].info(" -- INPUT: type=#{input[:type]}, bus=#{input[:bus]}")
end
env[:ui].info(" -- Command line : #{@cmd_line}")

View File

@ -28,6 +28,11 @@ module VagrantPlugins
end
end
# must remove managed saves
if libvirt_domain.has_managed_save?
libvirt_domain.managed_save_remove
end
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
if env[:machine].provider_config.disks.empty?

View File

@ -11,8 +11,29 @@ module VagrantPlugins
def call(env)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
env[:result] = domain.state.to_s == 'paused'
config = env[:machine].provider_config
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
if config.suspend_mode == 'managedsave'
if libvirt_domain.has_managed_save?
env[:result] = libvirt_domain.has_managed_save?
else
env[:result] = domain.state.to_s == 'paused'
if env[:result]
env[:ui].warn('One time switching to pause suspend mode, found a paused VM.')
config.suspend_mode = 'pause'
end
end
else
if libvirt_domain.has_managed_save?
env[:ui].warn('One time switching to managedsave suspend mode, state found.')
env[:result] = true
config.suspend_mode = 'managedsave'
else
env[:result] = domain.state.to_s == 'paused'
end
end
@app.call(env)
end
end

View File

@ -16,7 +16,14 @@ module VagrantPlugins
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
domain.resume
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
config = env[:machine].provider_config
if config.suspend_mode == 'managedsave'
domain.start
else
domain.resume
end
@logger.info("Machine #{env[:machine].id} is resumed.")
@app.call(env)

View File

@ -1,9 +1,9 @@
require 'log4r'
require 'rexml/document'
module VagrantPlugins
module ProviderLibvirt
module Action
# Just start the domain.
class StartDomain
def initialize(app, env)
@ -16,8 +16,157 @@ module VagrantPlugins
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
config = env[:machine].provider_config
begin
# update domain settings on change.
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
if config.memory*1024 != libvirt_domain.max_memory
libvirt_domain.max_memory = config.memory*1024
libvirt_domain.memory = libvirt_domain.max_memory
end
begin
# XML definition manipulation
descr = libvirt_domain.xml_desc(1)
xml_descr = REXML::Document.new descr
descr_changed = false
# disk_bus
REXML::XPath.each(xml_descr,'/domain/devices/disk[@device="disk"]/target') {|disk_target|
if disk_target.attributes['bus'] != config.disk_bus
descr_changed = true
disk_target.attributes['bus'] = config.disk_bus
disk_target.parent.delete_element('//address')
end
}
# Iterface type
REXML::XPath.each(xml_descr,'/domain/devices/interface/model') {|iface_model|
if iface_model.attributes['type'] != config.nic_model_type
descr_changed = true
iface_model.attributes['type'] = config.nic_model_type
end
}
# vCpu count
if config.cpus.to_i != libvirt_domain.vcpus.length
descr_changed = true
REXML::XPath.first(xml_descr,'/domain/vcpu').text = config.cpus
end
# cpu_mode
cpu = REXML::XPath.first(xml_descr,'/domain/cpu')
if cpu.nil?
descr_changed = true
cpu = REXML::Element.new('cpu', REXML::XPath.first(xml_descr,'/domain'))
cpu.attributes['mode'] = config.cpu_mode
else
if cpu.attributes['mode'] != config.cpu_mode
descr_changed = true
cpu.attributes['mode'] = config.cpu_mode
end
end
if config.cpu_mode != 'host-passthrough'
cpu_model = REXML::XPath.first(xml_descr,'/domain/cpu/model')
if cpu_model.nil?
descr_changed = true
cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr,'/domain/cpu'))
cpu_model.attributes['fallback'] = 'allow'
cpu_model.text = 'qemu64'
end
vmx_feature = REXML::XPath.first(xml_descr,'/domain/cpu/feature[@name="vmx"]')
svm_feature = REXML::XPath.first(xml_descr,'/domain/cpu/feature[@name="svm"]')
if config.nested
if vmx_feature.nil?
descr_changed = true
vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr,'/domain/cpu'))
vmx_feature.attributes['policy'] = 'optional'
vmx_feature.attributes['name'] = 'vmx'
end
if svm_feature.nil?
descr_changed = true
svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr,'/domain/cpu'))
svm_feature.attributes['policy'] = 'optional'
svm_feature.attributes['name'] = 'svm'
end
else
if !vmx_feature.nil?
descr_changed = true
cpu.delete_element(vmx_feature)
end
if !svm_feature.nil?
descr_changed = true
cpu.delete_element(svm_feature)
end
end
else
if cpu.elements.to_a.length > 0
descr_changed = true
cpu.elements.each {|elem|
cpu.delete_element(elem)
}
end
end
# Graphics
graphics = REXML::XPath.first(xml_descr,'/domain/devices/graphics')
if graphics.attributes['type'] != config.graphics_type
descr_changed = true
graphics.attributes['type'] = config.graphics_type
end
if graphics.attributes['listen'] != config.graphics_ip
descr_changed = true
graphics.attributes['listen'] = config.graphics_ip
graphics.delete_element('//listen')
end
if graphics.attributes['autoport'] != config.graphics_autoport
descr_changed = true
graphics.attributes['autoport'] = config.graphics_autoport
if config.graphics_autoport == 'no'
graphics.attributes['port'] = config.graphics_port
end
end
if graphics.attributes['keymap'] != config.keymap
descr_changed = true
graphics.attributes['keymap'] = config.keymap
end
if graphics.attributes['passwd'] != config.graphics_passwd
descr_changed = true
if config.graphics_passwd.nil?
graphics.attributes.delete 'passwd'
else
graphics.attributes['passwd'] = config.graphics_passwd
end
end
# Video device
video = REXML::XPath.first(xml_descr,'/domain/devices/video/model')
if video.attributes['type'] != config.video_type || video.attributes['vram'] != config.video_vram
descr_changed = true
video.attributes.each_attribute {|attr| video.attributes.delete attr}
video.attributes['type'] = config.video_type
video.attributes['vram'] = config.video_vram
end
# Apply
if descr_changed
begin
libvirt_domain.undefine
new_descr = ""
xml_descr.write new_descr
server = env[:machine].provider.driver.connection.servers.create(xml: new_descr)
rescue Fog::Errors::Error => e
server = env[:machine].provider.driver.connection.servers.create(xml: descr)
raise Errors::FogCreateServerError, error_message: e.message
end
end
rescue => e
env[:ui].error("Error when updating domain settings: #{e.message}")
end
# Actually start the domain
domain.start
rescue => e
raise Errors::FogError, :message => e.message

View File

@ -17,7 +17,19 @@ module VagrantPlugins
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
domain.suspend
config = env[:machine].provider_config
if config.suspend_mode == 'managedsave'
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
begin
libvirt_domain.managed_save
rescue => e
env[:ui].error("Error doing a managed save for domain. It may have entered a paused state.
Check the output of `virsh managedsave DOMAIN_NAME --verbose` on the VM host, error: #{e.message}")
end
else
domain.suspend
end
@logger.info("Machine #{env[:machine].id} is suspended ")
@app.call(env)

View File

@ -53,6 +53,7 @@ module VagrantPlugins
attr_accessor :default_prefix
# Domain specific settings used while creating new domain.
attr_accessor :uuid
attr_accessor :memory
attr_accessor :cpus
attr_accessor :cpu_mode
@ -89,6 +90,9 @@ module VagrantPlugins
# Inputs
attr_accessor :inputs
# Suspend mode
attr_accessor :suspend_mode
def initialize
@uri = UNSET_VALUE
@driver = UNSET_VALUE
@ -105,6 +109,7 @@ module VagrantPlugins
@management_network_mac = UNSET_VALUE
# Domain specific settings.
@uuid = UNSET_VALUE
@memory = UNSET_VALUE
@cpus = UNSET_VALUE
@cpu_mode = UNSET_VALUE
@ -138,6 +143,9 @@ module VagrantPlugins
# Inputs
@inputs = UNSET_VALUE
# Suspend mode
@suspend_mode = UNSET_VALUE
end
def boot(device)
@ -317,6 +325,7 @@ module VagrantPlugins
@uri = _generate_uri() if @uri == UNSET_VALUE
# Domain specific settings.
@uuid = '' if @uuid == UNSET_VALUE
@memory = 512 if @memory == UNSET_VALUE
@cpus = 1 if @cpus == UNSET_VALUE
@cpu_mode = 'host-model' if @cpu_mode == UNSET_VALUE
@ -351,7 +360,13 @@ module VagrantPlugins
# Storage
@disks = [] if @disks == UNSET_VALUE
@cdroms = [] if @cdroms == UNSET_VALUE
# Inputs
@inputs = [{:type => "mouse", :bus => "ps2"}] if @inputs == UNSET_VALUE
# Suspend mode
@suspend_mode = "pause" if @suspend_mode == UNSET_VALUE
end
def validate(machine)

View File

@ -1,5 +1,6 @@
<domain type='<%= @domain_type %>'>
<name><%= @name %></name>
<uuid><%= @uuid %></uuid>
<memory><%= @memory_size %></memory>
<vcpu><%= @cpus %></vcpu>
@ -87,9 +88,9 @@
<%# Video device -%>
<graphics type='<%= @graphics_type %>' port='<%= @graphics_port %>' autoport='<%= @graphics_autoport %>' listen='<%= @graphics_ip %>' keymap='<%= @keymap %>' <%= @graphics_passwd%> />
<video>
<model type='<%= @video_type %>' vram='<%= @video_vram %>' heads='1'/>
</video>
<video>
<model type='<%= @video_type %>' vram='<%= @video_vram %>' heads='1'/>
</video>
<%#End Video -%>
</devices>
</domain>