/
vsphere_util.go
187 lines (169 loc) · 6.33 KB
/
vsphere_util.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package vsphere
import (
"context"
"fmt"
"path/filepath"
"regexp"
"strings"
"github.com/libopenstorage/cloudops"
"github.com/libopenstorage/cloudops/vsphere/lib/vsphere/vclib"
"github.com/sirupsen/logrus"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
// VSphereConfig represents the vsphere configuration
// derived from https://github.com/kubernetes/kubernetes/blob/release-1.9/pkg/cloudprovider/providers/vsphere/vsphere_util.go#L94
type VSphereConfig struct {
// User is the vCenter username.
User string
// Password is the vCenter password in clear text.
Password string
// VCenterIP is the vcenter IP to connect on
VCenterIP string
// VCenterPort is the vcenter port to connect on
VCenterPort string
// InsecureFlag True if vCenter uses self-signed cert.
InsecureFlag bool
// RoundTripperCount is the Soap round tripper count (retries = RoundTripper - 1)
RoundTripperCount uint
// VMUUID is the VM Instance UUID of virtual machine which can be retrieved from instanceUuid
// property in VmConfigInfo, or also set as vc.uuid in VMX file.
// If not set, will be fetched from the machine via sysfs (requires root)
VMUUID string
}
// VSphereInstance Represents a vSphere instance where one or more kubernetes nodes are running.
type VSphereInstance struct {
conn *vclib.VSphereConnection
}
var datastoreFolderIDMap = make(map[string]map[string]string)
// VirtualCenterConfig represents Virtual Center configuration
type VirtualCenterConfig struct {
// vCenter username.
User string
// vCenter password in clear text.
Password string
// vCenter port
VCenterPort string
// Datacenter in which VMs are located.
Datacenter string
// Soap round tripper count (retries = RoundTripper - 1)
RoundTripperCount uint
}
// ReadVSphereConfigFromEnv sources vsphere config from well known environment variables
func ReadVSphereConfigFromEnv() (*VSphereConfig, error) {
var cfg VSphereConfig
var err error
cfg.VCenterIP, err = cloudops.GetEnvValueStrict(VCenterEnvKey)
if err != nil {
return nil, err
}
cfg.VCenterPort, err = cloudops.GetEnvValueStrict(VCenterPortEnvKey)
if err != nil {
return nil, err
}
cfg.User, err = cloudops.GetEnvValueStrict(UserEnvKey)
if err != nil {
return nil, err
}
cfg.Password, err = cloudops.GetEnvValueStrict(PasswordEnvKey)
if err != nil {
return nil, err
}
cfg.InsecureFlag = false
insecure, err := cloudops.GetEnvValueStrict(InsecureEnvKey)
if err == nil && strings.ToLower(insecure) == "true" {
cfg.InsecureFlag = true
}
cfg.VMUUID, _ = cloudops.GetEnvValueStrict(VMUUIDEnvKey)
return &cfg, nil
}
// IsDevMode checks if requirement env variables are set to run the pkg outside vsphere in dev mode
func IsDevMode() bool {
_, err := cloudops.GetEnvValueStrict(VMUUIDEnvKey)
if err != nil {
return false
}
_, err = cloudops.GetEnvValueStrict(TestDatastoreEnvKey)
return err == nil
}
// Get canonical volume path for volume Path.
// Borrowed from https://github.com/kubernetes/kubernetes/blob/release-1.10/pkg/cloudprovider/providers/vsphere/vsphere_util.go#L312
// Example1: The canonical path for volume path - [vsanDatastore] kubevols/volume.vmdk will be [vsanDatastore] 25d8b159-948c-4b73-e499-02001ad1b044/volume.vmdk
// Example2: The canonical path for volume path - [vsanDatastore] 25d8b159-948c-4b73-e499-02001ad1b044/volume.vmdk will be same as volume Path.
func getCanonicalVolumePath(ctx context.Context, dc *vclib.Datacenter, volumePath string) (string, error) {
var folderID string
var folderExists bool
canonicalVolumePath := volumePath
dsPathObj, err := vclib.GetDatastorePathObjFromVMDiskPath(volumePath)
if err != nil {
return "", err
}
dsPath := strings.Split(strings.TrimSpace(dsPathObj.Path), "/")
if len(dsPath) <= 1 {
return canonicalVolumePath, nil
}
datastore := dsPathObj.Datastore
dsFolder := dsPath[0]
folderNameIDMap, datastoreExists := datastoreFolderIDMap[datastore]
if datastoreExists {
folderID, folderExists = folderNameIDMap[dsFolder]
}
// Get the datastore folder ID if datastore or folder doesn't exist in datastoreFolderIDMap
if !datastoreExists || !folderExists {
if !vclib.IsValidUUID(dsFolder) {
dummyDiskVolPath := "[" + datastore + "] " + dsFolder + "/" + dummyDiskName
// Querying a non-existent dummy disk on the datastore folder.
// It would fail and return an folder ID in the error message.
_, err := dc.GetVirtualDiskPage83Data(ctx, dummyDiskVolPath)
if err != nil {
re := regexp.MustCompile("File (.*?) was not found")
match := re.FindStringSubmatch(err.Error())
canonicalVolumePath = match[1]
}
}
diskPath := vclib.GetPathFromVMDiskPath(canonicalVolumePath)
if diskPath == "" {
return "", fmt.Errorf("Failed to parse canonicalVolumePath: %s in getcanonicalVolumePath method", canonicalVolumePath)
}
folderID = strings.Split(strings.TrimSpace(diskPath), "/")[0]
setdatastoreFolderIDMap(datastoreFolderIDMap, datastore, dsFolder, folderID)
}
canonicalVolumePath = strings.Replace(volumePath, dsFolder, folderID, 1)
if filepath.Base(datastore) != datastore {
// If datastore is within cluster, add cluster path to the volumePath
canonicalVolumePath = strings.Replace(canonicalVolumePath, filepath.Base(datastore), datastore, 1)
}
return canonicalVolumePath, nil
}
func setdatastoreFolderIDMap(
datastoreFolderIDMap map[string]map[string]string,
datastore string,
folderName string,
folderID string) {
folderNameIDMap := datastoreFolderIDMap[datastore]
if folderNameIDMap == nil {
folderNameIDMap = make(map[string]string)
datastoreFolderIDMap[datastore] = folderNameIDMap
}
folderNameIDMap[folderName] = folderID
}
// GetStoragePodMoList fetches the managed storage pod objects for the given references
//
// Only the properties is the given property list will be populated in the response
func GetStoragePodMoList(
ctx context.Context,
client *vim25.Client,
storagePodRefs []types.ManagedObjectReference,
properties []string) ([]mo.StoragePod, error) {
var storagePodMoList []mo.StoragePod
pc := property.DefaultCollector(client)
err := pc.Retrieve(ctx, storagePodRefs, properties, &storagePodMoList)
if err != nil {
logrus.Errorf("Failed to get Storagepod managed objects from storage pod refs: %+v, properties: %+v, err: %v",
storagePodRefs, properties, err)
return nil, err
}
return storagePodMoList, nil
}