vagrant-libvirt 0.0.41 → 0.0.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.github/issue_template.md +37 -0
- data/.gitignore +21 -0
- data/.travis.yml +24 -0
- data/Gemfile +26 -0
- data/LICENSE +22 -0
- data/README.md +1380 -0
- data/Rakefile +8 -0
- data/example_box/README.md +29 -0
- data/example_box/Vagrantfile +60 -0
- data/example_box/metadata.json +5 -0
- data/lib/vagrant-libvirt.rb +29 -0
- data/lib/vagrant-libvirt/action.rb +370 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +322 -0
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +87 -0
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +302 -0
- data/lib/vagrant-libvirt/action/create_networks.rb +361 -0
- data/lib/vagrant-libvirt/action/destroy_domain.rb +83 -0
- data/lib/vagrant-libvirt/action/destroy_networks.rb +95 -0
- data/lib/vagrant-libvirt/action/forward_ports.rb +227 -0
- data/lib/vagrant-libvirt/action/halt_domain.rb +41 -0
- data/lib/vagrant-libvirt/action/handle_box_image.rb +156 -0
- data/lib/vagrant-libvirt/action/handle_storage_pool.rb +57 -0
- data/lib/vagrant-libvirt/action/is_created.rb +18 -0
- data/lib/vagrant-libvirt/action/is_running.rb +21 -0
- data/lib/vagrant-libvirt/action/is_suspended.rb +42 -0
- data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
- data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +17 -0
- data/lib/vagrant-libvirt/action/package_domain.rb +105 -0
- data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +94 -0
- data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +17 -0
- data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +27 -0
- data/lib/vagrant-libvirt/action/read_mac_addresses.rb +40 -0
- data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +20 -0
- data/lib/vagrant-libvirt/action/remove_stale_volume.rb +50 -0
- data/lib/vagrant-libvirt/action/resume_domain.rb +34 -0
- data/lib/vagrant-libvirt/action/set_boot_order.rb +109 -0
- data/lib/vagrant-libvirt/action/set_name_of_domain.rb +64 -0
- data/lib/vagrant-libvirt/action/share_folders.rb +71 -0
- data/lib/vagrant-libvirt/action/start_domain.rb +307 -0
- data/lib/vagrant-libvirt/action/suspend_domain.rb +40 -0
- data/lib/vagrant-libvirt/action/wait_till_up.rb +109 -0
- data/lib/vagrant-libvirt/cap/mount_p9.rb +42 -0
- data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +17 -0
- data/lib/vagrant-libvirt/cap/synced_folder.rb +113 -0
- data/lib/vagrant-libvirt/config.rb +746 -0
- data/lib/vagrant-libvirt/driver.rb +118 -0
- data/lib/vagrant-libvirt/errors.rb +153 -0
- data/lib/vagrant-libvirt/plugin.rb +92 -0
- data/lib/vagrant-libvirt/provider.rb +130 -0
- data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
- data/lib/vagrant-libvirt/templates/domain.xml.erb +244 -0
- data/lib/vagrant-libvirt/templates/private_network.xml.erb +42 -0
- data/lib/vagrant-libvirt/templates/public_interface.xml.erb +26 -0
- data/lib/vagrant-libvirt/util.rb +11 -0
- data/lib/vagrant-libvirt/util/collection.rb +19 -0
- data/lib/vagrant-libvirt/util/erb_template.rb +22 -0
- data/lib/vagrant-libvirt/util/error_codes.rb +100 -0
- data/lib/vagrant-libvirt/util/network_util.rb +151 -0
- data/lib/vagrant-libvirt/util/timer.rb +17 -0
- data/lib/vagrant-libvirt/version.rb +5 -0
- data/locales/en.yml +162 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/environment_helper.rb +46 -0
- data/spec/support/libvirt_context.rb +30 -0
- data/spec/support/sharedcontext.rb +34 -0
- data/spec/unit/action/destroy_domain_spec.rb +97 -0
- data/spec/unit/action/set_name_of_domain_spec.rb +21 -0
- data/spec/unit/action/wait_till_up_spec.rb +127 -0
- data/spec/unit/config_spec.rb +113 -0
- data/spec/unit/templates/domain_all_settings.xml +137 -0
- data/spec/unit/templates/domain_defaults.xml +46 -0
- data/spec/unit/templates/domain_spec.rb +84 -0
- data/tools/create_box.sh +130 -0
- data/tools/prepare_redhat_for_box.sh +119 -0
- data/vagrant-libvirt.gemspec +54 -0
- metadata +93 -3
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ProviderLibvirt
|
5
|
+
module Action
|
6
|
+
# Suspend domain.
|
7
|
+
class SuspendDomain
|
8
|
+
def initialize(app, _env)
|
9
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::suspend_domain')
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
# make pause
|
14
|
+
def call(env)
|
15
|
+
env[:ui].info(I18n.t('vagrant_libvirt.suspending_domain'))
|
16
|
+
|
17
|
+
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
18
|
+
raise Errors::NoDomainError if domain.nil?
|
19
|
+
|
20
|
+
config = env[:machine].provider_config
|
21
|
+
if config.suspend_mode == 'managedsave'
|
22
|
+
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
|
23
|
+
begin
|
24
|
+
libvirt_domain.managed_save
|
25
|
+
rescue => e
|
26
|
+
env[:ui].error("Error doing a managed save for domain. It may have entered a paused state.
|
27
|
+
Check the output of `virsh managedsave DOMAIN_NAME --verbose` on the VM host, error: #{e.message}")
|
28
|
+
end
|
29
|
+
else
|
30
|
+
domain.suspend
|
31
|
+
end
|
32
|
+
|
33
|
+
@logger.info("Machine #{env[:machine].id} is suspended ")
|
34
|
+
|
35
|
+
@app.call(env)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'vagrant-libvirt/errors'
|
3
|
+
require 'vagrant-libvirt/util/timer'
|
4
|
+
require 'vagrant/util/retryable'
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module ProviderLibvirt
|
8
|
+
module Action
|
9
|
+
# Wait till domain is started, till it obtains an IP address and is
|
10
|
+
# accessible via ssh.
|
11
|
+
class WaitTillUp
|
12
|
+
include Vagrant::Util::Retryable
|
13
|
+
|
14
|
+
def initialize(app, _env)
|
15
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::wait_till_up')
|
16
|
+
@app = app
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
# Initialize metrics if they haven't been
|
21
|
+
env[:metrics] ||= {}
|
22
|
+
|
23
|
+
# Get domain object
|
24
|
+
domain = env[:machine].provider.driver.get_domain(env[:machine].id.to_s)
|
25
|
+
if domain.nil?
|
26
|
+
raise Errors::NoDomainError,
|
27
|
+
error_message: "Domain #{env[:machine].id} not found"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Wait for domain to obtain an ip address. Ip address is searched
|
31
|
+
# from arp table, either localy or remotely via ssh, if libvirt
|
32
|
+
# connection was done via ssh.
|
33
|
+
env[:ip_address] = nil
|
34
|
+
env[:metrics]['instance_ip_time'] = Util::Timer.time do
|
35
|
+
@logger.debug("Searching for IP for MAC address: #{domain.mac}")
|
36
|
+
env[:ui].info(I18n.t('vagrant_libvirt.waiting_for_ip'))
|
37
|
+
retryable(on: Fog::Errors::TimeoutError, tries: 300) do
|
38
|
+
# If we're interrupted don't worry about waiting
|
39
|
+
return terminate(env) if env[:interrupted]
|
40
|
+
|
41
|
+
# Wait for domain to obtain an ip address
|
42
|
+
domain.wait_for(2) do
|
43
|
+
addresses.each_pair do |_type, ip|
|
44
|
+
env[:ip_address] = ip[0] unless ip[0].nil?
|
45
|
+
end
|
46
|
+
!env[:ip_address].nil?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
@logger.info("Got IP address #{env[:ip_address]}")
|
51
|
+
@logger.info("Time for getting IP: #{env[:metrics]['instance_ip_time']}")
|
52
|
+
|
53
|
+
# Machine has ip address assigned, now wait till we are able to
|
54
|
+
# connect via ssh.
|
55
|
+
env[:metrics]['instance_ssh_time'] = Util::Timer.time do
|
56
|
+
env[:ui].info(I18n.t('vagrant_libvirt.waiting_for_ssh'))
|
57
|
+
retryable(on: Fog::Errors::TimeoutError, tries: 60) do
|
58
|
+
# If we're interrupted don't worry about waiting
|
59
|
+
next if env[:interrupted]
|
60
|
+
|
61
|
+
# Wait till we are able to connect via ssh.
|
62
|
+
loop do
|
63
|
+
# If we're interrupted then just back out
|
64
|
+
break if env[:interrupted]
|
65
|
+
break if env[:machine].communicate.ready?
|
66
|
+
sleep 2
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
# if interrupted above, just terminate immediately
|
71
|
+
return terminate(env) if env[:interrupted]
|
72
|
+
@logger.info("Time for SSH ready: #{env[:metrics]['instance_ssh_time']}")
|
73
|
+
|
74
|
+
# Booted and ready for use.
|
75
|
+
# env[:ui].info(I18n.t("vagrant_libvirt.ready"))
|
76
|
+
|
77
|
+
@app.call(env)
|
78
|
+
end
|
79
|
+
|
80
|
+
def recover(env)
|
81
|
+
return if env['vagrant.error'].is_a?(Vagrant::Errors::VagrantError)
|
82
|
+
|
83
|
+
# Undo the import
|
84
|
+
terminate(env)
|
85
|
+
end
|
86
|
+
|
87
|
+
def terminate(env)
|
88
|
+
if env[:machine].provider.state.id != :not_created
|
89
|
+
# If we're not supposed to destroy on error then just return
|
90
|
+
return unless env[:destroy_on_error]
|
91
|
+
|
92
|
+
if env[:halt_on_error]
|
93
|
+
halt_env = env.dup
|
94
|
+
halt_env.delete(:interrupted)
|
95
|
+
halt_env[:config_validate] = false
|
96
|
+
env[:action_runner].run(Action.action_halt, halt_env)
|
97
|
+
else
|
98
|
+
destroy_env = env.dup
|
99
|
+
destroy_env.delete(:interrupted)
|
100
|
+
destroy_env[:config_validate] = false
|
101
|
+
destroy_env[:force_confirm_destroy] = true
|
102
|
+
env[:action_runner].run(Action.action_destroy, destroy_env)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'vagrant/util/retryable'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderLibvirt
|
6
|
+
module Cap
|
7
|
+
class MountP9
|
8
|
+
extend Vagrant::Util::Retryable
|
9
|
+
|
10
|
+
def self.mount_p9_shared_folder(machine, folders)
|
11
|
+
folders.each do |_name, opts|
|
12
|
+
# Expand the guest path so we can handle things like "~/vagrant"
|
13
|
+
expanded_guest_path = machine.guest.capability(
|
14
|
+
:shell_expand_guest_path, opts[:guestpath]
|
15
|
+
)
|
16
|
+
|
17
|
+
# Do the actual creating and mounting
|
18
|
+
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
|
19
|
+
|
20
|
+
# Mount
|
21
|
+
mount_tag = Digest::MD5.new.update(opts[:hostpath]).to_s[0, 31]
|
22
|
+
|
23
|
+
mount_opts = '-o trans=virtio'
|
24
|
+
mount_opts += ",access=#{opts[:owner]}" if opts[:owner]
|
25
|
+
mount_opts += ",version=#{opts[:version]}" if opts[:version]
|
26
|
+
mount_opts += ",#{opts[:mount_opts]}" if opts[:mount_opts]
|
27
|
+
|
28
|
+
mount_command = "mount -t 9p #{mount_opts} '#{mount_tag}' #{expanded_guest_path}"
|
29
|
+
retryable(on: Vagrant::Errors::LinuxMountFailed,
|
30
|
+
tries: 5,
|
31
|
+
sleep: 3) do
|
32
|
+
machine.communicate.sudo('modprobe 9p')
|
33
|
+
machine.communicate.sudo('modprobe 9pnet_virtio')
|
34
|
+
machine.communicate.sudo(mount_command,
|
35
|
+
error_class: Vagrant::Errors::LinuxMountFailed)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProviderLibvirt
|
3
|
+
module Cap
|
4
|
+
class NicMacAddresses
|
5
|
+
def self.nic_mac_addresses(machine)
|
6
|
+
# Vagrant expects a Hash with an index starting at 1 as key
|
7
|
+
# and the mac as uppercase string without colons as value
|
8
|
+
nic_macs = {}
|
9
|
+
machine.provider.mac_addresses.each do |index, mac|
|
10
|
+
nic_macs[index + 1] = mac.upcase.delete(':')
|
11
|
+
end
|
12
|
+
nic_macs
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'digest/md5'
|
5
|
+
|
6
|
+
require 'vagrant/util/subprocess'
|
7
|
+
require 'vagrant/errors'
|
8
|
+
require 'vagrant-libvirt/errors'
|
9
|
+
# require_relative "helper"
|
10
|
+
|
11
|
+
module VagrantPlugins
|
12
|
+
module SyncedFolder9p
|
13
|
+
class SyncedFolder < Vagrant.plugin('2', :synced_folder)
|
14
|
+
include Vagrant::Util
|
15
|
+
include VagrantPlugins::ProviderLibvirt::Util::ErbTemplate
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
super
|
19
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::synced_folders::9p')
|
20
|
+
end
|
21
|
+
|
22
|
+
def usable?(machine, _raise_error = false)
|
23
|
+
# bail now if not using libvirt since checking version would throw error
|
24
|
+
return false unless machine.provider_name == :libvirt
|
25
|
+
|
26
|
+
# <filesystem/> support in device attach/detach introduced in 1.2.2
|
27
|
+
# version number format is major * 1,000,000 + minor * 1,000 + release
|
28
|
+
libvirt_version = machine.provider.driver.connection.client.libversion
|
29
|
+
libvirt_version >= 1_002_002
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare(machine, folders, _opts)
|
33
|
+
raise Vagrant::Errors::Error('No libvirt connection') if machine.provider.driver.connection.nil?
|
34
|
+
@conn = machine.provider.driver.connection.client
|
35
|
+
|
36
|
+
begin
|
37
|
+
# loop through folders
|
38
|
+
folders.each do |id, folder_opts|
|
39
|
+
folder_opts.merge!(target: id,
|
40
|
+
accessmode: 'passthrough',
|
41
|
+
mount: true,
|
42
|
+
readonly: nil) { |_k, ov, _nv| ov }
|
43
|
+
|
44
|
+
mount_tag = Digest::MD5.new.update(folder_opts[:hostpath]).to_s[0, 31]
|
45
|
+
folder_opts[:mount_tag] = mount_tag
|
46
|
+
|
47
|
+
machine.ui.info "================\nMachine id: #{machine.id}\nShould be mounting folders\n #{id}, opts: #{folder_opts}"
|
48
|
+
|
49
|
+
#xml = to_xml('filesystem', folder_opts)
|
50
|
+
xml = Nokogiri::XML::Builder.new do |xml|
|
51
|
+
xml.filesystem(type: 'mount', accessmode: folder_opts[:accessmode]) do
|
52
|
+
xml.driver(type: 'path', wrpolicy: 'immediate')
|
53
|
+
xml.source(dir: folder_opts[:hostpath])
|
54
|
+
xml.target(dir: mount_tag)
|
55
|
+
xml.readonly unless folder_opts[:readonly].nil?
|
56
|
+
end
|
57
|
+
end.to_xml(
|
58
|
+
save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION |
|
59
|
+
Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS |
|
60
|
+
Nokogiri::XML::Node::SaveOptions::FORMAT
|
61
|
+
)
|
62
|
+
# puts "<<<<< XML:\n #{xml}\n >>>>>"
|
63
|
+
@conn.lookup_domain_by_uuid(machine.id).attach_device(xml, 0)
|
64
|
+
end
|
65
|
+
rescue => e
|
66
|
+
machine.ui.error("could not attach device because: #{e}")
|
67
|
+
raise VagrantPlugins::ProviderLibvirt::Errors::AttachDeviceError,
|
68
|
+
error_message: e.message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# TODO: once up, mount folders
|
73
|
+
def enable(machine, folders, _opts)
|
74
|
+
# Go through each folder and mount
|
75
|
+
machine.ui.info('mounting p9 share in guest')
|
76
|
+
# Only mount folders that have a guest path specified.
|
77
|
+
mount_folders = {}
|
78
|
+
folders.each do |id, opts|
|
79
|
+
next unless opts[:mount] && opts[:guestpath] && !opts[:guestpath].empty?
|
80
|
+
mount_folders[id] = opts.dup
|
81
|
+
# merge common options if not given
|
82
|
+
mount_folders[id].merge!(version: '9p2000.L') { |_k, ov, _nv| ov }
|
83
|
+
end
|
84
|
+
# Mount the actual folder
|
85
|
+
machine.guest.capability(
|
86
|
+
:mount_p9_shared_folder, mount_folders
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def cleanup(machine, _opts)
|
91
|
+
if machine.provider.driver.connection.nil?
|
92
|
+
raise Vagrant::Errors::Error('No libvirt connection')
|
93
|
+
end
|
94
|
+
@conn = machine.provider.driver.connection.client
|
95
|
+
begin
|
96
|
+
if machine.id && machine.id != ''
|
97
|
+
dom = @conn.lookup_domain_by_uuid(machine.id)
|
98
|
+
Nokogiri::XML(dom.xml_desc).xpath(
|
99
|
+
'/domain/devices/filesystem'
|
100
|
+
).each do |xml|
|
101
|
+
dom.detach_device(xml.to_s)
|
102
|
+
machine.ui.info 'Cleaned up shared folders'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
rescue => e
|
106
|
+
machine.ui.error("could not detach device because: #{e}")
|
107
|
+
raise VagrantPlugins::ProviderLibvirt::Errors::DetachDeviceError,
|
108
|
+
error_message: e.message
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,746 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
|
3
|
+
class Numeric
|
4
|
+
Alphabet = ('a'..'z').to_a
|
5
|
+
def vdev
|
6
|
+
s = ''
|
7
|
+
q = self
|
8
|
+
(q, r = (q - 1).divmod(26)) && s.prepend(Alphabet[r]) until q.zero?
|
9
|
+
'vd' + s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module VagrantPlugins
|
14
|
+
module ProviderLibvirt
|
15
|
+
class Config < Vagrant.plugin('2', :config)
|
16
|
+
# manually specify URI
|
17
|
+
# will supercede most other options if provided
|
18
|
+
attr_accessor :uri
|
19
|
+
|
20
|
+
# A hypervisor name to access via Libvirt.
|
21
|
+
attr_accessor :driver
|
22
|
+
|
23
|
+
# The name of the server, where libvirtd is running.
|
24
|
+
attr_accessor :host
|
25
|
+
|
26
|
+
# If use ssh tunnel to connect to Libvirt.
|
27
|
+
attr_accessor :connect_via_ssh
|
28
|
+
# Path towards the libvirt socket
|
29
|
+
attr_accessor :socket
|
30
|
+
|
31
|
+
# The username to access Libvirt.
|
32
|
+
attr_accessor :username
|
33
|
+
|
34
|
+
# Password for Libvirt connection.
|
35
|
+
attr_accessor :password
|
36
|
+
|
37
|
+
# ID SSH key file
|
38
|
+
attr_accessor :id_ssh_key_file
|
39
|
+
|
40
|
+
# Libvirt storage pool name, where box image and instance snapshots will
|
41
|
+
# be stored.
|
42
|
+
attr_accessor :storage_pool_name
|
43
|
+
|
44
|
+
# Turn on to prevent hostname conflicts
|
45
|
+
attr_accessor :random_hostname
|
46
|
+
|
47
|
+
# Libvirt default network
|
48
|
+
attr_accessor :management_network_name
|
49
|
+
attr_accessor :management_network_address
|
50
|
+
attr_accessor :management_network_mode
|
51
|
+
attr_accessor :management_network_mac
|
52
|
+
attr_accessor :management_network_guest_ipv6
|
53
|
+
attr_accessor :management_network_autostart
|
54
|
+
attr_accessor :management_network_pci_bus
|
55
|
+
attr_accessor :management_network_pci_slot
|
56
|
+
|
57
|
+
# Default host prefix (alternative to use project folder name)
|
58
|
+
attr_accessor :default_prefix
|
59
|
+
|
60
|
+
# Domain specific settings used while creating new domain.
|
61
|
+
attr_accessor :uuid
|
62
|
+
attr_accessor :memory
|
63
|
+
attr_accessor :memory_backing
|
64
|
+
attr_accessor :channel
|
65
|
+
attr_accessor :cpus
|
66
|
+
attr_accessor :cpu_mode
|
67
|
+
attr_accessor :cpu_model
|
68
|
+
attr_accessor :cpu_fallback
|
69
|
+
attr_accessor :cpu_features
|
70
|
+
attr_accessor :cpu_topology
|
71
|
+
attr_accessor :features
|
72
|
+
attr_accessor :numa_nodes
|
73
|
+
attr_accessor :loader
|
74
|
+
attr_accessor :boot_order
|
75
|
+
attr_accessor :machine_type
|
76
|
+
attr_accessor :machine_arch
|
77
|
+
attr_accessor :machine_virtual_size
|
78
|
+
attr_accessor :disk_bus
|
79
|
+
attr_accessor :disk_device
|
80
|
+
attr_accessor :nic_model_type
|
81
|
+
attr_accessor :nested
|
82
|
+
attr_accessor :volume_cache
|
83
|
+
attr_accessor :kernel
|
84
|
+
attr_accessor :cmd_line
|
85
|
+
attr_accessor :initrd
|
86
|
+
attr_accessor :dtb
|
87
|
+
attr_accessor :emulator_path
|
88
|
+
attr_accessor :graphics_type
|
89
|
+
attr_accessor :graphics_autoport
|
90
|
+
attr_accessor :graphics_port
|
91
|
+
attr_accessor :graphics_passwd
|
92
|
+
attr_accessor :graphics_ip
|
93
|
+
attr_accessor :video_type
|
94
|
+
attr_accessor :video_vram
|
95
|
+
attr_accessor :keymap
|
96
|
+
attr_accessor :kvm_hidden
|
97
|
+
attr_accessor :sound_type
|
98
|
+
|
99
|
+
# Sets the information for connecting to a host TPM device
|
100
|
+
# Only supports socket-based TPMs
|
101
|
+
attr_accessor :tpm_model
|
102
|
+
attr_accessor :tpm_type
|
103
|
+
attr_accessor :tpm_path
|
104
|
+
|
105
|
+
# Sets the max number of NICs that can be created
|
106
|
+
# Default set to 8. Don't change the default unless you know
|
107
|
+
# what are doing
|
108
|
+
attr_accessor :nic_adapter_count
|
109
|
+
|
110
|
+
# Storage
|
111
|
+
attr_accessor :disks
|
112
|
+
attr_accessor :cdroms
|
113
|
+
|
114
|
+
# Inputs
|
115
|
+
attr_accessor :inputs
|
116
|
+
|
117
|
+
# Channels
|
118
|
+
attr_accessor :channels
|
119
|
+
|
120
|
+
# PCI device passthrough
|
121
|
+
attr_accessor :pcis
|
122
|
+
|
123
|
+
# Random number device passthrough
|
124
|
+
attr_accessor :rng
|
125
|
+
|
126
|
+
# Watchdog device
|
127
|
+
attr_accessor :watchdog_dev
|
128
|
+
|
129
|
+
# USB device passthrough
|
130
|
+
attr_accessor :usbs
|
131
|
+
|
132
|
+
# Redirected devices
|
133
|
+
attr_accessor :redirdevs
|
134
|
+
attr_accessor :redirfilters
|
135
|
+
|
136
|
+
# smartcard device
|
137
|
+
attr_accessor :smartcard_dev
|
138
|
+
|
139
|
+
# Suspend mode
|
140
|
+
attr_accessor :suspend_mode
|
141
|
+
|
142
|
+
# Autostart
|
143
|
+
attr_accessor :autostart
|
144
|
+
|
145
|
+
# Attach mgmt network
|
146
|
+
attr_accessor :mgmt_attach
|
147
|
+
|
148
|
+
# Additional qemuargs arguments
|
149
|
+
attr_accessor :qemu_args
|
150
|
+
|
151
|
+
def initialize
|
152
|
+
@uri = UNSET_VALUE
|
153
|
+
@driver = UNSET_VALUE
|
154
|
+
@host = UNSET_VALUE
|
155
|
+
@connect_via_ssh = UNSET_VALUE
|
156
|
+
@username = UNSET_VALUE
|
157
|
+
@password = UNSET_VALUE
|
158
|
+
@id_ssh_key_file = UNSET_VALUE
|
159
|
+
@storage_pool_name = UNSET_VALUE
|
160
|
+
@random_hostname = UNSET_VALUE
|
161
|
+
@management_network_name = UNSET_VALUE
|
162
|
+
@management_network_address = UNSET_VALUE
|
163
|
+
@management_network_mode = UNSET_VALUE
|
164
|
+
@management_network_mac = UNSET_VALUE
|
165
|
+
@management_network_guest_ipv6 = UNSET_VALUE
|
166
|
+
@management_network_autostart = UNSET_VALUE
|
167
|
+
@management_network_pci_slot = UNSET_VALUE
|
168
|
+
@management_network_pci_bus = UNSET_VALUE
|
169
|
+
|
170
|
+
# Domain specific settings.
|
171
|
+
@uuid = UNSET_VALUE
|
172
|
+
@memory = UNSET_VALUE
|
173
|
+
@memory_backing = UNSET_VALUE
|
174
|
+
@cpus = UNSET_VALUE
|
175
|
+
@cpu_mode = UNSET_VALUE
|
176
|
+
@cpu_model = UNSET_VALUE
|
177
|
+
@cpu_fallback = UNSET_VALUE
|
178
|
+
@cpu_features = UNSET_VALUE
|
179
|
+
@cpu_topology = UNSET_VALUE
|
180
|
+
@features = UNSET_VALUE
|
181
|
+
@numa_nodes = UNSET_VALUE
|
182
|
+
@loader = UNSET_VALUE
|
183
|
+
@machine_type = UNSET_VALUE
|
184
|
+
@machine_arch = UNSET_VALUE
|
185
|
+
@machine_virtual_size = UNSET_VALUE
|
186
|
+
@disk_bus = UNSET_VALUE
|
187
|
+
@disk_device = UNSET_VALUE
|
188
|
+
@nic_model_type = UNSET_VALUE
|
189
|
+
@nested = UNSET_VALUE
|
190
|
+
@volume_cache = UNSET_VALUE
|
191
|
+
@kernel = UNSET_VALUE
|
192
|
+
@initrd = UNSET_VALUE
|
193
|
+
@dtb = UNSET_VALUE
|
194
|
+
@cmd_line = UNSET_VALUE
|
195
|
+
@emulator_path = UNSET_VALUE
|
196
|
+
@graphics_type = UNSET_VALUE
|
197
|
+
@graphics_autoport = UNSET_VALUE
|
198
|
+
@graphics_port = UNSET_VALUE
|
199
|
+
@graphics_ip = UNSET_VALUE
|
200
|
+
@graphics_passwd = UNSET_VALUE
|
201
|
+
@video_type = UNSET_VALUE
|
202
|
+
@video_vram = UNSET_VALUE
|
203
|
+
@sound_type = UNSET_VALUE
|
204
|
+
@keymap = UNSET_VALUE
|
205
|
+
@kvm_hidden = UNSET_VALUE
|
206
|
+
|
207
|
+
@tpm_model = UNSET_VALUE
|
208
|
+
@tpm_type = UNSET_VALUE
|
209
|
+
@tpm_path = UNSET_VALUE
|
210
|
+
|
211
|
+
@nic_adapter_count = UNSET_VALUE
|
212
|
+
|
213
|
+
# Boot order
|
214
|
+
@boot_order = []
|
215
|
+
# Storage
|
216
|
+
@disks = []
|
217
|
+
@cdroms = []
|
218
|
+
|
219
|
+
# Inputs
|
220
|
+
@inputs = UNSET_VALUE
|
221
|
+
|
222
|
+
# Channels
|
223
|
+
@channels = UNSET_VALUE
|
224
|
+
|
225
|
+
# PCI device passthrough
|
226
|
+
@pcis = UNSET_VALUE
|
227
|
+
|
228
|
+
# Random number device passthrough
|
229
|
+
@rng = UNSET_VALUE
|
230
|
+
|
231
|
+
# Watchdog device
|
232
|
+
@watchdog_dev = UNSET_VALUE
|
233
|
+
|
234
|
+
# USB device passthrough
|
235
|
+
@usbs = UNSET_VALUE
|
236
|
+
|
237
|
+
# Redirected devices
|
238
|
+
@redirdevs = UNSET_VALUE
|
239
|
+
@redirfilters = UNSET_VALUE
|
240
|
+
|
241
|
+
# smartcard device
|
242
|
+
@smartcard_dev = UNSET_VALUE
|
243
|
+
|
244
|
+
# Suspend mode
|
245
|
+
@suspend_mode = UNSET_VALUE
|
246
|
+
|
247
|
+
# Autostart
|
248
|
+
@autostart = UNSET_VALUE
|
249
|
+
|
250
|
+
# Attach mgmt network
|
251
|
+
@mgmt_attach = UNSET_VALUE
|
252
|
+
|
253
|
+
@qemu_args = []
|
254
|
+
end
|
255
|
+
|
256
|
+
def boot(device)
|
257
|
+
@boot_order << device # append
|
258
|
+
end
|
259
|
+
|
260
|
+
def _get_device(disks)
|
261
|
+
# skip existing devices and also the first one (vda)
|
262
|
+
exist = disks.collect { |x| x[:device] } + [1.vdev.to_s]
|
263
|
+
skip = 1 # we're 1 based, not 0 based...
|
264
|
+
loop do
|
265
|
+
dev = skip.vdev # get lettered device
|
266
|
+
return dev unless exist.include?(dev)
|
267
|
+
skip += 1
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def _get_cdrom_dev(cdroms)
|
272
|
+
exist = Hash[cdroms.collect { |x| [x[:dev], true] }]
|
273
|
+
# hda - hdc
|
274
|
+
curr = 'a'.ord
|
275
|
+
while curr <= 'd'.ord
|
276
|
+
dev = 'hd' + curr.chr
|
277
|
+
if exist[dev]
|
278
|
+
curr += 1
|
279
|
+
next
|
280
|
+
else
|
281
|
+
return dev
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# is it better to raise our own error, or let libvirt cause the exception?
|
286
|
+
raise 'Only four cdroms may be attached at a time'
|
287
|
+
end
|
288
|
+
|
289
|
+
def _generate_numa
|
290
|
+
@numa_nodes.collect { |x|
|
291
|
+
# Perform some validation of cpu values
|
292
|
+
unless x[:cpus] =~ /^\d+-\d+$/
|
293
|
+
raise 'numa_nodes[:cpus] must be in format "integer-integer"'
|
294
|
+
end
|
295
|
+
|
296
|
+
# Convert to KiB
|
297
|
+
x[:memory] = x[:memory].to_i * 1024
|
298
|
+
}
|
299
|
+
|
300
|
+
# Grab the value of the last @numa_nodes[:cpus] and verify @cpus matches
|
301
|
+
# Note: [:cpus] is zero based and @cpus is not, so we need to +1
|
302
|
+
last_cpu = @numa_nodes.last[:cpus]
|
303
|
+
last_cpu = last_cpu.scan(/\d+$/)[0]
|
304
|
+
last_cpu = last_cpu.to_i + 1
|
305
|
+
|
306
|
+
if @cpus != last_cpu.to_i
|
307
|
+
raise 'The total number of numa_nodes[:cpus] must equal config.cpus'
|
308
|
+
end
|
309
|
+
|
310
|
+
@numa_nodes
|
311
|
+
end
|
312
|
+
|
313
|
+
def cpu_feature(options = {})
|
314
|
+
if options[:name].nil? || options[:policy].nil?
|
315
|
+
raise 'CPU Feature name AND policy must be specified'
|
316
|
+
end
|
317
|
+
|
318
|
+
@cpu_features = [] if @cpu_features == UNSET_VALUE
|
319
|
+
|
320
|
+
@cpu_features.push(name: options[:name],
|
321
|
+
policy: options[:policy])
|
322
|
+
end
|
323
|
+
|
324
|
+
def cputopology(options = {})
|
325
|
+
if options[:sockets].nil? || options[:cores].nil? || options[:threads].nil?
|
326
|
+
raise 'CPU topology must have all of sockets, cores and threads specified'
|
327
|
+
end
|
328
|
+
|
329
|
+
if @cpu_topology == UNSET_VALUE
|
330
|
+
@cpu_topology = {}
|
331
|
+
end
|
332
|
+
|
333
|
+
@cpu_topology[:sockets] = options[:sockets]
|
334
|
+
@cpu_topology[:cores] = options[:cores]
|
335
|
+
@cpu_topology[:threads] = options[:threads]
|
336
|
+
end
|
337
|
+
|
338
|
+
def memorybacking(option, config = {})
|
339
|
+
case option
|
340
|
+
when :source
|
341
|
+
raise 'Source type must be specified' if config[:type].nil?
|
342
|
+
when :access
|
343
|
+
raise 'Access mode must be specified' if config[:mode].nil?
|
344
|
+
when :allocation
|
345
|
+
raise 'Allocation mode must be specified' if config[:mode].nil?
|
346
|
+
end
|
347
|
+
|
348
|
+
@memory_backing = [] if @memory_backing == UNSET_VALUE
|
349
|
+
@memory_backing.push(name: option,
|
350
|
+
config: config)
|
351
|
+
end
|
352
|
+
|
353
|
+
def input(options = {})
|
354
|
+
if options[:type].nil? || options[:bus].nil?
|
355
|
+
raise 'Input type AND bus must be specified'
|
356
|
+
end
|
357
|
+
|
358
|
+
@inputs = [] if @inputs == UNSET_VALUE
|
359
|
+
|
360
|
+
@inputs.push(type: options[:type],
|
361
|
+
bus: options[:bus])
|
362
|
+
end
|
363
|
+
|
364
|
+
def channel(options = {})
|
365
|
+
if options[:type].nil?
|
366
|
+
raise 'Channel type must be specified.'
|
367
|
+
elsif options[:type] == 'unix' && options[:target_type] == 'guestfwd'
|
368
|
+
# Guest forwarding requires a target (ip address) and a port
|
369
|
+
if options[:target_address].nil? || options[:target_port].nil? ||
|
370
|
+
options[:source_path].nil?
|
371
|
+
raise 'guestfwd requires target_address, target_port and source_path'
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
@channels = [] if @channels == UNSET_VALUE
|
376
|
+
|
377
|
+
@channels.push(type: options[:type],
|
378
|
+
source_mode: options[:source_mode],
|
379
|
+
source_path: options[:source_path],
|
380
|
+
target_address: options[:target_address],
|
381
|
+
target_name: options[:target_name],
|
382
|
+
target_port: options[:target_port],
|
383
|
+
target_type: options[:target_type])
|
384
|
+
end
|
385
|
+
|
386
|
+
def random(options = {})
|
387
|
+
if !options[:model].nil? && options[:model] != 'random'
|
388
|
+
raise 'The only supported rng backend is "random".'
|
389
|
+
end
|
390
|
+
|
391
|
+
@rng = {} if @rng == UNSET_VALUE
|
392
|
+
|
393
|
+
@rng[:model] = options[:model]
|
394
|
+
end
|
395
|
+
|
396
|
+
def pci(options = {})
|
397
|
+
if options[:bus].nil? || options[:slot].nil? || options[:function].nil?
|
398
|
+
raise 'Bus AND slot AND function must be specified. Check `lspci` for that numbers.'
|
399
|
+
end
|
400
|
+
|
401
|
+
@pcis = [] if @pcis == UNSET_VALUE
|
402
|
+
|
403
|
+
@pcis.push(bus: options[:bus],
|
404
|
+
slot: options[:slot],
|
405
|
+
function: options[:function])
|
406
|
+
end
|
407
|
+
|
408
|
+
def watchdog(options = {})
|
409
|
+
if options[:model].nil?
|
410
|
+
raise 'Model must be specified.'
|
411
|
+
end
|
412
|
+
|
413
|
+
if @watchdog_dev == UNSET_VALUE
|
414
|
+
@watchdog_dev = {}
|
415
|
+
end
|
416
|
+
|
417
|
+
@watchdog_dev[:model] = options[:model]
|
418
|
+
@watchdog_dev[:action] = options[:action] || 'reset'
|
419
|
+
end
|
420
|
+
|
421
|
+
|
422
|
+
def usb(options = {})
|
423
|
+
if (options[:bus].nil? || options[:device].nil?) && options[:vendor].nil? && options[:product].nil?
|
424
|
+
raise 'Bus and device and/or vendor and/or product must be specified. Check `lsusb` for these.'
|
425
|
+
end
|
426
|
+
|
427
|
+
@usbs = [] if @usbs == UNSET_VALUE
|
428
|
+
|
429
|
+
@usbs.push(bus: options[:bus],
|
430
|
+
device: options[:device],
|
431
|
+
vendor: options[:vendor],
|
432
|
+
product: options[:product],
|
433
|
+
startupPolicy: options[:startupPolicy])
|
434
|
+
end
|
435
|
+
|
436
|
+
def redirdev(options = {})
|
437
|
+
raise 'Type must be specified.' if options[:type].nil?
|
438
|
+
|
439
|
+
@redirdevs = [] if @redirdevs == UNSET_VALUE
|
440
|
+
|
441
|
+
@redirdevs.push(type: options[:type])
|
442
|
+
end
|
443
|
+
|
444
|
+
def redirfilter(options = {})
|
445
|
+
raise 'Option allow must be specified.' if options[:allow].nil?
|
446
|
+
|
447
|
+
@redirfilters = [] if @redirfilters == UNSET_VALUE
|
448
|
+
|
449
|
+
@redirfilters.push(class: options[:class] || -1,
|
450
|
+
vendor: options[:class] || -1,
|
451
|
+
product: options[:class] || -1,
|
452
|
+
version: options[:class] || -1,
|
453
|
+
allow: options[:allow])
|
454
|
+
end
|
455
|
+
|
456
|
+
def smartcard(options = {})
|
457
|
+
if options[:mode].nil?
|
458
|
+
raise 'Option mode must be specified.'
|
459
|
+
elsif options[:mode] != 'passthrough'
|
460
|
+
raise 'Currently only passthrough mode is supported!'
|
461
|
+
elsif options[:type] == 'tcp' && (options[:source_mode].nil? || options[:source_host].nil? || options[:source_service].nil?)
|
462
|
+
raise 'If using type "tcp", option "source_mode", "source_host" and "source_service" must be specified.'
|
463
|
+
end
|
464
|
+
|
465
|
+
if @smartcard_dev == UNSET_VALUE
|
466
|
+
@smartcard_dev = {}
|
467
|
+
end
|
468
|
+
|
469
|
+
@smartcard_dev[:mode] = options[:mode]
|
470
|
+
@smartcard_dev[:type] = options[:type] || 'spicevmc'
|
471
|
+
@smartcard_dev[:source_mode] = options[:source_mode] if @smartcard_dev[:type] == 'tcp'
|
472
|
+
@smartcard_dev[:source_host] = options[:source_host] if @smartcard_dev[:type] == 'tcp'
|
473
|
+
@smartcard_dev[:source_service] = options[:source_service] if @smartcard_dev[:type] == 'tcp'
|
474
|
+
end
|
475
|
+
|
476
|
+
# NOTE: this will run twice for each time it's needed- keep it idempotent
|
477
|
+
def storage(storage_type, options = {})
|
478
|
+
if storage_type == :file
|
479
|
+
if options[:device] == :cdrom
|
480
|
+
_handle_cdrom_storage(options)
|
481
|
+
else
|
482
|
+
_handle_disk_storage(options)
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
def _handle_cdrom_storage(options = {})
|
488
|
+
# <disk type="file" device="cdrom">
|
489
|
+
# <source file="/home/user/virtio-win-0.1-100.iso"/>
|
490
|
+
# <target dev="hdc"/>
|
491
|
+
# <readonly/>
|
492
|
+
# <address type='drive' controller='0' bus='1' target='0' unit='0'/>
|
493
|
+
# </disk>
|
494
|
+
#
|
495
|
+
# note the target dev will need to be changed with each cdrom drive (hdc, hdd, etc),
|
496
|
+
# as will the address unit number (unit=0, unit=1, etc)
|
497
|
+
|
498
|
+
options = {
|
499
|
+
bus: 'ide',
|
500
|
+
path: nil
|
501
|
+
}.merge(options)
|
502
|
+
|
503
|
+
cdrom = {
|
504
|
+
dev: options[:dev],
|
505
|
+
bus: options[:bus],
|
506
|
+
path: options[:path]
|
507
|
+
}
|
508
|
+
|
509
|
+
@cdroms << cdrom
|
510
|
+
end
|
511
|
+
|
512
|
+
def _handle_disk_storage(options = {})
|
513
|
+
options = {
|
514
|
+
type: 'qcow2',
|
515
|
+
size: '10G', # matches the fog default
|
516
|
+
path: nil,
|
517
|
+
bus: 'virtio'
|
518
|
+
}.merge(options)
|
519
|
+
|
520
|
+
disk = {
|
521
|
+
device: options[:device],
|
522
|
+
type: options[:type],
|
523
|
+
size: options[:size],
|
524
|
+
path: options[:path],
|
525
|
+
bus: options[:bus],
|
526
|
+
cache: options[:cache] || 'default',
|
527
|
+
allow_existing: options[:allow_existing],
|
528
|
+
shareable: options[:shareable],
|
529
|
+
serial: options[:serial]
|
530
|
+
}
|
531
|
+
|
532
|
+
@disks << disk # append
|
533
|
+
end
|
534
|
+
|
535
|
+
def qemuargs(options = {})
|
536
|
+
@qemu_args << options if options[:value]
|
537
|
+
end
|
538
|
+
|
539
|
+
# code to generate URI from a config moved out of the connect action
|
540
|
+
def _generate_uri
|
541
|
+
# builds the libvirt connection URI from the given driver config
|
542
|
+
# Setup connection uri.
|
543
|
+
uri = @driver.dup
|
544
|
+
virt_path = case uri
|
545
|
+
when 'qemu', 'openvz', 'uml', 'phyp', 'parallels', 'kvm'
|
546
|
+
'/system'
|
547
|
+
when '@en', 'esx'
|
548
|
+
'/'
|
549
|
+
when 'vbox', 'vmwarews', 'hyperv'
|
550
|
+
'/session'
|
551
|
+
else
|
552
|
+
raise "Require specify driver #{uri}"
|
553
|
+
end
|
554
|
+
if uri == 'kvm'
|
555
|
+
uri = 'qemu' # use qemu uri for kvm domain type
|
556
|
+
end
|
557
|
+
|
558
|
+
if @connect_via_ssh
|
559
|
+
uri << '+ssh://'
|
560
|
+
uri << @username + '@' if @username
|
561
|
+
|
562
|
+
uri << if @host
|
563
|
+
@host
|
564
|
+
else
|
565
|
+
'localhost'
|
566
|
+
end
|
567
|
+
else
|
568
|
+
uri << '://'
|
569
|
+
uri << @host if @host
|
570
|
+
end
|
571
|
+
|
572
|
+
uri << virt_path
|
573
|
+
uri << '?no_verify=1'
|
574
|
+
|
575
|
+
if @id_ssh_key_file
|
576
|
+
# set ssh key for access to libvirt host
|
577
|
+
uri << "\&keyfile="
|
578
|
+
# if no slash, prepend $HOME/.ssh/
|
579
|
+
@id_ssh_key_file.prepend("#{`echo ${HOME}`.chomp}/.ssh/") if @id_ssh_key_file !~ /\A\//
|
580
|
+
uri << @id_ssh_key_file
|
581
|
+
end
|
582
|
+
# set path to libvirt socket
|
583
|
+
uri << "\&socket=" + @socket if @socket
|
584
|
+
uri
|
585
|
+
end
|
586
|
+
|
587
|
+
def finalize!
|
588
|
+
@driver = 'kvm' if @driver == UNSET_VALUE
|
589
|
+
@host = nil if @host == UNSET_VALUE
|
590
|
+
@connect_via_ssh = false if @connect_via_ssh == UNSET_VALUE
|
591
|
+
@username = nil if @username == UNSET_VALUE
|
592
|
+
@password = nil if @password == UNSET_VALUE
|
593
|
+
@id_ssh_key_file = 'id_rsa' if @id_ssh_key_file == UNSET_VALUE
|
594
|
+
@storage_pool_name = 'default' if @storage_pool_name == UNSET_VALUE
|
595
|
+
@random_hostname = false if @random_hostname == UNSET_VALUE
|
596
|
+
@management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
|
597
|
+
@management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
|
598
|
+
@management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
|
599
|
+
@management_network_mac = nil if @management_network_mac == UNSET_VALUE
|
600
|
+
@management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
|
601
|
+
@management_network_autostart = false if @management_network_autostart == UNSET_VALUE
|
602
|
+
@management_network_pci_bus = nil if @management_network_pci_bus == UNSET_VALUE
|
603
|
+
@management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
|
604
|
+
|
605
|
+
# generate a URI if none is supplied
|
606
|
+
@uri = _generate_uri if @uri == UNSET_VALUE
|
607
|
+
|
608
|
+
# Domain specific settings.
|
609
|
+
@uuid = '' if @uuid == UNSET_VALUE
|
610
|
+
@memory = 512 if @memory == UNSET_VALUE
|
611
|
+
@memory_backing = [] if @memory_backing == UNSET_VALUE
|
612
|
+
@cpus = 1 if @cpus == UNSET_VALUE
|
613
|
+
@cpu_mode = 'host-model' if @cpu_mode == UNSET_VALUE
|
614
|
+
@cpu_model = if (@cpu_model == UNSET_VALUE) && (@cpu_mode == 'custom')
|
615
|
+
'qemu64'
|
616
|
+
elsif @cpu_mode != 'custom'
|
617
|
+
''
|
618
|
+
end
|
619
|
+
@cpu_topology = {} if @cpu_topology == UNSET_VALUE
|
620
|
+
@cpu_fallback = 'allow' if @cpu_fallback == UNSET_VALUE
|
621
|
+
@cpu_features = [] if @cpu_features == UNSET_VALUE
|
622
|
+
@features = ['acpi','apic','pae'] if @features == UNSET_VALUE
|
623
|
+
@numa_nodes = @numa_nodes == UNSET_VALUE ? nil : _generate_numa
|
624
|
+
@loader = nil if @loader == UNSET_VALUE
|
625
|
+
@machine_type = nil if @machine_type == UNSET_VALUE
|
626
|
+
@machine_arch = nil if @machine_arch == UNSET_VALUE
|
627
|
+
@machine_virtual_size = nil if @machine_virtual_size == UNSET_VALUE
|
628
|
+
@disk_bus = 'virtio' if @disk_bus == UNSET_VALUE
|
629
|
+
@disk_device = 'vda' if @disk_device == UNSET_VALUE
|
630
|
+
@nic_model_type = nil if @nic_model_type == UNSET_VALUE
|
631
|
+
@nested = false if @nested == UNSET_VALUE
|
632
|
+
@volume_cache = 'default' if @volume_cache == UNSET_VALUE
|
633
|
+
@kernel = nil if @kernel == UNSET_VALUE
|
634
|
+
@cmd_line = '' if @cmd_line == UNSET_VALUE
|
635
|
+
@initrd = '' if @initrd == UNSET_VALUE
|
636
|
+
@dtb = nil if @dtb == UNSET_VALUE
|
637
|
+
@graphics_type = 'vnc' if @graphics_type == UNSET_VALUE
|
638
|
+
@graphics_autoport = 'yes' if @graphics_port == UNSET_VALUE
|
639
|
+
@graphics_autoport = 'no' if @graphics_port != UNSET_VALUE
|
640
|
+
if (@graphics_type != 'vnc' && @graphics_type != 'spice') ||
|
641
|
+
@graphics_passwd == UNSET_VALUE
|
642
|
+
@graphics_passwd = nil
|
643
|
+
end
|
644
|
+
@graphics_port = -1 if @graphics_port == UNSET_VALUE
|
645
|
+
@graphics_ip = '127.0.0.1' if @graphics_ip == UNSET_VALUE
|
646
|
+
@video_type = 'cirrus' if @video_type == UNSET_VALUE
|
647
|
+
@video_vram = 9216 if @video_vram == UNSET_VALUE
|
648
|
+
@sound_type = nil if @sound_type == UNSET_VALUE
|
649
|
+
@keymap = 'en-us' if @keymap == UNSET_VALUE
|
650
|
+
@kvm_hidden = false if @kvm_hidden == UNSET_VALUE
|
651
|
+
@tpm_model = 'tpm-tis' if @tpm_model == UNSET_VALUE
|
652
|
+
@tpm_type = 'passthrough' if @tpm_type == UNSET_VALUE
|
653
|
+
@tpm_path = nil if @tpm_path == UNSET_VALUE
|
654
|
+
@nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
|
655
|
+
@emulator_path = nil if @emulator_path == UNSET_VALUE
|
656
|
+
|
657
|
+
# Boot order
|
658
|
+
@boot_order = [] if @boot_order == UNSET_VALUE
|
659
|
+
|
660
|
+
# Storage
|
661
|
+
@disks = [] if @disks == UNSET_VALUE
|
662
|
+
@disks.map! do |disk|
|
663
|
+
disk[:device] = _get_device(@disks) if disk[:device].nil?
|
664
|
+
disk
|
665
|
+
end
|
666
|
+
@cdroms = [] if @cdroms == UNSET_VALUE
|
667
|
+
@cdroms.map! do |cdrom|
|
668
|
+
cdrom[:dev] = _get_cdrom_dev(@cdroms) if cdrom[:dev].nil?
|
669
|
+
cdrom
|
670
|
+
end
|
671
|
+
|
672
|
+
# Inputs
|
673
|
+
@inputs = [{ type: 'mouse', bus: 'ps2' }] if @inputs == UNSET_VALUE
|
674
|
+
|
675
|
+
# Channels
|
676
|
+
@channels = [] if @channels == UNSET_VALUE
|
677
|
+
|
678
|
+
# PCI device passthrough
|
679
|
+
@pcis = [] if @pcis == UNSET_VALUE
|
680
|
+
|
681
|
+
# Random number generator passthrough
|
682
|
+
@rng = {} if @rng == UNSET_VALUE
|
683
|
+
|
684
|
+
# Watchdog device
|
685
|
+
@watchdog_dev = {} if @watchdog_dev == UNSET_VALUE
|
686
|
+
|
687
|
+
# USB device passthrough
|
688
|
+
@usbs = [] if @usbs == UNSET_VALUE
|
689
|
+
|
690
|
+
# Redirected devices
|
691
|
+
@redirdevs = [] if @redirdevs == UNSET_VALUE
|
692
|
+
@redirfilters = [] if @redirfilters == UNSET_VALUE
|
693
|
+
|
694
|
+
# smartcard device
|
695
|
+
@smartcard_dev = {} if @smartcard_dev == UNSET_VALUE
|
696
|
+
|
697
|
+
# Suspend mode
|
698
|
+
@suspend_mode = 'pause' if @suspend_mode == UNSET_VALUE
|
699
|
+
|
700
|
+
# Autostart
|
701
|
+
@autostart = false if @autostart == UNSET_VALUE
|
702
|
+
|
703
|
+
# Attach mgmt network
|
704
|
+
@mgmt_attach = true if @mgmt_attach == UNSET_VALUE
|
705
|
+
|
706
|
+
@qemu_args = [] if @qemu_args == UNSET_VALUE
|
707
|
+
end
|
708
|
+
|
709
|
+
def validate(machine)
|
710
|
+
errors = _detected_errors
|
711
|
+
|
712
|
+
machine.provider_config.disks.each do |disk|
|
713
|
+
if disk[:path] && (disk[:path][0] == '/')
|
714
|
+
errors << "absolute volume paths like '#{disk[:path]}' not yet supported"
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
machine.config.vm.networks.each do |_type, opts|
|
719
|
+
if opts[:mac]
|
720
|
+
opts[:mac].downcase!
|
721
|
+
if opts[:mac] =~ /\A([0-9a-f]{12})\z/
|
722
|
+
opts[:mac] = opts[:mac].scan(/../).join(':')
|
723
|
+
end
|
724
|
+
unless opts[:mac] =~ /\A([0-9a-f]{2}:){5}([0-9a-f]{2})\z/
|
725
|
+
errors << "Configured NIC MAC '#{opts[:mac]}' is not in 'xx:xx:xx:xx:xx:xx' or 'xxxxxxxxxxxx' format"
|
726
|
+
end
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
730
|
+
{ 'Libvirt Provider' => errors }
|
731
|
+
end
|
732
|
+
|
733
|
+
def merge(other)
|
734
|
+
super.tap do |result|
|
735
|
+
c = disks.dup
|
736
|
+
c += other.disks
|
737
|
+
result.disks = c
|
738
|
+
|
739
|
+
c = cdroms.dup
|
740
|
+
c += other.cdroms
|
741
|
+
result.cdroms = c
|
742
|
+
end
|
743
|
+
end
|
744
|
+
end
|
745
|
+
end
|
746
|
+
end
|