-
Notifications
You must be signed in to change notification settings - Fork 178
/
config.go
304 lines (264 loc) · 8.51 KB
/
config.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
klog "k8s.io/klog/v2"
)
/*
TODO:
When the INI based cloud-config is deprecated, this functions below should be preserved
*/
func getEnvKeyValue(match string, partial bool) (string, string, error) {
for _, e := range os.Environ() {
pair := strings.Split(e, "=")
if len(pair) != 2 {
continue
}
key := pair[0]
value := pair[1]
if partial && strings.Contains(key, match) {
return key, value, nil
}
if strings.Compare(key, match) == 0 {
return key, value, nil
}
}
matchType := "match"
if partial {
matchType = "partial match"
}
return "", "", fmt.Errorf("Failed to find %s with %s", matchType, match)
}
// FromEnv initializes the provided configuratoin object with values
// obtained from environment variables. If an environment variable is set
// for a property that's already initialized, the environment variable's value
// takes precedence.
func (cfg *Config) FromEnv() error {
//Init
if cfg.VirtualCenter == nil {
cfg.VirtualCenter = make(map[string]*VirtualCenterConfig)
}
//Globals
if v := os.Getenv("VSPHERE_VCENTER"); v != "" {
cfg.Global.VCenterIP = v
}
if v := os.Getenv("VSPHERE_VCENTER_PORT"); v != "" {
cfg.Global.VCenterPort = v
}
if v := os.Getenv("VSPHERE_USER"); v != "" {
cfg.Global.User = v
}
if v := os.Getenv("VSPHERE_PASSWORD"); v != "" {
cfg.Global.Password = v
}
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
cfg.Global.Datacenters = v
}
if v := os.Getenv("VSPHERE_SECRET_NAME"); v != "" {
cfg.Global.SecretName = v
}
if v := os.Getenv("VSPHERE_SECRET_NAMESPACE"); v != "" {
cfg.Global.SecretNamespace = v
}
if v := os.Getenv("VSPHERE_ROUNDTRIP_COUNT"); v != "" {
tmp, err := strconv.ParseUint(v, 10, 32)
if err != nil {
klog.Errorf("Failed to parse VSPHERE_ROUNDTRIP_COUNT: %s", err)
} else {
cfg.Global.RoundTripperCount = uint(tmp)
}
}
if v := os.Getenv("VSPHERE_INSECURE"); v != "" {
InsecureFlag, err := strconv.ParseBool(v)
if err != nil {
klog.Errorf("Failed to parse VSPHERE_INSECURE: %s", err)
} else {
cfg.Global.InsecureFlag = InsecureFlag
}
}
if v := os.Getenv("VSPHERE_SECRETS_DIRECTORY"); v != "" {
cfg.Global.SecretsDirectory = v
}
if cfg.Global.SecretsDirectory == "" {
cfg.Global.SecretsDirectory = DefaultSecretDirectory
}
if _, err := os.Stat(cfg.Global.SecretsDirectory); os.IsNotExist(err) {
cfg.Global.SecretsDirectory = "" //Dir does not exist, set to empty string
}
if v := os.Getenv("VSPHERE_CAFILE"); v != "" {
cfg.Global.CAFile = v
}
if v := os.Getenv("VSPHERE_THUMBPRINT"); v != "" {
cfg.Global.Thumbprint = v
}
if v := os.Getenv("VSPHERE_LABEL_REGION"); v != "" {
cfg.Labels.Region = v
}
if v := os.Getenv("VSPHERE_LABEL_ZONE"); v != "" {
cfg.Labels.Zone = v
}
//Build VirtualCenter from ENVs
for _, e := range os.Environ() {
pair := strings.Split(e, "=")
if len(pair) != 2 {
continue
}
key := pair[0]
value := pair[1]
if strings.HasPrefix(key, "VSPHERE_VCENTER_") && len(value) > 0 {
id := strings.TrimPrefix(key, "VSPHERE_VCENTER_")
vcenter := value
_, username, errUsername := getEnvKeyValue("VCENTER_"+id+"_USERNAME", false)
if errUsername != nil {
username = cfg.Global.User
}
_, password, errPassword := getEnvKeyValue("VCENTER_"+id+"_PASSWORD", false)
if errPassword != nil {
password = cfg.Global.Password
}
_, server, errServer := getEnvKeyValue("VCENTER_"+id+"_SERVER", false)
if errServer != nil {
server = ""
}
_, port, errPort := getEnvKeyValue("VCENTER_"+id+"_PORT", false)
if errPort != nil {
port = cfg.Global.VCenterPort
}
insecureFlag := false
_, insecureTmp, errInsecure := getEnvKeyValue("VCENTER_"+id+"_INSECURE", false)
if errInsecure != nil {
insecureFlagTmp, errTmp := strconv.ParseBool(insecureTmp)
if errTmp == nil {
insecureFlag = insecureFlagTmp
}
}
_, datacenters, errDatacenters := getEnvKeyValue("VCENTER_"+id+"_DATACENTERS", false)
if errDatacenters != nil {
datacenters = cfg.Global.Datacenters
}
roundtrip := DefaultRoundTripperCount
_, roundtripTmp, errRoundtrip := getEnvKeyValue("VCENTER_"+id+"_ROUNDTRIP", false)
if errRoundtrip != nil {
roundtripFlagTmp, errTmp := strconv.ParseUint(roundtripTmp, 10, 32)
if errTmp == nil {
roundtrip = uint(roundtripFlagTmp)
}
}
_, caFile, errCaFile := getEnvKeyValue("VCENTER_"+id+"_CAFILE", false)
if errCaFile != nil {
caFile = cfg.Global.CAFile
}
_, thumbprint, errThumbprint := getEnvKeyValue("VCENTER_"+id+"_THUMBPRINT", false)
if errThumbprint != nil {
thumbprint = cfg.Global.Thumbprint
}
_, secretName, secretNameErr := getEnvKeyValue("VCENTER_"+id+"_SECRET_NAME", false)
_, secretNamespace, secretNamespaceErr := getEnvKeyValue("VCENTER_"+id+"_SECRET_NAMESPACE", false)
if secretNameErr != nil || secretNamespaceErr != nil {
secretName = ""
secretNamespace = ""
}
secretRef := DefaultCredentialManager
if secretName != "" && secretNamespace != "" {
secretRef = vcenter
}
iPFamilyPriority := []string{DefaultIPFamily}
_, ipFamily, errIPFamily := getEnvKeyValue("VCENTER_"+id+"_IP_FAMILY", false)
if errIPFamily != nil {
iPFamilyPriority = []string{ipFamily}
}
// If server is explicitly set, that means the vcenter value above is the TenantRef
vcenterIP := vcenter
tenantRef := vcenter
if server != "" {
vcenterIP = server
tenantRef = vcenter
}
var vcc *VirtualCenterConfig
if cfg.VirtualCenter[tenantRef] != nil {
vcc = cfg.VirtualCenter[tenantRef]
} else {
vcc = &VirtualCenterConfig{}
cfg.VirtualCenter[tenantRef] = vcc
}
vcc.User = username
vcc.Password = password
vcc.TenantRef = tenantRef
vcc.VCenterIP = vcenterIP
vcc.VCenterPort = port
vcc.InsecureFlag = insecureFlag
vcc.Datacenters = datacenters
vcc.RoundTripperCount = roundtrip
vcc.CAFile = caFile
vcc.Thumbprint = thumbprint
vcc.SecretRef = secretRef
vcc.SecretName = secretName
vcc.SecretNamespace = secretNamespace
vcc.IPFamilyPriority = iPFamilyPriority
}
}
return nil
}
/*
TODO:
When the INI based cloud-config is deprecated, the references to the
INI based code (ie the call to ReadConfigINI) below should be deleted.
*/
// ReadConfig parses vSphere cloud config file and stores it into VSphereConfig.
// Environment variables are also checked
func ReadConfig(byConfig []byte) (*Config, error) {
var cfg *Config
if len(byConfig) == 0 {
return nil, fmt.Errorf("Invalid YAML/INI file")
}
// Check to see if yaml file before calling parser to prevent unnecessary error messages.
yamlErr := isConfigYaml(byConfig)
if yamlErr == nil {
cfg, yamlErr = ReadConfigYAML(byConfig)
// ReadConfigYAML can fail for other config errors not related to YAML. So it is ok for yamlErr == nil initially
// and a new error occurs after read.
if yamlErr != nil {
klog.Errorf("ReadConfigYAML failed: %s", yamlErr)
return nil, yamlErr
}
klog.V(4).Info("ReadConfig YAML succeeded")
} else {
klog.V(4).Infof("YAML not detected. Attempting INI config load.")
var iniErr error
cfg, iniErr = ReadConfigINI(byConfig)
if iniErr != nil {
var cfgErr Err
if errors.As(iniErr, &cfgErr) {
// This error means it was valid INI but something was wrong w/ the config
return nil, iniErr
}
// If we are here, YAML and INI failed. Create an error with both failure messages so user can review to determine cause
klog.Errorf("ReadConfigYAML failed: %v", yamlErr)
klog.Errorf("ReadConfigINI failed: %v", iniErr)
return nil, fmt.Errorf("ReadConfig failed. YAML=[%v], INI=[%v]", yamlErr, iniErr)
}
klog.Info("ReadConfig INI succeeded. INI-based cloud-config is deprecated and will be removed in 2.0. Please use YAML based cloud-config.")
}
// Env Vars should override config file entries if present
if err := cfg.FromEnv(); err != nil {
klog.Errorf("FromEnv failed: %s", err)
return nil, err
}
klog.Info("Config initialized")
return cfg, nil
}