Skip to content

Commit

Permalink
feat(vm): Wait for the VM creation task to complete (#305)
Browse files Browse the repository at this point in the history
feat(vm): Add sync wait in VM create operation
  • Loading branch information
bpg authored Apr 18, 2023
1 parent d24f60a commit 8addb1d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 10 deletions.
39 changes: 38 additions & 1 deletion proxmox/virtual_environment_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,45 @@ func (c *VirtualEnvironmentClient) CreateVM(
ctx context.Context,
nodeName string,
d *VirtualEnvironmentVMCreateRequestBody,
timeout int,
) error {
return c.DoRequest(ctx, http.MethodPost, fmt.Sprintf("nodes/%s/qemu", url.PathEscape(nodeName)), d, nil)
taskID, err := c.CreateVMAsync(ctx, nodeName, d)
if err != nil {
return err
}

err = c.WaitForNodeTask(ctx, nodeName, *taskID, timeout, 1)

if err != nil {
return fmt.Errorf("error waiting for VM creation: %w", err)
}

return nil
}

// CreateVMAsync creates a virtual machine asynchronously.
func (c *VirtualEnvironmentClient) CreateVMAsync(
ctx context.Context,
nodeName string,
d *VirtualEnvironmentVMCreateRequestBody,
) (*string, error) {
resBody := &VirtualEnvironmentVMCreateResponseBody{}
err := c.DoRequest(
ctx,
http.MethodPost,
fmt.Sprintf("nodes/%s/qemu", url.PathEscape(nodeName)),
d,
resBody,
)
if err != nil {
return nil, err
}

if resBody.Data == nil {
return nil, errors.New("the server did not include a data object in the response")
}

return resBody.Data, nil
}

// DeleteVM deletes a virtual machine.
Expand Down
4 changes: 4 additions & 0 deletions proxmox/virtual_environment_vm_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ type VirtualEnvironmentVMCreateRequestBody struct {
WatchdogDevice *CustomWatchdogDevice `json:"watchdog,omitempty" url:"watchdog,omitempty"`
}

type VirtualEnvironmentVMCreateResponseBody struct {
Data *string `json:"data,omitempty"`
}

// VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseBody contains the body from a QEMU get network interfaces response.
type VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseBody struct {
Data *VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseData `json:"data,omitempty"`
Expand Down
12 changes: 3 additions & 9 deletions proxmoxtf/resource/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ const (
mkResourceVirtualEnvironmentVMVGAType = "type"
mkResourceVirtualEnvironmentVMVMID = "vm_id"
mkResourceVirtualEnvironmentVMSCSIHardware = "scsi_hardware"

vmCreateTimeoutSeconds = 10
)

func VM() *schema.Resource {
Expand Down Expand Up @@ -2072,21 +2074,13 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
createBody.PoolID = &poolID
}

err = veClient.CreateVM(ctx, nodeName, createBody)
err = veClient.CreateVM(ctx, nodeName, createBody, vmCreateTimeoutSeconds)
if err != nil {
return diag.FromErr(err)
}

d.SetId(strconv.Itoa(vmID))

// NOTE: The VM creation is not atomic, and not synchronous. This means that the VM might not be
// available immediately after the creation, or its state reported by the API might not be
// up to date. This is a problem for the following operations, which rely on the VM information
// returned by API calls, particularly read-back to populate the Terraform state.
// Would it be possible to wait for the VM to be fully available, or to wait for the API to report
// the correct state?
// time.Sleep(5 * time.Second)

return vmCreateCustomDisks(ctx, d, m)
}

Expand Down

0 comments on commit 8addb1d

Please sign in to comment.