vagrant-libvirt 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +134 -23
  3. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +4 -0
  4. data/lib/vagrant-libvirt/action/create_domain.rb +11 -3
  5. data/lib/vagrant-libvirt/action/create_domain_volume.rb +7 -2
  6. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +8 -2
  7. data/lib/vagrant-libvirt/action/create_networks.rb +12 -8
  8. data/lib/vagrant-libvirt/action/destroy_domain.rb +2 -0
  9. data/lib/vagrant-libvirt/action/destroy_networks.rb +2 -0
  10. data/lib/vagrant-libvirt/action/forward_ports.rb +7 -5
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +4 -34
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +18 -13
  13. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +7 -1
  14. data/lib/vagrant-libvirt/action/is_created.rb +2 -0
  15. data/lib/vagrant-libvirt/action/is_running.rb +2 -0
  16. data/lib/vagrant-libvirt/action/is_suspended.rb +2 -0
  17. data/lib/vagrant-libvirt/action/message_already_created.rb +2 -0
  18. data/lib/vagrant-libvirt/action/message_not_created.rb +2 -0
  19. data/lib/vagrant-libvirt/action/message_not_running.rb +2 -0
  20. data/lib/vagrant-libvirt/action/message_not_suspended.rb +2 -0
  21. data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +2 -0
  22. data/lib/vagrant-libvirt/action/package_domain.rb +133 -68
  23. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +2 -0
  24. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +2 -0
  25. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +2 -0
  26. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +2 -0
  27. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +2 -0
  28. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +2 -0
  29. data/lib/vagrant-libvirt/action/resume_domain.rb +2 -0
  30. data/lib/vagrant-libvirt/action/set_boot_order.rb +8 -2
  31. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +3 -1
  32. data/lib/vagrant-libvirt/action/share_folders.rb +2 -0
  33. data/lib/vagrant-libvirt/action/shutdown_domain.rb +49 -0
  34. data/lib/vagrant-libvirt/action/start_domain.rb +26 -17
  35. data/lib/vagrant-libvirt/action/suspend_domain.rb +2 -0
  36. data/lib/vagrant-libvirt/action/wait_till_up.rb +2 -0
  37. data/lib/vagrant-libvirt/action.rb +34 -4
  38. data/lib/vagrant-libvirt/cap/mount_9p.rb +2 -0
  39. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +2 -0
  40. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +2 -0
  41. data/lib/vagrant-libvirt/cap/public_address.rb +2 -0
  42. data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +5 -2
  43. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +5 -2
  44. data/lib/vagrant-libvirt/config.rb +58 -24
  45. data/lib/vagrant-libvirt/driver.rb +67 -12
  46. data/lib/vagrant-libvirt/errors.rb +2 -0
  47. data/lib/vagrant-libvirt/plugin.rb +2 -0
  48. data/lib/vagrant-libvirt/provider.rb +2 -0
  49. data/lib/vagrant-libvirt/templates/domain.xml.erb +4 -2
  50. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +1 -0
  51. data/lib/vagrant-libvirt/util/byte_number.rb +71 -0
  52. data/lib/vagrant-libvirt/util/collection.rb +2 -0
  53. data/lib/vagrant-libvirt/util/erb_template.rb +2 -0
  54. data/lib/vagrant-libvirt/util/error_codes.rb +2 -0
  55. data/lib/vagrant-libvirt/util/network_util.rb +3 -0
  56. data/lib/vagrant-libvirt/util/nfs.rb +2 -0
  57. data/lib/vagrant-libvirt/util/storage_util.rb +1 -0
  58. data/lib/vagrant-libvirt/util/timer.rb +2 -0
  59. data/lib/vagrant-libvirt/util/ui.rb +1 -0
  60. data/lib/vagrant-libvirt/util.rb +2 -0
  61. data/lib/vagrant-libvirt/version +1 -1
  62. data/lib/vagrant-libvirt/version.rb +2 -0
  63. data/lib/vagrant-libvirt.rb +2 -0
  64. data/locales/en.yml +2 -0
  65. data/spec/spec_helper.rb +2 -0
  66. data/spec/support/binding_proc.rb +2 -0
  67. data/spec/support/environment_helper.rb +2 -0
  68. data/spec/support/libvirt_context.rb +2 -0
  69. data/spec/support/matchers/have_file_content.rb +2 -0
  70. data/spec/support/sharedcontext.rb +3 -0
  71. data/spec/support/temporary_dir.rb +12 -0
  72. data/spec/unit/action/clean_machine_folder_spec.rb +16 -4
  73. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +61 -0
  74. data/spec/unit/action/create_domain_spec/default_domain.xml +55 -0
  75. data/spec/unit/action/create_domain_spec.rb +68 -32
  76. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +1 -1
  77. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +1 -1
  78. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +1 -1
  79. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +1 -1
  80. data/spec/unit/action/create_domain_volume_spec.rb +10 -4
  81. data/spec/unit/action/destroy_domain_spec.rb +8 -2
  82. data/spec/unit/action/forward_ports_spec.rb +2 -0
  83. data/spec/unit/action/halt_domain_spec.rb +30 -57
  84. data/spec/unit/action/handle_box_image_spec.rb +104 -24
  85. data/spec/unit/action/package_domain_spec.rb +304 -0
  86. data/spec/unit/action/set_name_of_domain_spec.rb +2 -0
  87. data/spec/unit/action/shutdown_domain_spec.rb +131 -0
  88. data/spec/unit/action/start_domain_spec/existing.xml +62 -0
  89. data/spec/unit/action/start_domain_spec.rb +18 -28
  90. data/spec/unit/action/wait_till_up_spec.rb +2 -0
  91. data/spec/unit/action_spec.rb +96 -0
  92. data/spec/unit/config_spec.rb +56 -3
  93. data/spec/unit/driver_spec.rb +155 -0
  94. data/spec/unit/templates/domain_all_settings.xml +4 -0
  95. data/spec/unit/templates/domain_spec.rb +2 -0
  96. data/spec/unit/util/byte_number_spec.rb +28 -0
  97. metadata +59 -38
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
 
3
5
  module VagrantPlugins
@@ -42,8 +44,12 @@ module VagrantPlugins
42
44
  @storage_pool_path = storage_pool_path(env)
43
45
  @storage_pool_uid = storage_uid(env)
44
46
  @storage_pool_gid = storage_gid(env)
47
+ xml = to_xml('default_storage_pool')
48
+ @logger.debug {
49
+ "Creating Storage Pool with XML:\n#{xml}"
50
+ }
45
51
  libvirt_pool = env[:machine].provider.driver.connection.client.define_storage_pool_xml(
46
- to_xml('default_storage_pool')
52
+ xml
47
53
  )
48
54
  libvirt_pool.build
49
55
  libvirt_pool.create
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,6 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'log4r'
3
5
 
6
+ class String
7
+ def unindent
8
+ gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
9
+ end
10
+ end
11
+
4
12
  module VagrantPlugins
5
13
  module ProviderLibvirt
6
14
  module Action
@@ -12,8 +20,9 @@ module VagrantPlugins
12
20
  def initialize(app, env)
13
21
  @logger = Log4r::Logger.new('vagrant_libvirt::action::package_domain')
14
22
  @app = app
15
- env['package.files'] ||= {}
16
- env['package.output'] ||= 'package.box'
23
+
24
+ @options = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPTIONS', '')
25
+ @operations = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPERATIONS', 'defaults,-ssh-userdir,-ssh-hostkeys,-customize')
17
26
  end
18
27
 
19
28
  def call(env)
@@ -22,90 +31,100 @@ module VagrantPlugins
22
31
  env[:machine].id
23
32
  )
24
33
  domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
25
- root_disk = domain.volumes.select do |x|
34
+
35
+ volumes = domain.volumes.select { |x| !x.nil? }
36
+ root_disk = volumes.select do |x|
26
37
  x.name == libvirt_domain.name + '.img'
27
38
  end.first
28
39
  raise Errors::NoDomainVolume if root_disk.nil?
29
- boxname = env['package.output']
30
- raise "#{boxname}: Already exists" if File.exist?(boxname)
31
- @tmp_dir = Dir.pwd + '/_tmp_package'
32
- @tmp_img = @tmp_dir + '/box.img'
33
- FileUtils.mkdir_p(@tmp_dir)
34
- env[:ui].info("Downloading #{root_disk.name} to #{@tmp_img}")
35
- ret = download_image(@tmp_img, env[:machine].provider_config.storage_pool_name,
36
- root_disk.name, env) do |progress,image_size|
37
- rewriting(env[:ui]) do |ui|
38
- ui.clear_line
39
- ui.report_progress(progress, image_size, false)
40
- end
41
- end
42
- # Clear the line one last time since the progress meter doesn't
43
- # disappear immediately.
44
- rewriting(env[:ui]) {|ui| ui.clear_line}
45
- backing = `qemu-img info "#{@tmp_img}" | grep 'backing file:' | cut -d ':' -f2`.chomp
46
- if backing
47
- env[:ui].info('Image has backing image, copying image and rebasing ...')
48
- `qemu-img rebase -p -b "" #{@tmp_img}`
49
- end
50
- # remove hw association with interface
51
- # working for centos with lvs default disks
52
- options = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPTIONS', '')
53
- operations = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPERATIONS', 'defaults,-ssh-userdir,-customize')
54
- `virt-sysprep --no-logfile --operations #{operations} -a #{@tmp_img} #{options}`
55
- `virt-sparsify --in-place #{@tmp_img}`
56
- # add any user provided file
57
- extra = ''
58
- @tmp_include = @tmp_dir + '/_include'
59
- if env['package.include']
60
- extra = './_include'
61
- Dir.mkdir(@tmp_include)
62
- env['package.include'].each do |f|
63
- env[:ui].info("Including user file: #{f}")
64
- FileUtils.cp(f, @tmp_include)
40
+
41
+ package_func = method(:package_v1)
42
+
43
+ box_format = ENV.fetch('VAGRANT_LIBVIRT_BOX_FORMAT_VERSION', nil)
44
+
45
+ case box_format
46
+ when nil
47
+ if volumes.length() > 1
48
+ msg = "Detected more than one volume for machine, in the future this will switch to using the v2 "
49
+ msg += "box format v2 automatically."
50
+ msg += "\nIf you want to include the additional disks attached when packaging please set the "
51
+ msg += "env variable VAGRANT_LIBVIRT_BOX_FORMAT_VERSION=v2 to use the new format. If you want "
52
+ msg += "to ensure that your box uses the old format for single disk only, please set the "
53
+ msg += "environment variable explicitly to 'v1'"
54
+ env[:ui].warn(msg)
65
55
  end
56
+ when 'v2'
57
+ package_func = method(:package_v2)
58
+ when 'v1'
59
+ else
60
+ env[:ui].warn("Unrecognized value for 'VAGRANT_LIBVIRT_BOX_FORMAT_VERSION', defaulting to v1")
66
61
  end
67
- if env['package.vagrantfile']
68
- extra = './_include'
69
- Dir.mkdir(@tmp_include) unless File.directory?(@tmp_include)
70
- env[:ui].info('Including user Vagrantfile')
71
- FileUtils.cp(env['package.vagrantfile'], @tmp_include + '/Vagrantfile')
72
- end
73
- Dir.chdir(@tmp_dir)
74
- info = JSON.parse(`qemu-img info --output=json #{@tmp_img}`)
75
- img_size = (Float(info['virtual-size'])/(1024**3)).ceil
76
- File.write(@tmp_dir + '/metadata.json', metadata_content(img_size))
77
- File.write(@tmp_dir + '/Vagrantfile', vagrantfile_content)
78
- assemble_box(boxname, extra)
79
- FileUtils.mv(@tmp_dir + '/' + boxname, '../' + boxname)
80
- FileUtils.rm_rf(@tmp_dir)
81
- env[:ui].info('Box created')
82
- env[:ui].info('You can now add the box:')
83
- env[:ui].info("vagrant box add #{boxname} --name any_comfortable_name")
62
+
63
+ metadata = package_func.call(env, volumes)
64
+
65
+ # metadata / Vagrantfile
66
+ package_directory = env["package.directory"]
67
+ File.write(package_directory + '/metadata.json', metadata)
68
+ File.write(package_directory + '/Vagrantfile', vagrantfile_content(env))
69
+
84
70
  @app.call(env)
85
71
  end
86
72
 
87
- def assemble_box(boxname, extra)
88
- `tar cvzf "#{boxname}" --totals ./metadata.json ./Vagrantfile ./box.img #{extra}`
73
+ def package_v1(env, volumes)
74
+ domain_img = download_volume(env, volumes.first, 'box.img')
75
+
76
+ sysprep_domain(domain_img)
77
+ sparsify_volume(domain_img)
78
+
79
+ info = JSON.parse(`qemu-img info --output=json #{domain_img}`)
80
+ img_size = (Float(info['virtual-size'])/(1024**3)).ceil
81
+
82
+ return metadata_content_v1(img_size)
83
+ end
84
+
85
+ def package_v2(env, volumes)
86
+ disks = []
87
+ volumes.each_with_index do |vol, idx|
88
+ disk = {:path => "box_#{idx+1}.img"}
89
+ volume_img = download_volume(env, vol, disk[:path])
90
+
91
+ if idx == 0
92
+ sysprep_domain(volume_img)
93
+ end
94
+
95
+ sparsify_volume(volume_img)
96
+
97
+ disks.push(disk)
98
+ end
99
+
100
+ return metadata_content_v2(disks)
89
101
  end
90
102
 
91
- def vagrantfile_content
92
- <<-EOF
103
+ def vagrantfile_content(env)
104
+ include_vagrantfile = ""
105
+
106
+ if env["package.vagrantfile"]
107
+ include_vagrantfile = <<-EOF
108
+
109
+ # Load include vagrant file if it exists after the auto-generated
110
+ # so it can override any of the settings
111
+ include_vagrantfile = File.expand_path("../include/_Vagrantfile", __FILE__)
112
+ load include_vagrantfile if File.exist?(include_vagrantfile)
113
+ EOF
114
+ end
115
+
116
+ <<-EOF.unindent
93
117
  Vagrant.configure("2") do |config|
94
118
  config.vm.provider :libvirt do |libvirt|
95
119
  libvirt.driver = "kvm"
96
- libvirt.host = ""
97
- libvirt.connect_via_ssh = false
98
- libvirt.storage_pool_name = "default"
99
120
  end
121
+ #{include_vagrantfile}
100
122
  end
101
-
102
- user_vagrantfile = File.expand_path('../_include/Vagrantfile', __FILE__)
103
- load user_vagrantfile if File.exists?(user_vagrantfile)
104
123
  EOF
105
124
  end
106
125
 
107
- def metadata_content(filesize)
108
- <<-EOF
126
+ def metadata_content_v1(filesize)
127
+ <<-EOF.unindent
109
128
  {
110
129
  "provider": "libvirt",
111
130
  "format": "qcow2",
@@ -114,8 +133,54 @@ module VagrantPlugins
114
133
  EOF
115
134
  end
116
135
 
136
+ def metadata_content_v2(disks)
137
+ data = {
138
+ "provider": "libvirt",
139
+ "format": "qcow2",
140
+ "disks": disks.each do |disk|
141
+ {'path': disk[:path]}
142
+ end
143
+ }
144
+ JSON.pretty_generate(data)
145
+ end
146
+
117
147
  protected
118
148
 
149
+ def sparsify_volume(volume_img)
150
+ `virt-sparsify --in-place #{volume_img}`
151
+ end
152
+
153
+ def sysprep_domain(domain_img)
154
+ # remove hw association with interface
155
+ # working for centos with lvs default disks
156
+ `virt-sysprep --no-logfile --operations #{@operations} -a #{domain_img} #{@options}`
157
+ end
158
+
159
+ def download_volume(env, volume, disk_path)
160
+ package_directory = env["package.directory"]
161
+ volume_img = package_directory + '/' + disk_path
162
+ env[:ui].info("Downloading #{volume.name} to #{volume_img}")
163
+ download_image(volume_img, env[:machine].provider_config.storage_pool_name,
164
+ volume.name, env) do |progress,image_size|
165
+ rewriting(env[:ui]) do |ui|
166
+ ui.clear_line
167
+ ui.report_progress(progress, image_size, false)
168
+ end
169
+ end
170
+ # Clear the line one last time since the progress meter doesn't
171
+ # disappear immediately.
172
+ rewriting(env[:ui]) {|ui| ui.clear_line}
173
+
174
+ # Prep domain disk
175
+ backing = `qemu-img info "#{volume_img}" | grep 'backing file:' | cut -d ':' -f2`.chomp
176
+ if backing
177
+ env[:ui].info('Image has backing image, copying image and rebasing ...')
178
+ `qemu-img rebase -p -b "" #{volume_img}`
179
+ end
180
+
181
+ return volume_img
182
+ end
183
+
119
184
  # Fog libvirt currently doesn't support downloading images from storage
120
185
  # pool volumes. Use ruby-libvirt client instead.
121
186
  def download_image(image_file, pool_name, volume_name, env)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
  require 'socket'
3
5
  require 'timeout'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderLibvirt
3
5
  module Action
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'vagrant-libvirt/util/nfs'
2
4
  require 'yaml'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
 
3
5
  module VagrantPlugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
 
3
5
  module VagrantPlugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
  # require 'log4r/yamlconfigurator'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
 
3
5
  module VagrantPlugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
  require 'nokogiri'
3
5
 
@@ -86,9 +88,13 @@ module VagrantPlugins
86
88
 
87
89
  def search_network(nets, xml)
88
90
  str = '/domain/devices/interface'
89
- str += "[(@type='network' or @type='udp' or @type='bridge')"
91
+ str += "[(@type='network' or @type='udp' or @type='bridge' or @type='direct')"
90
92
  unless nets.empty?
91
- str += " and source[@network='#{nets.first['network']}']"
93
+ net = nets.first
94
+ network = net['network']
95
+ dev = net['dev']
96
+ str += " and source[@network='#{network}']" if network
97
+ str += " and source[@dev='#{dev}']" if dev
92
98
  end
93
99
  str += ']'
94
100
  @logger.debug(str)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'securerandom'
2
4
  module VagrantPlugins
3
5
  module ProviderLibvirt
@@ -46,7 +48,7 @@ module VagrantPlugins
46
48
  env[:root_path].basename.to_s.dup.concat('_')
47
49
  elsif config.default_prefix.empty?
48
50
  # don't have any prefix, not even "_"
49
- ''
51
+ String.new
50
52
  else
51
53
  config.default_prefix.to_s.dup
52
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
 
3
5
  require 'log4r'
@@ -0,0 +1,49 @@
1
+ require 'log4r'
2
+
3
+ module VagrantPlugins
4
+ module ProviderLibvirt
5
+ module Action
6
+ # Shutdown the domain.
7
+ class ShutdownDomain
8
+ def initialize(app, _env, target_state, source_state)
9
+ @logger = Log4r::Logger.new('vagrant_libvirt::action::shutdown_domain')
10
+ @target_state = target_state
11
+ @source_state = source_state
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ timeout = env[:machine].config.vm.graceful_halt_timeout
17
+
18
+ start_time = Time.now
19
+
20
+ # call nested action first under the assumption it should try to
21
+ # handle shutdown via client capabilities
22
+ @app.call(env)
23
+
24
+ # return if successful, otherwise will ensure result is set to false
25
+ env[:result] = env[:machine].state.id == @target_state
26
+
27
+ return if env[:result]
28
+
29
+ current_time = Time.now
30
+
31
+ # if we've already exceeded the timeout
32
+ return if current_time - start_time >= timeout
33
+
34
+ # otherwise construct a new timeout.
35
+ timeout = timeout - (current_time - start_time)
36
+
37
+ domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
38
+ if env[:machine].state.id == @source_state
39
+ env[:ui].info(I18n.t('vagrant_libvirt.shutdown_domain'))
40
+ domain.shutdown
41
+ domain.wait_for(timeout) { !ready? }
42
+ end
43
+
44
+ env[:result] = env[:machine].state.id == @target_state
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
  require 'rexml/document'
3
5
 
@@ -56,7 +58,7 @@ module VagrantPlugins
56
58
  # disk_bus
57
59
  REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="vda"]') do |disk_target|
58
60
  next unless disk_target.attributes['bus'] != config.disk_bus
59
- @logger.debug "domain disk bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
61
+ @logger.debug "domain disk bus updated from '#{disk_target.attributes['bus']}' to '#{config.disk_bus}'"
60
62
  descr_changed = true
61
63
  disk_target.attributes['bus'] = config.disk_bus
62
64
  disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
@@ -99,11 +101,13 @@ module VagrantPlugins
99
101
  if config.cpu_mode != 'host-passthrough'
100
102
  cpu_model = REXML::XPath.first(xml_descr, '/domain/cpu/model')
101
103
  if cpu_model.nil?
102
- @logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
103
- descr_changed = true
104
- cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
105
- cpu_model.attributes['fallback'] = 'allow'
106
- cpu_model.text = config.cpu_model
104
+ if config.cpu_model.strip != ''
105
+ @logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
106
+ descr_changed = true
107
+ cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
108
+ cpu_model.attributes['fallback'] = 'allow'
109
+ cpu_model.text = config.cpu_model
110
+ end
107
111
  else
108
112
  if (cpu_model.text or '').strip != config.cpu_model.strip
109
113
  @logger.debug "cpu_model text updated from #{cpu_model.text} to '#{config.cpu_model}'"
@@ -165,7 +169,7 @@ module VagrantPlugins
165
169
 
166
170
  # clock timers - because timers can be added/removed, just rebuild and then compare
167
171
  if !config.clock_timers.empty? || clock.has_elements?
168
- oldclock = ''
172
+ oldclock = String.new
169
173
  formatter.write(REXML::XPath.first(xml_descr, '/domain/clock'), oldclock)
170
174
  clock.delete_element('//timer')
171
175
  config.clock_timers.each do |clock_timer|
@@ -175,7 +179,7 @@ module VagrantPlugins
175
179
  end
176
180
  end
177
181
 
178
- newclock = ''
182
+ newclock = String.new
179
183
  formatter.write(clock, newclock)
180
184
  unless newclock.eql? oldclock
181
185
  @logger.debug "clock timers config changed"
@@ -320,10 +324,12 @@ module VagrantPlugins
320
324
  if config.initrd
321
325
  initrd = REXML::XPath.first(xml_descr, '/domain/os/initrd')
322
326
  if initrd.nil?
323
- @logger.debug "initrd updated from not set to '#{config.initrd}'"
324
- descr_changed = true
325
- initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os'))
326
- initrd.text = config.initrd
327
+ if config.initrd.strip != ''
328
+ @logger.debug "initrd updated from not set to '#{config.initrd}'"
329
+ descr_changed = true
330
+ initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os'))
331
+ initrd.text = config.initrd
332
+ end
327
333
  else
328
334
  if (initrd.text or '').strip != config.initrd
329
335
  @logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'"
@@ -337,22 +343,25 @@ module VagrantPlugins
337
343
  if descr_changed
338
344
  begin
339
345
  libvirt_domain.undefine
340
- new_descr = ''
346
+ new_descr = String.new
341
347
  xml_descr.write new_descr
342
- server = env[:machine].provider.driver.connection.servers.create(xml: new_descr)
348
+ env[:machine].provider.driver.connection.servers.create(xml: new_descr)
343
349
  rescue Fog::Errors::Error => e
344
- server = env[:machine].provider.driver.connection.servers.create(xml: descr)
350
+ env[:machine].provider.driver.connection.servers.create(xml: descr)
345
351
  raise Errors::FogCreateServerError, error_message: e.message
346
352
  end
347
353
  end
348
- rescue => e
354
+ rescue Errors::VagrantLibvirtError => e
349
355
  env[:ui].error("Error when updating domain settings: #{e.message}")
350
356
  end
351
357
  # Autostart with host if enabled in Vagrantfile
352
358
  libvirt_domain.autostart = config.autostart
359
+ @logger.debug {
360
+ "Starting Domain with XML:\n#{libvirt_domain.xml_desc}"
361
+ }
353
362
  # Actually start the domain
354
363
  domain.start
355
- rescue => e
364
+ rescue Fog::Errors::Error, Errors::VagrantLibvirtError => e
356
365
  raise Errors::FogError, message: e.message
357
366
  end
358
367
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
 
3
5
  module VagrantPlugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'log4r'
2
4
  require 'vagrant-libvirt/errors'
3
5
  require 'vagrant-libvirt/util/timer'
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'vagrant/action/builder'
2
4
  require 'log4r'
3
5
 
4
6
  module VagrantPlugins
5
7
  module ProviderLibvirt
6
8
  module Action
7
- # Include the built-in modules so we can use them as top-level things.
9
+ # Include the built-in & general modules so we can use them as top-level things.
8
10
  include Vagrant::Action::Builtin
11
+ include Vagrant::Action::General
9
12
  @logger = Log4r::Logger.new('vagrant_libvirt::action')
10
13
 
11
14
  # remove image from Libvirt storage pool
@@ -136,11 +139,23 @@ module VagrantPlugins
136
139
  b3.use ResumeDomain if env2[:result]
137
140
  end
138
141
 
142
+ # only perform shutdown if VM is running
139
143
  b2.use Call, IsRunning do |env2, b3|
140
144
  next unless env2[:result]
141
145
 
142
- # VM is running, halt it.
143
- b3.use HaltDomain
146
+ b3.use Call, Message, "Attempting nice shutdowns..." do |_, b4|
147
+ # ShutdownDomain will perform the domain shutdown on the out calls
148
+ # so it runs after the remaining actions in the same action builder.
149
+ b4.use ShutdownDomain, :shutoff, :running
150
+ b4.use GracefulHalt, :shutoff, :running
151
+ end
152
+
153
+ # Only force halt if previous actions insufficient.
154
+ b3.use Call, IsRunning do |env3, b4|
155
+ next unless env3[:result]
156
+
157
+ b4.use HaltDomain
158
+ end
144
159
  end
145
160
  end
146
161
  end
@@ -167,7 +182,18 @@ module VagrantPlugins
167
182
  def self.action_package
168
183
  Vagrant::Action::Builder.new.tap do |b|
169
184
  b.use ConfigValidate
170
- b.use PackageDomain
185
+ b.use Call, IsCreated do |env, b2|
186
+ unless env[:result]
187
+ b2.use MessageNotCreated
188
+ next
189
+ end
190
+
191
+ b2.use PackageSetupFolders
192
+ b2.use PackageSetupFiles
193
+ b2.use action_halt
194
+ b2.use Package
195
+ b2.use PackageDomain
196
+ end
171
197
  end
172
198
  end
173
199
 
@@ -334,6 +360,7 @@ module VagrantPlugins
334
360
  autoload :ForwardPorts, action_root.join('forward_ports')
335
361
  autoload :ClearForwardedPorts, action_root.join('forward_ports')
336
362
  autoload :HaltDomain, action_root.join('halt_domain')
363
+ autoload :ShutdownDomain, action_root.join('shutdown_domain')
337
364
  autoload :HandleBoxImage, action_root.join('handle_box_image')
338
365
  autoload :HandleStoragePool, action_root.join('handle_storage_pool')
339
366
  autoload :RemoveLibvirtImage, action_root.join('remove_libvirt_image')
@@ -366,6 +393,9 @@ module VagrantPlugins
366
393
  autoload :WaitTillUp, action_root.join('wait_till_up')
367
394
  autoload :PrepareNFSValidIds, action_root.join('prepare_nfs_valid_ids')
368
395
 
396
+ autoload :Package, 'vagrant/action/general/package'
397
+ autoload :PackageSetupFiles, 'vagrant/action/general/package_setup_files'
398
+ autoload :PackageSetupFolders, 'vagrant/action/general/package_setup_folders'
369
399
  autoload :SSHRun, 'vagrant/action/builtin/ssh_run'
370
400
  autoload :HandleBox, 'vagrant/action/builtin/handle_box'
371
401
  autoload :SyncedFolders, 'vagrant/action/builtin/synced_folders'