Skip to content

Commit fd46ff9

Browse files
authored
Merge pull request #389 from gwang550/gw-dual-stack-support
fix dual stack is not supported
2 parents 22e8563 + 13c8597 commit fd46ff9

File tree

4 files changed

+187
-5
lines changed

4 files changed

+187
-5
lines changed

pkg/cloudprovider/vsphere/cloud.go

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package vsphere
1818

1919
import (
20+
"errors"
2021
"io"
2122
"io/ioutil"
2223
"os"
@@ -198,6 +199,16 @@ func buildVSphereFromConfig(cfg *ccfg.CPIConfig, lbcfg *lcfg.LBConfig) (*VSphere
198199
lb = nil
199200
}
200201

202+
// add alpha dual stack feature
203+
for tenant := range cfg.VirtualCenter {
204+
if len(cfg.VirtualCenter[tenant].IPFamilyPriority) > 1 {
205+
if _, ok := os.LookupEnv("ENABLE_ALPHA_DUAL_STACK"); !ok {
206+
klog.Errorf("number of ip family provided for VCenter %s is 2, ENABLE_ALPHA_DUAL_STACK env var is not set", tenant)
207+
return nil, errors.New("two IP families provided, but dual stack feature is not enabled")
208+
}
209+
}
210+
}
211+
201212
vs := VSphere{
202213
cfg: cfg,
203214
cfgLB: lbcfg,

pkg/cloudprovider/vsphere/nodemanager.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ func (nm *NodeManager) DiscoverNode(nodeID string, searchBy cm.FindVM) error {
267267
// Must break out of loop in the event of ipv6,ipv4 where the NIC does
268268
// contain a valid IPv6 and IPV4 address
269269
for _, family := range ipFamily {
270+
foundInternal = false
271+
foundExternal = false
272+
270273
ips := returnIPsFromSpecificFamily(family, v.IpAddress)
271274

272275
for _, ip := range ips {
@@ -330,7 +333,7 @@ func (nm *NodeManager) DiscoverNode(nodeID string, searchBy cm.FindVM) error {
330333
} else if !foundInternal && foundExternal {
331334
klog.Warning("External address found, but internal address not found. Returning what addresses were discovered.")
332335
}
333-
break
336+
continue
334337
}
335338

336339
// Neither internal or external addresses were found. This defaults to the old
@@ -353,11 +356,11 @@ func (nm *NodeManager) DiscoverNode(nodeID string, searchBy cm.FindVM) error {
353356
foundExternal = true
354357
break
355358
}
356-
}
357-
}
358359

359-
if !foundInternal && !foundExternal {
360-
return fmt.Errorf("unable to find suitable IP address for node %s with IP family %s", nodeID, ipFamily)
360+
if !foundInternal && !foundExternal {
361+
return fmt.Errorf("unable to find suitable IP address for node %s with IP family %s", nodeID, ipFamily)
362+
}
363+
}
361364
}
362365

363366
klog.V(2).Infof("Found node %s as vm=%+v in vc=%s and datacenter=%s",

pkg/cloudprovider/vsphere/nodemanager_test.go

+74
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,80 @@ func TestDiscoverNodeByName(t *testing.T) {
127127
}
128128
}
129129

130+
func TestAlphaDualStack(t *testing.T) {
131+
cfg, ok := configFromEnvOrSim(true)
132+
defer ok()
133+
134+
connMgr := cm.NewConnectionManager(cfg, nil, nil)
135+
defer connMgr.Logout()
136+
137+
ipv4Ip := "10.0.0.1"
138+
ipv6Ip := "fd01:0:101:2609:bdd2:ee20:7bd7:5836"
139+
140+
nm := newNodeManager(nil, connMgr)
141+
142+
vm := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
143+
vm.Guest.HostName = strings.ToLower(vm.Name) // simulator.SearchIndex.FindByDnsName matches against the guest.hostName property
144+
vm.Guest.Net = []vimtypes.GuestNicInfo{
145+
{
146+
Network: "foo-bar",
147+
IpAddress: []string{ipv4Ip, ipv6Ip},
148+
},
149+
}
150+
151+
err := connMgr.Connect(context.Background(), connMgr.VsphereInstanceMap[cfg.Global.VCenterIP])
152+
if err != nil {
153+
t.Errorf("Failed to Connect to vSphere: %s", err)
154+
}
155+
156+
// set config for ip for vc to ipv4, ipv6 (dual-stack)
157+
vcInstance := nm.connectionManager.VsphereInstanceMap[cfg.Global.VCenterIP]
158+
vcInstance.Cfg.IPFamilyPriority = []string{"ipv6", "ipv4"}
159+
160+
name := vm.Name
161+
UUID := vm.Config.Uuid
162+
k8sUUID := ConvertK8sUUIDtoNormal(UUID)
163+
164+
node := &v1.Node{
165+
ObjectMeta: metav1.ObjectMeta{
166+
Name: name,
167+
},
168+
Status: v1.NodeStatus{
169+
NodeInfo: v1.NodeSystemInfo{
170+
SystemUUID: k8sUUID,
171+
},
172+
},
173+
}
174+
175+
// get node registered so node can be exported
176+
nm.RegisterNode(node)
177+
err = nm.DiscoverNode(name, cm.FindVMByName)
178+
if err != nil {
179+
t.Errorf("Failed DiscoverNode: %s", err)
180+
}
181+
182+
nodeList := make([]*pb.Node, 0)
183+
_ = nm.ExportNodes("", "", &nodeList)
184+
185+
ips := nodeList[0].Addresses
186+
187+
ipv4Ips := returnIPsFromSpecificFamily(vcfg.IPv4Family, ips)
188+
size := len(ipv4Ips)
189+
if size != 1 {
190+
t.Errorf("Should only return single IPv4 address. expected: 1, actual: %d", size)
191+
} else if !strings.EqualFold(ipv4Ips[0], ipv4Ip) {
192+
t.Errorf("IPv6 does not match. expected: %s, actual: %s", ipv4Ip, ipv4Ips[0])
193+
}
194+
195+
ipv6Ips := returnIPsFromSpecificFamily(vcfg.IPv6Family, ips)
196+
size = len(ipv6Ips)
197+
if size != 1 {
198+
t.Errorf("Should only return single IPv6 address. expected: 1, actual: %d", size)
199+
} else if !strings.EqualFold(ipv6Ips[0], ipv6Ip) {
200+
t.Errorf("IPv6 does not match. expected: fd01:0:101:2609:bdd2:ee20:7bd7:5836, actual: %s", ipv6Ips[0])
201+
}
202+
}
203+
130204
func TestExport(t *testing.T) {
131205
cfg, ok := configFromEnvOrSim(true)
132206
defer ok()

pkg/cloudprovider/vsphere/vsphere_test.go

+94
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"crypto/tls"
2222
"log"
23+
"os"
2324
"testing"
2425

2526
lookup "github.com/vmware/govmomi/lookup/simulator"
@@ -216,6 +217,99 @@ func TestVSphereLoginByToken(t *testing.T) {
216217
vcInstance.Conn.Logout(ctx)
217218
}
218219

220+
func TestAlphaDualStackConfig(t *testing.T) {
221+
var testCases = []struct {
222+
testName string
223+
conf string
224+
enableDualStackFeature bool
225+
expectedError string
226+
}{
227+
{
228+
testName: "Verifying dual stack env var required when providing two ip families",
229+
conf: `[Global]
230+
user = user
231+
password = password
232+
datacenters = us-west
233+
[VirtualCenter "0.0.0.0"]
234+
user = user
235+
password = password
236+
ip-family = ipv6,ipv4
237+
238+
`,
239+
enableDualStackFeature: false,
240+
expectedError: "two IP families provided, but dual stack feature is not enabled",
241+
},
242+
{
243+
testName: "Verifying dual stack env var existing when providing two ip families",
244+
conf: `[Global]
245+
user = user
246+
password = password
247+
datacenters = us-west
248+
[VirtualCenter "0.0.0.0"]
249+
user = user
250+
password = password
251+
ip-family = ipv6,ipv4
252+
253+
`,
254+
enableDualStackFeature: true,
255+
expectedError: "",
256+
},
257+
{
258+
testName: "Dual stack env var not required when providing single ip family",
259+
conf: `[Global]
260+
user = user
261+
password = password
262+
datacenters = us-west
263+
[VirtualCenter "0.0.0.0"]
264+
user = user
265+
password = password
266+
ip-family = ipv6
267+
268+
`,
269+
enableDualStackFeature: false,
270+
expectedError: "",
271+
},
272+
}
273+
for _, testcase := range testCases {
274+
t.Run(testcase.testName, func(t *testing.T) {
275+
cfg, err := ccfg.ReadCPIConfig([]byte(testcase.conf))
276+
if err != nil {
277+
if testcase.expectedError != "" {
278+
if err.Error() != testcase.expectedError {
279+
t.Fatalf("readConfig: expected err: %s, received err: %s", testcase.expectedError, err)
280+
}
281+
} else {
282+
t.Fatalf("readConfig: unexpected error returned: %v", err)
283+
}
284+
}
285+
286+
if testcase.enableDualStackFeature {
287+
err := os.Setenv("ENABLE_ALPHA_DUAL_STACK", "1")
288+
if err != nil {
289+
t.Fatalf("Received error %s when setting env var ENABLE_ALPHA_DUAL_STACK", err)
290+
}
291+
defer func() {
292+
err := os.Unsetenv("ENABLE_ALPHA_DUAL_STACK")
293+
if err != nil {
294+
t.Fatalf("Received error %s when unsetting env var", err)
295+
}
296+
}()
297+
}
298+
299+
_, err = buildVSphereFromConfig(cfg, nil)
300+
if err != nil {
301+
if testcase.expectedError != "" {
302+
if err.Error() != testcase.expectedError {
303+
t.Fatalf("buildVSphereFromConfig: expected err: %s, receiver err: %s", testcase.expectedError, err)
304+
}
305+
} else {
306+
t.Fatalf("buildVSphereFromConfig: Should succeed when a valid config is provided: %v", err)
307+
}
308+
}
309+
})
310+
}
311+
}
312+
219313
func TestSecretVSphereConfig(t *testing.T) {
220314
var vs *VSphere
221315
var (

0 commit comments

Comments
 (0)