vagrant-libvirt 0.0.41 → 0.0.42

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/issue_template.md +37 -0
  4. data/.gitignore +21 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +26 -0
  7. data/LICENSE +22 -0
  8. data/README.md +1380 -0
  9. data/Rakefile +8 -0
  10. data/example_box/README.md +29 -0
  11. data/example_box/Vagrantfile +60 -0
  12. data/example_box/metadata.json +5 -0
  13. data/lib/vagrant-libvirt.rb +29 -0
  14. data/lib/vagrant-libvirt/action.rb +370 -0
  15. data/lib/vagrant-libvirt/action/create_domain.rb +322 -0
  16. data/lib/vagrant-libvirt/action/create_domain_volume.rb +87 -0
  17. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +302 -0
  18. data/lib/vagrant-libvirt/action/create_networks.rb +361 -0
  19. data/lib/vagrant-libvirt/action/destroy_domain.rb +83 -0
  20. data/lib/vagrant-libvirt/action/destroy_networks.rb +95 -0
  21. data/lib/vagrant-libvirt/action/forward_ports.rb +227 -0
  22. data/lib/vagrant-libvirt/action/halt_domain.rb +41 -0
  23. data/lib/vagrant-libvirt/action/handle_box_image.rb +156 -0
  24. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +57 -0
  25. data/lib/vagrant-libvirt/action/is_created.rb +18 -0
  26. data/lib/vagrant-libvirt/action/is_running.rb +21 -0
  27. data/lib/vagrant-libvirt/action/is_suspended.rb +42 -0
  28. data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
  29. data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
  30. data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
  31. data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
  32. data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +17 -0
  33. data/lib/vagrant-libvirt/action/package_domain.rb +105 -0
  34. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +94 -0
  35. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +17 -0
  36. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +27 -0
  37. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +40 -0
  38. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +20 -0
  39. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +50 -0
  40. data/lib/vagrant-libvirt/action/resume_domain.rb +34 -0
  41. data/lib/vagrant-libvirt/action/set_boot_order.rb +109 -0
  42. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +64 -0
  43. data/lib/vagrant-libvirt/action/share_folders.rb +71 -0
  44. data/lib/vagrant-libvirt/action/start_domain.rb +307 -0
  45. data/lib/vagrant-libvirt/action/suspend_domain.rb +40 -0
  46. data/lib/vagrant-libvirt/action/wait_till_up.rb +109 -0
  47. data/lib/vagrant-libvirt/cap/mount_p9.rb +42 -0
  48. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +17 -0
  49. data/lib/vagrant-libvirt/cap/synced_folder.rb +113 -0
  50. data/lib/vagrant-libvirt/config.rb +746 -0
  51. data/lib/vagrant-libvirt/driver.rb +118 -0
  52. data/lib/vagrant-libvirt/errors.rb +153 -0
  53. data/lib/vagrant-libvirt/plugin.rb +92 -0
  54. data/lib/vagrant-libvirt/provider.rb +130 -0
  55. data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
  56. data/lib/vagrant-libvirt/templates/domain.xml.erb +244 -0
  57. data/lib/vagrant-libvirt/templates/private_network.xml.erb +42 -0
  58. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +26 -0
  59. data/lib/vagrant-libvirt/util.rb +11 -0
  60. data/lib/vagrant-libvirt/util/collection.rb +19 -0
  61. data/lib/vagrant-libvirt/util/erb_template.rb +22 -0
  62. data/lib/vagrant-libvirt/util/error_codes.rb +100 -0
  63. data/lib/vagrant-libvirt/util/network_util.rb +151 -0
  64. data/lib/vagrant-libvirt/util/timer.rb +17 -0
  65. data/lib/vagrant-libvirt/version.rb +5 -0
  66. data/locales/en.yml +162 -0
  67. data/spec/spec_helper.rb +9 -0
  68. data/spec/support/environment_helper.rb +46 -0
  69. data/spec/support/libvirt_context.rb +30 -0
  70. data/spec/support/sharedcontext.rb +34 -0
  71. data/spec/unit/action/destroy_domain_spec.rb +97 -0
  72. data/spec/unit/action/set_name_of_domain_spec.rb +21 -0
  73. data/spec/unit/action/wait_till_up_spec.rb +127 -0
  74. data/spec/unit/config_spec.rb +113 -0
  75. data/spec/unit/templates/domain_all_settings.xml +137 -0
  76. data/spec/unit/templates/domain_defaults.xml +46 -0
  77. data/spec/unit/templates/domain_spec.rb +84 -0
  78. data/tools/create_box.sh +130 -0
  79. data/tools/prepare_redhat_for_box.sh +119 -0
  80. data/vagrant-libvirt.gemspec +54 -0
  81. metadata +93 -3
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+
5
+ require 'vagrant-libvirt/action/destroy_domain'
6
+
7
+ describe VagrantPlugins::ProviderLibvirt::Action::DestroyDomain do
8
+ subject { described_class.new(app, env) }
9
+
10
+ include_context 'unit'
11
+ include_context 'libvirt'
12
+
13
+ let(:libvirt_domain) { double('libvirt_domain') }
14
+ let(:libvirt_client) { double('libvirt_client') }
15
+ let(:servers) { double('servers') }
16
+
17
+ describe '#call' do
18
+ before do
19
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
20
+ .to receive(:connection).and_return(connection)
21
+ allow(connection).to receive(:client).and_return(libvirt_client)
22
+ allow(libvirt_client).to receive(:lookup_domain_by_uuid)
23
+ .and_return(libvirt_domain)
24
+ allow(connection).to receive(:servers).and_return(servers)
25
+ allow(servers).to receive(:get).and_return(domain)
26
+ # always see this at the start of #call
27
+ expect(ui).to receive(:info).with('Removing domain...')
28
+ end
29
+
30
+ context 'when no snapshots' do
31
+ let(:root_disk) { double('libvirt_root_disk') }
32
+
33
+ before do
34
+ allow(libvirt_domain).to receive(:list_snapshots).and_return([])
35
+ allow(libvirt_domain).to receive(:has_managed_save?).and_return(nil)
36
+ root_disk.stub(name: 'test.img')
37
+ end
38
+
39
+ context 'when only has root disk' do
40
+ it 'calls fog to destroy volumes' do
41
+ expect(domain).to receive(:destroy).with(destroy_volumes: true)
42
+ expect(subject.call(env)).to be_nil
43
+ end
44
+ end
45
+
46
+ context 'when has additional disks' do
47
+ let(:vagrantfile) do
48
+ <<-EOF
49
+ Vagrant.configure('2') do |config|
50
+ config.vm.define :test
51
+ config.vm.provider :libvirt do |libvirt|
52
+ libvirt.storage :file
53
+ end
54
+ end
55
+ EOF
56
+ end
57
+
58
+ let(:extra_disk) { double('libvirt_extra_disk') }
59
+ before do
60
+ extra_disk.stub(name: 'test-vdb.qcow2')
61
+ end
62
+
63
+ it 'destroys disks individually' do
64
+ allow(libvirt_domain).to receive(:name).and_return('test')
65
+ allow(domain).to receive(:volumes).and_return([extra_disk], [root_disk])
66
+
67
+ expect(domain).to receive(:destroy).with(destroy_volumes: false)
68
+ expect(extra_disk).to receive(:destroy) # extra disk remove
69
+ expect(root_disk).to receive(:destroy) # root disk remove
70
+ expect(subject.call(env)).to be_nil
71
+ end
72
+ end
73
+
74
+ context 'when has CDROMs attached' do
75
+ let(:vagrantfile) do
76
+ <<-EOF
77
+ Vagrant.configure('2') do |config|
78
+ config.vm.define :test
79
+ config.vm.provider :libvirt do |libvirt|
80
+ libvirt.storage :file, :device => :cdrom
81
+ end
82
+ end
83
+ EOF
84
+ end
85
+
86
+ it 'uses explicit removal of disks' do
87
+ allow(libvirt_domain).to receive(:name).and_return('test')
88
+ allow(domain).to receive(:volumes).and_return([root_disk])
89
+
90
+ expect(domain).to_not receive(:destroy).with(destroy_volumes: true)
91
+ expect(root_disk).to receive(:destroy) # root disk remove
92
+ expect(subject.call(env)).to be_nil
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe VagrantPlugins::ProviderLibvirt::Action::SetNameOfDomain do
4
+ before :each do
5
+ @env = EnvironmentHelper.new
6
+ end
7
+
8
+ it 'builds unique domain name' do
9
+ @env.random_hostname = true
10
+ dmn = VagrantPlugins::ProviderLibvirt::Action::SetNameOfDomain.new(Object.new, @env)
11
+ first = dmn.build_domain_name(@env)
12
+ second = dmn.build_domain_name(@env)
13
+ first.should_not eq(second)
14
+ end
15
+
16
+ it 'builds simple domain name' do
17
+ @env.default_prefix = 'pre'
18
+ dmn = VagrantPlugins::ProviderLibvirt::Action::SetNameOfDomain.new(Object.new, @env)
19
+ dmn.build_domain_name(@env).should eq('pre_')
20
+ end
21
+ end
@@ -0,0 +1,127 @@
1
+ require 'vagrant-libvirt/action/wait_till_up'
2
+ require 'vagrant-libvirt/errors'
3
+
4
+ require 'spec_helper'
5
+ require 'support/sharedcontext'
6
+ require 'support/libvirt_context'
7
+
8
+ describe VagrantPlugins::ProviderLibvirt::Action::WaitTillUp do
9
+ subject { described_class.new(app, env) }
10
+
11
+ include_context 'vagrant-unit'
12
+ include_context 'libvirt'
13
+ include_context 'unit'
14
+
15
+ describe '#call' do
16
+ before do
17
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
18
+ .to receive(:get_domain).and_return(domain)
19
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver).to receive(:state)
20
+ .and_return(:running)
21
+ end
22
+
23
+ context 'when machine does not exist' do
24
+ before do
25
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
26
+ .to receive(:get_domain).and_return(nil)
27
+ end
28
+
29
+ it 'raises exception' do
30
+ expect(app).to_not receive(:call)
31
+ expect { subject.call(env) }.to raise_error(::VagrantPlugins::ProviderLibvirt::Errors::NoDomainError,
32
+ /No domain found. Domain dummy-vagrant_dummy not found/)
33
+ end
34
+ end
35
+
36
+ context 'when machine is booting' do
37
+ context 'if interrupted looking for IP' do
38
+ before do
39
+ env[:interrupted] = true
40
+ end
41
+ it 'should exit' do
42
+ expect(app).to_not receive(:call)
43
+ expect(ui).to receive(:info).with('Waiting for domain to get an IP address...')
44
+ expect(subject.call(env)).to be_nil
45
+ end
46
+ end
47
+
48
+ context 'if interrupted waiting for SSH' do
49
+ before do
50
+ allow(domain).to receive(:wait_for).and_return(true)
51
+ allow(env).to receive(:[]).and_call_original
52
+ allow(env).to receive(:[]).with(:interrupted).and_return(false, true, true)
53
+ allow(env).to receive(:[]).with(:ip_address).and_return('192.168.121.2')
54
+ end
55
+ it 'should exit after getting IP' do
56
+ expect(app).to_not receive(:call)
57
+ expect(ui).to receive(:info).with('Waiting for domain to get an IP address...')
58
+ expect(ui).to receive(:info).with('Waiting for SSH to become available...')
59
+ logger = subject.instance_variable_get(:@logger)
60
+ expect(logger).to receive(:debug).with(/Searching for IP for MAC address: .*/)
61
+ expect(logger).to receive(:info).with('Got IP address 192.168.121.2')
62
+ expect(logger).to receive(:info).with(/Time for getting IP: .*/)
63
+ expect(env[:machine].communicate).to_not receive(:ready?)
64
+ expect(subject.call(env)).to be_nil
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'when machine boots and ssh available' do
70
+ before do
71
+ allow(domain).to receive(:wait_for).and_return(true)
72
+ allow(env).to receive(:[]).and_call_original
73
+ allow(env).to receive(:[]).with(:interrupted).and_return(false)
74
+ allow(env).to receive(:[]).with(:ip_address).and_return('192.168.121.2')
75
+ end
76
+ it 'should call the next hook' do
77
+ expect(app).to receive(:call)
78
+ expect(ui).to receive(:info).with('Waiting for domain to get an IP address...')
79
+ expect(ui).to receive(:info).with('Waiting for SSH to become available...')
80
+ expect(env[:machine].communicate).to receive(:ready?).and_return(true)
81
+ expect(subject.call(env)).to be_nil
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#recover' do
87
+ before do
88
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver).to receive(:get_domain).and_return(machine)
89
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver).to receive(:state)
90
+ .and_return(:not_created)
91
+ allow(env).to receive(:[]).and_call_original
92
+ end
93
+
94
+ it 'should do nothing by default' do
95
+ expect(env).to_not receive(:[]).with(:action_runner) # cleanup
96
+ expect(subject.recover(env)).to be_nil
97
+ end
98
+
99
+ context 'with machine coming up' do
100
+ before do
101
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver).to receive(:state)
102
+ .and_return(:running)
103
+ env[:destroy_on_error] = true
104
+ end
105
+
106
+ context 'and user has disabled destroy on failure' do
107
+ before do
108
+ env[:destroy_on_error] = false
109
+ end
110
+
111
+ it 'skips terminate on failure' do
112
+ expect(env).to_not receive(:[]).with(:action_runner) # cleanup
113
+ expect(subject.recover(env)).to be_nil
114
+ end
115
+ end
116
+
117
+ context 'and using default settings' do
118
+ let(:runner) { double('runner') }
119
+ it 'deletes VM on failure' do
120
+ expect(env).to receive(:[]).with(:action_runner).and_return(runner) # cleanup
121
+ expect(runner).to receive(:run)
122
+ expect(subject.recover(env)).to be_nil
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+
4
+ require 'vagrant-libvirt/config'
5
+
6
+ describe VagrantPlugins::ProviderLibvirt::Config do
7
+ include_context 'unit'
8
+
9
+ def assert_invalid
10
+ errors = subject.validate(machine)
11
+ raise "No errors: #{errors.inspect}" if errors.values.all?(&:empty?)
12
+ end
13
+
14
+ def assert_valid
15
+ errors = subject.validate(machine)
16
+ raise "Errors: #{errors.inspect}" unless errors.values.all?(&:empty?)
17
+ end
18
+
19
+ describe '#validate' do
20
+ it 'is valid with defaults' do
21
+ assert_valid
22
+ end
23
+
24
+ context 'with disks defined' do
25
+ before { expect(machine).to receive(:provider_config).and_return(subject).at_least(:once) }
26
+
27
+ it 'is valid if relative path used for disk' do
28
+ subject.storage :file, path: '../path/to/file.qcow2'
29
+ assert_valid
30
+ end
31
+
32
+ it 'should be invalid if absolute path used for disk' do
33
+ subject.storage :file, path: '/absolute/path/to/file.qcow2'
34
+ assert_invalid
35
+ end
36
+ end
37
+
38
+ context 'with mac defined' do
39
+ let (:vm) { double('vm') }
40
+ before { expect(machine.config).to receive(:vm).and_return(vm) }
41
+
42
+ it 'is valid with valid mac' do
43
+ expect(vm).to receive(:networks).and_return([[:public, { mac: 'aa:bb:cc:dd:ee:ff' }]])
44
+ assert_valid
45
+ end
46
+
47
+ it 'is valid with MAC containing no delimiters' do
48
+ network = [:public, { mac: 'aabbccddeeff' }]
49
+ expect(vm).to receive(:networks).and_return([network])
50
+ assert_valid
51
+ expect(network[1][:mac]).to eql('aa:bb:cc:dd:ee:ff')
52
+ end
53
+
54
+ it 'should be invalid if MAC not formatted correctly' do
55
+ expect(vm).to receive(:networks).and_return([[:public, { mac: 'aa/bb/cc/dd/ee/ff' }]])
56
+ assert_invalid
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#merge' do
62
+ let(:one) { described_class.new }
63
+ let(:two) { described_class.new }
64
+
65
+ subject { one.merge(two) }
66
+
67
+ context 'storage' do
68
+ context 'with disks' do
69
+ context 'assigned specific devices' do
70
+ it 'should merge disks with specific devices' do
71
+ one.storage(:file, device: 'vdb')
72
+ two.storage(:file, device: 'vdc')
73
+ subject.finalize!
74
+ expect(subject.disks).to include(include(device: 'vdb'),
75
+ include(device: 'vdc'))
76
+ end
77
+ end
78
+
79
+ context 'without devices given' do
80
+ it 'should merge disks with different devices assigned automatically' do
81
+ one.storage(:file)
82
+ two.storage(:file)
83
+ subject.finalize!
84
+ expect(subject.disks).to include(include(device: 'vdb'),
85
+ include(device: 'vdc'))
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'with cdroms only' do
91
+ context 'assigned specific devs' do
92
+ it 'should merge disks with specific devices' do
93
+ one.storage(:file, device: :cdrom, dev: 'hda')
94
+ two.storage(:file, device: :cdrom, dev: 'hdb')
95
+ subject.finalize!
96
+ expect(subject.cdroms).to include(include(dev: 'hda'),
97
+ include(dev: 'hdb'))
98
+ end
99
+ end
100
+
101
+ context 'without devs given' do
102
+ it 'should merge cdroms with different devs assigned automatically' do
103
+ one.storage(:file, device: :cdrom)
104
+ two.storage(:file, device: :cdrom)
105
+ subject.finalize!
106
+ expect(subject.cdroms).to include(include(dev: 'hda'),
107
+ include(dev: 'hdb'))
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,137 @@
1
+ <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
2
+ <name></name>
3
+ <uuid></uuid>
4
+ <memory></memory>
5
+ <vcpu>1</vcpu>
6
+
7
+
8
+ <cpu mode='custom'>
9
+ <model fallback='allow'>qemu64</model>
10
+ <feature name='AAA' policy='required'/>
11
+ <topology sockets='1' cores='3' threads='2'/>
12
+ </cpu>
13
+
14
+
15
+ <os>
16
+ <type arch='x86_64' machine='pc-compatible'>hvm</type>
17
+ <loader readonly='yes' type='rom'>/efi/loader</loader>
18
+ <bootmenu enable='yes'/>
19
+ <kernel></kernel>
20
+ <initrd></initrd>
21
+ <cmdline></cmdline>
22
+ </os>
23
+ <features>
24
+ <acpi/>
25
+ <apic/>
26
+ <pae/>
27
+ </features>
28
+ <clock offset='utc'/>
29
+ <devices>
30
+ <emulator>/usr/bin/kvm-spice</emulator>
31
+ <disk type='file' device='disk'>
32
+ <driver name='qemu' type='qcow2' cache='unsafe'/>
33
+ <source file='/var/lib/libvirt/images/test.qcow2'/>
34
+ <target dev='vda' bus='ide'/>
35
+ </disk>
36
+ <disk type='file' device='disk'>
37
+ <driver name='qemu' type='qcow2' cache='default'/>
38
+ <source file='/var/lib/libvirt/images/test-disk1.qcow2'/>
39
+ <target dev='vdb' bus='virtio'/>
40
+ </disk>
41
+ <disk type='file' device='disk'>
42
+ <driver name='qemu' type='qcow2' cache='default'/>
43
+ <source file='/var/lib/libvirt/images/test-disk2.qcow2'/>
44
+ <target dev='vdc' bus='virtio'/>
45
+ </disk>
46
+
47
+ <disk type='file' device='cdrom'>
48
+ <source file=''/>
49
+ <target dev='hda' bus='ide'/>
50
+ <readonly/>
51
+ </disk>
52
+ <disk type='file' device='cdrom'>
53
+ <source file=''/>
54
+ <target dev='hdb' bus='ide'/>
55
+ <readonly/>
56
+ </disk>
57
+
58
+ <serial type='pty'>
59
+ <target port='0'/>
60
+ </serial>
61
+ <console type='pty'>
62
+ <target port='0'/>
63
+ </console>
64
+
65
+ <channel type='unix' >
66
+ <target type='virtio'
67
+ name="org.qemu.guest_agent.0"
68
+ />
69
+ </channel>
70
+ <channel type='spicevmc' >
71
+ <target type='virtio'
72
+ name="com.redhat.spice.0"
73
+ />
74
+ </channel>
75
+ <channel type='unix' >
76
+ <source
77
+ path="/tmp/foo"
78
+ />
79
+ <target type='guestfwd'
80
+ address="192.0.2.42"
81
+ port="4242"
82
+ />
83
+ </channel>
84
+
85
+ <input type='mouse' bus='ps2'/>
86
+
87
+ <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us' />
88
+ <video>
89
+ <model type='cirrus' vram='9216' heads='1'/>
90
+ </video>
91
+ <rng model='virtio'>
92
+ <backend model='random'>/dev/random</backend>
93
+ </rng>
94
+ <hostdev mode='subsystem' type='pci' managed='yes'>
95
+ <source>
96
+ <address domain='0x0000'
97
+ bus='0x06'
98
+ slot='0x12'
99
+ function='0x5'/>
100
+ </source>
101
+ </hostdev>
102
+ <hostdev mode='subsystem' type='pci' managed='yes'>
103
+ <source>
104
+ <address domain='0x0000'
105
+ bus='0x03'
106
+ slot='0x00'
107
+ function='0x0'/>
108
+ </source>
109
+ </hostdev>
110
+ <hostdev mode='subsystem' type='usb'>
111
+ <source startupPolicy='mandatory'>
112
+ <vendor id='0x1234'/>
113
+ <product id='0xabcd'/>
114
+ <address bus='1' device='2'/>
115
+ </source>
116
+ </hostdev>
117
+ <redirdev bus='usb' type='tcp'>
118
+ </redirdev>
119
+ <redirfilter>
120
+ <usbdev class='0x0b' vendor='0x0b' product='0x0b' version='0x0b' allow='yes'/>
121
+ </redirfilter>
122
+ <watchdog model='i6300esb' action='reset'/>
123
+
124
+ <smartcard mode='passthrough' type='spicevmc'/>
125
+
126
+ <tpm model='tpm-tis'>
127
+ <backend type='passthrough'>
128
+ <device path='/dev/tpm0'/>
129
+ </backend>
130
+ </tpm>
131
+ </devices>
132
+
133
+ <qemu:commandline>
134
+ <qemu:arg value='-device'/>
135
+ <qemu:arg value='dummy-device'/>
136
+ </qemu:commandline>
137
+ </domain>