Skip to content

Commit

Permalink
feat: TPM state
Browse files Browse the repository at this point in the history
  • Loading branch information
Tinyblargon committed Mar 14, 2024
1 parent 9c58332 commit 4a24c6f
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 3 deletions.
39 changes: 36 additions & 3 deletions proxmox/config_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ type ConfigQemu struct {
Smbios1 string `json:"smbios1,omitempty"` // TODO should be custom type with enum?
Sshkeys string `json:"sshkeys,omitempty"` // TODO should be an array of strings
Startup string `json:"startup,omitempty"` // TODO should be a struct?
TPM *TpmState `json:"tpm,omitempty"`
Tablet *bool `json:"tablet,omitempty"`
Tags string `json:"tags,omitempty"` // TODO should be an array of a custom type as there are character and length limitations
VmID int `json:"vmid,omitempty"` // TODO should be a custom type as there are limitations
Expand Down Expand Up @@ -391,6 +392,11 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (rebootRequire
if config.Smbios1 != "" {
params["smbios1"] = config.Smbios1
}
if config.TPM != nil {
if delete := config.TPM.mapToApi(params, currentConfig.TPM); delete != "" {
itemsToDelete = AddToList(itemsToDelete, delete)
}
}

if config.Iso != nil {
if config.Disks == nil {
Expand Down Expand Up @@ -545,6 +551,9 @@ func (ConfigQemu) mapToStruct(vmr *VmRef, params map[string]interface{}) (*Confi
if _, isSet := params["onboot"]; isSet {
config.Onboot = util.Pointer(Itob(int(params["onboot"].(float64))))
}
if itemValue, isSet := params["tpmstate0"]; isSet {
config.TPM = TpmState{}.mapToSDK(itemValue.(string))
}
if _, isSet := params["cores"]; isSet {
config.QemuCores = int(params["cores"].(float64))
}
Expand Down Expand Up @@ -840,20 +849,21 @@ func (config *ConfigQemu) setVmr(vmr *VmRef) (err error) {
return
}

// currentConfig will be mutated
func (newConfig ConfigQemu) setAdvanced(currentConfig *ConfigQemu, rebootIfNeeded bool, vmr *VmRef, client *Client) (rebootRequired bool, err error) {
err = newConfig.setVmr(vmr)
if err != nil {
return
}
err = newConfig.Validate()
if err != nil {
if err = newConfig.Validate(currentConfig); err != nil {
return
}

var params map[string]interface{}
var exitStatus string

if currentConfig != nil { // Update
// TODO implement tmp move and version change
url := "/nodes/" + vmr.node + "/" + vmr.vmType + "/" + strconv.Itoa(vmr.vmId) + "/config"
var itemsToDeleteBeforeUpdate string // this is for items that should be removed before they can be created again e.g. cloud-init disks. (convert to array when needed)
stopped := false
Expand All @@ -873,6 +883,18 @@ func (newConfig ConfigQemu) setAdvanced(currentConfig *ConfigQemu, rebootIfNeede
itemsToDeleteBeforeUpdate = newConfig.Disks.cloudInitRemove(*currentConfig.Disks)
}

if newConfig.TPM != nil && currentConfig.TPM != nil { // delete or move TPM
delete, disk := newConfig.TPM.markChanges(*currentConfig.TPM)
if delete != "" { // delete
itemsToDeleteBeforeUpdate = AddToList(itemsToDeleteBeforeUpdate, delete)
currentConfig.TPM = nil
} else if disk != nil { // move
if _, err := disk.move(true, vmr, client); err != nil {
return false, err
}
}
}

if itemsToDeleteBeforeUpdate != "" {
err = client.Put(map[string]interface{}{"delete": itemsToDeleteBeforeUpdate}, url)
if err != nil {
Expand Down Expand Up @@ -980,7 +1002,7 @@ func (newConfig ConfigQemu) setAdvanced(currentConfig *ConfigQemu, rebootIfNeede
return
}

func (config ConfigQemu) Validate() (err error) {
func (config ConfigQemu) Validate(current *ConfigQemu) (err error) {
// TODO test all other use cases
// TODO has no context about changes caused by updating the vm
if config.Disks != nil {
Expand All @@ -989,6 +1011,17 @@ func (config ConfigQemu) Validate() (err error) {
return
}
}
if config.TPM != nil {
if current == nil {
if err = config.TPM.Validate(nil); err != nil {
return
}
} else {
if err = config.TPM.Validate(current.TPM); err != nil {
return
}
}
}

return
}
Expand Down
94 changes: 94 additions & 0 deletions proxmox/config_qemu_tpm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package proxmox

import (
"errors"
"strings"

"github.com/Telmate/proxmox-api-go/internal/util"
)

type TpmState struct {
Delete bool `json:"remove,omitempty"` // If true, the tpmstate will be deleted.
Storage string `json:"storage"` // TODO change to proper type once the type is added.
Version *TpmVersion `json:"version,omitempty"` // Changing version will delete the current tpmstate and create a new one. Optional during update, required during create.
}

const TmpState_Error_VersionRequired string = "version is required"

func (t TpmState) mapToApi(params map[string]interface{}, currentTpm *TpmState) string {
if t.Delete {
return "tpmstate0"
}
if currentTpm == nil { // create
params["tpmstate0"] = t.Storage + ":1,version=" + t.Version.mapToApi()
}
return ""
}

func (TpmState) mapToSDK(param string) *TpmState {
setting := splitStringOfSettings(param)
splitString := strings.Split(param, ":")
tmp := TpmState{}
if len(splitString) > 1 {
tmp.Storage = splitString[0]
}
if itemValue, isSet := setting["version"]; isSet {
tmp.Version = util.Pointer(TpmVersion(itemValue.(string)))
}
return &tmp

}

func (t TpmState) markChanges(currentTpm TpmState) (delete string, disk *qemuDiskMove) {
if t.Delete {
return "", nil
}
if t.Version != nil && t.Version.mapToApi() != string(*currentTpm.Version) {
return "tpmstate0", nil
}
if t.Storage != currentTpm.Storage {
return "", &qemuDiskMove{Storage: t.Storage, Id: "tpmstate0"}
}
return "", nil
}

func (t TpmState) Validate(current *TpmState) error {
if t.Storage == "" {
return errors.New("storage is required")
}
if t.Version == nil {
if current == nil { // create
return errors.New(TmpState_Error_VersionRequired)
}
} else {
if err := t.Version.Validate(); err != nil {
return err
}
}
return nil
}

type TpmVersion string // enum

const (
TpmVersion_1_2 TpmVersion = "v1.2"
TpmVersion_2_0 TpmVersion = "v2.0"
TpmVersion_Error_Invalid string = "enum TmpVersion should be one of: " + string(TpmVersion_1_2) + ", " + string(TpmVersion_2_0)
)

func (t TpmVersion) mapToApi() string {
switch t {
case TpmVersion_1_2, "1.2":
return string(t)
case TpmVersion_2_0, "v2", "2.0", "2":
return string(TpmVersion_2_0)
}
return ""
}

func (t TpmVersion) Validate() error {
if t.mapToApi() == "" {
return errors.New(TpmVersion_Error_Invalid)
}
return nil
}

0 comments on commit 4a24c6f

Please sign in to comment.