forked from hashicorp/terraform-provider-vsphere
-
Notifications
You must be signed in to change notification settings - Fork 0
/
virtual_disk_helper.go
145 lines (137 loc) · 5.05 KB
/
virtual_disk_helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package virtualdisk
import (
"context"
"fmt"
"log"
"path"
"github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/provider"
"github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/structure"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
// DatastorePathFromString is a convenience method that returns a
// fully-populated DatastorePath from a string containing a datastore path. A
// flag indicating a successful parsing is also returned.
func DatastorePathFromString(p string) (*object.DatastorePath, bool) {
dp := new(object.DatastorePath)
success := dp.FromString(p)
log.Printf("[DEBUG] DatastorePathFromString: success: %t, path: %q", success, p)
return dp, success
}
// IsVmdkDatastorePath ensures that a string can be parsed as a datastore path
// pointing to a virtual disk. This only checks the validity of the path, not
// whether or not the file exists.
func IsVmdkDatastorePath(p string) bool {
dp, success := DatastorePathFromString(p)
if !success {
log.Printf("[DEBUG] IsVmdkDatastorePath: %q is not a datastore path", p)
return false
}
isVMDK := dp.IsVMDK()
log.Printf("[DEBUG] IsVmdkDatastorePath: %q %s a datastore path", p, structure.LogCond(isVMDK, "is", "is not"))
return isVMDK
}
// Move moves a virtual disk from one location to another. The move is not
// forced.
//
// srcPath needs to be a datastore path (ie: "[datastore1] vm/vm.vmdk"),
// however the destination path (dstPath) can be a simple path - if it is, the
// source datastore is used and dstDC is ignored. Further, if dstPath has no
// directory, the directory of srcPath is used. dstDC can be nil if the
// destination datastore is in the same datacenter.
//
// The new datastore path is returned along with any error, to avoid the need
// to re-calculate the path separately.
func Move(client *govmomi.Client, srcPath string, srcDC *object.Datacenter, dstPath string, dstDC *object.Datacenter) (string, error) {
vdm := object.NewVirtualDiskManager(client.Client)
if srcDC == nil {
return "", fmt.Errorf("source datacenter cannot be nil")
}
if !IsVmdkDatastorePath(srcPath) {
return "", fmt.Errorf("path %q is not a datastore path", srcPath)
}
if !IsVmdkDatastorePath(dstPath) {
ddp := dstDataStorePathFromLocalSrc(srcPath, dstPath)
// One more validation
if !IsVmdkDatastorePath(ddp) {
return "", fmt.Errorf("path %q is not a valid destination path", dstPath)
}
dstPath = ddp
dstDC = nil
}
log.Printf("[DEBUG] Moving virtual disk from %q in datacenter %s to destination %s%s",
srcPath,
srcDC,
dstPath,
structure.LogCond(dstDC != nil, fmt.Sprintf("in datacenter %s", dstDC), ""),
)
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
task, err := vdm.MoveVirtualDisk(ctx, srcPath, srcDC, dstPath, dstDC, false)
if err != nil {
return "", err
}
tctx, tcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer tcancel()
if err := task.Wait(tctx); err != nil {
return "", err
}
log.Printf("[DEBUG] Virtual disk %q in datacenter %s successfully moved to destination %s%s",
srcPath,
srcDC,
dstPath,
structure.LogCond(dstDC != nil, fmt.Sprintf("in datacenter %s", dstDC), ""),
)
return dstPath, nil
}
// QueryDiskType queries the disk type of the specified virtual disk.
func QueryDiskType(client *govmomi.Client, name string, dc *object.Datacenter) (types.VirtualDiskType, error) {
vdm := object.NewVirtualDiskManager(client.Client)
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
di, err := vdm.QueryVirtualDiskInfo(ctx, name, dc, false)
if err != nil {
return types.VirtualDiskType(""), err
}
t := di[0].DiskType
log.Printf("[DEBUG] QueryDiskType: Disk %q is of type %q", name, t)
return types.VirtualDiskType(t), nil
}
func dstDataStorePathFromLocalSrc(src, dst string) string {
ddpTmp, success := DatastorePathFromString(dst)
if success {
dst = ddpTmp.Path
}
dstDP, success := DatastorePathFromString(src)
if !success {
panic(fmt.Errorf("dstDataStorePathFromLocalSrc: Expected valid source, got %q", src))
}
if path.Dir(dst) == "." {
dstDP.Path = path.Join(path.Dir(dstDP.Path), dst)
} else {
dstDP.Path = dst
}
return dstDP.String()
}
// Delete deletes the virtual disk at the specified datastore path.
func Delete(client *govmomi.Client, name string, dc *object.Datacenter) error {
if dc == nil {
return fmt.Errorf("datacenter cannot be nil")
}
log.Printf("[DEBUG] Deleting virtual disk %q in datacenter %s", name, dc)
vdm := object.NewVirtualDiskManager(client.Client)
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
task, err := vdm.DeleteVirtualDisk(ctx, name, dc)
if err != nil {
return err
}
tctx, tcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer tcancel()
if err := task.Wait(tctx); err != nil {
return err
}
log.Printf("[DEBUG] Virtual disk %q in datacenter %s deleted succesfully", name, dc)
return nil
}