diff --git a/README.md b/README.md
index 52c55a8..af06302 100644
--- a/README.md
+++ b/README.md
@@ -504,6 +504,7 @@ end
* `tpm_model` - The model of the TPM to which you wish to connect.
* `tpm_type` - The type of TPM device to which you are connecting.
* `tpm_path` - The path to the TPM device on the host system.
+* `tpm_version` - The TPM version to use.
* `dtb` - The device tree blob file, mostly used for non-x86 platforms. In case
the device tree isn't added in-line to the kernel, it can be manually
specified here.
@@ -579,6 +580,7 @@ defined domain:
* `tpm_model` - Updated
* `tpm_type` - Updated
* `tpm_path` - Updated
+* `tpm_version` - Updated
## Networks
@@ -1408,13 +1410,14 @@ Modern versions of Libvirt support connecting to TPM devices on the host
system. This allows you to enable Trusted Boot Extensions, among other
features, on your guest VMs.
-In general, you will only need to modify the `tpm_path` variable in your guest
-configuration. However, advanced usage, such as the application of a Software
-TPM, may require modifying the `tpm_model` and `tpm_type` variables.
+To passthrough a hardware TPM, you will generally only need to modify the
+`tpm_path` variable in your guest configuration. However, advanced usage,
+such as the application of a Software TPM, may require modifying the
+`tpm_model`, `tpm_type` and `tpm_version` variables.
-The TPM options will only be used if you specify a TPM path. Declarations of
-any TPM options without specifying a path will result in those options being
-ignored.
+The TPM options will only be used if you specify a TPM path or version.
+Declarations of any TPM options without specifying a path or version will
+result in those options being ignored.
Here is an example of using the TPM options:
@@ -1428,6 +1431,19 @@ Vagrant.configure("2") do |config|
end
```
+It's also possible for Libvirt to start an emulated TPM device on the host.
+Requires `swtpm` and `swtpm-tools`
+
+```ruby
+Vagrant.configure("2") do |config|
+ config.vm.provider :libvirt do |libvirt|
+ libvirt.tpm_model = "tpm-crb"
+ libvirt.tpm_type = "emulator"
+ libvirt.tpm_version = "2.0"
+ end
+end
+```
+
## Libvirt communication channels
For certain functionality to be available within a guest, a private
diff --git a/lib/vagrant-libvirt/action/create_domain.rb b/lib/vagrant-libvirt/action/create_domain.rb
index 9ed0766..ddd45a5 100644
--- a/lib/vagrant-libvirt/action/create_domain.rb
+++ b/lib/vagrant-libvirt/action/create_domain.rb
@@ -81,6 +81,7 @@ module VagrantPlugins
@tpm_model = config.tpm_model
@tpm_type = config.tpm_type
@tpm_path = config.tpm_path
+ @tpm_version = config.tpm_version
# Boot order
@boot_order = config.boot_order
@@ -254,7 +255,13 @@ module VagrantPlugins
env[:ui].info(" -- Video VRAM: #{@video_vram}")
env[:ui].info(" -- Sound Type: #{@sound_type}")
env[:ui].info(" -- Keymap: #{@keymap}")
- env[:ui].info(" -- TPM Path: #{@tpm_path}")
+ env[:ui].info(" -- TPM Backend: #{@tpm_type}")
+ if @tpm_type == 'emulator'
+ env[:ui].info(" -- TPM Model: #{@tpm_model}")
+ env[:ui].info(" -- TPM Version: #{@tpm_version}")
+ else
+ env[:ui].info(" -- TPM Path: #{@tpm_path}")
+ end
@boot_order.each do |device|
env[:ui].info(" -- Boot device: #{device}")
diff --git a/lib/vagrant-libvirt/action/start_domain.rb b/lib/vagrant-libvirt/action/start_domain.rb
index 7fa6ab4..1058015 100644
--- a/lib/vagrant-libvirt/action/start_domain.rb
+++ b/lib/vagrant-libvirt/action/start_domain.rb
@@ -193,36 +193,31 @@ module VagrantPlugins
end
# TPM
- if config.tpm_path
- raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
+ if [config.tpm_path, config.tpm_version].any?
+ if config.tpm_path
+ raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
+ end
- tpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
- if tpm.nil?
- @logger.debug "tpm created from previously not defined"
+ # just build the tpm element every time
+ # check at the end if it is different
+ oldtpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
+ REXML::XPath.first(xml_descr, '/domain/devices').delete_element("tpm")
+ newtpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices'))
+
+ newtpm.attributes['model'] = config.tpm_model
+ backend = newtpm.add_element('backend')
+ backend.attributes['type'] = config.tpm_type
+
+ case config.tpm_type
+ when 'emulator'
+ backend.attributes['version'] = config.tpm_version
+ when 'passthrough'
+ backend.add_element('device').attributes['path'] = config.tpm_path
+ end
+
+ unless "'#{newtpm}'".eql? "'#{oldtpm}'"
+ @logger.debug "tpm config changed"
descr_changed = true
- tpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices'))
- tpm.attributes['model'] = config.tpm_model
- tpm_backend_type = tpm.add_element('backend')
- tpm_backend_type.attributes['type'] = config.tpm_type
- tpm_device_path = tpm_backend_type.add_element('device')
- tpm_device_path.attributes['path'] = config.tpm_path
- else
- if tpm.attributes['model'] != config.tpm_model
- @logger.debug "tpm model updated from '#{tpm.attributes['model']}' to '#{config.tpm_model}'"
- descr_changed = true
- tpm.attributes['model'] = config.tpm_model
- end
- backend = tpm.elements['backend']
- if backend.attributes['type'] != config.tpm_type
- @logger.debug "tpm type updated from '#{backend.attributes['type']}' to '#{config.tpm_type}'"
- descr_changed = true
- backend.attributes['type'] = config.tpm_type
- end
- if backend.elements['device'].attributes['path'] != config.tpm_path
- @logger.debug "tpm path updated from '#{backend.elements['device'].attributes['path']}' to '#{config.tpm_path}'"
- descr_changed = true
- backend.elements['device'].attributes['path'] = config.tpm_path
- end
end
end
diff --git a/lib/vagrant-libvirt/config.rb b/lib/vagrant-libvirt/config.rb
index 4fbc7a8..175e88b 100644
--- a/lib/vagrant-libvirt/config.rb
+++ b/lib/vagrant-libvirt/config.rb
@@ -117,6 +117,7 @@ module VagrantPlugins
attr_accessor :tpm_model
attr_accessor :tpm_type
attr_accessor :tpm_path
+ attr_accessor :tpm_version
# Sets the max number of NICs that can be created
# Default set to 8. Don't change the default unless you know
@@ -245,6 +246,7 @@ module VagrantPlugins
@tpm_model = UNSET_VALUE
@tpm_type = UNSET_VALUE
@tpm_path = UNSET_VALUE
+ @tpm_version = UNSET_VALUE
@nic_adapter_count = UNSET_VALUE
@@ -781,6 +783,7 @@ module VagrantPlugins
@tpm_model = 'tpm-tis' if @tpm_model == UNSET_VALUE
@tpm_type = 'passthrough' if @tpm_type == UNSET_VALUE
@tpm_path = nil if @tpm_path == UNSET_VALUE
+ @tpm_version = nil if @tpm_version == UNSET_VALUE
@nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
@emulator_path = nil if @emulator_path == UNSET_VALUE
diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb
index 824872c..d04336e 100644
--- a/lib/vagrant-libvirt/templates/domain.xml.erb
+++ b/lib/vagrant-libvirt/templates/domain.xml.erb
@@ -257,11 +257,13 @@
<% end %>
<% end -%>
- <% if @tpm_path -%>
+ <% if @tpm_path || @tpm_version -%>
<%# TPM Device -%>
-
+ version='<%= @tpm_version %>'<% end %>>
+ <% if @tpm_path -%>
+ <% end -%>
<% end -%>
diff --git a/spec/unit/action/start_domain_spec.rb b/spec/unit/action/start_domain_spec.rb
index 31cc635..1c0743c 100644
--- a/spec/unit/action/start_domain_spec.rb
+++ b/spec/unit/action/start_domain_spec.rb
@@ -48,8 +48,19 @@ describe VagrantPlugins::ProviderLibvirt::Action::StartDomain do
expect(subject.call(env)).to be_nil
end
+ end
- context 'tpm_path added' do
+ context 'tpm' do
+ let(:test_file) { 'default.xml' }
+
+ before do
+ 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)
+ end
+
+ context 'passthrough tpm added' do
let(:updated_test_file) { 'default_added_tpm_path.xml' }
let(:vagrantfile_providerconfig) do
<<-EOF
@@ -61,7 +72,90 @@ describe VagrantPlugins::ProviderLibvirt::Action::StartDomain do
it 'should modify the domain tpm_path' do
expect(libvirt_domain).to receive(:undefine)
- expect(logger).to receive(:debug).with('tpm created from previously not defined')
+ expect(logger).to receive(:debug).with('tpm config changed')
+ expect(servers).to receive(:create).with(xml: updated_domain_xml)
+ 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
+ expect(libvirt_domain).to receive(:undefine)
+ expect(logger).to receive(:debug).with('tpm config changed')
+ expect(servers).to receive(:create).with(xml: updated_domain_xml)
+ 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
+ expect(logger).to_not receive(:debug)
+ 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
+ expect(logger).to_not receive(:debug)
+ 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
+ expect(libvirt_domain).to receive(:undefine)
+ expect(logger).to receive(:debug).with('tpm config changed')
expect(servers).to receive(:create).with(xml: updated_domain_xml)
expect(libvirt_domain).to receive(:autostart=)
expect(domain).to receive(:start)
diff --git a/spec/unit/action/start_domain_spec/default_added_tpm_version.xml b/spec/unit/action/start_domain_spec/default_added_tpm_version.xml
new file mode 100644
index 0000000..beaba37
--- /dev/null
+++ b/spec/unit/action/start_domain_spec/default_added_tpm_version.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spec/unit/templates/domain_spec.rb b/spec/unit/templates/domain_spec.rb
index c800e05..056dd3b 100644
--- a/spec/unit/templates/domain_spec.rb
+++ b/spec/unit/templates/domain_spec.rb
@@ -105,4 +105,28 @@ describe 'templates/domain' do
expect(domain.to_xml('domain')).to eq xml_expected
end
end
+
+ context 'when tpm 2.0 device is specified' do
+ before do
+ domain.tpm_version = '2.0'
+ domain.tpm_type = 'emulator'
+ domain.tpm_model = 'tpm-crb'
+ end
+ let(:test_file) { 'tpm/version_2.0.xml' }
+ it 'renders template' do
+ domain.finalize!
+ expect(domain.to_xml('domain')).to eq xml_expected
+ end
+ end
+
+ context 'when tpm 1.2 device is implicitly used' do
+ before do
+ domain.tpm_path = '/dev/tpm0'
+ end
+ let(:test_file) { 'tpm/version_1.2.xml' }
+ it 'renders template' do
+ domain.finalize!
+ expect(domain.to_xml('domain')).to eq xml_expected
+ end
+ end
end
diff --git a/spec/unit/templates/tpm/version_1.2.xml b/spec/unit/templates/tpm/version_1.2.xml
new file mode 100644
index 0000000..c33f9d0
--- /dev/null
+++ b/spec/unit/templates/tpm/version_1.2.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spec/unit/templates/tpm/version_2.0.xml b/spec/unit/templates/tpm/version_2.0.xml
new file mode 100644
index 0000000..fc92aef
--- /dev/null
+++ b/spec/unit/templates/tpm/version_2.0.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+