vagrant-libvirt 0.0.40 → 0.0.41

Sign up to get free protection for your applications and to get access to all the features.
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