vagrant-libvirt 0.6.0 → 0.7.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.
@@ -9,6 +9,10 @@ module VagrantPlugins
9
9
  error_namespace('vagrant_libvirt.errors')
10
10
  end
11
11
 
12
+ class CallChainError < VagrantLibvirtError
13
+ error_key(:call_chain_error)
14
+ end
15
+
12
16
  # package not supported
13
17
  class PackageNotSupported < VagrantLibvirtError
14
18
  error_key(:package_not_supported)
@@ -177,6 +181,10 @@ module VagrantPlugins
177
181
  class DeleteSnapshotError < VagrantLibvirtError
178
182
  error_key(:delete_snapshot_error)
179
183
  end
184
+
185
+ class SerialCannotCreatePathError < VagrantLibvirtError
186
+ error_key(:serial_cannot_create_path_error)
187
+ end
180
188
  end
181
189
  end
182
190
  end
@@ -162,10 +162,19 @@
162
162
  </disk>
163
163
  <% end %>
164
164
 
165
- <serial type='pty'>
166
- <target port='0'/>
165
+ <% @serials.each_with_index do |serial, port| %>
166
+ <serial type='<%= serial[:type] %>'>
167
+ <% unless serial[:source].nil? %>
168
+ <source path='<%= serial[:source][:path] %>'/>
169
+ <% end %>
170
+ <target port='<%= port %>'/>
167
171
  </serial>
168
- <console type='pty'>
172
+ <% end %>
173
+ <% console_log = @serials.first %>
174
+ <console type='<%= console_log[:type] %>'>
175
+ <% unless console_log[:source].nil? %>
176
+ <source path='<%= console_log[:source][:path] %>'/>
177
+ <% end %>
169
178
  <target port='0'/>
170
179
  </console>
171
180
 
@@ -207,9 +216,13 @@
207
216
  <% end %>
208
217
  <% if @graphics_type != 'none' %>
209
218
  <%# Video device -%>
210
- <graphics type='<%= @graphics_type %>' port='<%= @graphics_port %>' autoport='<%= @graphics_autoport %>' listen='<%= @graphics_ip %>' keymap='<%= @keymap %>' <%= @graphics_passwd%> />
219
+ <graphics type='<%= @graphics_type %>' port='<%= @graphics_port %>' autoport='<%= @graphics_autoport %>' listen='<%= @graphics_ip %>' keymap='<%= @keymap %>' <%= @graphics_passwd %> <% if not @graphics_gl %>/><% else %>>
220
+ <gl enable='yes' />
221
+ </graphics><% end %>
211
222
  <video>
212
- <model type='<%= @video_type %>' vram='<%= @video_vram %>' heads='1'/>
223
+ <model type='<%= @video_type %>' vram='<%= @video_vram %>' heads='1'<% if not @video_accel3d %>/><% else %>>
224
+ <acceleration accel3d='yes'/>
225
+ </model><% end %>
213
226
  </video>
214
227
  <%#End Video -%>
215
228
  <% end %>
@@ -119,7 +119,8 @@ module VagrantPlugins
119
119
  IPAddr.new(options[:network_address]).get_mask :
120
120
  '255.255.255.0',
121
121
  dhcp_enabled: true,
122
- forward_mode: 'nat'
122
+ forward_mode: 'nat',
123
+ always_destroy: true
123
124
  }.merge(options)
124
125
 
125
126
  if options[:type].to_s == 'dhcp' && options[:ip].nil?
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'vagrant/action/builtin/mixin_synced_folders'
4
+
3
5
  module VagrantPlugins
4
6
  module ProviderLibvirt
5
7
  module Util
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.0
data/locales/en.yml CHANGED
@@ -15,6 +15,10 @@ en:
15
15
  manual_resize_required: |-
16
16
  Created volume larger than box defaults, will require manual resizing of
17
17
  filesystems to utilize.
18
+ box_version_missing: |-
19
+ No verison detected for %{name}, using timestamp to watch for modifications. Consider
20
+ generating a local metadata for the box with a version to allow better handling.
21
+ See https://www.vagrantup.com/docs/boxes/format#box-metadata for further details.
18
22
  uploading_volume: |-
19
23
  Uploading base box image as volume into Libvirt storage...
20
24
  creating_domain_volume: |-
@@ -60,8 +64,11 @@ en:
60
64
  the minimum box image size of '%{minimum}'.
61
65
  forwarding_udp: |-
62
66
  Forwarding UDP ports is not supported. Ignoring.
67
+ creating_domain_console_access_disabled: |-
68
+ Serial console is being redirected, access via virsh will be disabled.
63
69
 
64
70
  errors:
71
+ call_chain_error: Invalid action chain, must ensure that '%{require_action}' is called prior to calling '%{current_action}'
65
72
  package_not_supported: No support for package with Libvirt. Create box manually.
66
73
  fog_error: |-
67
74
  There was an error talking to Libvirt. The error message is shown
@@ -161,6 +168,8 @@ en:
161
168
  management_network_required: |-
162
169
  Management network can't be disabled when VM use box.
163
170
  Please fix your configuration and run vagrant again.
171
+ serial_cannot_create_path_error: |-
172
+ Error creating path for serial port output log: %{path}
164
173
 
165
174
  states:
166
175
  paused: |-
data/spec/spec_helper.rb CHANGED
@@ -42,4 +42,12 @@ RSpec.configure do |config|
42
42
  config.before(:suite) do
43
43
  ENV.delete('LIBVIRT_DEFAULT_URI')
44
44
  end
45
+
46
+ config.mock_with :rspec do |mocks|
47
+ # This option should be set when all dependencies are being loaded
48
+ # before a spec run, as is the case in a typical spec helper. It will
49
+ # cause any verifying double instantiation for a class that does not
50
+ # exist to raise, protecting against incorrectly spelt names.
51
+ mocks.verify_doubled_constant_names = true
52
+ end
45
53
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fog/libvirt'
4
+ require 'fog/libvirt/models/compute/server'
5
+ require 'libvirt'
4
6
 
5
7
  shared_context 'libvirt' do
6
8
  include_context 'unit'
@@ -8,7 +10,9 @@ shared_context 'libvirt' do
8
10
  let(:libvirt_context) { true }
9
11
  let(:id) { 'dummy-vagrant_dummy' }
10
12
  let(:connection) { double('connection') }
11
- let(:domain) { double('domain') }
13
+ let(:domain) { instance_double('::Fog::Libvirt::Compute::Server') }
14
+ let(:libvirt_client) { instance_double('::Libvirt::Connect') }
15
+ let(:libvirt_domain) { instance_double('::Libvirt::Domain') }
12
16
  let(:logger) { double('logger') }
13
17
 
14
18
  def connection_result(options = {})
@@ -22,11 +26,10 @@ shared_context 'libvirt' do
22
26
  stub_const('::Fog::Compute', connection)
23
27
 
24
28
  # drivers also call vm_exists? during init;
25
- allow(connection).to receive(:servers).with(kind_of(String))
29
+ allow(connection).to receive(:servers)
26
30
  .and_return(connection_result(result: nil))
27
31
 
28
- # return some information for domain when needed
29
- allow(domain).to receive(:mac).and_return('9C:D5:53:F1:5A:E7')
32
+ allow(connection).to receive(:client).and_return(libvirt_client)
30
33
 
31
34
  allow(machine).to receive(:id).and_return(id)
32
35
  allow(Log4r::Logger).to receive(:new).and_return(logger)
@@ -36,6 +36,6 @@ shared_context 'unit' do
36
36
 
37
37
  before (:each) do
38
38
  allow(machine).to receive(:guest).and_return(guest)
39
- allow(machine).to receive(:communicator).and_return(communicator)
39
+ allow(machine).to receive(:communicate).and_return(communicator)
40
40
  end
41
41
  end
@@ -98,6 +98,36 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
98
98
  )
99
99
  end
100
100
 
101
+ context 'when no box version set' do
102
+ let(:box_mtime) { Time.now }
103
+
104
+ before do
105
+ expect(env[:machine]).to receive_message_chain("box.version") { nil }
106
+ expect(File).to receive(:mtime).and_return(box_mtime)
107
+ end
108
+
109
+ it 'should use the box file timestamp' do
110
+ expect(ui).to receive(:warn).with(
111
+ "No verison detected for test, using timestamp to watch for modifications. Consider\n" +
112
+ "generating a local metadata for the box with a version to allow better handling.\n" +
113
+ 'See https://www.vagrantup.com/docs/boxes/format#box-metadata for further details.'
114
+ )
115
+
116
+ expect(subject.call(env)).to be_nil
117
+ expect(env[:box_volume_number]).to eq(1)
118
+ expect(env[:box_volumes]).to eq(
119
+ [
120
+ {
121
+ :path=>"/test/box.img",
122
+ :name=>"test_vagrant_box_image_0_#{box_mtime.to_i}_box.img",
123
+ :virtual_size=>byte_number_5G,
124
+ :format=>"qcow2"
125
+ }
126
+ ]
127
+ )
128
+ end
129
+ end
130
+
101
131
  context 'When config.machine_virtual_size is set and smaller than box_virtual_size' do
102
132
  before do
103
133
  allow(env[:machine]).to receive_message_chain("provider_config.machine_virtual_size").and_return(1)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'support/sharedcontext'
5
+
6
+ require 'vagrant-libvirt/action/prepare_nfs_settings'
7
+
8
+
9
+ describe VagrantPlugins::ProviderLibvirt::Action::PrepareNFSSettings do
10
+ subject { described_class.new(app, env) }
11
+
12
+ include_context 'unit'
13
+
14
+ describe '#call' do
15
+ before do
16
+ # avoid requiring nfsd installed to run tests
17
+ allow(machine.env.host).to receive(:capability?).with(:nfs_installed).and_return(true)
18
+ allow(machine.env.host).to receive(:capability).with(:nfs_installed).and_return(true)
19
+ end
20
+
21
+ context 'when enabled' do
22
+ let(:vagrantfile) do
23
+ <<-EOF
24
+ Vagrant.configure('2') do |config|
25
+ config.vm.box = "vagrant-libvirt/test"
26
+ config.vm.define :test
27
+ config.vm.synced_folder ".", "/vagrant", type: "nfs"
28
+ config.vm.provider :libvirt do |libvirt|
29
+ #{vagrantfile_providerconfig}
30
+ end
31
+ end
32
+ EOF
33
+ end
34
+ let(:socket) { double('socket') }
35
+
36
+ before do
37
+ allow(::TCPSocket).to receive(:new).and_return(socket)
38
+ allow(socket).to receive(:close)
39
+ end
40
+
41
+ it 'should retrieve the guest IP address' do
42
+ times_called = 0
43
+ expect(::TCPSocket).to receive(:new) do
44
+ # force reaching later code
45
+ times_called += 1
46
+ times_called < 2 ? raise("StandardError") : socket
47
+ end
48
+ expect(machine).to receive(:ssh_info).and_return({:host => '192.168.1.2'})
49
+ expect(communicator).to receive(:execute).and_yield(:stdout, "192.168.1.2\n192.168.2.2")
50
+
51
+ expect(subject.call(env)).to be_nil
52
+ end
53
+ end
54
+ end
55
+ end
@@ -3,6 +3,20 @@ require 'support/sharedcontext'
3
3
  require 'support/libvirt_context'
4
4
  require 'vagrant-libvirt/action/shutdown_domain'
5
5
 
6
+ describe VagrantPlugins::ProviderLibvirt::Action::StartShutdownTimer do
7
+ subject { described_class.new(app, env) }
8
+
9
+ include_context 'unit'
10
+
11
+ describe '#call' do
12
+ it 'should set shutdown_start_time' do
13
+ expect(env[:shutdown_start_time]).to eq(nil)
14
+ expect(subject.call(env)).to eq(nil)
15
+ expect(env[:shutdown_start_time]).to_not eq(nil)
16
+ end
17
+ end
18
+ end
19
+
6
20
  describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
7
21
  subject { described_class.new(app, env, target_state, current_state) }
8
22
 
@@ -26,6 +40,8 @@ describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
26
40
  allow(connection).to receive(:servers).and_return(servers)
27
41
  allow(servers).to receive(:get).and_return(domain)
28
42
  allow(ui).to receive(:info).with('Attempting direct shutdown of domain...')
43
+ allow(env).to receive(:[]).and_call_original
44
+ allow(env).to receive(:[]).with(:shutdown_start_time).and_return(Time.now)
29
45
  end
30
46
 
31
47
  context "when state is shutoff" do
@@ -34,7 +50,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
34
50
  end
35
51
 
36
52
  it "should not shutdown" do
37
- expect(domain).not_to receive(:shutoff)
53
+ expect(domain).not_to receive(:poweroff)
38
54
  subject.call(env)
39
55
  end
40
56
 
@@ -97,7 +113,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
97
113
  context "when timeout exceeded" do
98
114
  before do
99
115
  expect(machine).to receive_message_chain('config.vm.graceful_halt_timeout').and_return(1)
100
- expect(app).to receive(:call) { sleep 1.5 }
116
+ expect(Time).to receive(:now).and_return(env[:shutdown_start_time] + 2)
101
117
  expect(driver).to receive(:state).and_return(:running).exactly(1).times
102
118
  expect(domain).to_not receive(:wait_for)
103
119
  expect(domain).to_not receive(:shutdown)
@@ -112,7 +128,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
112
128
  context "when timeout not exceeded" do
113
129
  before do
114
130
  expect(machine).to receive_message_chain('config.vm.graceful_halt_timeout').and_return(2)
115
- expect(app).to receive(:call) { sleep 1 }
131
+ expect(Time).to receive(:now).and_return(env[:shutdown_start_time] + 1.5)
116
132
  expect(driver).to receive(:state).and_return(:running).exactly(3).times
117
133
  expect(domain).to receive(:wait_for) do |time|
118
134
  expect(time).to be < 1
@@ -127,5 +143,18 @@ describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
127
143
  end
128
144
  end
129
145
  end
146
+
147
+ context "when required action not run" do
148
+ before do
149
+ expect(env).to receive(:[]).with(:shutdown_start_time).and_call_original
150
+ end
151
+
152
+ it "should raise an exception" do
153
+ expect { subject.call(env) }.to raise_error(
154
+ VagrantPlugins::ProviderLibvirt::Errors::CallChainError,
155
+ /Invalid action chain, must ensure that '.*ShutdownTimer' is called prior to calling '.*ShutdownDomain'/
156
+ )
157
+ end
158
+ end
130
159
  end
131
160
  end
@@ -22,6 +22,8 @@ describe VagrantPlugins::ProviderLibvirt::Action::WaitTillUp do
22
22
  .and_return(driver)
23
23
  allow(driver).to receive(:get_domain).and_return(domain)
24
24
  allow(driver).to receive(:state).and_return(:running)
25
+ # return some information for domain when needed
26
+ allow(domain).to receive(:mac).and_return('9C:D5:53:F1:5A:E7')
25
27
  end
26
28
 
27
29
  context 'when machine does not exist' do
@@ -62,7 +64,6 @@ describe VagrantPlugins::ProviderLibvirt::Action::WaitTillUp do
62
64
  expect(app).to_not receive(:call)
63
65
  expect(ui).to receive(:info).with('Waiting for domain to get an IP address...')
64
66
  expect(ui).to_not receive(:info).with('Waiting for SSH to become available...')
65
- expect(env[:machine].communicate).to_not receive(:ready?)
66
67
  expect {subject.call(env) }.to raise_error(::Fog::Errors::TimeoutError)
67
68
  end
68
69
  end
@@ -93,4 +93,82 @@ describe VagrantPlugins::ProviderLibvirt::Action do
93
93
  end
94
94
  end
95
95
  end
96
+
97
+ describe '#action_ssh' do
98
+ context 'when not created' do
99
+ before do
100
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsCreated, false)
101
+ end
102
+
103
+ it 'should cause an error' do
104
+ expect{ machine.action(:ssh, ssh_opts: {})}.to raise_error(Vagrant::Errors::VMNotCreatedError)
105
+ end
106
+ end
107
+
108
+ context 'when created' do
109
+ before do
110
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsCreated, true)
111
+ end
112
+
113
+ context 'when not running' do
114
+ before do
115
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsRunning, false)
116
+ end
117
+
118
+ it 'should cause an error' do
119
+ expect{ machine.action(:ssh, ssh_opts: {})}.to raise_error(Vagrant::Errors::VMNotRunningError)
120
+ end
121
+ end
122
+
123
+ context 'when running' do
124
+ before do
125
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsRunning, true)
126
+ end
127
+
128
+ it 'should call SSHExec' do
129
+ expect_any_instance_of(Vagrant::Action::Builtin::SSHExec).to receive(:call).and_return(0)
130
+ expect(machine.action(:ssh, ssh_opts: {})).to match(hash_including({:action_name => :machine_action_ssh}))
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ describe '#action_ssh_run' do
137
+ context 'when not created' do
138
+ before do
139
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsCreated, false)
140
+ end
141
+
142
+ it 'should cause an error' do
143
+ expect{ machine.action(:ssh_run, ssh_opts: {})}.to raise_error(Vagrant::Errors::VMNotCreatedError)
144
+ end
145
+ end
146
+
147
+ context 'when created' do
148
+ before do
149
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsCreated, true)
150
+ end
151
+
152
+ context 'when not running' do
153
+ before do
154
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsRunning, false)
155
+ end
156
+
157
+ it 'should cause an error' do
158
+ expect{ machine.action(:ssh_run, ssh_opts: {})}.to raise_error(Vagrant::Errors::VMNotRunningError)
159
+ end
160
+ end
161
+
162
+ context 'when running' do
163
+ before do
164
+ allow_action_env_result(VagrantPlugins::ProviderLibvirt::Action::IsRunning, true)
165
+ end
166
+
167
+ it 'should call SSHRun' do
168
+ expect_any_instance_of(Vagrant::Action::Builtin::SSHRun).to receive(:call).and_return(0)
169
+ expect(machine.action(:ssh_run, ssh_opts: {})).to match(hash_including({:action_name => :machine_action_ssh_run}))
170
+ end
171
+ end
172
+ end
173
+ end
96
174
  end
@@ -338,6 +338,54 @@ describe VagrantPlugins::ProviderLibvirt::Config do
338
338
  end
339
339
  end
340
340
 
341
+ context '@system_uri' do
342
+ [
343
+ # system uri
344
+ [ # transport and hostname
345
+ {:uri => "qemu+ssh://localhost/session"},
346
+ {:uri => "qemu+ssh://localhost/session", :system_uri => "qemu+ssh://localhost/system"},
347
+ ],
348
+ [ # explicitly set
349
+ {:qemu_use_session => true, :system_uri => "custom://remote/system"},
350
+ {:uri => "qemu:///session", :system_uri => "custom://remote/system"},
351
+ ],
352
+ ].each do |inputs, outputs, options|
353
+ opts = {}
354
+ opts.merge!(options) if options
355
+
356
+ it "should handle inputs #{inputs} with env (#{opts[:env]})" do
357
+ # allow some of these to fail for now if marked as such
358
+ if !opts[:allow_failure].nil?
359
+ pending(opts[:allow_failure])
360
+ end
361
+
362
+ if !opts[:setup].nil?
363
+ opts[:setup].apply_binding(binding)
364
+ end
365
+
366
+ inputs.each do |k, v|
367
+ subject.instance_variable_set("@#{k}", v)
368
+ end
369
+
370
+ if !opts[:env].nil?
371
+ opts[:env].each do |k, v|
372
+ fake_env[k] = v
373
+ end
374
+ end
375
+
376
+ subject.finalize!
377
+
378
+ # ensure failed output indicates which settings are incorrect in the failed test
379
+ got = subject.instance_variables.each_with_object({}) do |name, hash|
380
+ if outputs.key?(name.to_s[1..-1].to_sym)
381
+ hash["#{name.to_s[1..-1]}".to_sym] =subject.instance_variable_get(name)
382
+ end
383
+ end
384
+ expect(got).to eq(outputs)
385
+ end
386
+ end
387
+ end
388
+
341
389
  context '@proxy_command' do
342
390
  before(:example) do
343
391
  stub_const("ENV", fake_env)