From 3c23caa014c49769c27c0ca92484596818ceef64 Mon Sep 17 00:00:00 2001 From: Cooper Tseng Date: Tue, 24 Sep 2024 17:58:07 +0800 Subject: [PATCH] Add cpu_pinning option and isolate_emulator_thread to vm resource Signed-off-by: Cooper Tseng --- .../resource_virtualmachine_constructor.go | 19 +- .../virtualmachine/schema_virtualmachine.go | 12 + .../tests/resource_virtualmachine_test.go | 381 +++++++++++++++--- pkg/constants/constants_virtualmachine.go | 36 +- .../resource_virtualmachine_importer.go | 55 ++- 5 files changed, 407 insertions(+), 96 deletions(-) diff --git a/internal/provider/virtualmachine/resource_virtualmachine_constructor.go b/internal/provider/virtualmachine/resource_virtualmachine_constructor.go index 4f79a3c2..baf5cef6 100644 --- a/internal/provider/virtualmachine/resource_virtualmachine_constructor.go +++ b/internal/provider/virtualmachine/resource_virtualmachine_constructor.go @@ -5,13 +5,14 @@ import ( "errors" "fmt" - "github.com/harvester/harvester/pkg/builder" - harvesterutil "github.com/harvester/harvester/pkg/util" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" kubevirtv1 "kubevirt.io/api/core/v1" + "github.com/harvester/harvester/pkg/builder" + harvesterutil "github.com/harvester/harvester/pkg/util" + "github.com/harvester/terraform-provider-harvester/internal/util" "github.com/harvester/terraform-provider-harvester/pkg/client" "github.com/harvester/terraform-provider-harvester/pkg/constants" @@ -306,6 +307,20 @@ func (c *Constructor) Setup() util.Processors { return nil }, }, + { + Field: constants.FieldVirtualMachineCPUPinning, + Parser: func(i interface{}) error { + vmBuilder.VirtualMachine.Spec.Template.Spec.Domain.CPU.DedicatedCPUPlacement = i.(bool) + return nil + }, + }, + { + Field: constants.FieldVirtualMachineIsolateEmulatorThread, + Parser: func(i interface{}) error { + vmBuilder.VirtualMachine.Spec.Template.Spec.Domain.CPU.IsolateEmulatorThread = i.(bool) + return nil + }, + }, } return append(processors, customProcessors...) } diff --git a/internal/provider/virtualmachine/schema_virtualmachine.go b/internal/provider/virtualmachine/schema_virtualmachine.go index 99a2dc8d..3f56d025 100644 --- a/internal/provider/virtualmachine/schema_virtualmachine.go +++ b/internal/provider/virtualmachine/schema_virtualmachine.go @@ -127,6 +127,18 @@ please use %s instead of this deprecated field: Optional: true, Default: false, }, + constants.FieldVirtualMachineCPUPinning: { + Type: schema.TypeBool, + Description: "To enable VM CPU pinning, ensure that at least one node has the CPU manager enabled", + Optional: true, + Default: false, + }, + constants.FieldVirtualMachineIsolateEmulatorThread: { + Type: schema.TypeBool, + Description: "To enable isolate emulator thread, ensure that at least one node has the CPU manager enabled, also VM CPU pinning must be enabled. Note that enable option will allocate an additional dedicated CPU.", + Optional: true, + Default: false, + }, } util.NamespacedSchemaWrap(s, false) return s diff --git a/internal/tests/resource_virtualmachine_test.go b/internal/tests/resource_virtualmachine_test.go index 6514b399..efcb5c3f 100644 --- a/internal/tests/resource_virtualmachine_test.go +++ b/internal/tests/resource_virtualmachine_test.go @@ -2,14 +2,24 @@ package tests import ( "context" + "crypto/tls" + "errors" "fmt" + "io" + "net/http" + "net/url" + "os" + "strconv" + "strings" "testing" + "time" "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" kubevirtv1 "kubevirt.io/api/core/v1" "github.com/harvester/terraform-provider-harvester/pkg/client" @@ -18,63 +28,130 @@ import ( ) const ( - testAccVirtualMachineDescription = "Terraform Harvester vm acceptance test" + defaultVMDesciption = "Terraform Harvester vm acceptance test" + defaultVMMemory = "1Gi" +) - testAccVirtualMachineMemory = "1Gi" - testAccVirtualMachineMemoryUpdate = "2Gi" +type VMResourceBuilder struct { + name string + description string + cpu int + memory string // e.g. "1Gi" + cpuPinning bool + isolateEmulatorThread bool + runStrategy string + machineType string + networkName string + diskConfig *DiskConfig + inputConfig *InputDeviceConfig +} - testAccVirtualMachineConfigTemplate = ` -resource %s "%s" { - %s = "%s" - %s = "%s" +type DiskConfig struct { + Name string + Type string + Bus string + BootOrder int + ContainerImageName string +} - cpu = 1 - %s = "%s" +type InputDeviceConfig struct { + Name string + Type string + Bus string +} - run_strategy = "RerunOnFailure" - machine_type = "q35" +func NewVMResourceBuilder(resourceName string) *VMResourceBuilder { + return &VMResourceBuilder{ + name: resourceName, + description: defaultVMDesciption, + cpu: 1, + cpuPinning: false, + isolateEmulatorThread: false, + memory: defaultVMMemory, + runStrategy: "RerunOnFailure", + machineType: "q35", + networkName: "default", + diskConfig: &DiskConfig{ + Name: "rootdisk", + Type: "disk", + Bus: "virtio", + BootOrder: 1, + ContainerImageName: "kubevirt/fedora-cloud-container-disk-demo:v0.35.0", + }, + } +} - network_interface { - name = "default" - } +func (b *VMResourceBuilder) SetMemory(memory string) *VMResourceBuilder { + b.memory = memory + return b +} - disk { - name = "rootdisk" - type = "disk" - bus = "virtio" - boot_order = 1 +func (b *VMResourceBuilder) SetCPUPinning(cpuPinning bool) *VMResourceBuilder { + b.cpuPinning = cpuPinning + return b +} - container_image_name = "kubevirt/fedora-cloud-container-disk-demo:v0.35.0" - } +func (b *VMResourceBuilder) SetIsolateEmulatorThread(isolateEmulatorThread bool) *VMResourceBuilder { + b.isolateEmulatorThread = isolateEmulatorThread + return b } -` - testAccInputBlockTemplate = ` - input { - name = "%s" - type = "%s" - bus = "%s" - } -` -) -func addInputBlockConfig(name, inputType, bus, vmConfig string) string { - inputBlock := fmt.Sprintf(testAccInputBlockTemplate, name, inputType, bus) - return vmConfig[:(len(vmConfig)-3)] + inputBlock + vmConfig[(len(vmConfig)-3):] +func (b *VMResourceBuilder) SetInputDeviceConfig(name, inputType, bus string) *VMResourceBuilder { + b.inputConfig = &InputDeviceConfig{ + Name: name, + Type: inputType, + Bus: bus, + } + return b } -func buildVirtualMachineConfig(name, description, memory string) string { - return fmt.Sprintf(testAccVirtualMachineConfigTemplate, - constants.ResourceTypeVirtualMachine, name, - constants.FieldCommonName, name, - constants.FieldCommonDescription, description, - constants.FieldVirtualMachineMemory, memory) +// Build generates the terraform resource string. +func (b *VMResourceBuilder) Build() string { + var sb strings.Builder + sb.WriteString(fmt.Sprintf("resource %s \"%s\" {\n", constants.ResourceTypeVirtualMachine, b.name)) + + sb.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", constants.FieldCommonName, b.name)) + sb.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", constants.FieldCommonDescription, b.description)) + + sb.WriteString(fmt.Sprintf("\t%s = %d\n", constants.FieldVirtualMachineCPU, b.cpu)) + sb.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", constants.FieldVirtualMachineMemory, b.memory)) + sb.WriteString(fmt.Sprintf("\t%s = %s\n", constants.FieldVirtualMachineCPUPinning, strconv.FormatBool(b.cpuPinning))) + sb.WriteString(fmt.Sprintf("\t%s = %s\n", constants.FieldVirtualMachineIsolateEmulatorThread, strconv.FormatBool(b.isolateEmulatorThread))) + sb.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", constants.FieldVirtualMachineRunStrategy, b.runStrategy)) + sb.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", constants.FieldVirtualMachineMachineType, b.machineType)) + + sb.WriteString(fmt.Sprintf("\t%s {\n", constants.FieldVirtualMachineNetworkInterface)) + sb.WriteString(fmt.Sprintf("\t\tname = \"%s\"\n", b.networkName)) + sb.WriteString("\t}\n") + + if b.diskConfig != nil { + sb.WriteString(fmt.Sprintf("\t%s {\n", constants.FieldVirtualMachineDisk)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldDiskName, b.diskConfig.Name)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldDiskType, b.diskConfig.Type)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldDiskBus, b.diskConfig.Bus)) + sb.WriteString(fmt.Sprintf("\t\t%s = %d\n", constants.FieldDiskBootOrder, b.diskConfig.BootOrder)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldDiskContainerImageName, b.diskConfig.ContainerImageName)) + sb.WriteString("\t}\n") + } + + if b.inputConfig != nil { + sb.WriteString(fmt.Sprintf("\t%s {\n", constants.FieldVirtualMachineInput)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldInputName, b.inputConfig.Name)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldInputType, b.inputConfig.Type)) + sb.WriteString(fmt.Sprintf("\t\t%s = \"%s\"\n", constants.FieldInputBus, b.inputConfig.Bus)) + sb.WriteString("\t}\n") + } + + sb.WriteString("}\n") + return sb.String() } func TestAccVirtualMachine_basic(t *testing.T) { var ( testAccVirtualMachineName = "test-acc-basic-" + uuid.New().String()[:6] testAccVirtualMachineResourceName = constants.ResourceTypeVirtualMachine + "." + testAccVirtualMachineName - vm *kubevirtv1.VirtualMachine + testAccVirtualMachineMemoryUpdate = "2Gi" + vm = &kubevirtv1.VirtualMachine{} ctx = context.Background() ) resource.Test(t, resource.TestCase{ @@ -83,32 +160,117 @@ func TestAccVirtualMachine_basic(t *testing.T) { CheckDestroy: testAccCheckVirtualMachineDestroy(ctx), Steps: []resource.TestStep{ { - Config: buildVirtualMachineConfig(testAccVirtualMachineName, testAccVirtualMachineDescription, testAccVirtualMachineMemory), + Config: NewVMResourceBuilder(testAccVirtualMachineName).Build(), Check: resource.ComposeTestCheckFunc( testAccVirtualMachineExists(ctx, testAccVirtualMachineResourceName, vm), resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonName, testAccVirtualMachineName), - resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonDescription, testAccVirtualMachineDescription), - resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineMemory, testAccVirtualMachineMemory), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonDescription, defaultVMDesciption), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineMemory, defaultVMMemory), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineCPUPinning, "false"), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineIsolateEmulatorThread, "false"), ), }, { - Config: buildVirtualMachineConfig(testAccVirtualMachineName, testAccVirtualMachineDescription, testAccVirtualMachineMemoryUpdate), + Config: NewVMResourceBuilder(testAccVirtualMachineName).SetMemory(testAccVirtualMachineMemoryUpdate).Build(), Check: resource.ComposeTestCheckFunc( testAccVirtualMachineExists(ctx, testAccVirtualMachineResourceName, vm), resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonName, testAccVirtualMachineName), - resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonDescription, testAccVirtualMachineDescription), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonDescription, defaultVMDesciption), resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineMemory, testAccVirtualMachineMemoryUpdate), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineCPUPinning, "false"), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineIsolateEmulatorThread, "false"), + ), + }, + }, + }) +} + +func TestAccVirtualMachine_cpu_pinning(t *testing.T) { + var ( + testAccVirtualMachineName = "test-acc-cpu-pinning" + uuid.New().String()[:6] + testAccVirtualMachineResourceName = constants.ResourceTypeVirtualMachine + "." + testAccVirtualMachineName + vm = &kubevirtv1.VirtualMachine{} + ctx = context.Background() + ) + + if os.Getenv("TF_ACC") == "" { + t.Skip("Skipping test: TF_ACC is not set") + } + + // enableCPUManager and disableCPUManager are placed outside acc test because acc tests lack beforeAll/afterAll support. + // To minimize delays, CPUManager is enable/disable only once rather than before/after each test step. + testAccPreCheck(t) + nodes, err := testAccProvider.Meta().(*client.Client).KubeClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) + if err != nil { + t.Fatal(err) + } + if len(nodes.Items) == 0 { + t.Fatal("failed to find any node") + } + nodeName := nodes.Items[0].Name + + t.Log("enable cpu manager on node " + nodeName) + enableCPUManager(t, ctx, nodeName) + + resource.Test(t, resource.TestCase{ + Providers: testAccProviders, + CheckDestroy: func(s *terraform.State) error { + err := testAccCheckVirtualMachineDestroy(ctx)(s) + return err + }, + Steps: []resource.TestStep{ + { + Config: NewVMResourceBuilder(testAccVirtualMachineName).SetCPUPinning(true).Build(), + Check: resource.ComposeTestCheckFunc( + testAccVirtualMachineExists(ctx, testAccVirtualMachineResourceName, vm), + func(s *terraform.State) error { + if vm.Spec.Template == nil || vm.Spec.Template.Spec.Domain.CPU == nil || !vm.Spec.Template.Spec.Domain.CPU.DedicatedCPUPlacement { + return errors.New("DedicatedCPUPlacement should be true") + } + if vm.Spec.Template == nil || vm.Spec.Template.Spec.Domain.CPU == nil || vm.Spec.Template.Spec.Domain.CPU.IsolateEmulatorThread { + return errors.New("IsolateEmulatorThread should be false") + } + return nil + }, + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonName, testAccVirtualMachineName), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonDescription, defaultVMDesciption), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineMemory, defaultVMMemory), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineCPUPinning, "true"), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineIsolateEmulatorThread, "false"), + ), + }, + { + Config: NewVMResourceBuilder(testAccVirtualMachineName).SetCPUPinning(true).SetIsolateEmulatorThread(true).Build(), + Check: resource.ComposeTestCheckFunc( + testAccVirtualMachineExists(ctx, testAccVirtualMachineResourceName, vm), + func(s *terraform.State) error { + if vm.Spec.Template == nil || vm.Spec.Template.Spec.Domain.CPU == nil || !vm.Spec.Template.Spec.Domain.CPU.DedicatedCPUPlacement { + return errors.New("DedicatedCPUPlacement should be true") + } + if vm.Spec.Template == nil || vm.Spec.Template.Spec.Domain.CPU == nil || !vm.Spec.Template.Spec.Domain.CPU.IsolateEmulatorThread { + return errors.New("IsolateEmulatorThread should be true") + } + return nil + }, + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonName, testAccVirtualMachineName), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldCommonDescription, defaultVMDesciption), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineMemory, defaultVMMemory), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineCPUPinning, "true"), + resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineIsolateEmulatorThread, "true"), ), }, }, }) + + t.Log("disable cpu manager on node " + nodeName) + disableCPUManager(t, ctx, nodeName) } func TestAccVirtualMachine_input(t *testing.T) { var ( testAccVirtualMachineName = "test-acc-input-" + uuid.New().String()[:6] testAccVirtualMachineResourceName = constants.ResourceTypeVirtualMachine + "." + testAccVirtualMachineName - vm *kubevirtv1.VirtualMachine + vm = &kubevirtv1.VirtualMachine{} ctx = context.Background() ) resource.Test(t, resource.TestCase{ @@ -117,14 +279,7 @@ func TestAccVirtualMachine_input(t *testing.T) { CheckDestroy: testAccCheckVirtualMachineDestroy(ctx), Steps: []resource.TestStep{ { - Config: addInputBlockConfig( - "tablet", "tablet", "usb", - buildVirtualMachineConfig( - testAccVirtualMachineName, - testAccVirtualMachineDescription, - testAccVirtualMachineMemoryUpdate, - ), - ), + Config: NewVMResourceBuilder(testAccVirtualMachineName).SetInputDeviceConfig("tablet", "tablet", "usb").Build(), Check: resource.ComposeTestCheckFunc( testAccVirtualMachineExists(ctx, testAccVirtualMachineResourceName, vm), resource.TestCheckResourceAttr(testAccVirtualMachineResourceName, constants.FieldVirtualMachineInput+".#", "1"), @@ -159,7 +314,7 @@ func testAccVirtualMachineExists(ctx context.Context, n string, vm *kubevirtv1.V if err != nil { return err } - vm = foundVM + *vm = *foundVM return nil } } @@ -189,3 +344,119 @@ func testAccCheckVirtualMachineDestroy(ctx context.Context) resource.TestCheckFu return nil } } + +func enableCPUManager(t *testing.T, ctx context.Context, nodeName string) { + if err := updateCPUManagerPolicy(ctx, nodeName, true); err != nil { + t.Fatalf("failed to enable cpu manager: %v", err) + } +} + +func disableCPUManager(t *testing.T, ctx context.Context, nodeName string) { + if err := updateCPUManagerPolicy(ctx, nodeName, false); err != nil { + t.Fatalf("failed to disable cpu manager: %v", err) + } +} + +func updateCPUManagerPolicy(ctx context.Context, nodeName string, enableCPUManager bool) error { + c := testAccProvider.Meta().(*client.Client) + action := "disableCPUManager" + if enableCPUManager { + action = "enableCPUManager" + } + apiURL, err := buildNodeActionURL(c.RestConfig, nodeName, action) + if err != nil { + return fmt.Errorf("failed to build node action url: %v", err) + } + req, err := createRequest(apiURL, c.RestConfig.BearerToken) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, // #nosec G402 + }, + }, + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed to read response, status code: %d, err: %v", resp.StatusCode, err) + } + return fmt.Errorf("status code: %d, err: %s", resp.StatusCode, string(bodyBytes)) + } + + err = waitForCPUMangerLabel(ctx, c, nodeName, enableCPUManager) + if err != nil { + return fmt.Errorf("wait cpu manager label failed: %v", err) + } + return nil +} + +func buildNodeActionURL(config *rest.Config, nodeName, action string) (string, error) { + parsedURL, err := url.Parse(config.Host) + if err != nil { + return "", fmt.Errorf("failed to parse restconfig host to url: %v", err) + } + + parsedURL.Path = "/v1/harvester/nodes/" + nodeName + query := parsedURL.Query() + query.Set("action", action) + parsedURL.RawQuery = query.Encode() + + return parsedURL.String(), nil +} + +func createRequest(apiURL, bearerToken string) (*http.Request, error) { + req, err := http.NewRequest(http.MethodPost, apiURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %v", err) + } + req.Header.Set("Authorization", "Bearer "+bearerToken) + return req, nil +} + +func waitForCPUMangerLabel(ctx context.Context, c *client.Client, nodeName string, enableCPUManager bool) error { + return waitUntil(func() (bool, error) { + node, err := c.KubeClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{}) + if err != nil { + return false, nil + } + + expectedValue := strconv.FormatBool(enableCPUManager) + if value, exists := node.Labels["cpumanager"]; exists && value == expectedValue { + return true, nil + } + return false, nil + }) +} + +func waitUntil(fun func() (bool, error)) error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("timeout reached, the condition was not met within 5 minutes") + case <-ticker.C: + ok, err := fun() + if err != nil { + return err + } + if ok { + return nil + } + } + } +} diff --git a/pkg/constants/constants_virtualmachine.go b/pkg/constants/constants_virtualmachine.go index ad8e614a..9bad6bd1 100644 --- a/pkg/constants/constants_virtualmachine.go +++ b/pkg/constants/constants_virtualmachine.go @@ -3,23 +3,25 @@ package constants const ( ResourceTypeVirtualMachine = "harvester_virtualmachine" - FieldVirtualMachineMachineType = "machine_type" - FieldVirtualMachineHostname = "hostname" - FieldVirtualMachineReservedMemory = "reserved_memory" - FieldVirtualMachineRestartAfterUpdate = "restart_after_update" - FieldVirtualMachineStart = "start" - FieldVirtualMachineRunStrategy = "run_strategy" - FieldVirtualMachineCPU = "cpu" - FieldVirtualMachineMemory = "memory" - FieldVirtualMachineSSHKeys = "ssh_keys" - FieldVirtualMachineCloudInit = "cloudinit" - FieldVirtualMachineDisk = "disk" - FieldVirtualMachineNetworkInterface = "network_interface" - FieldVirtualMachineInput = "input" - FieldVirtualMachineTPM = "tpm" - FieldVirtualMachineInstanceNodeName = "node_name" - FieldVirtualMachineEFI = "efi" - FieldVirtualMachineSecureBoot = "secure_boot" + FieldVirtualMachineMachineType = "machine_type" + FieldVirtualMachineHostname = "hostname" + FieldVirtualMachineReservedMemory = "reserved_memory" + FieldVirtualMachineRestartAfterUpdate = "restart_after_update" + FieldVirtualMachineStart = "start" + FieldVirtualMachineRunStrategy = "run_strategy" + FieldVirtualMachineCPU = "cpu" + FieldVirtualMachineMemory = "memory" + FieldVirtualMachineSSHKeys = "ssh_keys" + FieldVirtualMachineCloudInit = "cloudinit" + FieldVirtualMachineDisk = "disk" + FieldVirtualMachineNetworkInterface = "network_interface" + FieldVirtualMachineInput = "input" + FieldVirtualMachineTPM = "tpm" + FieldVirtualMachineInstanceNodeName = "node_name" + FieldVirtualMachineEFI = "efi" + FieldVirtualMachineSecureBoot = "secure_boot" + FieldVirtualMachineCPUPinning = "cpu_pinning" + FieldVirtualMachineIsolateEmulatorThread = "isolate_emulator_thread" StateVirtualMachineStarting = "Starting" StateVirtualMachineRunning = "Running" diff --git a/pkg/importer/resource_virtualmachine_importer.go b/pkg/importer/resource_virtualmachine_importer.go index 58c276ab..49b3886c 100644 --- a/pkg/importer/resource_virtualmachine_importer.go +++ b/pkg/importer/resource_virtualmachine_importer.go @@ -4,11 +4,12 @@ import ( "encoding/json" "fmt" - "github.com/harvester/harvester/pkg/builder" - harvesterutil "github.com/harvester/harvester/pkg/util" corev1 "k8s.io/api/core/v1" kubevirtv1 "kubevirt.io/api/core/v1" + "github.com/harvester/harvester/pkg/builder" + harvesterutil "github.com/harvester/harvester/pkg/util" + "github.com/harvester/terraform-provider-harvester/pkg/constants" "github.com/harvester/terraform-provider-harvester/pkg/helper" ) @@ -50,6 +51,14 @@ func (v *VMImporter) CPU() int { return int(v.VirtualMachine.Spec.Template.Spec.Domain.CPU.Cores) } +func (v *VMImporter) DedicatedCPUPlacement() bool { + return bool(v.VirtualMachine.Spec.Template.Spec.Domain.CPU.DedicatedCPUPlacement) +} + +func (v *VMImporter) IsolateEmulatorThread() bool { + return bool(v.VirtualMachine.Spec.Template.Spec.Domain.CPU.IsolateEmulatorThread) +} + func (v *VMImporter) EFI() bool { firmware := v.VirtualMachine.Spec.Template.Spec.Domain.Firmware return firmware != nil && firmware.Bootloader != nil && firmware.Bootloader.EFI != nil @@ -360,26 +369,28 @@ func ResourceVirtualMachineStateGetter(vm *kubevirtv1.VirtualMachine, vmi *kubev Name: vm.Name, ResourceType: constants.ResourceTypeVirtualMachine, States: map[string]interface{}{ - constants.FieldCommonNamespace: vm.Namespace, - constants.FieldCommonName: vm.Name, - constants.FieldCommonDescription: GetDescriptions(vm.Annotations), - constants.FieldCommonTags: GetTags(vm.Labels), - constants.FieldCommonState: vmImporter.State(networkInterface, oldInstanceUID), - constants.FieldVirtualMachineCPU: vmImporter.CPU(), - constants.FieldVirtualMachineMemory: vmImporter.Memory(), - constants.FieldVirtualMachineHostname: vmImporter.HostName(), - constants.FieldVirtualMachineReservedMemory: vmImporter.ReservedMemory(), - constants.FieldVirtualMachineMachineType: vmImporter.MachineType(), - constants.FieldVirtualMachineRunStrategy: string(runStrategy), - constants.FieldVirtualMachineNetworkInterface: networkInterface, - constants.FieldVirtualMachineDisk: disk, - constants.FieldVirtualMachineInput: input, - constants.FieldVirtualMachineTPM: vmImporter.TPM(), - constants.FieldVirtualMachineCloudInit: cloudInit, - constants.FieldVirtualMachineSSHKeys: sshKeys, - constants.FieldVirtualMachineInstanceNodeName: vmImporter.NodeName(), - constants.FieldVirtualMachineEFI: vmImporter.EFI(), - constants.FieldVirtualMachineSecureBoot: vmImporter.SecureBoot(), + constants.FieldCommonNamespace: vm.Namespace, + constants.FieldCommonName: vm.Name, + constants.FieldCommonDescription: GetDescriptions(vm.Annotations), + constants.FieldCommonTags: GetTags(vm.Labels), + constants.FieldCommonState: vmImporter.State(networkInterface, oldInstanceUID), + constants.FieldVirtualMachineCPU: vmImporter.CPU(), + constants.FieldVirtualMachineMemory: vmImporter.Memory(), + constants.FieldVirtualMachineHostname: vmImporter.HostName(), + constants.FieldVirtualMachineReservedMemory: vmImporter.ReservedMemory(), + constants.FieldVirtualMachineMachineType: vmImporter.MachineType(), + constants.FieldVirtualMachineRunStrategy: string(runStrategy), + constants.FieldVirtualMachineNetworkInterface: networkInterface, + constants.FieldVirtualMachineDisk: disk, + constants.FieldVirtualMachineInput: input, + constants.FieldVirtualMachineTPM: vmImporter.TPM(), + constants.FieldVirtualMachineCloudInit: cloudInit, + constants.FieldVirtualMachineSSHKeys: sshKeys, + constants.FieldVirtualMachineInstanceNodeName: vmImporter.NodeName(), + constants.FieldVirtualMachineEFI: vmImporter.EFI(), + constants.FieldVirtualMachineSecureBoot: vmImporter.SecureBoot(), + constants.FieldVirtualMachineCPUPinning: vmImporter.DedicatedCPUPlacement(), + constants.FieldVirtualMachineIsolateEmulatorThread: vmImporter.IsolateEmulatorThread(), }, }, nil }