2021-06-30 13:27:03 +01:00
# frozen_string_literal: true
2020-11-15 23:28:43 +00:00
require 'spec_helper'
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 )
2022-10-01 14:59:36 +01:00
allow ( ui ) . 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 = )
2022-09-22 17:14:49 +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 )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
context 'when xml elements and attributes reordered' do
let ( :test_file ) { 'existing.xml' }
let ( :updated_test_file ) { 'existing_reordered.xml' }
let ( :vagrantfile_providerconfig ) do
<<-EOF
libvirt . cpu_mode = " host-passthrough "
EOF
end
it 'should correctly detect the domain was updated' do
expect ( ui ) . to_not receive ( :warn )
expect ( libvirt_domain ) . to receive ( :autostart = )
2022-08-28 12:10:46 +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 )
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-10-30 14:29:21 +00:00
context 'cpu' do
let ( :test_file ) { 'existing.xml' }
let ( :updated_domain_xml ) {
new_xml = domain_xml . dup
new_xml . gsub! (
/ <cpu .* \/ > / ,
<<-EOF
< cpu check = 'partial' mode = 'custom' >
< model fallback = 'allow' > Haswell < / model>
< feature name = 'vmx' policy = 'optional' / >
< feature name = 'svm' policy = 'optional' / >
< / cpu>
EOF
)
new_xml
}
let ( :vagrantfile_providerconfig ) {
<<-EOF
libvirt . cpu_mode = 'custom'
libvirt . cpu_model = 'Haswell'
libvirt . nested = true
EOF
}
it 'should set cpu related settings when changed' do
expect ( ui ) . to_not receive ( :warn )
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 ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
let ( :domain_xml_no_cpu ) {
new_xml = domain_xml . dup
new_xml . gsub! ( / <cpu .* \/ > / , '' )
new_xml
}
let ( :updated_domain_xml_new_cpu ) {
new_xml = domain_xml . dup
new_xml . gsub! (
/ <cpu .* \/ > / ,
<<-EOF
< cpu mode = 'custom' >
< model fallback = 'allow' > Haswell < / model>
< feature name = 'vmx' policy = 'optional' / >
< feature name = 'svm' policy = 'optional' / >
< / cpu>
EOF
)
new_xml
}
it 'should add cpu settings if not already present' do
expect ( ui ) . to_not receive ( :warn )
expect ( connection ) . to receive ( :define_domain ) . and_return ( libvirt_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml_no_cpu , updated_domain_xml_new_cpu )
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( subject . call ( env ) ) . to be_nil
end
end
2022-10-01 14:59:36 +01:00
context 'graphics' do
context 'autoport not disabled' do
let ( :test_file ) { 'existing.xml' }
let ( :launched_domain_xml ) {
new_xml = domain_xml . dup
new_xml . gsub! ( / graphics type='vnc' port='-1' /m , " graphics type='vnc' port='5900' " )
new_xml
}
it 'should retrieve the port from XML' do
expect ( ui ) . to_not receive ( :warn )
expect ( connection ) . to_not receive ( :define_domain )
expect ( libvirt_domain ) . to receive ( :xml_desc ) . and_return ( domain_xml , launched_domain_xml )
expect ( libvirt_domain ) . to receive ( :autostart = )
expect ( domain ) . to receive ( :start )
expect ( ui ) . to receive ( :info ) . with ( ' -- Graphics Port: 5900' )
expect ( subject . call ( env ) ) . to be_nil
end
end
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