2021-06-30 13:27:03 +01:00
# frozen_string_literal: true
2020-11-15 23:28:43 +00:00
require 'spec_helper'
require 'support/sharedcontext'
require 'support/libvirt_context'
require 'vagrant-libvirt/errors'
require 'vagrant-libvirt/action/start_domain'
describe VagrantPlugins :: ProviderLibvirt :: Action :: StartDomain do
subject { described_class . new ( app , env ) }
include_context 'unit'
include_context 'libvirt'
let ( :servers ) { double ( 'servers' ) }
let ( :domain_xml ) { File . read ( File . join ( File . dirname ( __FILE__ ) , File . basename ( __FILE__ , '.rb' ) , test_file ) ) }
2020-12-05 15:24:42 +00:00
let ( :updated_domain_xml ) { File . read ( File . join ( File . dirname ( __FILE__ ) , File . basename ( __FILE__ , '.rb' ) , updated_test_file ) ) }
2020-11-15 23:28:43 +00:00
2022-05-06 20:30:55 +01:00
before do
allow ( driver ) . to receive ( :created? ) . and_return ( true )
end
2020-11-15 23:28:43 +00:00
describe '#call' do
2021-09-11 22:00:33 +01:00
let ( :test_file ) { 'default.xml' }
2020-11-15 23:28:43 +00:00
before do
allow ( connection ) . to receive ( :client ) . and_return ( libvirt_client )
allow ( libvirt_client ) . to receive ( :lookup_domain_by_uuid ) . and_return ( libvirt_domain )
allow ( connection ) . to receive ( :servers ) . and_return ( servers )
allow ( servers ) . to receive ( :get ) . and_return ( domain )
2020-12-16 20:19:24 +01:00
2021-09-11 19:29:45 +01:00
allow ( logger ) . to receive ( :debug )
2022-06-03 10:42:28 +01:00
allow ( logger ) . to receive ( :info )
2021-09-11 22:00:33 +01:00
allow ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml )
allow ( libvirt_domain ) . to receive ( :max_memory ) . and_return ( 512 * 1024 )
allow ( libvirt_domain ) . to receive ( :num_vcpus ) . and_return ( 1 )
2020-11-15 23:28:43 +00:00
end
2021-09-11 22:00:33 +01:00
it 'should execute without changing' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2022-06-03 10:42:28 +01:00
expect ( libvirt_client ) . to_not receive ( :define_domain_xml )
2021-09-11 22:00:33 +01:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
2020-11-15 23:28:43 +00:00
2021-09-11 22:00:33 +01:00
expect ( subject . call ( env ) ) . to be_nil
end
2020-11-15 23:28:43 +00:00
2022-08-28 12:10:46 +01:00
context 'when xml is formatted differently' do
let ( :test_file ) { 'default_with_different_formatting.xml' }
let ( :updated_domain_xml ) {
new_xml = domain_xml . dup
new_xml . gsub! ( / <cpu .*< \/ cpu> /m , '<cpu check="none" mode="host-passthrough"/>' )
new_xml
}
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . cpu_mode = " host-passthrough "
EOF
end
it 'should correctly detect the domain was updated' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2022-08-28 12:10:46 +01:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( connection ) . to receive ( :define_domain ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
2022-08-30 12:47:05 +01:00
end
context 'when xml not applied' do
let ( :test_file ) { 'default_with_different_formatting.xml' }
let ( :updated_domain_xml ) {
new_xml = domain_xml . dup
new_xml . gsub! ( / <cpu .*< \/ cpu> /m , '<cpu mode="host-passthrough"/>' )
new_xml
}
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . cpu_mode = " host-passthrough "
EOF
end
2022-08-28 12:10:46 +01:00
2022-08-30 12:47:05 +01:00
it 'should error and revert the update' do
2022-09-07 11:35:25 +01:00
expect ( ui ) . to receive ( :warn ) . with ( / \ + <cpu mode="host-passthrough" \/ >.*Typically this means there is a bug in the XML being sent, please log an issue /m )
2022-08-30 12:47:05 +01:00
expect ( connection ) . to receive ( :define_domain ) . and_return ( libvirt_domain )
2022-09-07 11:35:25 +01:00
#expect(connection).to receive(:define_domain).with(domain_xml) # undo
2022-08-30 12:47:05 +01:00
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2022-09-07 11:35:25 +01:00
#expect(domain).to_not receive(:start)
2022-08-30 12:47:05 +01:00
2022-09-07 11:35:25 +01:00
#expect { subject.call(env) }.to raise_error(VagrantPlugins::ProviderLibvirt::Errors::UpdateServerError)
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
2022-08-30 12:47:05 +01:00
end
2022-08-28 12:10:46 +01:00
end
2022-06-03 10:42:28 +01:00
context 'when any setting changed' do
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . cpus = 2
EOF
end
let ( :updated_domain_xml ) {
new_xml = domain_xml . dup
new_xml [ '<vcpu>1</vcpu>' ] = '<vcpu>2</vcpu>'
new_xml
}
2020-11-15 23:28:43 +00:00
2022-06-03 10:42:28 +01:00
it 'should update the domain' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-11-15 23:28:43 +00:00
expect ( libvirt_domain ) . to receive ( :autostart = )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2020-11-15 23:28:43 +00:00
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
2022-06-03 10:42:28 +01:00
context 'when there is an error during update' do
it 'should skip attempting to start' do
expect ( ui ) . to receive ( :error )
expect ( connection ) . to receive ( :define_domain ) . and_raise ( :: Libvirt :: Error )
expect { subject . call ( env ) } . to raise_error ( VagrantPlugins :: ProviderLibvirt :: Errors :: VagrantLibvirtError )
end
end
context 'when there is an interrupt' do
it 'should skip attempting to start' do
expect ( connection ) . to receive ( :define_domain ) . and_raise ( Interrupt )
expect { subject . call ( env ) } . to raise_error ( Interrupt )
end
end
2020-12-15 06:43:46 -06:00
end
2022-05-06 13:43:42 +02:00
context 'nvram' do
context 'when being added to existing' do
let ( :vagrantfile_providerconfig ) do
<<-EOF
2022-05-17 15:03:55 +01:00
libvirt . loader = " /path/to/loader/file "
2022-05-06 13:43:42 +02:00
libvirt . nvram = " /path/to/nvram/file "
EOF
end
let ( :test_file ) { 'existing.xml' }
let ( :updated_test_file ) { 'existing_added_nvram.xml' }
2022-06-03 10:42:28 +01:00
it 'should add the nvram element' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( updated_domain_xml ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2022-05-06 13:43:42 +02:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'when it was already in use' do
let ( :vagrantfile_providerconfig ) do
<<-EOF
2022-05-17 15:03:55 +01:00
libvirt . loader = " /path/to/loader/file "
2022-06-03 10:42:28 +01:00
libvirt . nvram = " /path/to/nvram/file1 "
2022-05-06 13:43:42 +02:00
EOF
end
let ( :test_file ) { 'nvram_domain.xml' }
let ( :updated_test_file ) { 'nvram_domain_other_setting.xml' }
2022-06-03 10:42:28 +01:00
it 'should keep the XML element' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( updated_domain_xml ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2022-05-06 13:43:42 +02:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
context 'when it is being disabled' do
let ( :vagrantfile_providerconfig ) { }
let ( :updated_test_file ) { 'nvram_domain_removed.xml' }
2022-06-03 10:42:28 +01:00
it 'should delete the XML element' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( updated_domain_xml ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2022-05-06 13:43:42 +02:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
end
end
2020-12-15 06:43:46 -06:00
context 'tpm' do
context 'passthrough tpm added' do
2020-12-05 15:24:42 +00:00
let ( :updated_test_file ) { 'default_added_tpm_path.xml' }
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . tpm_path = '/dev/tpm0'
libvirt . tpm_type = 'passthrough'
libvirt . tpm_model = 'tpm-tis'
EOF
end
it 'should modify the domain tpm_path' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-15 06:43:46 -06:00
expect ( logger ) . to receive ( :debug ) . with ( 'tpm config changed' )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( updated_domain_xml ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2020-12-15 06:43:46 -06:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'emulated tpm added' do
let ( :updated_test_file ) { 'default_added_tpm_version.xml' }
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . tpm_type = 'emulator'
libvirt . tpm_model = 'tpm-crb'
libvirt . tpm_version = '2.0'
EOF
end
it 'should modify the domain tpm_path' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-15 06:43:46 -06:00
expect ( logger ) . to receive ( :debug ) . with ( 'tpm config changed' )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( updated_domain_xml ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2020-12-15 06:43:46 -06:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'same passthrough tpm config' do
let ( :test_file ) { 'default_added_tpm_path.xml' }
let ( :updated_test_file ) { 'default_added_tpm_path.xml' }
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . tpm_path = '/dev/tpm0'
libvirt . tpm_type = 'passthrough'
libvirt . tpm_model = 'tpm-tis'
EOF
end
it 'should execute without changing' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-15 06:43:46 -06:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'same emulated tpm config' do
let ( :test_file ) { 'default_added_tpm_version.xml' }
let ( :updated_test_file ) { 'default_added_tpm_version.xml' }
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . tpm_type = 'emulator'
libvirt . tpm_model = 'tpm-crb'
libvirt . tpm_version = '2.0'
EOF
end
it 'should execute without changing' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-15 06:43:46 -06:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'change from passthrough to emulated' do
let ( :test_file ) { 'default_added_tpm_path.xml' }
let ( :updated_test_file ) { 'default_added_tpm_version.xml' }
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . tpm_type = 'emulator'
libvirt . tpm_model = 'tpm-crb'
libvirt . tpm_version = '2.0'
EOF
end
it 'should modify the domain' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-15 06:43:46 -06:00
expect ( logger ) . to receive ( :debug ) . with ( 'tpm config changed' )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( updated_domain_xml ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2020-12-05 15:24:42 +00:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
2020-11-15 23:28:43 +00:00
end
2020-12-16 20:19:24 +01:00
context 'clock_timers' do
let ( :test_file ) { 'clock_timer_rtc.xml' }
context 'timers unchanged' do
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . clock_timer ( :name = > " rtc " )
EOF
end
it 'should not modify the domain' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-16 20:19:24 +01:00
expect ( logger ) . to_not receive ( :debug ) . with ( 'clock timers config changed' )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to_not receive ( :define_domain )
2020-12-16 20:19:24 +01:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'timers added' do
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . clock_timer ( :name = > " rtc " )
libvirt . clock_timer ( :name = > " tsc " )
EOF
end
2022-06-03 10:42:28 +01:00
let ( :updated_test_file ) { 'clock_timer_rtc_tsc.xml' }
2020-12-16 20:19:24 +01:00
it 'should modify the domain' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-16 20:19:24 +01:00
expect ( logger ) . to receive ( :debug ) . with ( 'clock timers config changed' )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( match ( / <clock offset='utc'> \ s*<timer name='rtc' \/ > \ s*<timer name='tsc' \/ > \ s*< \/ clock> / ) ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2020-12-16 20:19:24 +01:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'timers removed' do
2022-06-03 10:42:28 +01:00
let ( :updated_test_file ) { 'clock_timer_removed.xml' }
2020-12-16 20:19:24 +01:00
it 'should modify the domain' do
2022-09-22 16:12:16 +01:00
expect ( ui ) . to_not receive ( :warn )
2020-12-16 20:19:24 +01:00
expect ( logger ) . to receive ( :debug ) . with ( 'clock timers config changed' )
2022-06-03 10:42:28 +01:00
expect ( connection ) . to receive ( :define_domain ) . with ( match ( / <clock offset='utc'> \ s*< \/ clock> / ) ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , updated_domain_xml )
2020-12-16 20:19:24 +01:00
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
end
2020-11-15 23:28:43 +00:00
end
end