diff --git a/README.md b/README.md index 475e2d7..80d8b4a 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,8 @@ Known issues with vmware_esxi Version History --------------- +* 1.0.1 Validate DiskStores and refresh +* 1.0.0 First Major release * 0.1.2 Add ability to manage existing Guest VMs. A lot of code cleanup, various fixes, more validation. * 0.1.0 Add virtual_disk resource. * 0.0.8 Add virthwver. diff --git a/esxi/config.go b/esxi/config.go index 8877d49..be63cda 100644 --- a/esxi/config.go +++ b/esxi/config.go @@ -1,8 +1,8 @@ package esxi import ( - //"fmt" - //"log" + "fmt" + "log" ) type Config struct { @@ -13,5 +13,16 @@ type Config struct { } func (c *Config) validateEsxiCreds() error { + esxiSSHinfo := SshConnectionStruct{c.esxiHostName, c.esxiHostPort, c.esxiUserName, c.esxiPassword} + log.Printf("[validateEsxiCreds]\n") + + var remote_cmd string + var err error + + remote_cmd = fmt.Sprintf("vmware --version") + _, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "Connectivity test, get vmware version") + if err != nil { + return fmt.Errorf("Failed to connect to esxi host: %s\n", err) + } return nil } diff --git a/esxi/guest-create.go b/esxi/guest-create.go index 11fe679..4da8659 100644 --- a/esxi/guest-create.go +++ b/esxi/guest-create.go @@ -29,12 +29,12 @@ func guestCREATE(c *Config, guest_name string, disk_store string, // // Check if Disk Store already exists // - remote_cmd = fmt.Sprintf("ls -d \"/vmfs/volumes/%s\"", disk_store) - _, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "check if disk_store already exists.") + err = diskStoreValidate(c, disk_store) if err != nil { - return "", fmt.Errorf("Disk Store does not exists :%s\n", disk_store) + return "", err } + // // Check if guest already exists // @@ -46,7 +46,7 @@ func guestCREATE(c *Config, guest_name string, disk_store string, if vmid != "" { // We don't need to create the VM. It already exists. - fmt.Printf("[provider-esxi] guest %s already exists vmid: \n",guest_name, stdout) + fmt.Printf("[guestCREATE] guest %s already exists vmid: \n",guest_name, stdout) // // Power off guest if it's powered on. @@ -145,7 +145,7 @@ func guestCREATE(c *Config, guest_name string, disk_store string, // // Write vmx file to esxi host // - log.Printf("[provider-esxi] New guest_name.vmx: %s\n", vmx_contents) + log.Printf("[guestCREATE] New guest_name.vmx: %s\n", vmx_contents) dst_vmx_file := fmt.Sprintf("%s/%s.vmx", fullPATH, guest_name) @@ -163,7 +163,7 @@ func guestCREATE(c *Config, guest_name string, disk_store string, } poolID, err := getPoolID(c, resource_pool_name) - log.Println("[provider-esxi] DEBUG: " + poolID) + log.Println("[guestCREATE] DEBUG: " + poolID) if err != nil { log.Printf("Failed to use Resource Pool ID:%s\n", poolID) return "", fmt.Errorf("Failed to use Resource Pool ID:%s\n", poolID) @@ -186,11 +186,11 @@ func guestCREATE(c *Config, guest_name string, disk_store string, "-dm=%s --name='%s' --overwrite -ds='%s' '%s' '%s'",boot_disk_type, guest_name, disk_store, src_path, dst_path) cmd := exec.Command("/bin/bash", "-c", ovf_cmd) - log.Println("[provider-esxi] ovf_cmd: " + ovf_cmd ) + log.Println("[guestCREATE] ovf_cmd: " + ovf_cmd ) cmd.Stdout = &out err = cmd.Run() - log.Printf("[provider-esxi] ovftool output: %q\n", out.String()) + log.Printf("[guestCREATE] ovftool output: %q\n", out.String()) if err != nil { log.Printf("Failed, There was an ovftool Error:%s\n", err.Error()) return "", fmt.Errorf("There was an ovftool Error:%s\n", err.Error()) @@ -203,7 +203,7 @@ func guestCREATE(c *Config, guest_name string, disk_store string, "tail -1", guest_name, guest_name) vmid, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "get vmid") - log.Printf("[provider-esxi] get_vmid_cmd: %s\n", vmid) + log.Printf("[guestCREATE] get_vmid_cmd: %s\n", vmid) if err != nil { log.Printf("Failed get vmid: %s\n", err) return "", fmt.Errorf("Failed get vmid: %s\n", err) diff --git a/esxi/guest-delete.go b/esxi/guest-delete.go index e539822..c46a6d5 100644 --- a/esxi/guest-delete.go +++ b/esxi/guest-delete.go @@ -24,14 +24,14 @@ func resourceGUESTDelete(d *schema.ResourceData, m interface{}) error { // remove storage from vmx so it doesn't get deleted by the vim-cmd destroy err = cleanStorageFromVmx(c, vmid) if err != nil { - log.Printf("[provider-esxi] Failed clean storage from vmid: %s (to be deleted)\n", vmid) + log.Printf("[resourceGUESTDelete] Failed clean storage from vmid: %s (to be deleted)\n", vmid) } remote_cmd = fmt.Sprintf("vim-cmd vmsvc/destroy %s", vmid) stdout, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "vmsvc/destroy") if err != nil { // todo more descriptive err message - log.Printf("[provider-esxi] Failed destroy vmid: %s\n", stdout) + log.Printf("[resourceGUESTDelete] Failed destroy vmid: %s\n", stdout) return err } diff --git a/esxi/guest-read.go b/esxi/guest-read.go index c5751d3..8449595 100644 --- a/esxi/guest-read.go +++ b/esxi/guest-read.go @@ -18,7 +18,7 @@ func resourceGUESTRead(d *schema.ResourceData, m interface{}) error { var power string guest_name, disk_store, disk_size, resource_pool_name, memsize, numvcpus, virthwver, guestos, ip_address, virtual_networks, power, err := guestREAD(c, d.Id(), guest_startup_timeout) - if err != nil { + if err != nil || guest_name == "" { d.SetId("") return nil } @@ -68,6 +68,10 @@ func guestREAD(c *Config, vmid string, guest_startup_timeout int) (string, strin remote_cmd := fmt.Sprintf("vim-cmd vmsvc/get.summary %s", vmid) stdout, err := runRemoteSshCommand(esxiSSHinfo, remote_cmd, "Get Guest summary") + if strings.Contains(stdout, "Unable to find a VM corresponding") { + return "", "", "", "", "", "", "", "", "", virtual_networks, "", nil + } + scanner := bufio.NewScanner(strings.NewReader(stdout)) for scanner.Scan() { switch { @@ -109,8 +113,8 @@ func guestREAD(c *Config, vmid string, guest_startup_timeout int) (string, strin dst_vmx_file = "/vmfs/volumes/" + dst_vmx_ds + "/" + dst_vmx - log.Printf("[provider-esxi] dst_vmx_file: %s\n", dst_vmx_file) - log.Printf("[provider-esxi] disk_store: %s dst_vmx_ds:%s\n", disk_store, dst_vmx_file) + log.Printf("[resourceGUESTRead] dst_vmx_file: %s\n", dst_vmx_file) + log.Printf("[resourceGUESTRead] disk_store: %s dst_vmx_ds:%s\n", disk_store, dst_vmx_file) remote_cmd = fmt.Sprintf("cat \"%s\"", dst_vmx_file) vmx_contents, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "read guest_name.vmx file") @@ -128,26 +132,26 @@ func guestREAD(c *Config, vmid string, guest_startup_timeout int) (string, strin stdout = r.FindString(scanner.Text()) nr = strings.NewReplacer(`"`,"", `"`,"") memsize = nr.Replace(stdout) - log.Printf("[provider-esxi] memsize found: %s\n", memsize) + log.Printf("[resourceGUESTRead] memsize found: %s\n", memsize) case strings.Contains(scanner.Text(),"numvcpus = "): r,_ = regexp.Compile(`\".*\"`) stdout = r.FindString(scanner.Text()) nr = strings.NewReplacer(`"`,"", `"`,"") numvcpus = nr.Replace(stdout) - log.Printf("[provider-esxi] numvcpus found: %s\n", numvcpus) + log.Printf("[resourceGUESTRead] numvcpus found: %s\n", numvcpus) case strings.Contains(scanner.Text(),"virtualHW.version = "): r,_ = regexp.Compile(`\".*\"`) stdout = r.FindString(scanner.Text()) virthwver = strings.Replace(stdout,`"`,"",-1) - log.Printf("[provider-esxi] virthwver found: %s\n", virthwver) + log.Printf("[resourceGUESTRead] virthwver found: %s\n", virthwver) case strings.Contains(scanner.Text(),"guestOS = "): r,_ = regexp.Compile(`\".*\"`) stdout = r.FindString(scanner.Text()) guestos = strings.Replace(stdout,`"`,"",-1) - log.Printf("[provider-esxi] guestos found: %s\n", guestos) + log.Printf("[resourceGUESTRead] guestos found: %s\n", guestos) case strings.Contains(scanner.Text(),"ethernet"): re := regexp.MustCompile("ethernet(.).(.*) = \"(.*)\"") @@ -157,7 +161,7 @@ func guestREAD(c *Config, vmid string, guest_startup_timeout int) (string, strin switch results[2] { case "networkName": virtual_networks[index][0] = results[3] - log.Printf("[provider-esxi] %s : %s\n", results[0], results[3]) + log.Printf("[resourceGUESTRead] %s : %s\n", results[0], results[3]) case "addressType": if results[3] == "generated" { @@ -167,18 +171,18 @@ func guestREAD(c *Config, vmid string, guest_startup_timeout int) (string, strin case "generatedAddress": if isGeneratedMAC[index] == true { virtual_networks[index][1] = results[3] - log.Printf("[provider-esxi] %s : %s\n", results[0], results[3]) + log.Printf("[resourceGUESTRead] %s : %s\n", results[0], results[3]) } case "address": if isGeneratedMAC[index] == false { virtual_networks[index][1] = results[3] - log.Printf("[provider-esxi] %s : %s\n", results[0], results[3]) + log.Printf("[resourceGUESTRead] %s : %s\n", results[0], results[3]) } case "virtualDev": virtual_networks[index][2] = results[3] - log.Printf("[provider-esxi] %s : %s\n", results[0], results[3]) + log.Printf("[resourceGUESTRead] %s : %s\n", results[0], results[3]) } } } diff --git a/esxi/guest_functions.go b/esxi/guest_functions.go index 4fd7623..7e47db1 100644 --- a/esxi/guest_functions.go +++ b/esxi/guest_functions.go @@ -20,7 +20,7 @@ func getBootDiskPath(c *Config, vmid string) (string, error) { remote_cmd = fmt.Sprintf("vim-cmd vmsvc/device.getdevices %s | grep -A10 'key = 2000'|grep -m 1 fileName", vmid) stdout, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "get boot disk") if err != nil { - log.Printf("[provider-esxi] Failed get boot disk path: %s\n", stdout) + log.Printf("[getBootDiskPath] Failed get boot disk path: %s\n", stdout) return "Failed get boot disk path:", err } r := strings.NewReplacer("fileName = \"[", "/vmfs/volumes/", @@ -72,9 +72,12 @@ func updateVmx_contents(c *Config, vmid string, iscreate bool, memsize int, numv vmx_contents, err := readVmx_contents(c, vmid) if err != nil { - log.Printf("[provider-esxi] Failed get vmx contents: %s\n", err) + log.Printf("[updateVmx_contents] Failed get vmx contents: %s\n", err) return err } + if strings.Contains(vmx_contents, "Unable to find a VM corresponding") { + return nil + } // modify memsize if memsize != 0 { @@ -134,12 +137,12 @@ func updateVmx_contents(c *Config, vmid string, iscreate bool, memsize int, numv networkType = "" for i := 0; i < 4; i++ { - log.Printf("[provider-esxi] i: %s\n", i) + log.Printf("[updateVmx_contents] i: %s\n", i) if virtual_networks[i][0] != "" { // Set virtual_network name - log.Printf("[provider-esxi] virtual_networks[i][0]: %s\n", virtual_networks[i][0]) + log.Printf("[updateVmx_contents] virtual_networks[i][0]: %s\n", virtual_networks[i][0]) tmpvar = fmt.Sprintf("ethernet%d.networkName = \"%s\"\n", i, virtual_networks[i][0]) vmx_contents_new = vmx_contents_new + tmpvar @@ -211,7 +214,7 @@ func updateVmx_contents(c *Config, vmid string, iscreate bool, memsize int, numv // Write vmx file to esxi host // vmx_contents = strings.Replace(vmx_contents, "\"", "\\\"", -1) - log.Printf("[provider-esxi] New guest_name.vmx: %s\n", vmx_contents) + log.Printf("[updateVmx_contents] New guest_name.vmx: %s\n", vmx_contents) dst_vmx_file,err := getDst_vmx_file(c, vmid) remote_cmd = fmt.Sprintf("echo \"%s\" >%s", vmx_contents, dst_vmx_file) @@ -230,7 +233,7 @@ func cleanStorageFromVmx(c *Config, vmid string) error { vmx_contents, err := readVmx_contents(c, vmid) if err != nil { - log.Printf("[provider-esxi] Failed get vmx contents: %s\n", err) + log.Printf("[updateVmx_contents] Failed get vmx contents: %s\n", err) return err } @@ -324,6 +327,9 @@ func guestPowerGetState(c *Config, vmid string) string { remote_cmd := fmt.Sprintf("vim-cmd vmsvc/power.getstate %s", vmid) stdout, _ := runRemoteSshCommand(esxiSSHinfo, remote_cmd, "vmsvc/power.getstate") + if strings.Contains(stdout, "Unable to find a VM corresponding") { + return "Unknown" + } if strings.Contains(stdout, "Powered off") == true { return "off" diff --git a/esxi/resource-pool_functions.go b/esxi/resource-pool_functions.go index 1a182d6..e1f3335 100644 --- a/esxi/resource-pool_functions.go +++ b/esxi/resource-pool_functions.go @@ -99,11 +99,11 @@ func resourcePoolRead(c *Config, pool_id string) (string, int, string, int, stri stdout, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "resource pool_config_get") if strings.Contains(stdout, "deleted") == true { - log.Printf("[provider-esxi] Already deleted: %s\n", err) + log.Printf("[resourcePoolRead] Already deleted: %s\n", err) return "", 0, "", 0, "", 0, "", 0, "", nil } if err != nil { - log.Printf("[provider-esxi] Failed to get %s: %s\n", "resource pool_config_get", err) + log.Printf("[resourcePoolRead] Failed to get %s: %s\n", "resource pool_config_get", err) return "", 0, "", 0, "", 0, "", 0, "", errors.New("Failed to get Resource Pool config.") } @@ -165,7 +165,7 @@ func resourcePoolRead(c *Config, pool_id string) (string, int, string, int, stri resource_pool_name, err := getPoolNAME(c, pool_id) if err != nil { - log.Printf("[provider-esxi] Failed to get Resource Pool name: %s\n", err) + log.Printf("[resourcePoolRead] Failed to get Resource Pool name: %s\n", err) return "", 0, "", 0, "", 0, "", 0, "", errors.New("Failed to get Resource Pool name.") } diff --git a/esxi/virtual-disk_create.go b/esxi/virtual-disk_create.go index 3d65ecf..e01fd69 100644 --- a/esxi/virtual-disk_create.go +++ b/esxi/virtual-disk_create.go @@ -45,8 +45,9 @@ func resourceVIRTUALDISKCreate(d *schema.ResourceData, m interface{}) error { if err == nil { d.SetId(virtdisk_id) } else { - log.Println("[provider-esxi] Error: " + err.Error()) + log.Println("[resourceVIRTUALDISKCreate] Error: " + err.Error()) d.SetId("") + return fmt.Errorf("Failed to create virtual Disk :%s\n", virtual_disk_name) } return nil diff --git a/esxi/virtual-disk_functions.go b/esxi/virtual-disk_functions.go index afcb5f1..d77386f 100644 --- a/esxi/virtual-disk_functions.go +++ b/esxi/virtual-disk_functions.go @@ -8,6 +8,43 @@ import ( "errors" ) +// +// Validate Disk Store +// +func diskStoreValidate(c *Config, disk_store string) error { + esxiSSHinfo := SshConnectionStruct{c.esxiHostName, c.esxiHostPort, c.esxiUserName, c.esxiPassword} + log.Printf("[diskStoreValidate]\n") + + var remote_cmd, stdout string + var err error + + // + // Check if Disk Store already exists + // + remote_cmd = fmt.Sprintf("esxcli storage filesystem list | grep '/vmfs/volumes/.*[VMFS|NFS]' | awk '{print $2}'") + stdout, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "Get list of disk stores") + if err != nil { + return fmt.Errorf("Unable to get list of disk stores :%s\n", err) + } + log.Printf("1: Available Disk Stores :%s\n", strings.Replace(stdout, "\n", " ", -1)) + + if strings.Contains(stdout, disk_store) == false { + remote_cmd = fmt.Sprintf("esxcli storage filesystem rescan") + _, _ = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "Refresh filesystems") + + remote_cmd = fmt.Sprintf("esxcli storage filesystem list | grep '/vmfs/volumes/.*[VMFS|NFS]' | awk '{print $2}'") + stdout, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "Get list of disk stores") + if err != nil { + return fmt.Errorf("Unable to get list of disk stores :%s\n", err) + } + log.Printf("2: Available Disk Stores :%s\n", strings.Replace(stdout, "\n", " ", -1)) + + if strings.Contains(stdout, disk_store) == false { + return fmt.Errorf("Disk Store %s does not exist.\nAvailable Disk Stores :%s\n", disk_store, stdout) + } + } + return nil +} // // Create virtual disk @@ -23,10 +60,9 @@ func virtualDiskCREATE(c *Config, virtual_disk_disk_store string, virtual_disk_d // // Validate disk store exists // - remote_cmd = fmt.Sprintf("ls -d \"/vmfs/volumes/%s\"", virtual_disk_disk_store) - _, err = runRemoteSshCommand(esxiSSHinfo, remote_cmd, "validate disk store exists") + err = diskStoreValidate(c, virtual_disk_disk_store) if err != nil { - return "", errors.New("virtual_disk_disk_store does not exist.") + return "", err } // @@ -79,7 +115,7 @@ func growVirtualDisk(c *Config, virtdisk_id string, virtdisk_size string) error newDiskSize, _ = strconv.Atoi(virtdisk_size) - log.Printf("[provider-esxi] currentDiskSize:%d new_size:%d fullPATH: %s\n", currentDiskSize, newDiskSize, virtdisk_id) + log.Printf("[growVirtualDisk] currentDiskSize:%d new_size:%d fullPATH: %s\n", currentDiskSize, newDiskSize, virtdisk_id) if currentDiskSize < newDiskSize { remote_cmd := fmt.Sprintf("/bin/vmkfstools -X %dG \"%s\"", newDiskSize, virtdisk_id) @@ -109,6 +145,9 @@ func virtualDiskREAD(c *Config, virtdisk_id string) (string, string, string, int // Split virtdisk_id into it's variables s = strings.Split(virtdisk_id, "/") log.Printf("[virtualDiskREAD] len=%d cap=%d %v\n", len(s), cap(s), s) + if len(s) < 6 { + return "","","",0,"", nil + } virtual_disk_disk_store = s[3] virtual_disk_dir = s[4] virtual_disk_name = s[5] diff --git a/version b/version index 0ec25f7..b18d465 100644 --- a/version +++ b/version @@ -1 +1 @@ -v1.0.0 +v1.0.1