vagrant-libvirt 0.1.2 → 0.5.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +530 -100
  3. data/lib/vagrant-libvirt/action.rb +7 -1
  4. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +28 -0
  5. data/lib/vagrant-libvirt/action/create_domain.rb +78 -22
  6. data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -57
  7. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -3
  8. data/lib/vagrant-libvirt/action/create_networks.rb +11 -4
  9. data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
  10. data/lib/vagrant-libvirt/action/forward_ports.rb +40 -40
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -72
  13. data/lib/vagrant-libvirt/action/is_running.rb +1 -3
  14. data/lib/vagrant-libvirt/action/is_suspended.rb +4 -4
  15. data/lib/vagrant-libvirt/action/package_domain.rb +10 -4
  16. data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
  17. data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
  18. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  19. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
  20. data/lib/vagrant-libvirt/cap/public_address.rb +16 -0
  21. data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
  22. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
  23. data/lib/vagrant-libvirt/config.rb +257 -34
  24. data/lib/vagrant-libvirt/driver.rb +49 -32
  25. data/lib/vagrant-libvirt/errors.rb +24 -1
  26. data/lib/vagrant-libvirt/plugin.rb +19 -5
  27. data/lib/vagrant-libvirt/provider.rb +2 -9
  28. data/lib/vagrant-libvirt/templates/domain.xml.erb +40 -10
  29. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  30. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +5 -1
  31. data/lib/vagrant-libvirt/util.rb +1 -0
  32. data/lib/vagrant-libvirt/util/erb_template.rb +6 -7
  33. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  34. data/lib/vagrant-libvirt/util/ui.rb +23 -0
  35. data/lib/vagrant-libvirt/version +1 -0
  36. data/lib/vagrant-libvirt/version.rb +72 -1
  37. data/locales/en.yml +12 -0
  38. data/spec/spec_helper.rb +37 -3
  39. data/spec/support/binding_proc.rb +24 -0
  40. data/spec/support/libvirt_context.rb +3 -1
  41. data/spec/support/matchers/have_file_content.rb +63 -0
  42. data/spec/support/sharedcontext.rb +7 -3
  43. data/spec/unit/action/clean_machine_folder_spec.rb +48 -0
  44. data/spec/unit/action/create_domain_spec.rb +166 -0
  45. data/spec/unit/action/create_domain_spec/default_system_storage_pool.xml +17 -0
  46. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  47. data/spec/unit/action/create_domain_volume_spec.rb +102 -0
  48. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  49. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  50. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  51. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  52. data/spec/unit/action/destroy_domain_spec.rb +3 -3
  53. data/spec/unit/action/forward_ports_spec.rb +202 -0
  54. data/spec/unit/action/halt_domain_spec.rb +90 -0
  55. data/spec/unit/action/handle_box_image_spec.rb +363 -0
  56. data/spec/unit/action/set_name_of_domain_spec.rb +2 -2
  57. data/spec/unit/action/start_domain_spec.rb +231 -0
  58. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  59. data/spec/unit/action/start_domain_spec/default.xml +48 -0
  60. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  61. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  62. data/spec/unit/action/wait_till_up_spec.rb +22 -21
  63. data/spec/unit/config_spec.rb +438 -0
  64. data/spec/unit/provider_spec.rb +11 -0
  65. data/spec/unit/templates/domain_all_settings.xml +16 -3
  66. data/spec/unit/templates/domain_custom_cpu_model.xml +4 -1
  67. data/spec/unit/templates/domain_defaults.xml +4 -1
  68. data/spec/unit/templates/domain_spec.rb +102 -3
  69. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  70. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  71. metadata +108 -16
  72. data/lib/vagrant-libvirt/action/halt_confirm.rb +0 -20
@@ -70,7 +70,7 @@ module VagrantPlugins
70
70
 
71
71
  # remove root storage
72
72
  root_disk = domain.volumes.select do |x|
73
- x.name == libvirt_domain.name + '.img'
73
+ x.name == libvirt_domain.name + '.img' if x
74
74
  end.first
75
75
  root_disk.destroy if root_disk
76
76
  end
@@ -11,10 +11,8 @@ module VagrantPlugins
11
11
  end
12
12
 
13
13
  def call(env)
14
- @env = env
15
-
16
14
  # Get the ports we're forwarding
17
- env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config)
15
+ env[:forwarded_ports] = compile_forwarded_ports(env, env[:machine].config)
18
16
 
19
17
  # Warn if we're port forwarding to any privileged ports
20
18
  env[:forwarded_ports].each do |fp|
@@ -28,51 +26,52 @@ module VagrantPlugins
28
26
  # Continue, we need the VM to be booted in order to grab its IP
29
27
  @app.call env
30
28
 
31
- if @env[:forwarded_ports].any?
29
+ if env[:forwarded_ports].any?
32
30
  env[:ui].info I18n.t('vagrant.actions.vm.forward_ports.forwarding')
33
- forward_ports
31
+ forward_ports(env)
34
32
  end
35
33
  end
36
34
 
37
- def forward_ports
38
- @env[:forwarded_ports].each do |fp|
35
+ def forward_ports(env)
36
+ env[:forwarded_ports].each do |fp|
39
37
  message_attributes = {
40
38
  adapter: fp[:adapter] || 'eth0',
41
39
  guest_port: fp[:guest],
42
40
  host_port: fp[:host]
43
41
  }
44
42
 
45
- @env[:ui].info(I18n.t(
43
+ env[:ui].info(I18n.t(
46
44
  'vagrant.actions.vm.forward_ports.forwarding_entry',
47
- message_attributes
45
+ **message_attributes
48
46
  ))
49
47
 
50
- if fp[:protocol] == 'udp'
51
- @env[:ui].warn I18n.t('vagrant_libvirt.warnings.forwarding_udp')
52
- next
53
- end
54
-
55
48
  ssh_pid = redirect_port(
56
- @env[:machine],
49
+ env,
50
+ env[:machine],
57
51
  fp[:host_ip] || '*',
58
52
  fp[:host],
59
- fp[:guest_ip] || @env[:machine].provider.ssh_info[:host],
53
+ fp[:guest_ip] || env[:machine].provider.ssh_info[:host],
60
54
  fp[:guest],
61
55
  fp[:gateway_ports] || false
62
56
  )
63
- store_ssh_pid(fp[:host], ssh_pid)
57
+ store_ssh_pid(env[:machine], fp[:host], ssh_pid)
64
58
  end
65
59
  end
66
60
 
67
61
  private
68
62
 
69
- def compile_forwarded_ports(config)
63
+ def compile_forwarded_ports(env, config)
70
64
  mappings = {}
71
65
 
72
66
  config.vm.networks.each do |type, options|
73
67
  next if options[:disabled]
74
68
 
75
- next unless type == :forwarded_port && options[:id] != 'ssh'
69
+ if options[:protocol] == 'udp'
70
+ env[:ui].warn I18n.t('vagrant_libvirt.warnings.forwarding_udp')
71
+ next
72
+ end
73
+
74
+ next if type != :forwarded_port || ( options[:id] == 'ssh' && !env[:machine].provider_config.forward_ssh_port )
76
75
  if options.fetch(:host_ip, '').to_s.strip.empty?
77
76
  options.delete(:host_ip)
78
77
  end
@@ -82,7 +81,7 @@ module VagrantPlugins
82
81
  mappings.values
83
82
  end
84
83
 
85
- def redirect_port(machine, host_ip, host_port, guest_ip, guest_port,
84
+ def redirect_port(env, machine, host_ip, host_port, guest_ip, guest_port,
86
85
  gateway_ports)
87
86
  ssh_info = machine.ssh_info
88
87
  params = %W(
@@ -98,6 +97,7 @@ module VagrantPlugins
98
97
  Port=#{ssh_info[:port]}
99
98
  UserKnownHostsFile=/dev/null
100
99
  ExitOnForwardFailure=yes
100
+ ControlMaster=no
101
101
  StrictHostKeyChecking=no
102
102
  PasswordAuthentication=no
103
103
  ForwardX11=#{ssh_info[:forward_x11] ? 'yes' : 'no'}
@@ -106,14 +106,14 @@ module VagrantPlugins
106
106
  "IdentityFile='\"#{pk}\"'"
107
107
  end).map { |s| s.prepend('-o ') }.join(' ')
108
108
 
109
- options += " -o ProxyCommand=\"#{ssh_info[:proxy_command]}\"" if machine.provider_config.connect_via_ssh
109
+ options += " -o ProxyCommand=\"#{ssh_info[:proxy_command]}\"" if machine.provider_config.proxy_command
110
110
 
111
111
  # TODO: instead of this, try and lock and get the stdin from spawn...
112
- ssh_cmd = 'exec '
112
+ ssh_cmd = ''
113
113
  if host_port <= 1024
114
114
  @@lock.synchronize do
115
115
  # TODO: add i18n
116
- @env[:ui].info 'Requesting sudo for host port(s) <= 1024'
116
+ env[:ui].info 'Requesting sudo for host port(s) <= 1024'
117
117
  r = system('sudo -v')
118
118
  if r
119
119
  ssh_cmd << 'sudo ' # add sudo prefix
@@ -124,14 +124,15 @@ module VagrantPlugins
124
124
  ssh_cmd << "ssh -n #{options} #{params}"
125
125
 
126
126
  @logger.debug "Forwarding port with `#{ssh_cmd}`"
127
- log_file = ssh_forward_log_file(host_ip, host_port,
128
- guest_ip, guest_port)
127
+ log_file = ssh_forward_log_file(
128
+ env[:machine], host_ip, host_port, guest_ip, guest_port,
129
+ )
129
130
  @logger.info "Logging to #{log_file}"
130
- spawn(ssh_cmd, [:out, :err] => [log_file, 'w'])
131
+ spawn(ssh_cmd, [:out, :err] => [log_file, 'w'], :pgroup => true)
131
132
  end
132
133
 
133
- def ssh_forward_log_file(host_ip, host_port, guest_ip, guest_port)
134
- log_dir = @env[:machine].data_dir.join('logs')
134
+ def ssh_forward_log_file(machine, host_ip, host_port, guest_ip, guest_port)
135
+ log_dir = machine.data_dir.join('logs')
135
136
  log_dir.mkdir unless log_dir.directory?
136
137
  File.join(
137
138
  log_dir,
@@ -140,8 +141,8 @@ module VagrantPlugins
140
141
  )
141
142
  end
142
143
 
143
- def store_ssh_pid(host_port, ssh_pid)
144
- data_dir = @env[:machine].data_dir.join('pids')
144
+ def store_ssh_pid(machine, host_port, ssh_pid)
145
+ data_dir = machine.data_dir.join('pids')
145
146
  data_dir.mkdir unless data_dir.directory?
146
147
 
147
148
  data_dir.join("ssh_#{host_port}.pid").open('w') do |pid_file|
@@ -168,13 +169,12 @@ module VagrantPlugins
168
169
  end
169
170
 
170
171
  def call(env)
171
- @env = env
172
-
173
- if ssh_pids.any?
172
+ pids = ssh_pids(env[:machine])
173
+ if pids.any?
174
174
  env[:ui].info I18n.t(
175
175
  'vagrant.actions.vm.clear_forward_ports.deleting'
176
176
  )
177
- ssh_pids.each do |tag|
177
+ pids.each do |tag|
178
178
  next unless ssh_pid?(tag[:pid])
179
179
  @logger.debug "Killing pid #{tag[:pid]}"
180
180
  kill_cmd = ''
@@ -190,7 +190,7 @@ module VagrantPlugins
190
190
  end
191
191
 
192
192
  @logger.info 'Removing ssh pid files'
193
- remove_ssh_pids
193
+ remove_ssh_pids(env[:machine])
194
194
  else
195
195
  @logger.info 'No ssh pids found'
196
196
  end
@@ -200,9 +200,9 @@ module VagrantPlugins
200
200
 
201
201
  protected
202
202
 
203
- def ssh_pids
204
- glob = @env[:machine].data_dir.join('pids').to_s + '/ssh_*.pid'
205
- @ssh_pids = Dir[glob].map do |file|
203
+ def ssh_pids(machine)
204
+ glob = machine.data_dir.join('pids').to_s + '/ssh_*.pid'
205
+ ssh_pids = Dir[glob].map do |file|
206
206
  {
207
207
  pid: File.read(file).strip.chomp,
208
208
  port: File.basename(file)['ssh_'.length..-1 * ('.pid'.length + 1)].to_i
@@ -216,8 +216,8 @@ module VagrantPlugins
216
216
  `ps -o command= #{pid}`.strip.chomp =~ /ssh/
217
217
  end
218
218
 
219
- def remove_ssh_pids
220
- glob = @env[:machine].data_dir.join('pids').to_s + '/ssh_*.pid'
219
+ def remove_ssh_pids(machine)
220
+ glob = machine.data_dir.join('pids').to_s + '/ssh_*.pid'
221
221
  Dir[glob].each do |file|
222
222
  File.delete file
223
223
  end
@@ -13,24 +13,40 @@ module VagrantPlugins
13
13
  def call(env)
14
14
  env[:ui].info(I18n.t('vagrant_libvirt.halt_domain'))
15
15
 
16
+ timeout = env[:machine].config.vm.graceful_halt_timeout
16
17
  domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
17
18
  raise Errors::NoDomainError if domain.nil?
18
19
 
19
- begin
20
- env[:machine].guest.capability(:halt)
21
- rescue
22
- @logger.info('Trying Libvirt graceful shutdown.')
23
- domain.shutdown
20
+ if env[:force_halt]
21
+ domain.poweroff
22
+ return @app.call(env)
24
23
  end
25
24
 
26
-
27
25
  begin
28
- domain.wait_for(30) do
29
- !ready?
26
+ Timeout.timeout(timeout) do
27
+ begin
28
+ env[:machine].guest.capability(:halt)
29
+ rescue Timeout::Error
30
+ raise
31
+ rescue
32
+ @logger.info('Trying Libvirt graceful shutdown.')
33
+ # Read domain object again
34
+ dom = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
35
+ if dom.state.to_s == 'running'
36
+ dom.shutdown
37
+ end
38
+ end
39
+
40
+ domain.wait_for(timeout) do
41
+ !ready?
42
+ end
30
43
  end
31
- rescue Fog::Errors::TimeoutError
44
+ rescue Timeout::Error
32
45
  @logger.info('VM is still running. Calling force poweroff.')
33
46
  domain.poweroff
47
+ rescue
48
+ @logger.error('Failed to shutdown cleanly. Calling force poweroff.')
49
+ domain.poweroff
34
50
  end
35
51
 
36
52
  @app.call(env)
@@ -5,6 +5,7 @@ module VagrantPlugins
5
5
  module Action
6
6
  class HandleBoxImage
7
7
  include VagrantPlugins::ProviderLibvirt::Util::StorageUtil
8
+ include VagrantPlugins::ProviderLibvirt::Util::Ui
8
9
 
9
10
 
10
11
  @@lock = Mutex.new
@@ -15,33 +16,69 @@ module VagrantPlugins
15
16
  end
16
17
 
17
18
  def call(env)
18
- # Verify box metadata for mandatory values.
19
- #
20
- # Virtual size has to be set for allocating space in storage pool.
21
- box_virtual_size = env[:machine].box.metadata['virtual_size']
22
- raise Errors::NoBoxVirtualSizeSet if box_virtual_size.nil?
19
+ # Handle box formats converting between v1 => v2 and ensuring
20
+ # any obsolete settings are rejected.
23
21
 
24
- # Support qcow2 format only for now, but other formats with backing
25
- # store capability should be usable.
26
- box_format = env[:machine].box.metadata['format']
27
- if box_format.nil?
28
- raise Errors::NoBoxFormatSet
29
- elsif box_format != 'qcow2'
30
- raise Errors::WrongBoxFormatSet
22
+ disks = env[:machine].box.metadata.fetch('disks', [])
23
+ if disks.empty?
24
+ # Handle box v1 format
25
+
26
+ # Only qcow2 format is supported in v1, but other formats with backing
27
+ # store capability should be usable.
28
+ box_format = env[:machine].box.metadata['format']
29
+ HandleBoxImage.verify_box_format(box_format)
30
+
31
+ env[:box_volume_number] = 1
32
+ env[:box_volumes] = [{
33
+ :path => HandleBoxImage.get_box_image_path(env[:machine].box, 'box.img'),
34
+ :name => HandleBoxImage.get_volume_name(env[:machine].box, 'box'),
35
+ :virtual_size => HandleBoxImage.get_virtual_size(env),
36
+ :format => box_format,
37
+ }]
38
+ else
39
+ # Handle box v2 format
40
+ # {
41
+ # 'path': '<path-of-file-box>',
42
+ # 'name': '<name-to-use-in-storage>' # optional, will use index
43
+ # }
44
+ #
45
+ env[:box_volume_number] = disks.length()
46
+ target_volumes = Hash[]
47
+ env[:box_volumes] = Array.new(env[:box_volume_number]) { |i|
48
+ raise Errors::BoxFormatMissingAttribute, attribute: "disks[#{i}]['path']" if disks[i]['path'].nil?
49
+
50
+ image_path = HandleBoxImage.get_box_image_path(env[:machine].box, disks[i]['path'])
51
+ format, virtual_size = HandleBoxImage.get_box_disk_settings(image_path)
52
+ volume_name = HandleBoxImage.get_volume_name(
53
+ env[:machine].box,
54
+ disks[i].fetch('name', disks[i]['path'].sub(/#{File.extname(disks[i]['path'])}$/, '')),
55
+ )
56
+
57
+ # allowing name means needing to check that it doesn't cause a clash
58
+ existing = target_volumes[volume_name]
59
+ if !existing.nil?
60
+ raise Errors::BoxFormatDuplicateVolume, volume: volume_name, new_disk: "disks[#{i}]", orig_disk: "disks[#{existing}]"
61
+ end
62
+ target_volumes[volume_name] = i
63
+
64
+ {
65
+ :path => image_path,
66
+ :name => volume_name,
67
+ :virtual_size => virtual_size.to_i,
68
+ :format => HandleBoxImage.verify_box_format(format)
69
+ }
70
+ }
31
71
  end
32
72
 
33
73
  # Get config options
34
74
  config = env[:machine].provider_config
35
- box_image_file = env[:machine].box.directory.join('box.img').to_s
36
- env[:box_volume_name] = env[:machine].box.name.to_s.dup.gsub('/', '-VAGRANTSLASH-')
37
- env[:box_volume_name] << "_vagrant_box_image_#{
38
- begin
39
- env[:machine].box.version.to_s
40
- rescue
41
- ''
42
- end}.img"
75
+ box_image_files = []
76
+ env[:box_volumes].each do |d|
77
+ box_image_files.push(d[:path])
78
+ end
43
79
 
44
80
  # Override box_virtual_size
81
+ box_virtual_size = env[:box_volumes][0][:virtual_size]
45
82
  if config.machine_virtual_size
46
83
  if config.machine_virtual_size < box_virtual_size
47
84
  # Warn that a virtual size less than the box metadata size
@@ -56,75 +93,129 @@ module VagrantPlugins
56
93
  end
57
94
  end
58
95
  # save for use by later actions
59
- env[:box_virtual_size] = box_virtual_size
96
+ env[:box_volumes][0][:virtual_size] = box_virtual_size
60
97
 
61
98
  # while inside the synchronize block take care not to call the next
62
99
  # action in the chain, as must exit this block first to prevent
63
100
  # locking all subsequent actions as well.
64
101
  @@lock.synchronize do
65
- # Don't continue if image already exists in storage pool.
66
- box_volume = env[:machine].provider.driver.connection.volumes.all(
67
- name: env[:box_volume_name]
68
- ).first
69
- break if box_volume && box_volume.id
70
-
71
- # Box is not available as a storage pool volume. Create and upload
72
- # it as a copy of local box image.
73
- env[:ui].info(I18n.t('vagrant_libvirt.uploading_volume'))
74
-
75
- # Create new volume in storage pool
76
- unless File.exist?(box_image_file)
77
- raise Vagrant::Errors::BoxNotFound, name: env[:machine].box.name
102
+ env[:box_volumes].each_index do |i|
103
+ # Don't continue if image already exists in storage pool.
104
+ box_volume = env[:machine].provider.driver.connection.volumes.all(
105
+ name: env[:box_volumes][i][:name]
106
+ ).first
107
+ next if box_volume && box_volume.id
108
+
109
+ send_box_image(env, config, box_image_files[i], env[:box_volumes][i])
78
110
  end
79
- box_image_size = File.size(box_image_file) # B
80
- message = "Creating volume #{env[:box_volume_name]}"
81
- message << " in storage pool #{config.storage_pool_name}."
82
- @logger.info(message)
111
+ end
83
112
 
84
- @storage_volume_uid = storage_uid env
85
- @storage_volume_gid = storage_gid env
113
+ @app.call(env)
114
+ end
115
+
116
+ protected
86
117
 
118
+ def self.get_volume_name(box, name)
119
+ vol_name = box.name.to_s.dup.gsub('/', '-VAGRANTSLASH-')
120
+ vol_name << "_vagrant_box_image_#{
87
121
  begin
88
- fog_volume = env[:machine].provider.driver.connection.volumes.create(
89
- name: env[:box_volume_name],
90
- allocation: "#{box_image_size / 1024 / 1024}M",
91
- capacity: "#{box_virtual_size}G",
92
- format_type: box_format,
93
- owner: @storage_volume_uid,
94
- group: @storage_volume_gid,
95
- pool_name: config.storage_pool_name
96
- )
97
- rescue Fog::Errors::Error => e
98
- raise Errors::FogCreateVolumeError,
99
- error_message: e.message
122
+ box.version.to_s
123
+ rescue
124
+ ''
100
125
  end
126
+ }_#{name.dup.gsub('/', '-SLASH-')}.img"
127
+ end
101
128
 
102
- # Upload box image to storage pool
103
- ret = upload_image(box_image_file, config.storage_pool_name,
104
- env[:box_volume_name], env) do |progress|
105
- env[:ui].clear_line
106
- env[:ui].report_progress(progress, box_image_size, false)
107
- end
129
+ def self.get_virtual_size(env)
130
+ # Virtual size has to be set for allocating space in storage pool.
131
+ box_virtual_size = env[:machine].box.metadata['virtual_size']
132
+ raise Errors::NoBoxVirtualSizeSet if box_virtual_size.nil?
133
+ return box_virtual_size
134
+ end
108
135
 
109
- # Clear the line one last time since the progress meter doesn't
110
- # disappear immediately.
111
- env[:ui].clear_line
112
-
113
- # If upload failed or was interrupted, remove created volume from
114
- # storage pool.
115
- if env[:interrupted] || !ret
116
- begin
117
- fog_volume.destroy
118
- rescue
119
- nil
120
- end
136
+ def self.get_box_image_path(box, box_name)
137
+ return box.directory.join(box_name).to_s
138
+ end
139
+
140
+ def self.verify_box_format(box_format, disk_index=nil)
141
+ if box_format.nil?
142
+ raise Errors::NoBoxFormatSet
143
+ elsif box_format != 'qcow2'
144
+ if disk_index.nil?
145
+ raise Errors::WrongBoxFormatSet
146
+ else
147
+ raise Errors::WrongDiskFormatSet,
148
+ disk_index: disk_index
121
149
  end
122
150
  end
151
+ return box_format
152
+ end
123
153
 
124
- @app.call(env)
154
+ def self.get_box_disk_settings(image_path)
155
+ stdout, stderr, status = Open3.capture3('qemu-img', 'info', image_path)
156
+ if !status.success?
157
+ raise Errors::BadBoxImage, image: image_path, out: stdout, err: stderr
158
+ end
159
+
160
+ image_info_lines = stdout.split("\n")
161
+ format = image_info_lines.find { |l| l.start_with?('file format:') }.split(' ')[2]
162
+ virtual_size = image_info_lines.find { |l| l.start_with?('virtual size:') }.split(' ')[2]
163
+
164
+ return format, virtual_size
125
165
  end
126
166
 
127
- protected
167
+ def send_box_image(env, config, box_image_file, box_volume)
168
+ # Box is not available as a storage pool volume. Create and upload
169
+ # it as a copy of local box image.
170
+ env[:ui].info(I18n.t('vagrant_libvirt.uploading_volume'))
171
+
172
+ # Create new volume in storage pool
173
+ unless File.exist?(box_image_file)
174
+ raise Vagrant::Errors::BoxNotFound, name: env[:machine].box.name
175
+ end
176
+ box_image_size = File.size(box_image_file) # B
177
+ message = "Creating volume #{box_volume[:name]}"
178
+ message << " in storage pool #{config.storage_pool_name}."
179
+ @logger.info(message)
180
+
181
+ begin
182
+ fog_volume = env[:machine].provider.driver.connection.volumes.create(
183
+ name: box_volume[:name],
184
+ allocation: "#{box_image_size / 1024 / 1024}M",
185
+ capacity: "#{box_volume[:virtual_size]}G",
186
+ format_type: box_volume[:format],
187
+ owner: storage_uid(env),
188
+ group: storage_gid(env),
189
+ pool_name: config.storage_pool_name
190
+ )
191
+ rescue Fog::Errors::Error => e
192
+ raise Errors::FogCreateVolumeError,
193
+ error_message: e.message
194
+ end
195
+
196
+ # Upload box image to storage pool
197
+ ret = upload_image(box_image_file, config.storage_pool_name,
198
+ box_volume[:name], env) do |progress|
199
+ rewriting(env[:ui]) do |ui|
200
+ ui.clear_line
201
+ ui.report_progress(progress, box_image_size, false)
202
+ end
203
+ end
204
+
205
+ # Clear the line one last time since the progress meter doesn't
206
+ # disappear immediately.
207
+ rewriting(env[:ui]) {|ui| ui.clear_line}
208
+
209
+ # If upload failed or was interrupted, remove created volume from
210
+ # storage pool.
211
+ if env[:interrupted] || !ret
212
+ begin
213
+ fog_volume.destroy
214
+ rescue
215
+ nil
216
+ end
217
+ end
218
+ end
128
219
 
129
220
  # Fog Libvirt currently doesn't support uploading images to storage
130
221
  # pool volumes. Use ruby-libvirt client instead.