I'm trying to use the govmomi library (https://github.com/vmware/govmomi) to make some automated changes to a VM but I can't seem to get around the nil pointer exceptions on line 134 and 136 for the last few hours. I got it to work at one point but then I'm not sure what I'm doing wrong now as I've tried so many combos but nothing seems to work now...
package main
import (
"context"
"flag"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
"net/url"
"os"
"strings"
"fmt"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vim25/types"
"log"
)
type change struct {
*flags.VirtualMachineFlag
}
const (
envURL = "GOVC_URL"
envUserName = "GOVC_USERNAME"
envPassword = "GOVC_PASSWORD"
envInsecure = "GOVC_INSECURE"
)
// getEnvString returns string from environment variable.
func getEnvString(v string, def string) string {
r := os.Getenv(v)
if r == "" {
return def
}
return r
}
// getEnvBool returns boolean from environment variable.
func getEnvBool(v string, def bool) bool {
r := os.Getenv(v)
if r == "" {
return def
}
switch strings.ToLower(r[0:1]) {
case "t", "y", "1":
return true
}
return false
}
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", getEnvString(envURL, "https://username:password@host"+vim25.Path), urlDescription)
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", getEnvBool(envInsecure, false), insecureDescription)
func processOverride(u *url.URL) {
envUsername := os.Getenv(envUserName)
envPassword := os.Getenv(envPassword)
// Override username if provided
if envUsername != "" {
var password string
var ok bool
if u.User != nil {
password, ok = u.User.Password()
}
if ok {
u.User = url.UserPassword(envUsername, password)
} else {
u.User = url.User(envUsername)
}
}
// Override password if provided
if envPassword != "" {
var username string
if u.User != nil {
username = u.User.Username()
}
u.User = url.UserPassword(username, envPassword)
}
}
func NewClient(ctx context.Context) (*govmomi.Client, error) {
flag.Parse()
// Parse URL from string
u, err := soap.ParseURL(*urlFlag)
if err != nil {
return nil, err
}
// Override username and/or password as required
processOverride(u)
// Connect and log in to ESX or vCenter
return govmomi.NewClient(ctx, u, *insecureFlag)
}
func main() {
ctx := context.Background()
// Connect and login to ESX or vCenter
c, err := NewClient(ctx)
if err != nil {
log.Fatal(err)
}
defer c.Logout(ctx)
var spec *types.VirtualMachineConfigSpec
var cmd *change
var flip bool
flip = false
spec.VPMCEnabled = &flip
vm, err := cmd.VirtualMachine()
task, err := vm.Reconfigure(ctx, *spec)
if err != nil {
println(err)
}
fmt.Println(task.Wait(ctx))
}
the 2 lines that are throwing errors are:
spec.VPMCEnabled = &flip
and
vm, err := cmd.VirtualMachine()
both seem to throw the same panic: runtime error: invalid memory address or nil pointer dereference
. If I comment out the first one throwing the error, the second one throws it then.
I think both are unrelated but I can't quite figure how how to do the dereferencing correctly.
----UPDATE EDIT 1--------------
I made some changes to this with the below response but still can't get around the error on at task, err := vm.Reconfigure(ctx, *spec)
...
package main
import (
"context"
"flag"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
"net/url"
"os"
"strings"
"fmt"
"github.com/vmware/govmomi/vim25/types"
"log"
)
const (
envURL = "GOVC_URL"
envUserName = "GOVC_USERNAME"
envPassword = "GOVC_PASSWORD"
envInsecure = "GOVC_INSECURE"
)
// getEnvString returns string from environment variable.
func getEnvString(v string, def string) string {
r := os.Getenv(v)
if r == "" {
return def
}
return r
}
// getEnvBool returns boolean from environment variable.
func getEnvBool(v string, def bool) bool {
r := os.Getenv(v)
if r == "" {
return def
}
switch strings.ToLower(r[0:1]) {
case "t", "y", "1":
return true
}
return false
}
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", getEnvString(envURL, "https://username:password@host"+vim25.Path), urlDescription)
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", getEnvBool(envInsecure, false), insecureDescription)
func processOverride(u *url.URL) {
envUsername := os.Getenv(envUserName)
envPassword := os.Getenv(envPassword)
// Override username if provided
if envUsername != "" {
var password string
var ok bool
if u.User != nil {
password, ok = u.User.Password()
}
if ok {
u.User = url.UserPassword(envUsername, password)
} else {
u.User = url.User(envUsername)
}
}
// Override password if provided
if envPassword != "" {
var username string
if u.User != nil {
username = u.User.Username()
}
u.User = url.UserPassword(username, envPassword)
}
}
func NewClient(ctx context.Context) (*govmomi.Client, error) {
flag.Parse()
// Parse URL from string
u, err := soap.ParseURL(*urlFlag)
if err != nil {
return nil, err
}
// Override username and/or password as required
processOverride(u)
// Connect and log in to ESX or vCenter
return govmomi.NewClient(ctx, u, *insecureFlag)
}
func main() {
ctx := context.Background()
// Connect and login to ESX or vCenter
c, err := NewClient(ctx)
if err != nil {
log.Fatal(err)
}
defer c.Logout(ctx)
var spec *types.VirtualMachineConfigSpec
spec = new(types.VirtualMachineConfigSpec)
var flip bool
flip = false
spec.VPMCEnabled = &flip
var vm *object.VirtualMachine
vm = new(object.VirtualMachine)
task, err := vm.Reconfigure(ctx, *spec)
if err != nil {
println(err)
}
fmt.Println(task.Wait(ctx))
}
the full error I'm getting is this:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x280 pc=0x14e18f6]
goroutine 1 [running]:
github.com/vmware/govmomi/vim25.(*Client).RoundTrip(0x0, 0x1886f00, 0xc000016088, 0x1884140, 0xc000298720, 0x1884140, 0xc000298740, 0x300, 0x16e8ac0)
/Users/ronakpatel/go/src/github.com/vmware/govmomi/vim25/client.go:89 +0x26
github.com/vmware/govmomi/vim25/methods.ReconfigVM_Task(0x1886f00, 0xc000016088, 0x1884060, 0x0, 0xc0002d0000, 0xc000288000, 0xc000080400, 0x0)
/Users/ronakpatel/go/src/github.com/vmware/govmomi/vim25/methods/methods.go:10879 +0xb8
github.com/vmware/govmomi/object.VirtualMachine.Reconfigure(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1886f00, 0xc000016088, 0x0, ...)
/Users/ronakpatel/go/src/github.com/vmware/govmomi/object/virtual_machine.go:207 +0x19b
main.main()
/Users/ronakpatel/go/src/awesomeProject1/main.go:143 +0x1ec
exit status 2
----UPDATE EDIT 2----------
I changed somethings around and used the answer provided below but now I'm getting the error again but at this part: task, err := vm.Reconfigure(ctx, spec1)
Error:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x153d05a]
goroutine 1 [running]:
main.main()
/Users/ronakpatel/go/src/awesomeProject1/main.go:134 +0x19a
exit status 2
Code:
spec1 := types.VirtualMachineConfigSpec{
VPMCEnabled: &[]bool{false}[0],
}
var vm *object.VirtualMachine
var vmf *flags.VirtualMachineFlag
vmf, ctx = flags.NewVirtualMachineFlag(ctx)
vm, _ = vmf.VirtualMachine()
task, err := vm.Reconfigure(ctx, spec1)
if err != nil {
println(err)
}
fmt.Println(task.Wait(ctx))