diff --git a/lib/fog/libvirt/compute.rb b/lib/fog/libvirt/compute.rb index 14f6c20..c12f579 100644 --- a/lib/fog/libvirt/compute.rb +++ b/lib/fog/libvirt/compute.rb @@ -22,6 +22,7 @@ class Compute < Fog::Service collection :nodes model :nic collection :nics + model :tpm request_path 'fog/libvirt/requests/compute' request :list_domains diff --git a/lib/fog/libvirt/models/compute/server.rb b/lib/fog/libvirt/models/compute/server.rb index 805898f..8aab3e6 100644 --- a/lib/fog/libvirt/models/compute/server.rb +++ b/lib/fog/libvirt/models/compute/server.rb @@ -36,6 +36,8 @@ class Server < Fog::Compute::Server attribute :guest_agent attribute :video attribute :virtio_rng + attribute :tpm + attribute :tpm_device attribute :state @@ -58,6 +60,7 @@ def initialize(attributes={} ) super defaults.merge(attributes) initialize_nics initialize_volumes + initialize_tpm @user_data = attributes.delete(:user_data) end @@ -411,6 +414,22 @@ def to_xml xml.backend(virtio_rng[:backend_path], :model => virtio_rng.fetch(:backend_model, "random")) end + if tpm_device + tpm_model_type = tpm_device.model == "spapr-tpm-proxy" ? "spapr-tpm-proxy" : "tpm-#{tpm_device.model}" + xml.tpm(:model => tpm_model_type) do + if tpm_device.type == "passthrough" + xml.backend(:type => tpm_device.type) do + xml.device(:path => tpm_device.passthrough_device_path) + end + else + xml.backend(:type => tpm_device.type, :version => tpm_device.version) + end + if %w[spapr spapr-tpm-proxy].include?(tpm_device.model) + xml.address(:type => tpm_device.par_address_type, :reg => tpm_device.spar_address_reg) + end + end + end + if arch == "s390x" xml.controller(:type => "scsi", :index => "0", :model => "virtio-scsi") xml.console(:type => "pty") do @@ -504,6 +523,17 @@ def initialize_volumes end end + def initialize_tpm + # tpm can be a boolean or hash + if tpm + # convert tpm to empty hash if not a hash value + if !tpm.is_a?(Hash) + tpm = {} + end + self.tpm_device = TPM.new(arch, tpm) + end + end + def create_or_clone_volume options = {:name => volume_name || default_volume_name} # Check if a disk template was specified @@ -561,6 +591,7 @@ def defaults :video => {:type => "virtio", :heads => 1}, :virtio_rng => {}, :firmware_features => { "secure-boot" => "no" }, + :tpm => false } end diff --git a/lib/fog/libvirt/models/compute/tpm.rb b/lib/fog/libvirt/models/compute/tpm.rb new file mode 100644 index 0000000..5b8b897 --- /dev/null +++ b/lib/fog/libvirt/models/compute/tpm.rb @@ -0,0 +1,97 @@ +require 'fog/core/model' + +module Fog + module Libvirt + class Compute + class TPM < Fog::Model + # Currently Qemu only allows for one TPM device + + identity :id + attribute :arch + attribute :model + attribute :type + attribute :version + attribute :device_path + attribute :spapr_address_type + attribute :spapr_address_reg + + # Types + # + TYPES = ['emulator', 'passthrough'].freeze + + # Models + # crb - TCG PC Client Platform TPM Profile (PTP) Specification (2017) + # tis - TCG PC Client Specific TPM Interface Specification (TIS) (2013) + # spapr - Used with pSeries (ppc64) + # spapr-tpm-proxy - Used with pSeries (ppc64), this is only used with 'passthrough' type + # + MODELS_X86_64 = ['crb', 'tis'].freeze + MODELS_PPC64 = ['spapr', 'spapr-tpm-proxy'].freeze + MODELS_ARM64 = ['tis'].freeze + MODELS_S390X = ['tis'].freeze + + # Versions + # + VERSIONS = ['1.2', '2.0'].freeze + + def initialize(arch = "", attributes = {}) + @id = "tpm0" + @arch = arch + super defaults.merge(attributes) + raise Fog::Errors::Error, "#{type} is not a supported TPM type" if new? && !TYPES.include?(type) + raise Fog::Errors::Error, "#{model} is not a supported TPM model" if new? && !supported_models.include?(model) + raise Fog::Errors::Error, "TPM model type crb does not a supported TPM version 1.2" if model == "crb" && version == "1.2" + end + + def new? + id.nil? + end + + def save + raise Fog::Errors::Error, 'Creating a new TPM device is not yet implemented. Contributions welcome!' + end + + def destroy + raise Fog::Errors::Error, 'Destroying a TPM device is not yet implemented. Contributions welcome!' + end + + def supported_models + case @arch + when "x86_64" + MODELS_X86_64 + when "ppc64" || "ppc64le" + MODELS_PPC64 + when "arm" || "aarch64" || "aarch64_be" + MODELS_ARM64 + when "s390x" + MODELS_S390X + else + raise Fog::Errors::Error, 'CPU Architecture does not have any supported TPM models!' + end + end + + def defaults + case @arch + when "x86_64" + { :model => "crb", :type => "emulator", :version => "2.0", :passthrough_device_path => "/dev/tpm0" } + when "ppc64" || "ppc64le" + { + :model => "spapr", + :type => "emulator", + :version => "2.0", + :passthrough_device_path => "/dev/tpm0", + :spapr_address_type => "spapr-vio", + :spapr_address_reg => "0x00004000" + } + when "arm" || "aarch64" || "aarch64_be" + { :model => "tis", :type => "emulator", :version => "2.0", :passthrough_device_path => "/dev/tpm0" } + when "s390x" + { :model => "tis", :type => "emulator", :version => "2.0", :passthrough_device_path => "/dev/tpm0" } + else + {} + end + end + end + end + end +end