Skip to content

Commit

Permalink
Unmount ISO when switching CDROM backends for a VM (#920)
Browse files Browse the repository at this point in the history
Unmount ISO when switching CDROM backends for a VM

If the guest OS mounts the virtual cdrom device then vsphere expects
someone to confirm that it should be "unlocked" first.

This is done via a VirtualMachineQuestionInfo object that we need to
find and then respond to via the "AnswerVM" method. We start a goroutine
right before we attempt any VM modifications and signal we're done right
after we're done. If a known question appears in the mean time, we will
send the appropriate answer.
  • Loading branch information
koikonom authored Dec 3, 2019
1 parent 90ff19e commit 861f95e
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package vsphere

import (
"context"
"errors"
"fmt"
"log"
"strings"
"time"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
Expand Down Expand Up @@ -59,6 +61,8 @@ again. For more information on how to do this, see the following page:
https://www.terraform.io/docs/commands/taint.html
`

const questionCheckIntervalSecs = 5

func resourceVSphereVirtualMachine() *schema.Resource {
s := map[string]*schema.Schema{
"resource_pool_id": {
Expand Down Expand Up @@ -553,12 +557,58 @@ func resourceVSphereVirtualMachineUpdate(d *schema.ResourceData, meta interface{
return fmt.Errorf("error shutting down virtual machine: %s", err)
}
}

// Start goroutine here that checks for questions
gChan := make(chan bool)

questions := map[string]string{
"msg.cdromdisconnect.locked": "0",
}
go func() {
// Sleep for a bit
time.Sleep(questionCheckIntervalSecs * time.Second)
for {
select {
case <-gChan:
// We're done
break
default:
vprops, err := virtualmachine.Properties(vm)
if err != nil {
log.Printf("[DEBUG] Error while retrieving VM properties. Error: %s", err)
continue
}
q := vprops.Runtime.Question
if q != nil {
log.Printf("[DEBUG] Question: %#v", q)
if len(q.Message) < 1 {
log.Printf("[DEBUG] No messages found")
continue
}
qMsg := q.Message[0].Id
if response, ok := questions[qMsg]; ok {
if err = vm.Answer(context.TODO(), q.Id, response); err != nil {
log.Printf("[DEBUG] Failed to answer question. Error: %s", err)
break
}
}
} else {
log.Printf("[DEBUG] No questions found")
}
}
}
}()

// Perform updates.
if _, ok := d.GetOk("datastore_cluster_id"); ok {
err = resourceVSphereVirtualMachineUpdateReconfigureWithSDRS(d, meta, vm, spec)
} else {
err = virtualmachine.Reconfigure(vm, spec)
}

// Regardless of the result we no longer need to watch for pending questions.
gChan <- true

if err != nil {
return fmt.Errorf("error reconfiguring virtual machine: %s", err)
}
Expand Down

0 comments on commit 861f95e

Please sign in to comment.