vagrant-libvirt 0.0.40 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. metadata +13 -103
  3. data/.coveralls.yml +0 -1
  4. data/.github/issue_template.md +0 -37
  5. data/.gitignore +0 -21
  6. data/.travis.yml +0 -28
  7. data/CHANGELOG.md +0 -99
  8. data/Gemfile +0 -27
  9. data/LICENSE +0 -22
  10. data/README.md +0 -1311
  11. data/Rakefile +0 -8
  12. data/example_box/README.md +0 -29
  13. data/example_box/Vagrantfile +0 -60
  14. data/example_box/metadata.json +0 -5
  15. data/lib/vagrant-libvirt.rb +0 -29
  16. data/lib/vagrant-libvirt/action.rb +0 -362
  17. data/lib/vagrant-libvirt/action/create_domain.rb +0 -313
  18. data/lib/vagrant-libvirt/action/create_domain_volume.rb +0 -87
  19. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +0 -294
  20. data/lib/vagrant-libvirt/action/create_networks.rb +0 -353
  21. data/lib/vagrant-libvirt/action/destroy_domain.rb +0 -83
  22. data/lib/vagrant-libvirt/action/destroy_networks.rb +0 -95
  23. data/lib/vagrant-libvirt/action/forward_ports.rb +0 -221
  24. data/lib/vagrant-libvirt/action/halt_domain.rb +0 -35
  25. data/lib/vagrant-libvirt/action/handle_box_image.rb +0 -156
  26. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +0 -57
  27. data/lib/vagrant-libvirt/action/is_created.rb +0 -18
  28. data/lib/vagrant-libvirt/action/is_running.rb +0 -21
  29. data/lib/vagrant-libvirt/action/is_suspended.rb +0 -42
  30. data/lib/vagrant-libvirt/action/message_already_created.rb +0 -16
  31. data/lib/vagrant-libvirt/action/message_not_created.rb +0 -16
  32. data/lib/vagrant-libvirt/action/message_not_running.rb +0 -16
  33. data/lib/vagrant-libvirt/action/message_not_suspended.rb +0 -16
  34. data/lib/vagrant-libvirt/action/package_domain.rb +0 -105
  35. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +0 -94
  36. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +0 -17
  37. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +0 -27
  38. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +0 -40
  39. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +0 -20
  40. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +0 -50
  41. data/lib/vagrant-libvirt/action/resume_domain.rb +0 -34
  42. data/lib/vagrant-libvirt/action/set_boot_order.rb +0 -109
  43. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +0 -64
  44. data/lib/vagrant-libvirt/action/share_folders.rb +0 -71
  45. data/lib/vagrant-libvirt/action/start_domain.rb +0 -303
  46. data/lib/vagrant-libvirt/action/suspend_domain.rb +0 -40
  47. data/lib/vagrant-libvirt/action/wait_till_up.rb +0 -102
  48. data/lib/vagrant-libvirt/cap/mount_p9.rb +0 -42
  49. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +0 -17
  50. data/lib/vagrant-libvirt/cap/synced_folder.rb +0 -113
  51. data/lib/vagrant-libvirt/config.rb +0 -698
  52. data/lib/vagrant-libvirt/driver.rb +0 -118
  53. data/lib/vagrant-libvirt/errors.rb +0 -149
  54. data/lib/vagrant-libvirt/plugin.rb +0 -92
  55. data/lib/vagrant-libvirt/provider.rb +0 -130
  56. data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +0 -13
  57. data/lib/vagrant-libvirt/templates/domain.xml.erb +0 -229
  58. data/lib/vagrant-libvirt/templates/private_network.xml.erb +0 -34
  59. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +0 -23
  60. data/lib/vagrant-libvirt/util.rb +0 -11
  61. data/lib/vagrant-libvirt/util/collection.rb +0 -19
  62. data/lib/vagrant-libvirt/util/erb_template.rb +0 -22
  63. data/lib/vagrant-libvirt/util/error_codes.rb +0 -100
  64. data/lib/vagrant-libvirt/util/network_util.rb +0 -138
  65. data/lib/vagrant-libvirt/util/timer.rb +0 -17
  66. data/lib/vagrant-libvirt/version.rb +0 -5
  67. data/locales/en.yml +0 -159
  68. data/spec/spec_helper.rb +0 -9
  69. data/spec/support/environment_helper.rb +0 -46
  70. data/spec/support/libvirt_context.rb +0 -30
  71. data/spec/support/sharedcontext.rb +0 -34
  72. data/spec/unit/action/destroy_domain_spec.rb +0 -97
  73. data/spec/unit/action/set_name_of_domain_spec.rb +0 -21
  74. data/spec/unit/action/wait_till_up_spec.rb +0 -127
  75. data/spec/unit/config_spec.rb +0 -106
  76. data/spec/unit/templates/domain_all_settings.xml +0 -133
  77. data/spec/unit/templates/domain_defaults.xml +0 -46
  78. data/spec/unit/templates/domain_spec.rb +0 -75
  79. data/tools/create_box.sh +0 -130
  80. data/tools/prepare_redhat_for_box.sh +0 -119
  81. data/vagrant-libvirt.gemspec +0 -28
@@ -1,40 +0,0 @@
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
@@ -1,102 +0,0 @@
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
- destroy_env = env.dup
93
- destroy_env.delete(:interrupted)
94
- destroy_env[:config_validate] = false
95
- destroy_env[:force_confirm_destroy] = true
96
- env[:action_runner].run(Action.action_destroy, destroy_env)
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,42 +0,0 @@
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
@@ -1,17 +0,0 @@
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
@@ -1,113 +0,0 @@
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
@@ -1,698 +0,0 @@
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
-
55
- # Default host prefix (alternative to use project folder name)
56
- attr_accessor :default_prefix
57
-
58
- # Domain specific settings used while creating new domain.
59
- attr_accessor :uuid
60
- attr_accessor :memory
61
- attr_accessor :channel
62
- attr_accessor :cpus
63
- attr_accessor :cpu_mode
64
- attr_accessor :cpu_model
65
- attr_accessor :cpu_fallback
66
- attr_accessor :cpu_features
67
- attr_accessor :features
68
- attr_accessor :numa_nodes
69
- attr_accessor :loader
70
- attr_accessor :boot_order
71
- attr_accessor :machine_type
72
- attr_accessor :machine_arch
73
- attr_accessor :machine_virtual_size
74
- attr_accessor :disk_bus
75
- attr_accessor :disk_device
76
- attr_accessor :nic_model_type
77
- attr_accessor :nested
78
- attr_accessor :volume_cache
79
- attr_accessor :kernel
80
- attr_accessor :cmd_line
81
- attr_accessor :initrd
82
- attr_accessor :dtb
83
- attr_accessor :emulator_path
84
- attr_accessor :graphics_type
85
- attr_accessor :graphics_autoport
86
- attr_accessor :graphics_port
87
- attr_accessor :graphics_passwd
88
- attr_accessor :graphics_ip
89
- attr_accessor :video_type
90
- attr_accessor :video_vram
91
- attr_accessor :keymap
92
- attr_accessor :kvm_hidden
93
- attr_accessor :sound_type
94
-
95
- # Sets the information for connecting to a host TPM device
96
- # Only supports socket-based TPMs
97
- attr_accessor :tpm_model
98
- attr_accessor :tpm_type
99
- attr_accessor :tpm_path
100
-
101
- # Sets the max number of NICs that can be created
102
- # Default set to 8. Don't change the default unless you know
103
- # what are doing
104
- attr_accessor :nic_adapter_count
105
-
106
- # Storage
107
- attr_accessor :disks
108
- attr_accessor :cdroms
109
-
110
- # Inputs
111
- attr_accessor :inputs
112
-
113
- # Channels
114
- attr_accessor :channels
115
-
116
- # PCI device passthrough
117
- attr_accessor :pcis
118
-
119
- # Random number device passthrough
120
- attr_accessor :rng
121
-
122
- # Watchdog device
123
- attr_accessor :watchdog_dev
124
-
125
- # USB device passthrough
126
- attr_accessor :usbs
127
-
128
- # Redirected devices
129
- attr_accessor :redirdevs
130
- attr_accessor :redirfilters
131
-
132
- # smartcard device
133
- attr_accessor :smartcard_dev
134
-
135
- # Suspend mode
136
- attr_accessor :suspend_mode
137
-
138
- # Autostart
139
- attr_accessor :autostart
140
-
141
- # Attach mgmt network
142
- attr_accessor :mgmt_attach
143
-
144
- # Additional qemuargs arguments
145
- attr_accessor :qemu_args
146
-
147
- def initialize
148
- @uri = UNSET_VALUE
149
- @driver = UNSET_VALUE
150
- @host = UNSET_VALUE
151
- @connect_via_ssh = UNSET_VALUE
152
- @username = UNSET_VALUE
153
- @password = UNSET_VALUE
154
- @id_ssh_key_file = UNSET_VALUE
155
- @storage_pool_name = UNSET_VALUE
156
- @random_hostname = UNSET_VALUE
157
- @management_network_name = UNSET_VALUE
158
- @management_network_address = UNSET_VALUE
159
- @management_network_mode = UNSET_VALUE
160
- @management_network_mac = UNSET_VALUE
161
- @management_network_guest_ipv6 = UNSET_VALUE
162
- @management_network_autostart = UNSET_VALUE
163
-
164
- # Domain specific settings.
165
- @uuid = UNSET_VALUE
166
- @memory = UNSET_VALUE
167
- @cpus = UNSET_VALUE
168
- @cpu_mode = UNSET_VALUE
169
- @cpu_model = UNSET_VALUE
170
- @cpu_fallback = UNSET_VALUE
171
- @cpu_features = UNSET_VALUE
172
- @features = UNSET_VALUE
173
- @numa_nodes = UNSET_VALUE
174
- @loader = UNSET_VALUE
175
- @machine_type = UNSET_VALUE
176
- @machine_arch = UNSET_VALUE
177
- @machine_virtual_size = UNSET_VALUE
178
- @disk_bus = UNSET_VALUE
179
- @disk_device = UNSET_VALUE
180
- @nic_model_type = UNSET_VALUE
181
- @nested = UNSET_VALUE
182
- @volume_cache = UNSET_VALUE
183
- @kernel = UNSET_VALUE
184
- @initrd = UNSET_VALUE
185
- @dtb = UNSET_VALUE
186
- @cmd_line = UNSET_VALUE
187
- @emulator_path = UNSET_VALUE
188
- @graphics_type = UNSET_VALUE
189
- @graphics_autoport = UNSET_VALUE
190
- @graphics_port = UNSET_VALUE
191
- @graphics_ip = UNSET_VALUE
192
- @graphics_passwd = UNSET_VALUE
193
- @video_type = UNSET_VALUE
194
- @video_vram = UNSET_VALUE
195
- @sound_type = UNSET_VALUE
196
- @keymap = UNSET_VALUE
197
- @kvm_hidden = UNSET_VALUE
198
-
199
- @tpm_model = UNSET_VALUE
200
- @tpm_type = UNSET_VALUE
201
- @tpm_path = UNSET_VALUE
202
-
203
- @nic_adapter_count = UNSET_VALUE
204
-
205
- # Boot order
206
- @boot_order = []
207
- # Storage
208
- @disks = []
209
- @cdroms = []
210
-
211
- # Inputs
212
- @inputs = UNSET_VALUE
213
-
214
- # Channels
215
- @channels = UNSET_VALUE
216
-
217
- # PCI device passthrough
218
- @pcis = UNSET_VALUE
219
-
220
- # Random number device passthrough
221
- @rng = UNSET_VALUE
222
-
223
- # Watchdog device
224
- @watchdog_dev = UNSET_VALUE
225
-
226
- # USB device passthrough
227
- @usbs = UNSET_VALUE
228
-
229
- # Redirected devices
230
- @redirdevs = UNSET_VALUE
231
- @redirfilters = UNSET_VALUE
232
-
233
- # smartcard device
234
- @smartcard_dev = UNSET_VALUE
235
-
236
- # Suspend mode
237
- @suspend_mode = UNSET_VALUE
238
-
239
- # Autostart
240
- @autostart = UNSET_VALUE
241
-
242
- # Attach mgmt network
243
- @mgmt_attach = UNSET_VALUE
244
-
245
- @qemu_args = []
246
- end
247
-
248
- def boot(device)
249
- @boot_order << device # append
250
- end
251
-
252
- def _get_device(disks)
253
- # skip existing devices and also the first one (vda)
254
- exist = disks.collect { |x| x[:device] } + [1.vdev.to_s]
255
- skip = 1 # we're 1 based, not 0 based...
256
- loop do
257
- dev = skip.vdev # get lettered device
258
- return dev unless exist.include?(dev)
259
- skip += 1
260
- end
261
- end
262
-
263
- def _get_cdrom_dev(cdroms)
264
- exist = Hash[cdroms.collect { |x| [x[:dev], true] }]
265
- # hda - hdc
266
- curr = 'a'.ord
267
- while curr <= 'd'.ord
268
- dev = 'hd' + curr.chr
269
- if exist[dev]
270
- curr += 1
271
- next
272
- else
273
- return dev
274
- end
275
- end
276
-
277
- # is it better to raise our own error, or let libvirt cause the exception?
278
- raise 'Only four cdroms may be attached at a time'
279
- end
280
-
281
- def _generate_numa
282
- raise 'NUMA nodes must be a factor of CPUs' if @cpus % @numa_nodes != 0
283
-
284
- if @memory % @numa_nodes != 0
285
- raise 'NUMA nodes must be a factor of memory'
286
- end
287
-
288
- numa = []
289
-
290
- (1..@numa_nodes).each do |node|
291
- numa_cpu_start = (@cpus / @numa_nodes) * (node - 1)
292
- numa_cpu_end = (@cpus / @numa_nodes) * node - 1
293
- numa_cpu = Array(numa_cpu_start..numa_cpu_end).join(',')
294
- numa_mem = @memory / @numa_nodes
295
-
296
- numa.push(id: node,
297
- cpu: numa_cpu,
298
- mem: numa_mem)
299
- end
300
-
301
- @numa_nodes = numa
302
- end
303
-
304
- def cpu_feature(options = {})
305
- if options[:name].nil? || options[:policy].nil?
306
- raise 'CPU Feature name AND policy must be specified'
307
- end
308
-
309
- @cpu_features = [] if @cpu_features == UNSET_VALUE
310
-
311
- @cpu_features.push(name: options[:name],
312
- policy: options[:policy])
313
- end
314
-
315
- def input(options = {})
316
- if options[:type].nil? || options[:bus].nil?
317
- raise 'Input type AND bus must be specified'
318
- end
319
-
320
- @inputs = [] if @inputs == UNSET_VALUE
321
-
322
- @inputs.push(type: options[:type],
323
- bus: options[:bus])
324
- end
325
-
326
- def channel(options = {})
327
- if options[:type].nil?
328
- raise 'Channel type must be specified.'
329
- elsif options[:type] == 'unix' && options[:target_type] == 'guestfwd'
330
- # Guest forwarding requires a target (ip address) and a port
331
- if options[:target_address].nil? || options[:target_port].nil? ||
332
- options[:source_path].nil?
333
- raise 'guestfwd requires target_address, target_port and source_path'
334
- end
335
- end
336
-
337
- @channels = [] if @channels == UNSET_VALUE
338
-
339
- @channels.push(type: options[:type],
340
- source_mode: options[:source_mode],
341
- source_path: options[:source_path],
342
- target_address: options[:target_address],
343
- target_name: options[:target_name],
344
- target_port: options[:target_port],
345
- target_type: options[:target_type])
346
- end
347
-
348
- def random(options = {})
349
- if !options[:model].nil? && options[:model] != 'random'
350
- raise 'The only supported rng backend is "random".'
351
- end
352
-
353
- @rng = {} if @rng == UNSET_VALUE
354
-
355
- @rng[:model] = options[:model]
356
- end
357
-
358
- def pci(options = {})
359
- if options[:bus].nil? || options[:slot].nil? || options[:function].nil?
360
- raise 'Bus AND slot AND function must be specified. Check `lspci` for that numbers.'
361
- end
362
-
363
- @pcis = [] if @pcis == UNSET_VALUE
364
-
365
- @pcis.push(bus: options[:bus],
366
- slot: options[:slot],
367
- function: options[:function])
368
- end
369
-
370
- def watchdog(options = {})
371
- if options[:model].nil?
372
- raise 'Model must be specified.'
373
- end
374
-
375
- if @watchdog_dev == UNSET_VALUE
376
- @watchdog_dev = {}
377
- end
378
-
379
- @watchdog_dev[:model] = options[:model]
380
- @watchdog_dev[:action] = options[:action] || 'reset'
381
- end
382
-
383
-
384
- def usb(options = {})
385
- if (options[:bus].nil? || options[:device].nil?) && options[:vendor].nil? && options[:product].nil?
386
- raise 'Bus and device and/or vendor and/or product must be specified. Check `lsusb` for these.'
387
- end
388
-
389
- @usbs = [] if @usbs == UNSET_VALUE
390
-
391
- @usbs.push(bus: options[:bus],
392
- device: options[:device],
393
- vendor: options[:vendor],
394
- product: options[:product],
395
- startupPolicy: options[:startupPolicy])
396
- end
397
-
398
- def redirdev(options = {})
399
- raise 'Type must be specified.' if options[:type].nil?
400
-
401
- @redirdevs = [] if @redirdevs == UNSET_VALUE
402
-
403
- @redirdevs.push(type: options[:type])
404
- end
405
-
406
- def redirfilter(options = {})
407
- raise 'Option allow must be specified.' if options[:allow].nil?
408
-
409
- @redirfilters = [] if @redirfilters == UNSET_VALUE
410
-
411
- @redirfilters.push(class: options[:class] || -1,
412
- vendor: options[:class] || -1,
413
- product: options[:class] || -1,
414
- version: options[:class] || -1,
415
- allow: options[:allow])
416
- end
417
-
418
- def smartcard(options = {})
419
- if options[:mode].nil?
420
- raise 'Option mode must be specified.'
421
- elsif options[:mode] != 'passthrough'
422
- raise 'Currently only passthrough mode is supported!'
423
- elsif options[:type] == 'tcp' && (options[:source_mode].nil? || options[:source_host].nil? || options[:source_service].nil?)
424
- raise 'If using type "tcp", option "source_mode", "source_host" and "source_service" must be specified.'
425
- end
426
-
427
- if @smartcard_dev == UNSET_VALUE
428
- @smartcard_dev = {}
429
- end
430
-
431
- @smartcard_dev[:mode] = options[:mode]
432
- @smartcard_dev[:type] = options[:type] || 'spicevmc'
433
- @smartcard_dev[:source_mode] = options[:source_mode] if @smartcard_dev[:type] == 'tcp'
434
- @smartcard_dev[:source_host] = options[:source_host] if @smartcard_dev[:type] == 'tcp'
435
- @smartcard_dev[:source_service] = options[:source_service] if @smartcard_dev[:type] == 'tcp'
436
- end
437
-
438
- # NOTE: this will run twice for each time it's needed- keep it idempotent
439
- def storage(storage_type, options = {})
440
- if storage_type == :file
441
- if options[:device] == :cdrom
442
- _handle_cdrom_storage(options)
443
- else
444
- _handle_disk_storage(options)
445
- end
446
- end
447
- end
448
-
449
- def _handle_cdrom_storage(options = {})
450
- # <disk type="file" device="cdrom">
451
- # <source file="/home/user/virtio-win-0.1-100.iso"/>
452
- # <target dev="hdc"/>
453
- # <readonly/>
454
- # <address type='drive' controller='0' bus='1' target='0' unit='0'/>
455
- # </disk>
456
- #
457
- # note the target dev will need to be changed with each cdrom drive (hdc, hdd, etc),
458
- # as will the address unit number (unit=0, unit=1, etc)
459
-
460
- options = {
461
- bus: 'ide',
462
- path: nil
463
- }.merge(options)
464
-
465
- cdrom = {
466
- dev: options[:dev],
467
- bus: options[:bus],
468
- path: options[:path]
469
- }
470
-
471
- @cdroms << cdrom
472
- end
473
-
474
- def _handle_disk_storage(options = {})
475
- options = {
476
- type: 'qcow2',
477
- size: '10G', # matches the fog default
478
- path: nil,
479
- bus: 'virtio'
480
- }.merge(options)
481
-
482
- disk = {
483
- device: options[:device],
484
- type: options[:type],
485
- size: options[:size],
486
- path: options[:path],
487
- bus: options[:bus],
488
- cache: options[:cache] || 'default',
489
- allow_existing: options[:allow_existing],
490
- shareable: options[:shareable],
491
- serial: options[:serial]
492
- }
493
-
494
- @disks << disk # append
495
- end
496
-
497
- def qemuargs(options = {})
498
- @qemu_args << options if options[:value]
499
- end
500
-
501
- # code to generate URI from a config moved out of the connect action
502
- def _generate_uri
503
- # builds the libvirt connection URI from the given driver config
504
- # Setup connection uri.
505
- uri = @driver.dup
506
- virt_path = case uri
507
- when 'qemu', 'openvz', 'uml', 'phyp', 'parallels', 'kvm'
508
- '/system'
509
- when '@en', 'esx'
510
- '/'
511
- when 'vbox', 'vmwarews', 'hyperv'
512
- '/session'
513
- else
514
- raise "Require specify driver #{uri}"
515
- end
516
- if uri == 'kvm'
517
- uri = 'qemu' # use qemu uri for kvm domain type
518
- end
519
-
520
- if @connect_via_ssh
521
- uri << '+ssh://'
522
- uri << @username + '@' if @username
523
-
524
- uri << if @host
525
- @host
526
- else
527
- 'localhost'
528
- end
529
- else
530
- uri << '://'
531
- uri << @host if @host
532
- end
533
-
534
- uri << virt_path
535
- uri << '?no_verify=1'
536
-
537
- if @id_ssh_key_file
538
- # set ssh key for access to libvirt host
539
- uri << "\&keyfile="
540
- # if no slash, prepend $HOME/.ssh/
541
- @id_ssh_key_file.prepend("#{`echo ${HOME}`.chomp}/.ssh/") if @id_ssh_key_file !~ /\A\//
542
- uri << @id_ssh_key_file
543
- end
544
- # set path to libvirt socket
545
- uri << "\&socket=" + @socket if @socket
546
- uri
547
- end
548
-
549
- def finalize!
550
- @driver = 'kvm' if @driver == UNSET_VALUE
551
- @host = nil if @host == UNSET_VALUE
552
- @connect_via_ssh = false if @connect_via_ssh == UNSET_VALUE
553
- @username = nil if @username == UNSET_VALUE
554
- @password = nil if @password == UNSET_VALUE
555
- @id_ssh_key_file = 'id_rsa' if @id_ssh_key_file == UNSET_VALUE
556
- @storage_pool_name = 'default' if @storage_pool_name == UNSET_VALUE
557
- @random_hostname = false if @random_hostname == UNSET_VALUE
558
- @management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
559
- @management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
560
- @management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
561
- @management_network_mac = nil if @management_network_mac == UNSET_VALUE
562
- @management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
563
- @management_network_autostart = false if @management_network_autostart == UNSET_VALUE
564
-
565
- # generate a URI if none is supplied
566
- @uri = _generate_uri if @uri == UNSET_VALUE
567
-
568
- # Domain specific settings.
569
- @uuid = '' if @uuid == UNSET_VALUE
570
- @memory = 512 if @memory == UNSET_VALUE
571
- @cpus = 1 if @cpus == UNSET_VALUE
572
- @cpu_mode = 'host-model' if @cpu_mode == UNSET_VALUE
573
- @cpu_model = if (@cpu_model == UNSET_VALUE) && (@cpu_mode == 'custom')
574
- 'qemu64'
575
- elsif @cpu_mode != 'custom'
576
- ''
577
- end
578
- @cpu_fallback = 'allow' if @cpu_fallback == UNSET_VALUE
579
- @cpu_features = [] if @cpu_features == UNSET_VALUE
580
- @features = ['acpi','apic','pae'] if @features == UNSET_VALUE
581
- @numa_nodes = @numa_nodes == UNSET_VALUE ? nil : _generate_numa
582
- @loader = nil if @loader == UNSET_VALUE
583
- @machine_type = nil if @machine_type == UNSET_VALUE
584
- @machine_arch = nil if @machine_arch == UNSET_VALUE
585
- @machine_virtual_size = nil if @machine_virtual_size == UNSET_VALUE
586
- @disk_bus = 'virtio' if @disk_bus == UNSET_VALUE
587
- @disk_device = 'vda' if @disk_device == UNSET_VALUE
588
- @nic_model_type = nil if @nic_model_type == UNSET_VALUE
589
- @nested = false if @nested == UNSET_VALUE
590
- @volume_cache = 'default' if @volume_cache == UNSET_VALUE
591
- @kernel = nil if @kernel == UNSET_VALUE
592
- @cmd_line = '' if @cmd_line == UNSET_VALUE
593
- @initrd = '' if @initrd == UNSET_VALUE
594
- @dtb = nil if @dtb == UNSET_VALUE
595
- @graphics_type = 'vnc' if @graphics_type == UNSET_VALUE
596
- @graphics_autoport = 'yes' if @graphics_port == UNSET_VALUE
597
- @graphics_autoport = 'no' if @graphics_port != UNSET_VALUE
598
- if (@graphics_type != 'vnc' && @graphics_type != 'spice') ||
599
- @graphics_passwd == UNSET_VALUE
600
- @graphics_passwd = nil
601
- end
602
- @graphics_port = 5900 if @graphics_port == UNSET_VALUE
603
- @graphics_ip = '127.0.0.1' if @graphics_ip == UNSET_VALUE
604
- @video_type = 'cirrus' if @video_type == UNSET_VALUE
605
- @video_vram = 9216 if @video_vram == UNSET_VALUE
606
- @sound_type = nil if @sound_type == UNSET_VALUE
607
- @keymap = 'en-us' if @keymap == UNSET_VALUE
608
- @kvm_hidden = false if @kvm_hidden == UNSET_VALUE
609
- @tpm_model = 'tpm-tis' if @tpm_model == UNSET_VALUE
610
- @tpm_type = 'passthrough' if @tpm_type == UNSET_VALUE
611
- @tpm_path = nil if @tpm_path == UNSET_VALUE
612
- @nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
613
- @emulator_path = nil if @emulator_path == UNSET_VALUE
614
-
615
- # Boot order
616
- @boot_order = [] if @boot_order == UNSET_VALUE
617
-
618
- # Storage
619
- @disks = [] if @disks == UNSET_VALUE
620
- @disks.map! do |disk|
621
- disk[:device] = _get_device(@disks) if disk[:device].nil?
622
- disk
623
- end
624
- @cdroms = [] if @cdroms == UNSET_VALUE
625
- @cdroms.map! do |cdrom|
626
- cdrom[:dev] = _get_cdrom_dev(@cdroms) if cdrom[:dev].nil?
627
- cdrom
628
- end
629
-
630
- # Inputs
631
- @inputs = [{ type: 'mouse', bus: 'ps2' }] if @inputs == UNSET_VALUE
632
-
633
- # Channels
634
- @channels = [] if @channels == UNSET_VALUE
635
-
636
- # PCI device passthrough
637
- @pcis = [] if @pcis == UNSET_VALUE
638
-
639
- # Random number generator passthrough
640
- @rng = {} if @rng == UNSET_VALUE
641
-
642
- # Watchdog device
643
- @watchdog_dev = {} if @watchdog_dev == UNSET_VALUE
644
-
645
- # USB device passthrough
646
- @usbs = [] if @usbs == UNSET_VALUE
647
-
648
- # Redirected devices
649
- @redirdevs = [] if @redirdevs == UNSET_VALUE
650
- @redirfilters = [] if @redirfilters == UNSET_VALUE
651
-
652
- # smartcard device
653
- @smartcard_dev = {} if @smartcard_dev == UNSET_VALUE
654
-
655
- # Suspend mode
656
- @suspend_mode = 'pause' if @suspend_mode == UNSET_VALUE
657
-
658
- # Autostart
659
- @autostart = false if @autostart == UNSET_VALUE
660
-
661
- # Attach mgmt network
662
- @mgmt_attach = true if @mgmt_attach == UNSET_VALUE
663
-
664
- @qemu_args = [] if @qemu_args == UNSET_VALUE
665
- end
666
-
667
- def validate(machine)
668
- errors = _detected_errors
669
-
670
- machine.provider_config.disks.each do |disk|
671
- if disk[:path] && (disk[:path][0] == '/')
672
- errors << "absolute volume paths like '#{disk[:path]}' not yet supported"
673
- end
674
- end
675
-
676
- machine.config.vm.networks.each do |_type, opts|
677
- if opts[:mac] && opts[:mac].downcase! && !(opts[:mac] =~ /\A([0-9a-f]{2}:){5}([0-9a-f]{2})\z/)
678
- errors << "Configured NIC MAC '#{opts[:mac]}' is not in 'xx:xx:xx:xx:xx:xx' format"
679
- end
680
- end
681
-
682
- { 'Libvirt Provider' => errors }
683
- end
684
-
685
- def merge(other)
686
- super.tap do |result|
687
- c = disks.dup
688
- c += other.disks
689
- result.disks = c
690
-
691
- c = cdroms.dup
692
- c += other.cdroms
693
- result.cdroms = c
694
- end
695
- end
696
- end
697
- end
698
- end